示例#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)
示例#2
0
def do_user_auth(environ, start_response):
    """
    Consumer authorization for the sake of a user.

    If no `code` is present then we send the user to the
    auth uri of the selected provider. If there is a code
    then we use that to get an access token, then use that
    access token to get some information about the user
    at the provider.

    XXX: Save the access token for later use.
    """

    query = environ['tiddlyweb.query']
    config = environ['tiddlyweb.config']

    code = query.get('code', [None])[0]
    error = query.get('error', [None])[0]
    server_name = query.get('server_name', [None])[0]
    redirect_uri = query.get('tiddlyweb_redirect', [None])[0]

    if not server_name:
        raise HTTP400('invalid request, server_name required')

    # initial redirect
    if not code and not error:
        raise HTTP302(get_auth_uri(config, server_name, redirect_uri))

    response_map = config['oauth.servers'][server_name].get('response_map')

    output = []
    if code:
        try:
            credentials, http = get_credentials(config, server_name, code)
        except OAuthError as exc:
            raise HTTP400('credentials failure: %s' % exc)

        credentials.authorize(http)
        response, content = http.request(
            config['oauth.servers'][server_name]['info_uri'])
        if response['status'] == '200':
            if response_map:
                return _do_login_or_register(environ, start_response,
                                             server_name, response_map,
                                             content)
            else:
                output.append('code: %s\n' % code)
                output.append(content)
        else:
            output.append('Unable to reach info_uri')

    if error:
        output.append('error: %s\n' % error)

    start_response('200 OK', [('Content-Type', 'text-plain')])
    return output
示例#3
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 []
示例#4
0
def forge(environ, start_response):
    """
    Handle a post to create a new tank.
    """
    query = environ['tiddlyweb.query']
    usersign = environ['tiddlyweb.usersign']

    try:
        tank_name = query['name'][0]
        tank_policy = query['policy_type'][0]
    except KeyError:
        raise HTTP400('tank_name and tank_policy required')

    tank_desc = query.get('desc', [''])[0]

    try:
        create_wiki(environ, tank_name, mode=tank_policy,
                username=usersign['name'], desc=tank_desc)
    except InvalidBagError:
        return dash(environ, start_response, message='Over quota!')

    uri = tank_uri(environ, tank_name)
    start_response('303 See Other', [
        ('Location', str(uri))])
    return []
示例#5
0
def delete(environ, start_response):
    """
    Handle ``DELETE`` on a single bag URI.

    Remove the :py:class:`bag <tiddlyweb.model.bag.Bag>` and the
    :py:class:`tiddlers <tiddlyweb.model.tiddler.Tiddler>` within
    from the :py:class:`store <tiddlyweb.store.Store>`.

    How the store chooses to handle remove and what it means is
    up to the store.
    """
    bag_name = web.get_route_value(environ, 'bag_name')
    bag_name = web.handle_extension(environ, bag_name)

    usersign = environ['tiddlyweb.usersign']

    bag = _get_bag(environ, bag_name)
    bag.policy.allows(usersign, 'manage')
    # reuse the store attribute that was set on the
    # bag when we "got" it.
    # we don't need to check for existence here because
    # the above get already did
    try:
        store = environ['tiddlyweb.store']
        store.delete(bag)
    except StoreMethodNotImplemented:
        raise HTTP400('Bag DELETE not supported')

    start_response("204 No Content", [])
    return []
示例#6
0
文件: query.py 项目: sgml/tiddlyweb
    def extract_query(self, environ):
        """
        Read the ``QUERY_STRING`` and body (if a POSTed form) to extract
        query parameters. Put the results in ``tiddlyweb.query`` in
        environ. The query names and values are decoded from UTF-8 to
        unicode.

        If there are file uploads in posted form data, the files are
        not put into ``tiddlyweb.query``. Instead the file handles are
        appended to ``tiddlyweb.input_files``.
        """
        content_type = environ.get('CONTENT_TYPE', '')
        environ['tiddlyweb.query'] = {}
        environ['tiddlyweb.input_files'] = []
        if _cgi_post(environ, content_type):
            _process_post(environ, content_type)
        filters, leftovers = parse_for_filters(environ.get('QUERY_STRING', ''),
                                               environ)
        query_data = parse_qs(leftovers, keep_blank_values=True)
        try:
            _update_tiddlyweb_query(environ, query_data, encoded=ENCODED_QUERY)
        except UnicodeDecodeError as exc:
            raise HTTP400(
                'Invalid encoding in query string, utf-8 required: %s', exc)
        environ['tiddlyweb.filters'] = filters
