Skip to content

Jelf Web Framework

Jean Yang edited this page Aug 27, 2014 · 10 revisions

Jelf Overview

Jelf is a web framework that extends the Jeeves execution model across the application and database layers.

Using Jelf

To use Jelf, you will need these dependencies. While macropy is required to run Jeeves at all, the other two are specific to Jelf.

pip install macropy
pip install django
pip install Jinja2

Note that Jelf should be considered completely experimental at this point. You can find a skeleton in demo/jelf-skeleton/.

Jelf Models

You can make a model in jelf/models.py and declare policies like this:

class UserProfile(JeevesModel):
    username = CharField(max_length=1024)
    email = CharField(max_length=1024)

    level = CharField(max_length=6,
                    choices=(('normal', 'normal'),
                        ('pc', 'pc'),
                        ('chair', 'chair')))

    # Declares the public value that should be shown
    # when the e-mail cannot be. In this case, just show
    # "" when the e-mail cannot be shown.
    @staticmethod
    def jeeves_get_private_email(user):
        return ""

    # Declare the policy for when the e-mail can be shown.
    # In this case, you can only see the e-mail if you are the
    # chair of the user in question.
    @staticmethod
    @label_for('email')
    @jeeves
    def jeeves_restrict_userprofilelabel(user, ctxt):
        return user == ctxt or (ctxt != None and ctxt.level == 'chair')

Remember to subclass all models from the JeevesModel class. Even better is:

from jeevesdb.JeevesModel import JeevesModel as Model

so you never accidentally use the old Django Model class.

Set all ForeignKeys to allow null values; it's unclear why this is needed. Also, because of the way Jelf stores records, models with policies (or models created by policies) may not enforce unique attributes.

Composition

When objects compose others, there can be two ways to implement policies: putting the policy on the container object, or the contained object. These two possible implementations might seem to have the same executions at some times. The decision on which to choose should be selected based on what the sense of the policies are:

  1. If a company has-a CEO, who has-an SSN, then the policy protecting the SSN should be on the CEO (e.g. 1 level up), as the CEO wants to protect their privacy, not the company.

  2. If a company has-a customer who has-a first name, then the policy protecting the first name should be on the company (e.g. 2 levels up), as the company (may) want to protect the name of their customers. A customer only cares about the access to their name when their data is connected to a company purchase, and so the policy should be at that level.

In this case, remember that the jeeves_get_private_* method must save the public value to the database before returning. (The returned object will create a faceted value of the containing object with a reference to the new contained object, and this reference can only be created if the object to refer to already exists.)

While this does not cover all object systems, it should be a guide as to how to think about implementing policies.

Jelf Application Code and Views

Application code goes in jelf/views.py. When adding a new object to the database, use create instead of save.

When Django saves a model that has not been saved previously, after it saves the model it updates the model with the newly created values, such as the id. The Jelf save method does not do that. However, the Model.objects.create does return an object with these new attributes. These new attributes are crucial if you'd like to later use the object in a foreign relationship.

Remember to wrap your view in the request_wrapper, and to have your view return a tuple<template, templateData>. The request_wrapper figures out which values to display based on your policies. It seems that eventually, this will be built into the codeset, and request_wrapper will not be needed.

In a view, exceptions cannot be raised from from within a facet. if x==None: raise Http404 will not work, if x is a faceted value.

See the comments and examples in the skeleton.

Templates

To view faceted values, you will need to concretize values with respect to the viewing context. We define a concretize function as follows with respect to the current viewer profile:

concretizeState = JeevesLib.jeevesState.policyenv.getNewSolverState(profile)
def concretize(val):
    return concretizeState.concretizeExp(val, JeevesLib.jeevesState.pathenv.getEnv())

We pass this function to the templates so we can call concretize(val) for producing the concrete version of a value val.