예제 #1
0
파일: methods.py 프로젝트: visd/VISD-Badges
def post_to_collection(
    parent=None, parent_id=None, resource=None, config=None, parent_instance=None, user=None, request=None
):
    this_model = help.model_for(resource)
    db_columns = help.db_columns_of(this_model)
    # We use this, and the config, to find out which fields on the model this user is
    # permitted to create.
    # Whatever was submitted in the request.POST gets filtered through this.
    write_fields = help.help.sorted_fields_of(config["fields"])["fields"]["write"]
    permitted_fields = list(set(request.POST) & set(write_fields) & set(db_columns))
    # And now, the permitted and user-supplied dictionary:
    values = {k: request.POST[k] for k in permitted_fields}
    # Now we're going to extend the set of fields, because most models will need
    # a user, a group and a parent.
    extensions = []

    # Someday put this next, ugly chunk of code into a loop, and perhaps figure
    # the values outside this method, in a config somewhere.

    if "user_id" in db_columns:
        values["user_id"] = user.pk
        extensions.append("user_id")
    if "group_id" in db_columns:
        values["group_id"] = user.status_over(
            parent and getattr(parent_instance, "group") or NestedGroup.objects.get(name=settings.INDEX_GROUP)
        )
        extensions.append("group_id")

    # If this new resource needs a parent, let's use the one in the URL.
    # This is assuming we've screened for validity -- we won't get here
    # without all our sanity checks in place.
    p = help.parent_of(resource)
    if p:
        pid = "%s_id" % p
        values[pid] = parent_id
        extensions.append(pid)

    permitted_fields.extend(extensions)

    form = modelform_factory(this_model, fields=permitted_fields)(values)
    opts = {
        "parent": parent,
        "parent_id": parent_id,
        "resource": resource,
        "user": user,
        "user": user_role,
        "config": config,
        "depth": 0,
    }
    if form.is_valid():
        new_inst = form.save(commit=False)
        # Now we need to sneak in a few more values.

        # Success! Now show the page this belongs on.
        return (True, get_collection(**opts))
    else:
        opts["form"] = form
        return (False, get_post_form(**opts))
예제 #2
0
파일: methods.py 프로젝트: visd/VISD-Badges
def get_post_form(
    parent=None,
    parent_id=None,
    resource=None,
    instance=None,
    user=None,
    user_role=None,
    config=None,
    depth=0,
    form=None,
):
    """ Returns a dictionary with:
        a form for posting one of this resource, and
        a target url/method for the form.

        We're already checked, and the user is allowed to post one of these.
    """
    if form is None:
        # The user is going to be the owner of this resource.
        this_config = permit.reduce_permissions_dictionary_to("owner", config)

        formfields = help.sorted_fields_of(this_config[resource]["fields"])["fields"]
        # We only want a form for the fields the owner can read and write.
        userfields = tuple(set(formfields["read"]) & set(formfields["write"]))

        # Now we create the form.
        this_model = help.model_for(resource)
        form = modelform_factory(this_model, fields=userfields)()

    result = {
        "target": {
            "url": reverse(
                "newviews:parsed-url", kwargs={"parent": parent, "parent_id": parent_id, "resource": resource}
            ),
            "method": "POST",
            "form": form,
        }
    }
    return result
