-
Notifications
You must be signed in to change notification settings - Fork 32
Jelf Web Framework
Jelf is a web framework that extends the Jeeves execution model across the application and database layers.
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/
.
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.
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:
-
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.
-
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.
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.
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
.