Add access control to document model and view
authorSverre Rabbelier <srabbelier@gmail.com>
Fri, 30 Jan 2009 22:01:27 +0000
changeset 1095 0122dc66e5d2
parent 1094 e143974a6e27
child 1096 258af84e2e56
Add access control to document model and view The access checks are not yet written, but at least the model is stable from now on. Also converted the document view to dynaform while at it. Patch by: Sverre Rabbelier
app/soc/logic/models/document.py
app/soc/models/document.py
app/soc/models/work.py
app/soc/views/models/document.py
--- a/app/soc/logic/models/document.py	Fri Jan 30 22:00:49 2009 +0000
+++ b/app/soc/logic/models/document.py	Fri Jan 30 22:01:27 2009 +0000
@@ -42,6 +42,24 @@
     super(Logic, self).__init__(model=model, base_model=base_model,
                                 scope_logic=scope_logic)
 
+  def getKeyValues(self, entity):
+    """See base.Logic.getKeyNameValues.
+    """
+
+    return [entity.prefix, entity.scope_path, entity.link_id]
+
+  def getKeyValuesFromFields(self, fields):
+    """See base.Logic.getKeyValuesFromFields.
+    """
+
+    return [fields['prefix'], fields['scope_path'], fields['link_id']]
+
+  def getKeyFieldNames(self):
+    """See base.Logic.getKeyFieldNames.
+    """
+
+    return ['prefix', 'scope_path', 'link_id']
+
   def _updateField(self, entity, name, value):
     """Special logic for role. If state changes to active we flush the sidebar.
     """
--- a/app/soc/models/document.py	Fri Jan 30 22:00:49 2009 +0000
+++ b/app/soc/models/document.py	Fri Jan 30 22:01:27 2009 +0000
@@ -46,6 +46,34 @@
 
   URL_NAME = 'document'
 
+  #: field storing the prefix of this document
+  prefix = db.StringProperty(default='user',
+      choices=['site','sponsor','program', 'club', 'organization', 'user'],
+      verbose_name=ugettext('Prefix'))
+  prefix.help_text = ugettext(
+      'Indicates the prefix of the document,'
+      ' determines which access scheme is used.')
+
+  #: field storing the access status of this document
+  # wiki = any user can read and write the document
+  # public = any user can read, only restricted can write
+  # member = member can read, only restricted can write
+  # restricted = restricted can read, only admin can write
+  # admin = admin can read, only admin can write
+  #
+  # example meanings for an organisations:
+  # admin = ['org_admin']
+  # restricted = ['org_admin', 'org_mentor']
+  # member = ['org_admin', 'org_mentor', 'org_student']
+  # public = anyone
+  # wiki = anyone
+  access_status = db.StringProperty(default='restricted', required=True,
+      choices=['admin','restricted', 'member', 'public', 'wiki'],
+      verbose_name=ugettext('Access type'))
+  access_status.help_text = ugettext(
+      'Indicates the state of the document, '
+      'determines the access scheme.')
+
   #: field storing whether a link to the Document should be featured in
   #: the sidebar menu (and possibly elsewhere); FAQs, Terms of Service,
   #: and the like are examples of "featured" Document
--- a/app/soc/models/work.py	Fri Jan 30 22:00:49 2009 +0000
+++ b/app/soc/models/work.py	Fri Jan 30 22:01:27 2009 +0000
@@ -80,16 +80,6 @@
                                      collection_name="modified_documents",
                                      verbose_name=ugettext('Modified by'))
 
-  # TODO: some sort of access control preferences are needed at this basic
-  #   level.  Works need to be restrict-able to:
-  #    * the authors only
-  #    * the administrators of the Groups that the authors are in
-  #    * any member of the authors' Groups
-  #    * logged-in User with a profile
-  #    * logged-in Users, but no profile is necessary
-  #    * anyone, even those not logged in
-  #  (and possibly others)
-
   def name(self):
     """Alias 'title' Property as 'name' for use in common templates.
     """
--- a/app/soc/views/models/document.py	Fri Jan 30 22:00:49 2009 +0000
+++ b/app/soc/views/models/document.py	Fri Jan 30 22:01:27 2009 +0000
@@ -28,12 +28,16 @@
 
 from django import forms
 
+from soc.logic import cleaning
 from soc.logic import dicts
 from soc.logic import validate