예제 #3
0
파일: views.py 프로젝트: visd/VISD-Badges
def handler(request, parent=None, parent_id=None,
            resource=None, resource_id=None):
    """Our job is to thoroughly screen the request so we can hand it
    to our methods freely.
    """
    # Until the day we hook Google's auth into our middleware:
    request.user = CustomUser.objects.all()[0]
    logging.info('User: %s, groups: %s' % (str(request.user), str(request.user.memberships.all())))
    # Are these even in our defined list of resources?
    if resource not in RESOURCES or (parent and parent not in RESOURCES):
        raise Http404

    # Does this parent (if there is one) even exist?
    if parent:
        try:
            parent_inst = model_for(parent).objects.get(pk=parent_id)
        except ObjectDoesNotExist:
            raise Http404
        # We'll see if the parent and child are even in the same family tree.
        if not same_tree(request.user, parent_inst):
            raise Http404
        # We need to see if the user is allowed to GET the parent_inst
        # because we will allow the resource to reveal some
        # information about its parent.

        conf = instance_permissions(request.user, parent_inst)
        if not conf[parent]['methods']['GET'] & 1:
            raise PermissionDenied
    else:
        conf = instance_permissions(request.user)

    # Now let's see if we can go from the parent (or index)
    # to this resource.
    traversals = sorted_traversals(resource=(parent or 'index'), config=conf)
    if not resource in traversals.get('many', []):
        raise PermissionDenied

    opts = {'resource': resource,
            'user': request.user,
            'parent': parent,
            'parent_id': parent_id,
            'config': conf
            }

    if resource_id:
        try:
            inst = model_for(resource).objects.get(pk=resource_id)
        except ObjectDoesNotExist:
            raise Http404
        if not same_tree(request.user, inst):
            raise Http404
        # Time to retrieve the user's permissions for this instance.
        conf = instance_permissions(request.user, inst)
        logging.info('config for resource %s: %s' % (resource, conf[resource]))
        # Now we find out of a user in this role can do this method to this instance.
        allowed = permit.allowed_methods_of(conf[resource]['methods'])['allowed']
        if not request.method in allowed:
            logger.error('Got resource_id, not allowed from method %s, allowed=%s' %
                (request.method, allowed))
            raise PermissionDenied

        if request.method == 'GET':
            opts['instance'] = inst
            opts['config'] = conf
            requested_form = request.GET.get('form')
            # We may be getting a request for a form, for PUTting or DELETEing.
            # If the user couldn't do this method anyway we just ignore the
            # QueryDict.
            if requested_form == 'edit' and 'PUT' in allowed:
                context = methods.get_put_form(**opts)
                template = 'put_form.html'
            if requested_form == 'delete' and 'DELETE' in allowed:
                context = methods.get_delete_form(**opts)
                template = 'delete_form.html'
            else:
                context = methods.get_instance(**opts)
                template = '%s_detail.html' % resource
        if request.method == 'PUT':
            pass
        if request.method == 'DELETE':
            pass 
    else:
        if request.method == 'GET':
            if request.GET.get('form') == 'create':
                context = methods.get_post_form(**opts)
                template = 'post_form.html'
            else:
                context = methods.get_collection(**opts)
                # magic naming again.
                template = '%s_in_%s.html' % (resource, parent or 'index')
        if request.method == 'POST':
            # We'll either get a redirect or a response containing a new form.
            opts['request'] = request
            opts['parent_instance'] = parent and parent_inst or None
            post_result = methods.post_to_collection(**opts)
            # post_result sends a tuple of (True/False, context).
            template = post_result[0] and '%s_in_%s.html' % (resource, parent or 'index')\
                or\
                'post_form.html'
            context = post_result[1]       
    return HttpResponse(render(request, template, context), mimetype='text/html')
예제 #4
0
파일: methods.py 프로젝트: visd/VISD-Badges
def get_collection(parent=None, parent_id=None, resource=None, user=None, config=None, depth=0):
    """ Requires a resource with a parent scope (which may be index if provided
        by the url router). Parent must come with an id.
        We set the depth to track our recursions and condition the views
        (deeper calls generally return less).

        User is a User instance.

        We will only recurse on GET (and perhaps someday OPTIONS), because it is idempotent.

        All the legal checks are in the handler. Once we recurse we assume
        our configuration is only throwing valid responses.
    """
    allowed = permit.methods_for_traversal(parent or "index", resource, config)
    if not depth:
        # Since we're already GETting this, no need to offer it to the client
        # again.
        allowed.remove("GET")

    this_model = help.model_for(resource)
    # We get to use the model's manager directly if it's the root,
    # or if there is a parent we use the parent's manager.
    if parent:
        # And now a bit of magic naming. We expect the verbose name of the resource
        # to be an attribute of the parent model.
        parent_model = help.model_for(parent)
        parent_inst = parent_model.objects.get(pk=parent_id)
        collection = getattr(parent_inst, resource)
    else:
        collection = this_model.collection

    # Now we need our query filter.
    q = help.build_Q_set(user, resource)

    result = {
        "meta": {
            "resource": resource,
            "url": collection.url(),
            "methods": [m for m in allowed],
            "count": collection.count(),
        }
    }
    if parent and not depth:
        result["traversals"] = [{"url": parent_inst.url, "method": "GET"}]
    if VIEW_TRAVERSE_DEPTH - depth:
        # We don't retrieve collection.all() here. We have to figure:
        logger.info("q = %s" % str(q))
        if q:
            instances = collection.filter(q).all()
        else:
            instances = collection.all()
        logger.info("The query was = %s" % str(instances.query))
        result["objects"] = [
            get_instance(
                resource=resource,
                instance=inst,
                parent=parent,
                parent_id=parent_id,
                user=user,
                config=help.instance_permissions(user, inst),
                depth=depth + 1,
            )
            for inst in instances
        ]

    return result