示例#7
0
def app_info(environ, start_response):
    """
    At the provider display the stored information
    about a app, given its id in the query parameter `app`.

    Only the client/app owner can see the secret.
    """
    query = environ['tiddlyweb.query']
    current_user = environ['tiddlyweb.usersign']['name']
    app_id = query.get('app', [None])[0]

    if not app_id:
        raise HTTP400('app parameter required')

    try:
        app = get_app(environ, app_id)
    except StoreError:
        raise HTTP404('no matching app found')

    start_response('200 OK', [(
        'Content-Type', 'text/plain; charset=UTF-8')])

    output = ['client id: %s' % app.title]
    if current_user == app.modifier:
        output.append('client secret: %s' % app.fields['client_secret'])
    return output
示例#8
0
def create_app(environ, start_response):
    """
    At the provider, register a client and provide them with
    an id, secret, etc.

    This is not part of the oAuth spec, but is fairly standard
    form for what is usually called "creating an app".

    On success redirects to the info page for the app.
    """
    query = environ['tiddlyweb.query']
    current_user = environ['tiddlyweb.usersign']['name']
    data = {}
    for key in ['name', 'app_url', 'callback_url', 'logo']:
        if key in query:
            data[key] = query[key][0]
    data['owner'] = current_user

    try:
        app_tiddler = create(**data)
    except TypeError as exc:
        raise HTTP400('Invalid form submission: %s' % exc)

    # let a store error raise to a 500 (for now)
    app_tiddler = store_app(environ, app_tiddler)

    raise HTTP303(server_base_url(environ)
            + '/_oauth/appinfo?app=%s' % app_tiddler.title)
示例#9
0
def _do_login_or_register(environ, start_response, server_name, response_map,
                          content):
    """
    We had a valid response from the oauth provider, let's see if that is
    a user or somebody we can register.
    """
    store = environ['tiddlyweb.store']
    config = environ['tiddlyweb.config']
    userinfo = simplejson.loads(content)
    userdata = {}
    for key, value in response_map.iteritems():
        userdata[key] = userinfo.get(value, '')

    server_login = None

    username = userdata['login']
    if not username:
        raise HTTP400('extractable username data required')

    userdata['server_name'] = server_name

    if config.get('oauth.use_mapuser', False):
        server_login = '******' % (server_name, username)
        map_bag_name = config.get('magicuser.map', 'MAPUSER')
        tiddler = Tiddler(server_login, map_bag_name)
        try:
            tiddler = store.get(tiddler)
            mapped_user = tiddler.fields.get('mapped_user')
            store.get(User(mapped_user))
            user = User(server_login)
            return _send_cookie(environ, start_response, user)
        except StoreError:
            try:
                local_user = store.get(User(username))
            except StoreError:
                local_user = None
            pass  # fall through to register
    else:
        try:
            user = store.get(User(username))
            return _send_cookie(environ, start_response, user)
        except StoreError:
            local_user = None
            pass  # fall through to register

    registration_template = get_template(environ, 'registration.html')

    start_response('200 OK', [('Content-Type', 'text/html; charset=UTF-8'),
                              ('Cache-Control', 'no-store')])

    if local_user:
        userdata['local_user'] = local_user.usersign
    userdata['server_name_sig'] = _sign(config, server_name)
    if server_login:
        userdata['server_login'] = server_login
        userdata['server_login_sig'] = _sign(config, server_login)
    return registration_template.generate(userdata)