-from soc.logic.models import user as user_logic
+from soc.logic.models.user import logic as user_logic
+from soc.logic.models.document import logic as document_logic
+from soc.models import linkable
 from soc.views import helper
 from soc.views.helper import access
 from soc.views.helper import redirects
+from soc.views.helper import params as params_helper
 from soc.views.models import base
 
 import soc.models.document
@@ -43,47 +47,6 @@
 import soc.views.helper.widgets
 
 
-class CreateForm(helper.forms.BaseForm):
-  """Django form displayed when Developer creates a Document.
-  """
-
-  content = forms.fields.CharField(widget=helper.widgets.TinyMCE(
-      attrs={'rows':10, 'cols':40}))
-
-  class Meta:
-    """Inner Meta class that defines some behavior for the form.
-    """
-    model = soc.models.document.Document
-
-    #: list of model fields which will *not* be gathered by the form
-    exclude = ['author', 'created', 'modified_by', 'modified', 'scope']
-
-  def clean_scope_path(self):
-    scope_path = self.cleaned_data.get('scope_path')
-    # TODO(tlarsen): combine path and link_id and check for uniqueness
-    if not validate.isScopePathFormatValid(scope_path):
-      raise forms.ValidationError("This scope path is in wrong format.")
-    return scope_path
-
-  def clean_link_id(self):
-    link_id = self.cleaned_data.get('link_id').lower()
-    # TODO(tlarsen): combine path and link_id and check for uniqueness
-    if not validate.isLinkIdFormatValid(link_id):
-      raise forms.ValidationError("This link ID is in wrong format.")
-    return link_id
-
-
-class EditForm(CreateForm):
-  """Django form displayed a Document is edited.
-  """
-
-  doc_key_name = forms.fields.CharField(widget=forms.HiddenInput)
-  created_by = forms.fields.CharField(widget=helper.widgets.ReadOnlyInput(),
-                                      required=False)
-  last_modified_by = forms.fields.CharField(
-      widget=helper.widgets.ReadOnlyInput(), required=False)
-
-
 class View(base.View):
   """View methods for the Document model.
   """
@@ -101,15 +64,44 @@
     rights['show'] = ['checkIsDocumentPublic']
 
     new_params = {}
-    new_params['logic'] = soc.logic.models.document.logic
+    new_params['logic'] = document_logic
     new_params['rights'] = rights
 
+    new_params['name'] = "Document"
+
     new_params['export_content_type'] = 'text/text'
 
-    new_params['name'] = "Document"
+    names = [i for i in document_logic.getKeyFieldNames() if i != 'link_id']
+    create_pattern = params_helper.getPattern(names, linkable.SCOPE_PATH_ARG_PATTERN)
+
+    new_params['extra_django_patterns'] = [
+        (r'^document/(?P<access_type>create)/%s$' % create_pattern,
+        'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
+
+    new_params['no_create_with_scope'] = True
+    new_params['no_create_with_key_fields'] = True
 
-    new_params['edit_form'] = EditForm
-    new_params['create_form'] = CreateForm
+    new_params['create_extra_dynafields'] = {
+        'content': forms.fields.CharField(
+            widget=helper.widgets.TinyMCE(attrs={'rows':10, 'cols':40})),
+        'scope_path': forms.fields.CharField(widget=forms.HiddenInput,
+                                             required=True),
+        'prefix': forms.fields.CharField(widget=helper.widgets.ReadOnlyInput(),
+                                        required=True),
+
+        'clean_link_id': cleaning.clean_link_id('link_id'),
+        'clean_scope_path': cleaning.clean_scope_path('scope_path'),
+        }
+    new_params['extra_dynaexclude'] = ['author', 'created',
+                                       'modified_by', 'modified']
+
+    new_params['edit_extra_dynafields'] = {
+        'doc_key_name': forms.fields.CharField(widget=forms.HiddenInput),
+        'created_by': forms.fields.CharField(widget=helper.widgets.ReadOnlyInput(),
+                                             required=False),
+        'last_modified_by': forms.fields.CharField(
+            widget=helper.widgets.ReadOnlyInput(), required=False),
+        }
 
     params = dicts.merge(params, new_params)
 
@@ -120,7 +112,7 @@
     """
 
     account = users.get_current_user()
-    user = user_logic.logic.getForFields({'account': account}, unique=True)
+    user = user_logic.getForFields({'account': account}, unique=True)
 
     if not entity:
       fields['author'] = user