diff options
-rw-r--r-- | coip/apps/membership/views.py | 4 | ||||
-rw-r--r-- | coip/apps/name/forms.py | 24 | ||||
-rw-r--r-- | coip/apps/name/models.py | 1 | ||||
-rw-r--r-- | coip/apps/name/views.py | 46 | ||||
-rw-r--r-- | coip/apps/userprofile/views.py | 2 | ||||
-rw-r--r-- | coip/extensions/templatetags/permdisplay.py | 4 | ||||
-rw-r--r-- | coip/urls.py | 10 | ||||
-rw-r--r-- | site-media/css/style.css | 3 | ||||
-rw-r--r-- | templates/apps/name/acls.html | 38 | ||||
-rw-r--r-- | templates/apps/name/addace.html | 51 | ||||
-rw-r--r-- | templates/apps/name/name.html | 2 | ||||
-rw-r--r-- | templates/edit.html | 52 | ||||
-rw-r--r-- | templates/edit_fieldsets.html | 8 |
13 files changed, 184 insertions, 61 deletions
diff --git a/coip/apps/membership/views.py b/coip/apps/membership/views.py index fd7036e..7c4c4e1 100644 --- a/coip/apps/membership/views.py +++ b/coip/apps/membership/views.py @@ -36,6 +36,10 @@ def join(request,id,membername=None): if form.is_valid(): m = form.save() return HttpResponseRedirect(name.url()) + else: + return respond_to(request, + {'text/html': 'apps/membership/edit.html'}, + {'form': form,'name': name, 'formtitle': 'Add a member to %s' % name.short}) else: if membername: try: diff --git a/coip/apps/name/forms.py b/coip/apps/name/forms.py index dc36ecd..549456f 100644 --- a/coip/apps/name/forms.py +++ b/coip/apps/name/forms.py @@ -6,7 +6,7 @@ Created on Jun 24, 2010 from django import forms from coip.apps.name.models import Name, Attribute, NameLink from django.forms import fields -from django.forms.widgets import HiddenInput, CheckboxSelectMultiple +from django.forms.widgets import HiddenInput, CheckboxSelectMultiple, TextInput from form_utils.forms import BetterModelForm, BetterForm class NameForm(forms.ModelForm): @@ -71,7 +71,23 @@ class NameLinkForm(forms.ModelForm): class NameLinkDeleteForm(forms.Form): confirm = fields.BooleanField(label="Confirm") -class PermissionForm(forms.Form): +class PermissionForm(BetterForm): dst = fields.IntegerField(widget=HiddenInput) - subject = fields.CharField(min_length=1024) - permissions = fields.MultipleChoiceField(widget=CheckboxSelectMultiple,choices=[('r','read'),('w','write'),('l','list'),('i','insert'),('d','delete')]) + subject = fields.CharField(max_length=1024,label="Group",widget=TextInput(attrs={'size': 40})) + permissions = fields.MultipleChoiceField(widget=CheckboxSelectMultiple, + choices=[('r','read'), + ('w','write'), + ('l','list members and groups'), + ('i','manage members'), + ('d','delete'), + ('a','manage access')]) + class Meta: + fieldsets = [('subject',{'fields': ['dst','subject'], + 'legend': 'Step 1: Select a group', + 'classes': ['step'], + 'description': 'Start typing in the textfield to find the group you want.'}), + ('permission',{'fields': ['permissions'], + 'legend': 'Step 2: Set permissions', + 'classes': ['step','submit_step'], + 'description': 'Select the rights that members of the group should have.'})] +
\ No newline at end of file diff --git a/coip/apps/name/models.py b/coip/apps/name/models.py index a1384a3..d8c089e 100644 --- a/coip/apps/name/models.py +++ b/coip/apps/name/models.py @@ -204,6 +204,7 @@ class NameLink(models.Model): access_control = 0 part_of = 1 + child_access_control = 2 def __unicode__(self): return "%s -> %s [%s %s]" % (self.src,self.dst,self.type,self.data) diff --git a/coip/apps/name/views.py b/coip/apps/name/views.py index 90c0773..36a0f16 100644 --- a/coip/apps/name/views.py +++ b/coip/apps/name/views.py @@ -9,12 +9,13 @@ from django.http import HttpResponseNotFound, HttpResponseForbidden,\ HttpResponseRedirect, Http404 from django.contrib.auth.decorators import login_required from coip.multiresponse import respond_to, json_response, render403 -from pprint import pformat +from pprint import pformat, pprint import logging from coip.apps.name.forms import NameEditForm, NewNameForm, NameDeleteForm,\ PermissionForm from django.shortcuts import get_object_or_404 from django.contrib.auth.models import User +from django.db.models import Q @login_required def delete(request,id): @@ -89,7 +90,18 @@ def edit(request,id): @login_required -def editacl(request,id,type): +def lsacl(request,id,type=NameLink.access_control): + name = get_object_or_404(Name,pk=id) + + if not name.has_permission(request.user,'a'): + return render403("You do not have permission to list permissions on %s" % (name)) + + return respond_to(request, + {'text/html': 'apps/name/acls.html'}, + {'name': name, 'acl': name.lsacl()}) + +@login_required +def addacl(request,id,type=NameLink.access_control): name = get_object_or_404(Name,pk=id) if not name.has_permission(request.user,'a'): @@ -103,13 +115,17 @@ def editacl(request,id,type): p = form.cleaned_data['permissions'] if not p: p = [] - perms = p.join('') - link = NameLink.objects.get_or_create(src=name,dst=dst,type=NameLink.access_control) + perms = "".join(p) + (link,created) = NameLink.objects.get_or_create(src=name,dst=dst,type=NameLink.access_control) link.data = perms link.save() - - form = PermissionForm() - return respond_to(request,{'text/html': 'apps/name/acls.html'},{'form': form, 'name': name, 'acl': name.lsacl(),'formtitle': 'Add Permission','submitname':'Add'}) + return HttpResponseRedirect("/name/%s/acl/%s" % (id,type)) + else: + form = PermissionForm() + + return respond_to(request, + {'text/html': 'apps/name/addace.html'}, + {'form': form, 'name': name,'formtitle': 'Add Permission','submitname':'Add'}) @login_required def links(request,id,type=NameLink.access_control): @@ -124,15 +140,15 @@ def links(request,id,type=NameLink.access_control): @login_required -def removelink(request,id): - link = get_object_or_404(NameLink,pk=id) +def rmacl(request,id,aclid): + link = get_object_or_404(NameLink,pk=aclid) name = link.src type = link.type if not name.has_permission(request.user,'w'): return render403("You do not have permission to remove name links from %s" % (name)) link.delete() - return HttpResponseRedirect("/name/{{name.id}}/link/{{type}}") + return HttpResponseRedirect("/name/%d/acl/%s" % (name.id,type)) @login_required def show_root(request): @@ -207,4 +223,12 @@ def rtree(request,id=None): @login_required def ctree(request,id=None): - return _tree(request,id,False)
\ No newline at end of file + return _tree(request,id,False) + +@login_required +def search(request): + list = [] + if request.REQUEST.has_key('term'): + term = request.REQUEST['term'] + list = [{'label': name.short,'value': name.id} for name in Name.objects.filter(Q(short__contains=term) | Q(value__contains=term))] + return json_response(list)
\ No newline at end of file diff --git a/coip/apps/userprofile/views.py b/coip/apps/userprofile/views.py index fd114c9..4660a52 100644 --- a/coip/apps/userprofile/views.py +++ b/coip/apps/userprofile/views.py @@ -48,7 +48,7 @@ def home(request): home.short = "%s (%s)" % (profile.display_name,profile.identifier) home.save() add_member(home,profile.user,hidden=True) - home.setacl(home,"rwl") #don't allow users to delete or reset acls on their home, nor invite members - that would be confusing as hell + home.setacl(home,"rwlda") #don't allow users to delete or reset acls on their home, nor invite members - that would be confusing as hell names = [(link.src,link.data) for link in NameLink.objects.filter(dst__memberships__user=request.user,type=NameLink.access_control,data__contains='i').all()] diff --git a/coip/extensions/templatetags/permdisplay.py b/coip/extensions/templatetags/permdisplay.py index 23e6ed3..3928094 100644 --- a/coip/extensions/templatetags/permdisplay.py +++ b/coip/extensions/templatetags/permdisplay.py @@ -25,7 +25,7 @@ permdisplay.is_safe = True register.filter(permdisplay) def acldstdisplay(dst): - if dst.display.startswith("user:"): + if dst.display.startswith("user:") and dst.display.count(":") == 1: (pfx,username) = split(dst.display,":",1) user = User.objects.get(username=username) if user: @@ -33,7 +33,7 @@ def acldstdisplay(dst): else: return "Unknown user \"%s\"" % username else: - return "Members of <a class=\"tip\" title=\"%s\" href=\"/name/id/%d\">%s</a>" % (dst.display,dst.id,dst.short) + return "members of %s (%s)" % (dst.short,dst.display) acldstdisplay.is_safe = True diff --git a/coip/urls.py b/coip/urls.py index 4391f38..2b30391 100644 --- a/coip/urls.py +++ b/coip/urls.py @@ -35,19 +35,23 @@ urlpatterns = patterns('', # Names (r'^name/id/(?P<id>[0-9]+)(?:\.([^\.]+))?$', 'coip.apps.name.views.show_by_id'), (r'^name$', 'coip.apps.name.views.show_root'), + (r'^name/search.json$', 'coip.apps.name.views.search'), (r'^name/(?P<id>[0-9]+)/edit$', 'coip.apps.name.views.edit'), (r'^name/(?P<id>[0-9]+)/delete$', 'coip.apps.name.views.delete'), (r'^name/(?P<id>[0-9]+)/add$', 'coip.apps.name.views.add'), (r'^name/(?P<id>[0-9]+)/join$', 'coip.apps.membership.views.join'), (r'^name/(?P<id>[0-9]+)/join/(?P<membername>[^\/]+)$', 'coip.apps.membership.views.join'), (r'^name/(?P<id>[0-9]+)/leave/(?P<membername>[^\/]+)$', 'coip.apps.membership.views.leave'), - (r'^name/(?P<name>.+)(?:\.([^\.]+))?$', 'coip.apps.name.views.show_by_name'), # Name Links (r'^name/(?P<id>[0-9]+)/link/(?P<type>[0-9]+).json$', 'coip.apps.name.views.links'), - (r'^namelink/(?P<id>[0-9]+)/remove$', 'coip.apps.name.views.removelink'), - (r'^name/(?P<id>[0-9]+)/link/(?P<type>[0-9]+)$', 'coip.apps.name.views.editacl'), + # ACL + (r'^name/(?P<id>[0-9]+)/acl/(?P<type>[0-9]+)$', 'coip.apps.name.views.lsacl'), + (r'^name/(?P<id>[0-9]+)/acl/(?P<type>[0-9]+)/add$', 'coip.apps.name.views.addacl'), + (r'^name/(?P<id>[0-9]+)/acl/(?P<type>[0-9]+)/copy$', 'coip.apps.name.views.copyacl'), + (r'^name/(?P<id>[0-9]+)/acl/(?P<aclid>[0-9]+)/remove$', 'coip.apps.name.views.rmacl'), # Links (r'^name/(?P<id>[0-9]+)/addlink$', 'coip.apps.link.views.add'), + (r'^name/(?P<name>.+)(?:\.([^\.]+))?$', 'coip.apps.name.views.show_by_name'), (r'^link/(?P<id>[0-9]+)/remove$', 'coip.apps.link.views.remove'), # Membership (r'^membership/(?P<id>[0-9]+)$', 'coip.apps.membership.views.show'), diff --git a/site-media/css/style.css b/site-media/css/style.css index b827c95..4dd4e45 100644 --- a/site-media/css/style.css +++ b/site-media/css/style.css @@ -14,6 +14,7 @@ div#footer li { float: left; margin: 0 0.15em} .ilist li { float: left; display: inline; padding: inherit; } .rlist ul { list-style: none inside; padding: inherit; } .rlist li { float: right; display: inline; padding: inherit; } +.formpadding { padding: 5px; } p.description { padding-top: 20px; padding-bottom: 5px; } div#headline{ font: 300% "Trebuchet MS", sans-serif; margin-bottom: 20px;} .name { font: 100% "Trebuchet MS", sans-serif; margin-top: 5px;} @@ -26,6 +27,8 @@ li.links { padding: 0; margin: 0; } form .ui-widget ul { list-style: none inside; padding: 0; margin: 0; } form .ui-widget li { float: right; border-right: 1px solid #CECECE; padding-right: 5px; margin: 0; vertical-align: middle;} .fieldlabel { font-weight: bold; } +.fieldinput ul { list-style: none inside; padding: 0; margin: 0; } +.fieldinput li { padding: 0; margin: 0; } div#tree { padding-bottom: 50px;} #linklist { float: right; margin-right: 50px; } #linklist ul{ list-style: none; padding: 0; margin: 0; } diff --git a/templates/apps/name/acls.html b/templates/apps/name/acls.html index 5b91429..7fe8250 100644 --- a/templates/apps/name/acls.html +++ b/templates/apps/name/acls.html @@ -1,14 +1,32 @@ -{% extends "edit.html" %} +{% extends "tree.html" %} {% load permdisplay %} -{% block beforeform %} -<h1>Permissions on {{name}}</h1> -<table style="margin-bottom: 20px;"> +{% block widgets %} + $("#acl").accordion({ + header: 'h3', + collapsible: true, + active: false + }); +{% endblock %} +{% block content %} +<h1>Permissions on {{name.short}}</h1> +<div id="acl" style="margin-bottom: 20px;"> {% for ace in acl %} -<tr> - <td>{{ace.dst|acldstdisplay}}</td> - <td>{{ace.data|permdisplay}}</td> - <td><a href="/namelink/{{ace.id}}/remove"><span class="ui-icon ui-icon-trash"></span></td> -</tr> + <div id="{{ace.id}}"> + <h3 class="listheader">Permissions for {{ace.dst|acldstdisplay}}</h3> + <div> + <div>{{ace.dst|acldstdisplay}} {{ace.data|permdisplay}}.</div> + <div class="rlist button"> + <ul> + <li><a href="/name/{{ace.src.id}}/acl/{{ace.id}}/remove">Remove</a></li> + </ul> + </div> + </div> + </div> {% endfor %} -</table> +</div> +<div class="ilist button"> + <ul> + <li><a href="/name/{{name.id}}/acl/0/add">Add Permission</a></li> + </ul> +</div> {% endblock %}
\ No newline at end of file diff --git a/templates/apps/name/addace.html b/templates/apps/name/addace.html new file mode 100644 index 0000000..17d8362 --- /dev/null +++ b/templates/apps/name/addace.html @@ -0,0 +1,51 @@ +{% extends "edit_fieldsets.html" %} +{% load permdisplay %} +{% block widgets %} + $('#wizard').formwizard({ + validationEnabled: true, + focusFirstInput: true, + textSubmit: "Finish", + validationOptions: { + rules: { + subject_label: 'required' + } + } + }); + $('#id_subject').autocomplete({ + source: "/name/search.json", + focus: function(event, ui) { + $('#id_subject').val(ui.item.label); + return false; + }, + select: function(event, ui) { + $('#id_subject').val(ui.item.label); + $('#id_dst').val(ui.item.value); + return false; + }, + minLength: 2, + open: function() { + $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" ); + }, + close: function() { + $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" ); + } + }); +{% endblock %} +{% block beforeform %} +<h1>Permissions on {{name.short}}</h1> +<div id="acl" style="margin-bottom: 20px;"> +{% for ace in acl %} +<div id="{{acc.id}}"> + <h3 class="listheader">Permissions for {{ace.dst|acldstdisplay}}</h3> + <div> + <div>{{ace.dst|acldstdisplay}} {{ace.data|permdisplay}}.</div> + <div class="rlist button"> + <ul> + <li><a href="/namelink/{{ace.id}}/remove">Remove</a></li> + </ul> + </div> + </div> +</div> +{% endfor %} +</div> +{% endblock %}
\ No newline at end of file diff --git a/templates/apps/name/name.html b/templates/apps/name/name.html index 2489004..e00a887 100644 --- a/templates/apps/name/name.html +++ b/templates/apps/name/name.html @@ -28,7 +28,7 @@ <div class="rlist"> <ul> {% if render.acl %} - <li class="button"><a href="/name/{{name.id}}/link/0">Modify Access</a></li> + <li class="button"><a href="/name/{{name.id}}/acl/0">Modify Access</a></li> {% endif %} {% if render.edit %} <li class="button"><a href="/name/{{name.id}}/edit">Modify</a></li> diff --git a/templates/edit.html b/templates/edit.html index 337264d..0a17922 100644 --- a/templates/edit.html +++ b/templates/edit.html @@ -4,31 +4,33 @@ $('#id_description').wysiwyg(); {% endblock %} {% block content %} - {% block beforeform %} - {% endblock %} - <form method="POST" class="ui-helper-reset ui-widget-contents ui-corner-all"> - <div class="infopanel"> - <h1>{{formtitle}}</h1> - <table class="formtable"> - {% for field in form %} - <tr> - <td> - {% if not field.is_hidden %} - <div class="ui-widget fieldlabel">{{ field.label_tag }}</div> - {% endif %} - {% if field.errors %} - <div class="ui-widget ui-state-error">{{ field.errors }}</div> - {% endif %} - <div class="ui-widget">{{ field }}</div> - </td> - </tr> - {% endfor %} - </table> - </div> - <br/> - <div class="button"> - <input type="submit" value="{{submitname}}" /> - <input type="button" onClick="document.location='{{name.url}}'" value="Cancel"/> +{% block beforeform %}{% endblock %} +<div> + <form method="POST" class="bbq ui-helper-reset ui-widget ui-widget-content ui-corner-all formpadding"> + <h1>{{formtitle}}</h1> + <table class="formtable"> + {% for field in form %} + <tr> + <td> + {% if not field.is_hidden %} + <div class="ui-widget fieldlabel">{{ field.label_tag }}</div> + {% endif %} + {% if field.errors %} + <div class="ui-widget ui-state-error">{{ field.errors }}</div> + {% endif %} + <div class="ui-widget">{{ field }}</div> + </td> + </tr> + {% endfor %} + </table> + <div class="ilist button" style="padding-bottom: 10px;"> + <ul> + <li><input type="submit" value="{{submitname}}" /></li> + {% if name %} + <li style="float: right;"><input type="button" onClick="document.location='{{name.url}}'" value="Done"/></li> + {% endif %} + </ul> </div> </form> +</div> {% endblock %}
\ No newline at end of file diff --git a/templates/edit_fieldsets.html b/templates/edit_fieldsets.html index d528a4c..0a8186f 100644 --- a/templates/edit_fieldsets.html +++ b/templates/edit_fieldsets.html @@ -3,8 +3,8 @@ {% block content %} {% block beforeform %} {% endblock %} - <div class="infopanel"> - <form method="POST" id="wizard" class="bbq" style="padding: 5px;"> + <div> + <form method="POST" id="wizard" class="bbq formpadding"> <h1>{{formtitle}}</h1> {% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %} {% for fieldset in form.fieldsets %} @@ -22,9 +22,9 @@ {% else %} <li class="links {% if field.field.required %}required{% endif %}" {{ field.row_attrs }}> {{ field.errors }} - <label for="id_{{ field.html_name }}">{{ field.label }} + <label for="id_{{ field.html_name }}" class="fieldlabel">{{ field.label }} {% if field.field.required %}<b>*</b>{% endif %}</label> - {{ field }} + <div class="fieldinput">{{ field }}</div> </li> {% endif %} {% endfor %} |