Example #1
0
def _process_request_body(environ, tiddler):
    """
    Read request body to set tiddler content.

    If a serializer exists for the content type, use it,
    otherwise treat the content as binary or pseudo-binary
    tiddler.
    """
    length, content_type = content_length_and_type(environ)
    content = read_request_body(environ, length)

    try:
        try:
            serialize_type = get_serialize_type(environ)[0]
            serializer = Serializer(serialize_type, environ)
            # Short circuit de-serialization attempt to avoid
            # decoding content multiple times.
            if hasattr(serializer.serialization, 'as_tiddler'):
                serializer.object = tiddler
                try:
                    serializer.from_string(content.decode('utf-8'))
                except TiddlerFormatError as exc:
                    raise HTTP400('unable to put tiddler: %s' % exc)
            else:
                raise NoSerializationError()
        except NoSerializationError:
            tiddler.type = content_type
            if pseudo_binary(tiddler.type):
                tiddler.text = content.decode('utf-8')
            else:
                tiddler.text = content
    except UnicodeDecodeError as exc:
        raise HTTP400('unable to decode tiddler, utf-8 expected: %s' % exc)
Example #2
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = web.get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type or
                mime_type.startswith(tiddler.type) or
                extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
    except (TiddlerFormatError, NoSerializationError), exc:
        raise HTTP415(exc)
Example #3
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is.
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')
    serialized = False

    # If this is a tiddler with a CANONICAL_URI_FIELD redirect
    # there unless we are requesting a json form
    if (CANONICAL_URI_FIELD in tiddler.fields
            and not CANONICAL_URI_PASS_TYPE in mime_type):
        raise HTTP302(tiddler.fields[CANONICAL_URI_FIELD])

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type or
                mime_type.startswith(tiddler.type) or
                extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type, serialized

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
        serialized = True
    except (TiddlerFormatError, NoSerializationError) as exc:
        raise HTTP415(exc)
    return content, mime_type, serialized
Example #4
0
def send_entity(environ, start_response, entity):
    """
    Send a bag or recipe out HTTP, first serializing to
    the correct type.
    """
    username = environ['tiddlyweb.usersign']['name']
    try:
        serialize_type, mime_type = get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = entity
        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % mime_type)

    etag_string = '"%s"' % (sha(_entity_etag(entity) +
        encode_name(username) + encode_name(mime_type)).hexdigest())

    start_response("200 OK",
            [('Content-Type', mime_type),
                ('ETag', etag_string),
                ('Vary', 'Accept')])

    if isinstance(content, basestring):
        return [content]
    else:
        return content
Example #5
0
def list(environ, start_response):
    """
    List all the bags that the current user can read.
    """
    store = environ["tiddlyweb.store"]
    bags = store.list_bags()
    kept_bags = []
    for bag in bags:
        try:
            bag.skinny = True
            bag = store.get(bag)
            bag.policy.allows(environ["tiddlyweb.usersign"], "read")
            kept_bags.append(bag)
        except (UserRequiredError, ForbiddenError):
            pass

    try:
        serialize_type, mime_type = web.get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)

        content = serializer.list_bags(kept_bags)

    except NoSerializationError:
        raise HTTP415("Content type not supported: %s" % mime_type)

    start_response("200 OK", [("Content-Type", mime_type)])

    return [content]
Example #6
0
def _process_request_body(environ, tiddler):
    """
    Read request body to set tiddler content.

    If a serializer exists for the content type, use it,
    otherwise treat the content as binary or pseudo-binary
    tiddler.
    """
    length, content_type = content_length_and_type(environ)
    content = read_request_body(environ, length)

    try:
        try:
            serialize_type = get_serialize_type(environ)[0]
            serializer = Serializer(serialize_type, environ)
            # Short circuit de-serialization attempt to avoid
            # decoding content multiple times.
            if hasattr(serializer.serialization, 'as_tiddler'):
                serializer.object = tiddler
                try:
                    serializer.from_string(content.decode('utf-8'))
                except TiddlerFormatError as exc:
                    raise HTTP400('unable to put tiddler: %s' % exc)
            else:
                raise NoSerializationError()
        except NoSerializationError:
            tiddler.type = content_type
            if pseudo_binary(tiddler.type):
                tiddler.text = content.decode('utf-8')
            else:
                tiddler.text = content
    except UnicodeDecodeError as exc:
        raise HTTP400('unable to decode tiddler, utf-8 expected: %s' % exc)
Example #7
0
def put(environ, start_response):
    """
    Put a bag to the server, meaning the description and
    policy of the bag, if policy allows.
    """
    bag_name = web.get_route_value(environ, 'bag_name')
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ['tiddlyweb.store']
    length = environ['CONTENT_LENGTH']

    usersign = environ['tiddlyweb.usersign']

    try:
        bag = store.get(bag)
        bag.policy.allows(usersign, 'manage')
    except NoBagError:
        create_policy_check(environ, 'bag', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = environ['wsgi.input'].read(int(length))
        serializer.from_string(content.decode('utf-8'))

        bag.policy.owner = usersign['name']

        _validate_bag(environ, bag)
        store.put(bag)
    except BagFormatError, exc:
        raise HTTP400('unable to put bag: %s' % exc)
def send_entity(environ, start_response, entity):
    """
    Send a bag or recipe out HTTP, first serializing to
    the correct type. If the incoming etag matches, raise
    304.
    """
    etag_string = entity_etag(environ, entity)
    incoming_etag = environ.get('HTTP_IF_NONE_MATCH', None)
    if incoming_etag:
        if incoming_etag == etag_string:
            raise HTTP304(incoming_etag)

    try:
        serialize_type, mime_type = get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = entity
        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % mime_type)

    start_response("200 OK",
            [('Content-Type', mime_type),
                ('Cache-Control', 'no-cache'),
                ('ETag', etag_string),
                ('Vary', 'Accept')])

    if isinstance(content, basestring):
        return [content]
    else:
        return content