示例#10
0
def post_createrecipe(environ, start_response):
    user = get_user_object(environ)
    store = environ['tiddlyweb.store']
    recipe_name = environ['tiddlyweb.query'].get('recipe', [''])[0]
    bag_name = environ['tiddlyweb.query'].get('bag', [''])[0]
    publicity = environ['tiddlyweb.query'].get('publicity', [''])[0]
    description = environ['tiddlyweb.query'].get('description', [''])[0]
    if not bag_name or not recipe_name:
        raise HTTP400('missing data')

    recipe = Recipe(recipe_name)
    bag = Bag(bag_name)
    try:
        recipe = store.get(recipe)
        raise HTTP400('recipe exists')
    except NoRecipeError:
        pass

    try:
        bag = store.get(bag)
        try:
            bag.policy.allows(user, 'read')
        except (UserRequiredError, ForbiddenError):
            raise HTTP400('bag not readable')
    except NoBagError:
        bag.policy.owner = user['name']
        for constraint in ['read', 'write', 'create', 'delete', 'manage']:
            setattr(bag.policy, constraint, [user['name']])
        store.put(bag)

    if publicity == 'private':
        recipe.policy.read = [user['name']]
    else:
        recipe.policy.read = []
    recipe.policy.manage = [user['name']]
    recipe.policy.owner = user['name']
    recipe.desc = description
    recipe.set_recipe([
        ('system', ''),
        (bag.name, ''),
    ])
    store.put(recipe)

    raise HTTP303('%s/home' % server_base_url(environ))
示例#11
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 []
示例#12
0
def editor(environ, start_response, extant_tiddler=None, message=''):
    store = environ['tiddlyweb.store']
    usersign = environ['tiddlyweb.usersign']
    query = environ['tiddlyweb.query']

    if extant_tiddler:
        tiddler = extant_tiddler
        bag = _fill_bag(store, Bag(tiddler.bag))
    else:
        try:
            bag_name = query['bag'][0]
            tiddler_title = query['tiddler'][0]
        except KeyError:
            raise HTTP400('bad query: bag and tiddler required')

        if not (bag_name and tiddler_title):
            raise HTTP400('bad query: bag and tiddler required')

        bag = _fill_bag(store, Bag(bag_name))

        tiddler = Tiddler(tiddler_title, bag_name)
        tiddler_new = False
        try:
            tiddler = store.get(tiddler)
        except NoTiddlerError:
            tiddler.text = ''
            tiddler.type = 'text/x-markdown'
            tiddler_new = True

        if tiddler_new:
            bag.policy.allows(usersign, 'create')
        else:
            bag.policy.allows(usersign, 'write')

    start_response('200 OK', [
        ('Content-Type', 'text/html; charset=UTF-8'),
        ('Cache-Control', 'no-cache')])
    return send_template(environ, EDIT_TEMPLATE, {
        'bag': bag,
        'message': message,
        'tiddler': tiddler,
        'etag': tiddler_etag(environ, tiddler).replace('"',
            '').split(':', 1)[0]
    })
示例#13
0
def get_tiddlers(environ, start_response):
    """
    Handle ``GET`` on a tiddlers-within-a-recipe URI.

    Get a list representation of the :py:class:`tiddlers
    <tiddlyweb.model.tiddler.Tiddler>` generated from a :py:class:`recipe
    <tiddlyweb.model.recipe.Recipe>`.

    The information sent is dependent on the serialization chosen
    via :py:mod:`tiddlyweb.web.negotiate`.
    """
    usersign = environ['tiddlyweb.usersign']
    store = environ['tiddlyweb.store']
    filters = environ['tiddlyweb.filters']
    recipe = _determine_recipe(environ)
    title = 'Tiddlers From Recipe %s' % recipe.name
    title = environ['tiddlyweb.query'].get('title', [title])[0]

    # check the recipe can be read
    recipe.policy.allows(usersign, 'read')

    # check the bags in the recipe can be read
    try:
        template = control.recipe_template(environ)
        for bag_name, _ in recipe.get_recipe(template):
            bag = Bag(bag_name)
            bag = store.get(bag)
            bag.policy.allows(usersign, 'read')
    except NoBagError as exc:
        raise HTTP404('recipe %s lists an unknown bag: %s' %
                      (recipe.name, exc))

    # from this point forward we know the tiddlers are
    # readable

    # get the tiddlers from the recipe and uniquify them
    try:
        candidate_tiddlers = control.get_tiddlers_from_recipe(recipe, environ)
    except NoBagError as exc:
        raise HTTP404('recipe %s lists an unknown bag: %s' %
                      (recipe.name, exc))
    except FilterError as exc:
        raise HTTP400('malformed filter: %s' % exc)

    tiddlers = Tiddlers(title=title)
    if not filters:
        tiddlers.store = store
    tiddlers.recipe = recipe.name

    for tiddler in candidate_tiddlers:
        tiddler.recipe = recipe.name
        tiddlers.add(tiddler)

    tiddlers.link = '%s/tiddlers' % web.recipe_url(environ, recipe, full=False)

    return send_tiddlers(environ, start_response, tiddlers=tiddlers)
