From bdbd4b02505a6645ef24529ba85ba0e39e05c847 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 12 Jun 2014 17:27:07 +0200 Subject: [PATCH] wip: Radicale extension. Check permissions and generate owner access rules. --- modoboa/extensions/radicale/forms.py | 6 +++++- .../management/commands/generate_rights.py | 4 ++++ modoboa/extensions/radicale/models.py | 13 ++++++++++++ .../radicale/static/radicale/js/radicale.js | 21 +++++++++++++------ .../templates/radicale/calendar_list.html | 4 +++- modoboa/extensions/radicale/views.py | 14 +++++++++---- modoboa/lib/formutils.py | 1 + 7 files changed, 51 insertions(+), 12 deletions(-) diff --git a/modoboa/extensions/radicale/forms.py b/modoboa/extensions/radicale/forms.py index ca551238d..51ee4fc21 100644 --- a/modoboa/extensions/radicale/forms.py +++ b/modoboa/extensions/radicale/forms.py @@ -128,7 +128,9 @@ class UserCalendarWizard(WizardForm): def __init__(self, request): super(UserCalendarWizard, self).__init__(request) self.add_step(UserCalendarForm, _("General")) - self.add_step(RightsForm, _("Rights")) + self.add_step( + RightsForm, _("Rights"), formtpl="radicale/rightsform.html" + ) def extra_context(self, context): context.update({ @@ -141,6 +143,8 @@ class UserCalendarWizard(WizardForm): calendar = self.first_step.form.save(commit=False) calendar.mailbox = self.request.user.mailbox_set.all()[0] calendar.save() + self.steps[1].form.calendar = calendar + self.steps[1].form.save() return render_to_json_response(_("Calendar created")) diff --git a/modoboa/extensions/radicale/management/commands/generate_rights.py b/modoboa/extensions/radicale/management/commands/generate_rights.py index 67ece9c2a..83e3aae57 100644 --- a/modoboa/extensions/radicale/management/commands/generate_rights.py +++ b/modoboa/extensions/radicale/management/commands/generate_rights.py @@ -86,6 +86,10 @@ permission = %s "domain-shared-calendars", r"^(.+)@(.+)$", r"{1}/shared/.+$", comment="Access rule to domain shared calendars" ) + self._generate_acr( + "owners-access", r"^(.+)@(.+)$", r"{1}/user/{0}/.+$", + comment="Read/Write permission for calendar owners" + ) self._user_access_rules() self._cfgfile.close() diff --git a/modoboa/extensions/radicale/models.py b/modoboa/extensions/radicale/models.py index 11d94f259..2a6625de0 100644 --- a/modoboa/extensions/radicale/models.py +++ b/modoboa/extensions/radicale/models.py @@ -31,6 +31,11 @@ class Calendar(models.Model): """Return calendar type""" raise NotImplementedError + @property + def owner(self): + """Return calendar owner""" + raise NotImplementedError + class UserCalendarManager(models.Manager): """Custom UserCalendar manager. @@ -70,6 +75,10 @@ class UserCalendar(Calendar): def type(self): return _("user") + @property + def owner(self): + return self.mailbox.user + class SharedCalendarManager(models.Manager): """Custom SharedCalendar manager. @@ -109,6 +118,10 @@ class SharedCalendar(Calendar): def type(self): return _("shared") + @property + def owner(self): + return self.domain + @python_2_unicode_compatible class AccessRule(models.Model): diff --git a/modoboa/extensions/radicale/static/radicale/js/radicale.js b/modoboa/extensions/radicale/static/radicale/js/radicale.js index 4b4070751..c04595fdd 100644 --- a/modoboa/extensions/radicale/static/radicale/js/radicale.js +++ b/modoboa/extensions/radicale/static/radicale/js/radicale.js @@ -19,7 +19,7 @@ Radicale.prototype = { this.options.defcallback = $.proxy(this.list_cb, this); this.navobj = new History(this.options); $(document).on( - "click", "a[name=delcalendar]", this.del_calendar + "click", "a[name=delcalendar]", $.proxy(this.del_calendar, this) ); }, @@ -34,13 +34,25 @@ Radicale.prototype = { * */ reload_listing: function(data) { + console.log("reload"); this.navobj.update(true); if (data) { $("body").notify("success", data, 2000); } }, + /** + * Rights form initialization. + */ + rightsform_init: function() { + $("#original_row").dynamicrule(); + $("#id_username").autocompleter({ + choices: $.proxy(this.get_username_list, this) + }); + }, + add_calendar_cb: function() { + this.rightsform_init(); $("#wizard").cwizard({ formid: "newcal_form", success_callback: $.proxy(this.reload_listing, this) @@ -64,10 +76,7 @@ Radicale.prototype = { }, edit_calendar_cb: function() { - $("#original_row").dynamicrule(); - $("#id_username").autocompleter({ - choices: $.proxy(this.get_username_list, this) - }); + this.rightsform_init(); $('.submit').on('click', $.proxy(function(e) { simple_ajax_form_post(e, { formid: "ucal_form", @@ -92,7 +101,7 @@ Radicale.prototype = { */ del_calendar: function(event) { event.preventDefault(); - var $link = $(this); + var $link = get_target(event, "a"); if (!confirm($link.attr("title"))) { return; diff --git a/modoboa/extensions/radicale/templates/radicale/calendar_list.html b/modoboa/extensions/radicale/templates/radicale/calendar_list.html index 294ae5ac2..219704a07 100644 --- a/modoboa/extensions/radicale/templates/radicale/calendar_list.html +++ b/modoboa/extensions/radicale/templates/radicale/calendar_list.html @@ -2,7 +2,8 @@ - + + {% if with_owner %}{% endif %} @@ -12,6 +13,7 @@ {% for cal in calendars %} + {% if with_owner %}{% endif %} diff --git a/modoboa/extensions/radicale/views.py b/modoboa/extensions/radicale/views.py index 863b446a5..b97031814 100644 --- a/modoboa/extensions/radicale/views.py +++ b/modoboa/extensions/radicale/views.py @@ -36,14 +36,16 @@ def calendars(request, tplname="radicale/calendar_list.html"): if request.user.group == "SimpleUsers": mbox = request.user.mailbox_set.all()[0] cals = UserCalendar.objects.filter(mailbox=mbox).select_related().all() + with_owner = False else: cals = chain( UserCalendar.objects.get_for_admin(request.user), SharedCalendar.objects.get_for_admin(request.user) ) + with_owner = True return render_to_json_response({ "table": _render_to_string(request, tplname, { - "calendars": cals + "calendars": cals, "with_owner": with_owner }) }) @@ -60,12 +62,14 @@ def user_calendar(request, pk): """Edit or remove a calendar. """ try: - ucal = UserCalendar.objects.get(pk=pk) + ucal = UserCalendar.objects.select_related().get(pk=pk) except UserCalendar.DoesNotExist: raise NotFound + if request.user != ucal.mailbox.user and \ + not request.user.can_access(ucal.mailbox.domain): + raise PermDeniedException instances = {"general": ucal, "rights": ucal} if request.method == "DELETE": - # Check ownership ucal.delete() return render_to_json_response(_("Calendar removed")) return UserCalendarEditionForm(request, instances=instances).process() @@ -104,12 +108,14 @@ def shared_calendar(request, pk): """Edit or remove a shared calendar. """ try: - scal = SharedCalendar.objects.get(pk=pk) + scal = SharedCalendar.objects.select_related().get(pk=pk) except SharedCalendar.DoesNotExist: raise NotFound if not request.user.can_access(scal.domain): raise PermDeniedException if request.method == "DELETE": + if not request.user.can_access(scal.domain): + raise PermDeniedException scal.delete() return render_to_json_response(_("Calendar removed")) if request.method == "POST": diff --git a/modoboa/lib/formutils.py b/modoboa/lib/formutils.py index 153021bdd..5ff1308c9 100644 --- a/modoboa/lib/formutils.py +++ b/modoboa/lib/formutils.py @@ -34,6 +34,7 @@ class WizardStep(object): @property def title(self): + """Return step title""" if self.index is None: return self._title return "%d. %s" % (self.index + 1, self._title)
{% trans "Name" %}{% trans "Name" %}{% trans "Owner" %}{% trans "Type" %} {% trans "Address" %} {% trans "Actions" %}
{% calendar_modify_link cal %}{{ cal.owner }} {{ cal.type }}