Example #9
0
def _validate_tiddler_list(environ, tiddlers):
    """
    Do Etag and Last modified checks on the
    collection of tiddlers.

    If ETag testing is done, no last modified handling
    is done, even if the ETag testing fails.

    If no 304 is raised, then just return last-modified
    and ETag for the caller to use in constructing
    its HTTP response.
    """
    last_modified_string = http_date_from_timestamp(tiddlers.modified)
    last_modified = ('Last-Modified', last_modified_string)

    username = environ.get('tiddlyweb.usersign', {}).get('name', '')

    try:
        _, mime_type = get_serialize_type(environ)
        mime_type = mime_type.split(';', 1)[0].strip()
    except TypeError:
        mime_type = ''
    etag_string = '"%s:%s"' % (tiddlers.hexdigest(),
            sha('%s:%s' % (username.encode('utf-8'), mime_type)).hexdigest())
    etag = ('Etag', etag_string)

    incoming_etag = check_incoming_etag(environ, etag_string)
    if not incoming_etag:  # only check last modified when no etag
        check_last_modified(environ, last_modified_string)

    return last_modified, etag
Example #10
0
File: bag.py Project: tup/tiddlyweb
def put(environ, start_response):
    """
    Put a bag to the server, meaning the description and
    policy of the bag, if policy allows.
    """
    bag_name = web.get_route_value(environ, 'bag_name')
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ['tiddlyweb.store']
    length, _ = web.content_length_and_type(environ)

    usersign = environ['tiddlyweb.usersign']

    try:
        bag = store.get(bag)
        bag.policy.allows(usersign, 'manage')
    except NoBagError:
        create_policy_check(environ, 'bag', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = web.read_request_body(environ, length)
        serializer.from_string(content.decode('utf-8'))

        bag.policy.owner = usersign['name']

        _validate_bag(environ, bag)
        store.put(bag)
    except BagFormatError, exc:
        raise HTTP400('unable to put bag: %s' % exc)
Example #11
0
def send_entity(environ, start_response, entity):
    """
    Send a bag or recipe out HTTP, first serializing to
    the correct type.
    """
    username = environ['tiddlyweb.usersign']['name']
    try:
        serialize_type, mime_type = get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = entity
        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % mime_type)

    etag_string = '"%s"' % (sha(
        _entity_etag(entity) + encode_name(username) +
        encode_name(mime_type)).hexdigest())

    start_response("200 OK", [('Content-Type', mime_type),
                              ('ETag', etag_string), ('Vary', 'Accept')])

    if isinstance(content, basestring):
        return [content]
    else:
        return content
Example #12
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is.
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type, accept = get_serialize_type(environ,
                                                           accept_type=True)
    extension = environ.get('tiddlyweb.extension')
    serialized = False

    # If this is a tiddler with a CANONICAL_URI_FIELD redirect
    # there unless we are requesting a json form
    if (CANONICAL_URI_FIELD in tiddler.fields
            and CANONICAL_URI_PASS_TYPE not in mime_type):
        raise HTTP302(tiddler.fields[CANONICAL_URI_FIELD])

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type
                or accept.startswith(tiddler.type) or extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type, serialized

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
        serialized = True
    except (TiddlerFormatError, NoSerializationError) as exc:
        raise HTTP415(exc)
    return content, mime_type, serialized
Example #13
0
def send_entity(environ, start_response, entity):
    """
    Send a bag or recipe out HTTP, first serializing to
    the correct type. If the incoming etag matches, raise
    304.
    """
    etag_string = entity_etag(environ, entity)
    incoming_etag = environ.get('HTTP_IF_NONE_MATCH', None)
    if incoming_etag:
        if incoming_etag == etag_string:
            raise HTTP304(incoming_etag)

    try:
        serialize_type, mime_type = get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = entity
        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % mime_type)

    start_response("200 OK", [('Content-Type', mime_type),
                              ('Cache-Control', 'no-cache'),
                              ('ETag', etag_string), ('Vary', 'Accept')])

    if isinstance(content, basestring):
        return [content]
    else:
        return content
Example #14
0
def get(environ, start_response):
    """
    Get a representation in some serialization of
    a bag (the bag itself not the tiddlers within).
    """
    bag_name = _determine_bag_name(environ)
    bag_name = web.handle_extension(environ, bag_name)
    bag = _get_bag(environ, bag_name, True)

    bag.policy.allows(environ['tiddlyweb.usersign'], 'manage')

    try:
        serialize_type, mime_type = web.get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag

        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type not supported: %s' % mime_type)

    start_response("200 Ok",
            [('Content-Type', mime_type),
                ('Vary', 'Accept')])

    return [content]
Example #15
0
def _generate_response(content, environ, start_response):
    serialize_type, mime_type = web.get_serialize_type(environ)  # XXX: not suitable here!?
    cache_header = ("Cache-Control", "no-cache")  # ensure accessing latest HEAD revision
    content_header = ("Content-Type", mime_type)  # XXX: should be determined by diff format
    response = [cache_header, content_header]
    start_response("200 OK", response)
    return [content]
Example #16
0
def send_entity(environ, start_response, entity):
    """
    Send a :py:class:`bag <tiddlyweb.model.bag.Bag>` or :py:class:`recipe
    <tiddlyweb.model.recipe.Recipe>` out over HTTP, first
    :py:class:`serializing <tiddlyweb.serializer.Serializer>` to
    the correct type. If an incoming ``Etag`` validates, raise a
    ``304`` response.
    """
    etag_string = entity_etag(environ, entity)
    check_incoming_etag(environ, etag_string)

    try:
        serialize_type, mime_type = get_serialize_type(environ)
        serializer = Serializer(serialize_type, environ)
        serializer.object = entity
        content = serializer.to_string()
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % mime_type)

    start_response("200 OK",
            [('Content-Type', mime_type),
                ('Cache-Control', 'no-cache'),
                ('ETag', etag_string),
                ('Vary', 'Accept')])

    if isinstance(content, basestring):
        return [content]
    else:
        return content