示例#14
0
文件: search.py 项目: sgml/tiddlyweb
def get_search_query(environ):
    """
    Inspect :py:mod:`tiddlyweb.query <tiddlyweb.web.query>` in the
    environment to find the search query in a parameter named ``q``.
    """
    try:
        search_query = environ['tiddlyweb.query']['q'][0]
    except (KeyError, IndexError):
        raise HTTP400('query string required')
    return search_query
示例#15
0
def entity_policy(environ, start_response):
    publicity = environ['tiddlyweb.query'].get('publicity', [''])[0]
    bag_name = environ['tiddlyweb.query'].get('bag', [''])[0]
    recipe_name = environ['tiddlyweb.query'].get('recipe', [''])[0]

    if bag_name:
        return _bag_policy(environ, bag_name, publicity)
    elif recipe_name:
        return _recipe_policy(environ, recipe_name, publicity)
    else:
        raise HTTP400('missing form data')
示例#16
0
文件: util.py 项目: sgml/tiddlyweb
def content_length_and_type(environ):
    """
    For ``PUT`` or ``POST`` request there must be ``Content-Length`` and
    ``Content-Type`` headers. Raise ``400`` if not present in the request.
    """
    try:
        length = environ['CONTENT_LENGTH']
        content_type = environ['tiddlyweb.type']
    except KeyError:
        raise HTTP400(
            'Content-Length and content-type required to PUT or POST')
    return length, content_type
示例#17
0
文件: query.py 项目: sgml/tiddlyweb
def _process_post(environ, content_type):
    """
    Process posted form data.
    """
    try:
        if content_type.startswith('application/x-www-form-urlencoded'):
            posted_data = _process_encodedform(environ)
        elif content_type.startswith('multipart/form-data'):
            posted_data = _process_multipartform(environ)
        _update_tiddlyweb_query(environ, posted_data, encoded=ENCODED_QUERY)
    except UnicodeDecodeError as exc:
        raise HTTP400('Invalid encoding in query data, utf-8 required: %s',
                      exc)
示例#18
0
文件: util.py 项目: sgml/tiddlyweb
def read_request_body(environ, length):
    """
    Read the ``wsgi.input`` handle to get the request body.

    Length is a required parameter because it is tested for existence
    earlier in the process.
    """
    try:
        length = int(length)
        input_handle = environ['wsgi.input']
        return input_handle.read(length)
    except (KeyError, ValueError, IOError) as exc:
        raise HTTP400('Error reading request body: %s' % exc)
示例#19
0
    def _handle_descendant(self, req_uri, space, visible_bags):
        """
        Process a request which is not /bags, /recipes, or /search,
        but a descendant of /bags or /recipes.

        If the URI points to things which are not in this space, 404.
        """
        try:
            entity_name = urllib.unquote(req_uri.split('/')[2]).decode('utf-8')
        except UnicodeDecodeError, exc:
            raise HTTP400(
                'incorrect encoding in URI, url-escaped utf-8 required: %s' %
                exc)
示例#20
0
文件: query.py 项目: sgml/tiddlyweb
def _process_encodedform(environ):
    """
    Read ``application/x-www-form-urlencoded`` from the request
    body and parse for form data and return.
    """
    try:
        length = environ['CONTENT_LENGTH']
        content = read_request_body(environ, length)
        if not ENCODED_QUERY:
            content = content.decode('UTF-8')
    except KeyError as exc:
        raise HTTP400('Invalid post, unable to read content: %s' % exc)
    return parse_qs(content, keep_blank_values=True)
示例#21
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
示例#22
0
文件: search.py 项目: sgml/tiddlyweb
def get(environ, start_response):
    """
    Handle ``GET`` on the search URI.

    Perform a search against the :py:class:`store <tiddlyweb.store.Store>`.

    What search means and what results are returned is dependent
    on the search implementation (if any) in the :py:class:`chosen store
    <tiddlyweb.stores.StorageInterface>`.
    """
    store = environ['tiddlyweb.store']
    filters = environ['tiddlyweb.filters']
    search_query = get_search_query(environ)
    title = 'Search for %s' % search_query
    title = environ['tiddlyweb.query'].get('title', [title])[0]

    try:
        tiddlers = get_tiddlers(environ)

        usersign = environ['tiddlyweb.usersign']

        if filters:
            candidate_tiddlers = Tiddlers(title=title)
        else:
            candidate_tiddlers = Tiddlers(title=title, store=store)
        candidate_tiddlers.is_search = True

        for tiddler in readable_tiddlers_by_bag(store, tiddlers, usersign):
            candidate_tiddlers.add(tiddler)

    except StoreMethodNotImplemented:
        raise HTTP400('Search system not implemented')
    except StoreError as exc:
        raise HTTP400('Error while processing search: %s' % exc)

    return send_tiddlers(environ, start_response, tiddlers=candidate_tiddlers)
示例#23
0
def post_createbag(environ, start_response):
    user = get_user_object(environ)
    store = environ['tiddlyweb.store']
    bag_name = environ['tiddlyweb.query'].get('bag', [''])[0]
    publicity = environ['tiddlyweb.query'].get('publicity', [''])[0]
    description = environ['tiddlyweb.query'].get('description', [''])[0]

    if not bag_name:
        raise HTTP400('missing data')

    bag = Bag(bag_name)

    try:
        bag = store.get(bag)
        raise HTTP400('bag exists')
    except NoBagError:
        pass
    if publicity == 'public':
        bag = ensure_public_bag(store,
                                user['name'],
                                desc=description,
                                name=bag_name)
    elif publicity == 'protected':
        bag = ensure_protected_bag(store,
                                   user['name'],
                                   desc=description,
                                   name=bag_name)
    else:
        bag = ensure_private_bag(store,
                                 user['name'],
                                 desc=description,
                                 name=bag_name)

    # the bag has already been stored

    raise HTTP303('%s/tiddlers' % bag_url(environ, bag))
示例#24
0
def _regular_tiddler(environ, bag_name, input_file, target_name):
    store = environ['tiddlyweb.store']
    username = environ['tiddlyweb.usersign']['name']

    content = input_file.file.read()

    tiddler = Tiddler(target_name, bag_name)
    try:
        tiddler.text = content.decode('utf-8')
    except UnicodeError as exc:
        raise HTTP400('tiddler content should be utf-8 encode: %s' % exc)
    tiddler.modifier = username
    tiddler.type = input_file.type
    store.put(tiddler)

    return tiddler
示例#25
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
示例#26
0
def _store_tiddler_revisions(environ, content, tiddler):
    """
    Given JSON revisions in content, store them
    as a revision history to tiddler.
    """
    try:
        json_tiddlers = simplejson.loads(content)
    except ValueError as exc:
        raise HTTP409('unable to handle json: %s' % exc)

    store = environ['tiddlyweb.store']
    serializer = Serializer('json', environ)
    serializer.object = tiddler
    try:
        for json_tiddler in reversed(json_tiddlers):
            json_string = simplejson.dumps(json_tiddler)
            serializer.from_string(json_string)
            store.put(tiddler)
    except NoTiddlerError as exc:
        raise HTTP400('Unable to store tiddler revisions: %s' % exc)