Example #17
0
def send_tiddlers(environ, start_response, bag):
    """
    Output the tiddlers contained in the provided
    bag in a Negotiated representation. Often, but
    not always, a wiki.
    """
    last_modified = None
    etag = None
    bags_tiddlers = bag.list_tiddlers()
    download = environ['tiddlyweb.query'].get('download', [None])[0]

    if bags_tiddlers:
        last_modified, etag = _validate_tiddler_list(environ, bags_tiddlers)
    else:
        raise HTTP404('No tiddlers in container')

    serialize_type, mime_type = get_serialize_type(environ)
    serializer = Serializer(serialize_type, environ)

    content_header = ('Content-Type', mime_type)
    cache_header = ('Cache-Control', 'no-cache')
    response = [content_header, cache_header]

    if serialize_type == 'wiki':
        if download:
            response.append(('Content-Disposition',
                'attachment; filename="%s"' % download))
    if last_modified:
        response.append(last_modified)
    if etag:
        response.append(etag)

    output = serializer.list_tiddlers(bag)
    start_response("200 OK", response)
    return [output]
Example #18
0
def _get_tiddler_content(environ, tiddler):
    """
    Extract the content of the tiddler, either straight up if
    the content is not considered text, or serialized if it is
    """
    config = environ['tiddlyweb.config']
    default_serializer = config['default_serializer']
    default_serialize_type = config['serializers'][default_serializer][0]
    serialize_type, mime_type = web.get_serialize_type(environ)
    extension = environ.get('tiddlyweb.extension')

    if not renderable(tiddler, environ):
        if (serialize_type == default_serialize_type
                or mime_type.startswith(tiddler.type) or extension == 'html'):
            mime_type = tiddler.type
            content = tiddler.text
            return content, mime_type

    serializer = Serializer(serialize_type, environ)
    serializer.object = tiddler

    try:
        content = serializer.to_string()
    except (TiddlerFormatError, NoSerializationError), exc:
        raise HTTP415(exc)
Example #19
0
def _validate_tiddler_list(environ, tiddlers):
    """
    Do Etag and Last modified checks on the
    collection of tiddlers.

    If ETag testing is done, no last modified handling
    is done, even if the ETag testing fails.

    If no 304 is raised, then just return last-modified
    and ETag for the caller to use in constructing
    its HTTP response.
    """
    last_modified_string = http_date_from_timestamp(tiddlers.modified)
    last_modified = ('Last-Modified', last_modified_string)

    username = environ.get('tiddlyweb.usersign', {}).get('name', '')

    try:
        _, mime_type = get_serialize_type(environ)
        mime_type = mime_type.split(';', 1)[0].strip()
    except TypeError:
        mime_type = ''
    etag_string = '"%s:%s"' % (tiddlers.hexdigest(),
                               sha('%s:%s' %
                                   (username, mime_type)).hexdigest())
    etag = ('Etag', etag_string)

    incoming_etag = check_incoming_etag(environ,
                                        etag_string,
                                        last_modified=last_modified_string)
    if not incoming_etag:  # only check last modified when no etag
        check_last_modified(environ, last_modified_string, etag=etag_string)

    return last_modified, etag
Example #20
0
def put(environ, start_response):
    """
    Put a bag to the server, meaning the description and
    policy of the bag, if policy allows.
    """
    bag_name = _determine_bag_name(environ)
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ["tiddlyweb.store"]
    length = environ["CONTENT_LENGTH"]

    usersign = environ["tiddlyweb.usersign"]

    try:
        bag = store.get(bag)
        bag.policy.allows(usersign, "manage")
    except NoBagError:
        create_policy_check(environ, "bag", usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = environ["wsgi.input"].read(int(length))
        serializer.from_string(content.decode("utf-8"))

        bag.policy.owner = usersign["name"]

        _validate_bag(environ, bag)
        store.put(bag)
    except BagFormatError, exc:
        raise HTTP400("unable to put bag: %s" % exc)
Example #21
0
def list_bags(environ, start_response):
    """
    List all the bags that the current user can read.
    """
    store = environ["tiddlyweb.store"]
    serialize_type, mime_type = web.get_serialize_type(environ)
    serializer = Serializer(serialize_type, environ)
    return list_entities(environ, start_response, mime_type, store.list_bags, serializer.list_bags)
Example #22
0
def list_recipes(environ, start_response):
    """
    Get a list of all recipes the current user can read.
    """
    store = environ['tiddlyweb.store']
    serialize_type, mime_type = web.get_serialize_type(environ)
    serializer = Serializer(serialize_type, environ)
    return list_entities(environ, start_response, mime_type,
                         store.list_recipes, serializer.list_recipes)
Example #23
0
def list_recipes(environ, start_response):
    """
    Get a list of all recipes the current user can read.
    """
    store = environ['tiddlyweb.store']
    serialize_type, mime_type = web.get_serialize_type(environ)
    serializer = Serializer(serialize_type, environ)
    return list_entities(environ, start_response, mime_type, store.list_recipes,
            serializer.list_recipes)
def _is_html_out(environ, status):
    if environ['REQUEST_METHOD'] == 'GET':
        try:
            _, mime_type = get_serialize_type(environ)
            return (not status.startswith('3') and
                    'html' in mime_type)
        except HTTP415:
            return False
    else:
        return False
Example #25
0
def replacement_root_handler(environ, start_response):
    """
    Check if we want HAL, if so send it, otherwise
    do the default.
    """
    _, mime_type = get_serialize_type(environ)
    if 'application/hal+json' in mime_type:
        return _hal_root(environ, start_response)
    else:
        return ORIGINAL_ROOT_HANDLER(environ, start_response)
Example #26
0
def get_space_tiddlers(environ, start_response):
    """
    Get the tiddlers that make up the current space in
    whatever the reqeusted representation is. Choose recipe
    based on membership status.
    """
    _setup_friendly_environ(environ)
    serializer, _ = get_serialize_type(environ)

    _extra_query_update(environ)

    return get_tiddlers(environ, start_response)
Example #27
0
def send_tiddlers(environ, start_response, tiddlers=None):
    """
    Output the :py:class:`tiddlers <tiddlyweb.model.tiddler.Tiddler>`
    contained in the provided :py:class:`Tiddlers collection
    <tiddlyweb.model.collections.Tiddlers>` in a :py:mod:`Negotiated
    <tiddlyweb.web.negotiate>` representation.
    """
    download = environ['tiddlyweb.query'].get('download', [None])[0]
    filters = environ['tiddlyweb.filters']
    store = environ['tiddlyweb.store']

    if tiddlers.store is None and not filters:
        LOGGER.warn('Incoming tiddlers no store set %s', inspect.stack()[1])

    if filters:
        candidate_tiddlers = _filter_tiddlers(filters, store, tiddlers)
    else:
        candidate_tiddlers = tiddlers

    last_modified, etag = _validate_tiddler_list(environ, candidate_tiddlers)

    serialize_type, mime_type = get_serialize_type(environ, collection=True)

    response = [('Content-Type', mime_type),
            ('Cache-Control', 'no-cache'),
            ('Vary', 'Accept')]

    if download:
        response.append(('Content-Disposition',
            'attachment; filename="%s"' % encode_name(download)))

    if last_modified:
        response.append(last_modified)

    if etag:
        response.append(etag)

    try:
        serializer = Serializer(serialize_type, environ)
        output = serializer.list_tiddlers(candidate_tiddlers)
    except NoSerializationError as exc:
        raise HTTP415('Content type not supported: %s:%s, %s' %
                (serialize_type, mime_type, exc))
    except FilterError as exc:  # serializations may filter tildders
        raise HTTP400('malformed filter or tiddler during filtering: %s' % exc)

    start_response("200 OK", response)

    if isinstance(output, basestring):
        return [output]
    else:
        return output
Example #28
0
def serve_space(environ, start_response, http_host):
    """
    Serve a space determined from the current virtual host and user.
    The user determines whether the recipe uses is public or private.
    """
    space_name = determine_space(environ, http_host)
    recipe_name = determine_space_recipe(environ, space_name)
    environ['wsgiorg.routing_args'][1]['recipe_name'] = recipe_name.encode(
        'UTF-8')
    _, mime_type = get_serialize_type(environ)
    if 'text/html' in mime_type:
        environ['tiddlyweb.type'] = 'text/x-tiddlywiki'
    return get_tiddlers(environ, start_response)
Example #29
0
def serve_space(environ, start_response, http_host):
    """
    Serve a space determined from the current virtual host and user.
    The user determines whether the recipe uses is public or private.
    """
    space_name = determine_space(environ, http_host)
    recipe_name = determine_space_recipe(environ, space_name)
    environ['wsgiorg.routing_args'][1]['recipe_name'] = recipe_name.encode(
            'UTF-8')
    _, mime_type = get_serialize_type(environ)
    if 'text/html' in mime_type:
        environ['tiddlyweb.type'] = 'text/x-tiddlywiki'
    return get_tiddlers(environ, start_response)
Example #30
0
def send_tiddlers(environ, start_response, tiddlers=None):
    """
    Output the :py:class:`tiddlers <tiddlyweb.model.tiddler.Tiddler>`
    contained in the provided :py:class:`Tiddlers collection
    <tiddlyweb.model.collections.Tiddlers>` in a :py:mod:`Negotiated
    <tiddlyweb.web.negotiate>` representation.
    """
    download = environ['tiddlyweb.query'].get('download', [None])[0]
    filters = environ['tiddlyweb.filters']
    store = environ['tiddlyweb.store']

    if tiddlers.store is None and not filters:
        LOGGER.warn('Incoming tiddlers no store set %s', inspect.stack()[1])

    if filters:
        candidate_tiddlers = _filter_tiddlers(filters, store, tiddlers)
    else:
        candidate_tiddlers = tiddlers

    last_modified, etag = _validate_tiddler_list(environ, candidate_tiddlers)

    serialize_type, mime_type = get_serialize_type(environ, collection=True)

    response = [('Content-Type', mime_type), ('Cache-Control', 'no-cache'),
                ('Vary', 'Accept')]

    if download:
        response.append(('Content-Disposition',
                         'attachment; filename="%s"' % encode_name(download)))

    if last_modified:
        response.append(last_modified)

    if etag:
        response.append(etag)

    try:
        serializer = Serializer(serialize_type, environ)
        output = serializer.list_tiddlers(candidate_tiddlers)
    except NoSerializationError as exc:
        raise HTTP415('Content type not supported: %s:%s, %s' %
                      (serialize_type, mime_type, exc))
    except FilterError as exc:  # serializations may filter tildders
        raise HTTP400('malformed filter or tiddler during filtering: %s' % exc)

    start_response("200 OK", response)

    if isinstance(output, basestring):
        return [output]
    else:
        return output
Example #31
0
def _tiddler_etag(environ, tiddler):
    """
    Calculate the ETAG of a tiddler, based on
    bag name, tiddler title and revision.
    """
    try:
        mime_type = web.get_serialize_type(environ)[1]
        mime_type = mime_type.split(';', 1)[0].strip()
    except (TypeError, AttributeError):
        mime_type = tiddler.type or ''
    username = environ.get('tiddlyweb.usersign', {}).get('name', '')
    digest = sha('%s:%s' % (username, mime_type)).hexdigest()
    return str('"%s/%s/%s;%s"' % (web.encode_name(tiddler.bag),
        web.encode_name(tiddler.title), tiddler.revision, digest))
Example #32
0
def put(environ, start_response):
    """
    Handle ``PUT`` on a single recipe URI.

    Put a :py:class:`recipe <tiddlyweb.model.recipe.Recipe>` to the server,
    meaning the description, policy and recipe list of the recipe,
    if :py:class:`policy <tiddlyweb.model.policy.Policy>` allows.
    """
    recipe_name = web.get_route_value(environ, 'recipe_name')
    recipe_name = web.handle_extension(environ, recipe_name)

    recipe = Recipe(recipe_name)
    store = environ['tiddlyweb.store']
    length, _ = web.content_length_and_type(environ)

    usersign = environ['tiddlyweb.usersign']

    try:
        recipe = store.get(recipe)
        recipe.policy.allows(usersign, 'manage')
    except NoRecipeError:
        create_policy_check(environ, 'recipe', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
    except TypeError:
        raise HTTP400('Content-type header required')

    try:
        serializer = Serializer(serialize_type, environ)
        serializer.object = recipe
        content = web.read_request_body(environ, length)
        serializer.from_string(content.decode('utf-8'))

        recipe.policy.owner = usersign['name']

        _validate_recipe(environ, recipe)
        store.put(recipe)
    except RecipeFormatError as exc:
        raise HTTP400('unable to put recipe: %s' % exc)
    except TypeError as exc:
        raise HTTP400('malformed input: %s' % exc)
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % serialize_type)

    start_response("204 No Content",
                   [('Location', web.recipe_url(environ, recipe))])

    return []
Example #33
0
def put(environ, start_response):
    """
    Handle ``PUT`` on a single recipe URI.

    Put a :py:class:`recipe <tiddlyweb.model.recipe.Recipe>` to the server,
    meaning the description, policy and recipe list of the recipe,
    if :py:class:`policy <tiddlyweb.model.policy.Policy>` allows.
    """
    recipe_name = web.get_route_value(environ, 'recipe_name')
    recipe_name = web.handle_extension(environ, recipe_name)

    recipe = Recipe(recipe_name)
    store = environ['tiddlyweb.store']
    length, _ = web.content_length_and_type(environ)

    usersign = environ['tiddlyweb.usersign']

    try:
        recipe = store.get(recipe)
        recipe.policy.allows(usersign, 'manage')
    except NoRecipeError:
        create_policy_check(environ, 'recipe', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
    except TypeError:
        raise HTTP400('Content-type header required')

    try:
        serializer = Serializer(serialize_type, environ)
        serializer.object = recipe
        content = web.read_request_body(environ, length)
        serializer.from_string(content.decode('utf-8'))

        recipe.policy.owner = usersign['name']

        _validate_recipe(environ, recipe)
        store.put(recipe)
    except RecipeFormatError as exc:
        raise HTTP400('unable to put recipe: %s' % exc)
    except TypeError as exc:
        raise HTTP400('malformed input: %s' % exc)
    except NoSerializationError:
        raise HTTP415('Content type %s not supported' % serialize_type)

    start_response("204 No Content",
            [('Location', web.recipe_url(environ, recipe))])

    return []
Example #34
0
def get_space_tiddlers(environ, start_response):
    """
    Get the tiddlers that make up the current space in
    whatever the reqeusted representation is. Choose recipe
    based on membership status.
    """
    space_name = _setup_friendly_environ(environ)
    serializer, _ = get_serialize_type(environ)
    # If we are a wiki read ServerSettings, but ignore index
    if ('betaserialization' in serializer
            or 'betalazyserialization' in serializer):
        _, lazy = update_space_settings(environ, space_name)
        if lazy:
            environ['tiddlyweb.type'] = 'text/x-ltiddlywiki'
    return get_tiddlers(environ, start_response)
Example #35
0
def get_space_tiddlers(environ, start_response):
    """
    Get the tiddlers that make up the current space in
    whatever the reqeusted representation is. Choose recipe
    based on membership status.
    """
    space_name = _setup_friendly_environ(environ)
    serializer, _ = get_serialize_type(environ)
    # If we are a wiki read ServerSettings, but ignore index
    if ('betaserialization' in serializer
            or 'betalazyserialization' in serializer):
        _, lazy = update_space_settings(environ, space_name)
        if lazy:
            environ['tiddlyweb.type'] = 'text/x-ltiddlywiki'
    return get_tiddlers(environ, start_response)
Example #36
0
def _tiddler_etag(environ, tiddler):
    """
    Calculate the ETAG of a tiddler, based on
    bag name, tiddler title and revision.
    """
    try:
        mime_type = web.get_serialize_type(environ)[1]
        mime_type = mime_type.split(';', 1)[0].strip()
    except (TypeError, AttributeError):
        mime_type = tiddler.type or ''
    username = environ.get('tiddlyweb.usersign', {}).get('name', '')
    digest = sha('%s:%s' % (username, mime_type)).hexdigest()
    return str('"%s/%s/%s;%s"' %
               (web.encode_name(tiddler.bag), web.encode_name(
                   tiddler.title), tiddler.revision, digest))
Example #37
0
def _validate_tiddler_list(environ, bag):
    """
    Calculate the Last modified and ETag for
    the tiddlers in bag. If the ETag matches an
    incoming If-None-Match, then raise a 304 and
    don't send the tiddler content. If the modified
    string in an If-Modified-Since is newer than the
    last-modified on the tiddlers, raise 304.

    If ETag testing is done, no last modified handling
    is done, even if the ETag testing fails.

    If no 304 is raised, then just return last-modified
    and ETag for the caller to use in constructing
    its HTTP response.
    """
    last_modified_number = _last_modified_tiddler(bag)
    last_modified = None
    if last_modified_number:
        last_modified_string = http_date_from_timestamp(last_modified_number)
        last_modified = ("Last-Modified", last_modified_string)

    username = environ.get("tiddlyweb.usersign", {}).get("name", "")

    try:
        serialize_type, mime_type = get_serialize_type(environ)
        mime_type = mime_type.split(";", 1)[0].strip()
    except TypeError:
        mime_type = ""
    etag_string = '"%s:%s;%s"' % (
        _sha_tiddler_titles(bag),
        last_modified_number,
        sha("%s:%s" % (username, mime_type)).hexdigest(),
    )
    etag = ("Etag", etag_string)

    incoming_etag = environ.get("HTTP_IF_NONE_MATCH", None)
    if incoming_etag:
        if incoming_etag == etag_string:
            raise HTTP304(incoming_etag)
    else:
        incoming_modified = environ.get("HTTP_IF_MODIFIED_SINCE", None)
        if incoming_modified and (
            datetime_from_http_date(incoming_modified) >= datetime_from_http_date(last_modified_string)
        ):
            raise HTTP304("")

    return last_modified, etag
Example #38
0
def profile(environ, start_response):
    """
    Choose between an atom or html profile.
    """
    http_host, host_url = determine_host(environ)
    if http_host != host_url:
        # Or should it be a 302?
        raise HTTP404('No profiles at this host: %s' % http_host)

    _, mime_type = get_serialize_type(environ)
    if 'atom' in mime_type:
        return atom_profile(environ, start_response)
    elif 'html' in mime_type:
        return html_profile(environ, start_response)
    else:
        raise HTTP415('Atom and HTML only')
Example #39
0
def profile(environ, start_response):
    """
    Choose between an atom or html profile.
    """
    http_host, host_url = determine_host(environ)
    if http_host != host_url:
        # Or should it be a 302?
        raise HTTP404('No profiles at this host: %s' % http_host)

    _, mime_type = get_serialize_type(environ)
    if 'atom' in mime_type:
        return atom_profile(environ, start_response)
    elif 'html' in mime_type:
        return html_profile(environ, start_response)
    else:
        raise HTTP415('Atom and HTML only')
Example #40
0
 def _check_etag(self, environ, url):
     if '/bags/' in url:
         try:
             etag = environ['HTTP_IF_NONE_MATCH']
             content_type = get_serialize_type(environ)[1]
             content_type = content_type.split(';', 1)[0]
             username = environ['tiddlyweb.usersign']['name']
             key = '%s:%s:%s' % (url, content_type, username)
             found_etag = ETAGS.get(str(key))
             logging.debug('checking etag: %s:%s:%s' %
                           (etag, key, found_etag))
             if etag == found_etag:
                 logging.debug('etag match in cache: %s:%s' % (etag, key))
                 raise HTTP304(found_etag)
         except KeyError:
             pass  # no etag just carry on with normal processing
     return  # etags didn't match we carry on
Example #41
0
def _put_tiddler(environ, start_response, tiddler):
    """
    The guts of putting a tiddler into the store.
    """
    store = environ['tiddlyweb.store']
    length = environ['CONTENT_LENGTH']

    content_type = environ['tiddlyweb.type']

    if content_type != 'text/plain' and content_type != 'application/json':
        tiddler.type = content_type

    try:
        bag = Bag(tiddler.bag)
        try:
            try:
                revision = store.list_tiddler_revisions(tiddler)[0]
            except StoreMethodNotImplemented:
                revision = 1
            tiddler.revision = revision
            # These both next will raise exceptions if
            # the contraints don't match.
            _check_bag_constraint(environ, bag, 'write')
            _validate_tiddler(environ, tiddler)
        except NoTiddlerError:
            _check_bag_constraint(environ, bag, 'create')

        content = environ['wsgi.input'].read(int(length))

        if not tiddler.type:
            serialize_type = web.get_serialize_type(environ)[0]
            serializer = Serializer(serialize_type, environ)
            serializer.object = tiddler
            serializer.from_string(content.decode('UTF-8'))
        else:
            tiddler.text = content

        user = environ['tiddlyweb.usersign']['name']
        if not user == 'GUEST':
            tiddler.modifier = user

        store.put(tiddler)
    except NoBagError, exc:
        raise HTTP409("Unable to put tiddler, %s. There is no bag named: " \
                "%s (%s). Create the bag." %
                (tiddler.title, tiddler.bag, exc))
Example #42
0
def put(environ, start_response):
    """
    Put a bag to the server, meaning the description and
    policy of the bag, if policy allows.
    """
    bag_name = _determine_bag_name(environ)
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ['tiddlyweb.store']
    length = environ['CONTENT_LENGTH']

    usersign = environ['tiddlyweb.usersign']

    try:
        bag.skinny = True
        bag = store.get(bag)
        bag.policy.allows(usersign, 'manage')
        try:
            delattr(bag, 'skinny')
        except AttributeError:
            pass
    except NoBagError:
        create_policy_check(environ, 'bag', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = environ['wsgi.input'].read(int(length))
        serializer.from_string(content.decode('utf-8'))

        bag.policy.owner = usersign['name']

        _validate_bag(environ, bag)
        store.put(bag)
    except TypeError:
        raise HTTP400('Content-type header required')
    except NoSerializationError:
        raise HTTP415('Content type not supported: %s' % serialize_type)

    start_response("204 No Content",
            [('Location', web.bag_url(environ, bag))])

    return []
Example #43
0
def put(environ, start_response):
    """
    Handle ``PUT`` on a single bag URI.

    Put a :py:class:`bag <tiddlyweb.model.bag.Bag>` to the server,
    meaning the description and policy of the bag, if :py:class:`policy
    <tiddlyweb.model.policy.Policy>` allows.
    """
    bag_name = web.get_route_value(environ, 'bag_name')
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ['tiddlyweb.store']
    length, _ = web.content_length_and_type(environ)

    usersign = environ['tiddlyweb.usersign']

    try:
        bag = store.get(bag)
        bag.policy.allows(usersign, 'manage')
    except NoBagError:
        create_policy_check(environ, 'bag', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = web.read_request_body(environ, length)
        serializer.from_string(content.decode('utf-8'))

        bag.policy.owner = usersign['name']

        _validate_bag(environ, bag)
        store.put(bag)
    except BagFormatError as exc:
        raise HTTP400('unable to put bag: %s' % exc)
    except TypeError:
        raise HTTP400('Content-type header required')
    except NoSerializationError:
        raise HTTP415('Content type not supported: %s' % serialize_type)

    start_response("204 No Content",
            [('Location', web.bag_url(environ, bag))])

    return []
Example #44
0
def put(environ, start_response):
    """
    Handle ``PUT`` on a single bag URI.

    Put a :py:class:`bag <tiddlyweb.model.bag.Bag>` to the server,
    meaning the description and policy of the bag, if :py:class:`policy
    <tiddlyweb.model.policy.Policy>` allows.
    """
    bag_name = web.get_route_value(environ, 'bag_name')
    bag_name = web.handle_extension(environ, bag_name)

    bag = Bag(bag_name)
    store = environ['tiddlyweb.store']
    length, _ = web.content_length_and_type(environ)

    usersign = environ['tiddlyweb.usersign']

    try:
        bag = store.get(bag)
        bag.policy.allows(usersign, 'manage')
    except NoBagError:
        create_policy_check(environ, 'bag', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
        serializer = Serializer(serialize_type, environ)
        serializer.object = bag
        content = web.read_request_body(environ, length)
        serializer.from_string(content.decode('utf-8'))

        bag.policy.owner = usersign['name']

        _validate_bag(environ, bag)
        store.put(bag)
    except BagFormatError as exc:
        raise HTTP400('unable to put bag: %s' % exc)
    except TypeError:
        raise HTTP400('Content-type header required')
    except NoSerializationError:
        raise HTTP415('Content type not supported: %s' % serialize_type)

    start_response("204 No Content", [('Location', web.bag_url(environ, bag))])

    return []
Example #45
0
def list_entities(environ, start_response, method_name,
        store_list=None, serializer_list=None):
    """
    Get a list of all the bags or recipes the current user can read.
    """
    store = environ['tiddlyweb.store']
    serialize_type, mime_type = get_serialize_type(environ, collection=True)
    serializer = Serializer(serialize_type, environ)
    filters = environ['tiddlyweb.filters']
    if method_name:
        if not store_list:
            store_list = getattr(store, method_name)
        if not serializer_list:
            serializer_list = getattr(serializer, method_name)

    try:
        kept_entities = _filter_readable(environ, store_list(), filters)
    except FilterError, exc:
        raise HTTP400(exc)
Example #46
0
def list_entities(environ,
                  start_response,
                  method_name,
                  store_list=None,
                  serializer_list=None):
    """
    Get an optionally :py:mod:`filtered <tiddlyweb.filters>` list
    of all the :py:class:`bags <tiddlyweb.model.bag.Bag>` or
    :py:class:`recipes <tiddlyweb.model.recipe.Recipe>`
    the current ``tiddlyweb.usersign`` can read.
    """
    store = environ['tiddlyweb.store']
    serialize_type, mime_type = get_serialize_type(environ, collection=True)
    serializer = Serializer(serialize_type, environ)
    filters = environ['tiddlyweb.filters']
    if method_name:
        if not store_list:
            store_list = getattr(store, method_name)
        if not serializer_list:
            serializer_list = getattr(serializer, method_name)

    try:
        kept_entities = _filter_readable(environ, store_list(), filters)
    except FilterError as exc:
        raise HTTP400(exc)

    etag_string = '"%s:%s"' % (kept_entities.hexdigest(),
                               sha(mime_type).hexdigest())
    check_incoming_etag(environ, etag_string)

    try:
        output = serializer_list(kept_entities)
    except NoSerializationError:
        raise HTTP415('Content type not supported: %s' % mime_type)

    start_response("200 OK", [('Content-Type', mime_type), ('Vary', 'Accept'),
                              ('Cache-Control', 'no-cache'),
                              ('Etag', etag_string)])

    if isinstance(output, basestring):
        return [output]
    else:
        return output
Example #47
0
def send_tiddlers(environ, start_response, tiddlers=None):
    """
    Output the tiddlers contained in the provided
    Tiddlers collection in a Negotiated representation.
    Often, but not always, a wiki.
    """
    download = environ['tiddlyweb.query'].get('download', [None])[0]
    filters = environ['tiddlyweb.filters']
    store = environ['tiddlyweb.store']

    if tiddlers.store is None and not filters:
        LOGGER.warn('Incoming tiddlers no store set %s', inspect.stack()[1])

    if filters:
        candidate_tiddlers = _filter_tiddlers(filters, store, tiddlers)
    else:
        candidate_tiddlers = tiddlers

    last_modified, etag = _validate_tiddler_list(environ, candidate_tiddlers)

    serialize_type, mime_type = get_serialize_type(environ, collection=True)

    response = [('Content-Type', mime_type),
            ('Cache-Control', 'no-cache'),
            ('Vary', 'Accept')]

    if download:
        response.append(('Content-Disposition',
            'attachment; filename="%s"' % download.encode('utf-8')))

    if last_modified:
        response.append(last_modified)

    if etag:
        response.append(etag)

    try:
        serializer = Serializer(serialize_type, environ)
        output = serializer.list_tiddlers(candidate_tiddlers)
    except NoSerializationError, exc:
        raise HTTP415('Content type not supported: %s:%s, %s' %
                (serialize_type, mime_type, exc))
Example #48
0
def _validate_tiddler_list(environ, tiddlers):
    """
    Do Etag and Last modified checks on the
    collection of tiddlers.

    If ETag testing is done, no last modified handling
    is done, even if the ETag testing fails.

    If no 304 is raised, then just return last-modified
    and ETag for the caller to use in constructing
    its HTTP response.
    """
    last_modified_number = tiddlers.modified
    last_modified_string = http_date_from_timestamp(last_modified_number)
    last_modified = ('Last-Modified', last_modified_string)

    username = environ.get('tiddlyweb.usersign', {}).get('name', '')

    try:
        _, mime_type = get_serialize_type(environ)
        mime_type = mime_type.split(';', 1)[0].strip()
    except TypeError:
        mime_type = ''
    etag_string = '"%s:%s;%s"' % (tiddlers.hexdigest(),
                                  str(last_modified_number),
                                  sha('%s:%s' %
                                      (username, mime_type)).hexdigest())
    etag = ('Etag', etag_string)

    incoming_etag = environ.get('HTTP_IF_NONE_MATCH', None)
    if incoming_etag:
        if incoming_etag == etag_string:
            raise HTTP304(incoming_etag)
    else:
        incoming_modified = environ.get('HTTP_IF_MODIFIED_SINCE', None)
        if incoming_modified and \
                (datetime_from_http_date(incoming_modified) >= \
                datetime_from_http_date(last_modified_string)):
            raise HTTP304('')

    return last_modified, etag
Example #49
0
def put(environ, start_response):
    """
    Put a new recipe to the server.
    """
    recipe_name = environ['wsgiorg.routing_args'][1]['recipe_name']
    recipe_name = urllib.unquote(recipe_name)
    recipe_name = unicode(recipe_name, 'utf-8')
    recipe_name = web.handle_extension(environ, recipe_name)

    recipe = Recipe(recipe_name)
    store = environ['tiddlyweb.store']
    length = environ['CONTENT_LENGTH']

    usersign = environ['tiddlyweb.usersign']

    try:
        recipe = store.get(recipe)
        recipe.policy.allows(usersign, 'manage')
    except NoRecipeError:
        create_policy_check(environ, 'recipe', usersign)

    try:
        serialize_type = web.get_serialize_type(environ)[0]
    except TypeError:
        raise HTTP400('Content-type header required')

    try:
        serializer = Serializer(serialize_type, environ)
        serializer.object = recipe
        content = environ['wsgi.input'].read(int(length))
        serializer.from_string(content.decode('utf-8'))

        recipe.policy.owner = usersign['name']

        _validate_recipe(environ, recipe)
        store.put(recipe)
    except RecipeFormatError, exc:
        raise HTTP400('unable to put recipe: %s' % exc)
Example #50
0
    def _handle_core_request(self, environ, req_uri, start_response):
        """
        Override a core request, adding filters or sending 404s where
        necessary to limit the view of entities.

        filtering can be disabled with a custom HTTP header X-ControlView set
        to false
        """
        http_host, host_url = determine_host(environ)

        disable_ControlView = environ.get('HTTP_X_CONTROLVIEW') == 'false'
        if http_host != host_url and not disable_ControlView:
            space_name = determine_space(environ, http_host)
            if space_name == None:
                return None
            recipe_name = determine_space_recipe(environ, space_name)
            store = environ['tiddlyweb.store']
            try:
                recipe = store.get(Recipe(recipe_name))
            except NoRecipeError, exc:
                raise HTTP404('No recipe for space: %s', exc)

            space = Space(space_name)

            template = recipe_template(environ)
            bags = space.extra_bags()
            for bag, _ in recipe.get_recipe(template):
                bags.append(bag)
            bags.extend(ADMIN_BAGS)

            search_string = None
            if req_uri.startswith('/recipes') and req_uri.count('/') == 1:
                serialize_type, mime_type = get_serialize_type(environ)
                serializer = Serializer(serialize_type, environ)

                if recipe_name == space.private_recipe():
                    recipes = space.list_recipes()
                else:
                    recipes = [space.public_recipe()]

                def lister():
                    for recipe in recipes:
                        yield Recipe(recipe)

                return list_entities(environ, start_response, mime_type,
                                     lister, serializer.list_recipes)

            elif req_uri.startswith('/bags') and req_uri.count('/') == 1:
                serialize_type, mime_type = get_serialize_type(environ)
                serializer = Serializer(serialize_type, environ)

                def lister():
                    for bag in bags:
                        yield Bag(bag)

                return list_entities(environ, start_response, mime_type,
                                     lister, serializer.list_bags)

            elif req_uri.startswith('/search') and req_uri.count('/') == 1:
                search_string = ' OR '.join(['bag:%s' % bag for bag in bags])
            else:
                entity_name = urllib.unquote(
                    req_uri.split('/')[2]).decode('utf-8')
                if '/recipes/' in req_uri:
                    valid_recipes = space.list_recipes()
                    if entity_name not in valid_recipes:
                        raise HTTP404(
                            'recipe %s not found due to ControlView' %
                            entity_name)
                else:
                    if entity_name not in bags:
                        raise HTTP404('bag %s not found due to ControlView' %
                                      entity_name)

            if search_string:
                search_query = environ['tiddlyweb.query'].get('q', [''])[0]
                environ['tiddlyweb.query.original'] = search_query
                if search_query:
                    search_query = '%s AND (%s)' % (search_query,
                                                    search_string)
                    environ['tiddlyweb.query']['q'][0] = search_query
                else:
                    search_query = '(%s)' % search_string
                    environ['tiddlyweb.query']['q'] = [search_query]
Example #51
0
        candidate_tiddlers = control.get_tiddlers_from_recipe(recipe, environ)
    except NoBagError, exc:
        raise HTTP404('recipe %s lists an unknown bag: %s' %
                (recipe.name, exc))
    tiddlers_to_send = Tiddlers()
    for tiddler in candidate_tiddlers:
        if not tiddler.store:
            tiddler = store.get(tiddler)
        if tiddler.bag not in [recipe_bag for
                recipe_bag, _ in Space.CORE_RECIPE]:
            if 'systemConfig' in tiddler.tags:
                tiddler.tags.append('systemConfigDisable')
        tiddler.recipe = recipe.name
        tiddlers_to_send.add(tiddler)

    _, mime_type = get_serialize_type(environ)
    if 'text/html' in mime_type or 'x-www-form' in environ['tiddlyweb.type']:
        environ['tiddlyweb.type'] = 'text/x-tiddlywiki'
    return send_tiddlers(environ, start_response, tiddlers=tiddlers_to_send)


def _delete_duplicates(environ, titles, recipe_name, space_name):
    store = environ['tiddlyweb.store']
    try:
        recipe = store.get(Recipe(recipe_name))
        template = control.recipe_template(environ)
        recipe_list = recipe.get_recipe(template)
        space_bags = [bag for bag, _ in recipe_list
                if bag.startswith('%s_' % space_name)]
        for title in titles:
            for bag in space_bags:
Example #52
0
    # We have to deserialize the tiddler here so that
    # PUTs to recipes are aware of values like tags when
    # doing filter checks.
    if environ['REQUEST_METHOD'] == 'PUT':
        length, content_type = _length_and_type(environ)
        content = environ['wsgi.input'].read(int(length))

        try:
            try:
                # XXX HACK! We don't want to decode content unless
                # the serializer has a as_tiddler. We should be able
                # to just rely on NoSerializationError, but we need
                # to call the method to do that, and to call the method we
                # need to decode the string...
                serialize_type = web.get_serialize_type(environ)[0]
                serializer = Serializer(serialize_type, environ)
                serializer.object = tiddler
                try:
                    serializer.from_string(content.decode('utf-8'))
                except TiddlerFormatError, exc:
                    raise HTTP400('unable to put tiddler: %s' % exc)
            except NoSerializationError:
                tiddler.type = content_type
                if pseudo_binary(tiddler.type):
                    tiddler.text = content.decode('utf-8')
                else:
                    tiddler.text = content
        except UnicodeDecodeError, exc:
            raise HTTP400('unable to decode tiddler, utf-8 expected: %s', exc)