示例#27
0
文件: query.py 项目: sgml/tiddlyweb
def _process_multipartform(environ):
    """
    Read ``multipart/form-data`` using ``FieldStorage``, return
    a dictionary of form data and set ``tiddlyweb.input_files``
    to a list of available files.
    """
    posted_data = {}
    try:
        field_storage = FieldStorage(fp=environ['wsgi.input'],
                                     environ=environ,
                                     keep_blank_values=True)
    except ValueError as exc:
        raise HTTP400('Invalid post, bad form: %s' % exc)
    for key in field_storage.keys():
        if (hasattr(field_storage[key], 'filename')
                and field_storage[key].filename):
            environ['tiddlyweb.input_files'].append(field_storage[key])
        else:
            posted_data[key] = field_storage.getlist(key)
    return posted_data
示例#28
0
def _filter_tiddlers(filters, store, tiddlers):
    """
    Filter the tiddlers by filters provided by the environment.
    """
    candidate_tiddlers = Tiddlers(store=store)
    try:
        candidate_tiddlers.title = tiddlers.title
        candidate_tiddlers.link = tiddlers.link
        candidate_tiddlers.is_search = tiddlers.is_search
        candidate_tiddlers.is_revisions = tiddlers.is_revisions
        candidate_tiddlers.bag = tiddlers.bag
        candidate_tiddlers.recipe = tiddlers.recipe
    except AttributeError:
        pass
    try:
        for tiddler in recursive_filter(filters, tiddlers):
            candidate_tiddlers.add(tiddler)
    except FilterError as exc:
        raise HTTP400('malformed filter: %s' % exc)
    return candidate_tiddlers
示例#29
0
def delete(environ, start_response):
    """
    Handle ``DELETE`` on a single recipe URI.

    Delete a :py:class:`recipe <tiddlyweb.model.recipe.Recipe>`.
    This just removes the recipe, not any associated :py:class:`bags
    <tiddlyweb.model.bag.Bag>` or :py:class:`tiddlers
    <tiddlyweb.model.tiddler.Tiddler>`.
    """
    recipe = _determine_recipe(environ)
    store = environ['tiddlyweb.store']

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

    try:
        store.delete(recipe)
    except StoreMethodNotImplemented:
        raise HTTP400('Recipe DELETE not supported')

    start_response("204 No Content", [])
    return []
示例#30
0
def _send_tiddler_revisions(environ, start_response, tiddler):
    """
    Push the list of tiddler revisions out the network.
    """
    store = environ['tiddlyweb.store']

    title = 'Revisions of Tiddler %s' % tiddler.title
    title = environ['tiddlyweb.query'].get('title', [title])[0]
    container = 'recipes' if tiddler.recipe else 'bags'

    if environ['tiddlyweb.filters']:
        tiddlers = Tiddlers(title=title)
    else:
        tiddlers = Tiddlers(title=title, store=store)

    tiddlers.is_revisions = True
    tiddlers.link = '%s/revisions' % tiddler_url(environ, tiddler,
            container=container, full=False)

    # Set the container on the tiddlers. Since tiddler.recipe
    # defaults to None, we're "safe" here.
    tiddlers.recipe = tiddler.recipe
    tiddlers.bag = tiddler.bag

    try:
        for revision in store.list_tiddler_revisions(tiddler):
            tmp_tiddler = Tiddler(title=tiddler.title, bag=tiddler.bag)
            tmp_tiddler.revision = revision
            tmp_tiddler.recipe = tiddler.recipe
            tiddlers.add(tmp_tiddler)
    except NoTiddlerError as exc:
        # If a tiddler is not present in the store.
        raise HTTP404('tiddler %s not found, %s' % (tiddler.title, exc))
    except NoBagError as exc:
        raise HTTP404('tiddler %s not found, bag %s does not exist, %s'
                % (tiddler.title, tiddler.bag, exc))
    except StoreMethodNotImplemented:
        raise HTTP400('no revision support')

    return send_tiddlers(environ, start_response, tiddlers=tiddlers)