From ec441a5c0796f54b79c6e7c19743fb501f695ff0 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 11 Feb 2015 13:24:09 +0100 Subject: [PATCH] Remove radicale extension. --- modoboa/extensions/radicale/__init__.py | 0 modoboa/extensions/radicale/app_settings.py | 42 --- modoboa/extensions/radicale/factories.py | 37 --- modoboa/extensions/radicale/forms.py | 215 -------------- .../extensions/radicale/general_callbacks.py | 38 --- .../radicale/management/__init__.py | 0 .../radicale/management/commands/__init__.py | 0 .../management/commands/generate_rights.py | 116 -------- .../radicale/migrations/0001_initial.py | 66 ----- .../radicale/migrations/__init__.py | 0 modoboa/extensions/radicale/models.py | 165 ----------- modoboa/extensions/radicale/modo_extension.py | 33 --- .../radicale/static/radicale/css/radicale.css | 21 -- .../static/radicale/js/jquery.dynamicrule.js | 105 ------- .../radicale/static/radicale/js/radicale.js | 125 --------- .../templates/radicale/accessrule.html | 9 - .../templates/radicale/calendar_detail.html | 10 - .../templates/radicale/calendars.html | 59 ---- .../templates/radicale/calendars_page.html | 9 - .../templates/radicale/rightsform.html | 8 - .../radicale/templatetags/__init__.py | 0 .../radicale/templatetags/radicale_tags.py | 113 -------- modoboa/extensions/radicale/tests.py | 265 ------------------ modoboa/extensions/radicale/urls.py | 20 -- modoboa/extensions/radicale/views.py | 217 -------------- 25 files changed, 1673 deletions(-) delete mode 100644 modoboa/extensions/radicale/__init__.py delete mode 100644 modoboa/extensions/radicale/app_settings.py delete mode 100644 modoboa/extensions/radicale/factories.py delete mode 100644 modoboa/extensions/radicale/forms.py delete mode 100644 modoboa/extensions/radicale/general_callbacks.py delete mode 100644 modoboa/extensions/radicale/management/__init__.py delete mode 100644 modoboa/extensions/radicale/management/commands/__init__.py delete mode 100644 modoboa/extensions/radicale/management/commands/generate_rights.py delete mode 100644 modoboa/extensions/radicale/migrations/0001_initial.py delete mode 100644 modoboa/extensions/radicale/migrations/__init__.py delete mode 100644 modoboa/extensions/radicale/models.py delete mode 100644 modoboa/extensions/radicale/modo_extension.py delete mode 100644 modoboa/extensions/radicale/static/radicale/css/radicale.css delete mode 100644 modoboa/extensions/radicale/static/radicale/js/jquery.dynamicrule.js delete mode 100644 modoboa/extensions/radicale/static/radicale/js/radicale.js delete mode 100644 modoboa/extensions/radicale/templates/radicale/accessrule.html delete mode 100644 modoboa/extensions/radicale/templates/radicale/calendar_detail.html delete mode 100644 modoboa/extensions/radicale/templates/radicale/calendars.html delete mode 100644 modoboa/extensions/radicale/templates/radicale/calendars_page.html delete mode 100644 modoboa/extensions/radicale/templates/radicale/rightsform.html delete mode 100644 modoboa/extensions/radicale/templatetags/__init__.py delete mode 100644 modoboa/extensions/radicale/templatetags/radicale_tags.py delete mode 100644 modoboa/extensions/radicale/tests.py delete mode 100644 modoboa/extensions/radicale/urls.py delete mode 100644 modoboa/extensions/radicale/views.py diff --git a/modoboa/extensions/radicale/__init__.py b/modoboa/extensions/radicale/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/radicale/app_settings.py b/modoboa/extensions/radicale/app_settings.py deleted file mode 100644 index 80a6f10f8..000000000 --- a/modoboa/extensions/radicale/app_settings.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.utils.translation import ugettext_lazy -from django import forms -from modoboa.lib.parameters import AdminParametersForm -from modoboa.lib.form_utils import SeparatorField, YesNoField - - -class ParametersForm(AdminParametersForm): - app = "radicale" - - server_settings = SeparatorField( - label=ugettext_lazy("Server settings") - ) - - server_location = forms.CharField( - label=ugettext_lazy("Server URL"), - help_text=ugettext_lazy( - "The URL of your Radicale server. " - "It will be used to construct calendar URLs." - ), - widget=forms.TextInput(attrs={"class": "form-control"}) - ) - - rights_management_sep = SeparatorField( - label=ugettext_lazy("Rights management")) - - rights_file_path = forms.CharField( - label=ugettext_lazy("Rights file's path"), - initial="/etc/radicale/rights", - help_text=ugettext_lazy( - "Path to the file that contains rights definition" - ), - widget=forms.TextInput(attrs={"class": "form-control"}) - ) - - allow_calendars_administration = YesNoField( - label=ugettext_lazy("Allow calendars administration"), - initial="no", - help_text=ugettext_lazy( - "Allow domain administrators to manage user calendars " - "(read and write)" - ) - ) diff --git a/modoboa/extensions/radicale/factories.py b/modoboa/extensions/radicale/factories.py deleted file mode 100644 index 278cc3232..000000000 --- a/modoboa/extensions/radicale/factories.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Fixtures factories. -""" -import factory - -from modoboa.extensions.admin.factories import ( - DomainFactory, MailboxFactory -) - -from . import models - - -class UserCalendarFactory(factory.DjangoModelFactory): - - class Meta: - model = models.UserCalendar - - name = factory.Sequence(lambda n: 'User calendar %s' % n) - mailbox = factory.SubFactory(MailboxFactory) - - -class SharedCalendarFactory(factory.DjangoModelFactory): - - class Meta: - model = models.SharedCalendar - - name = factory.Sequence(lambda n: 'Shared calendar %s' % n) - domain = factory.SubFactory(DomainFactory) - - -class AccessRuleFactory(factory.DjangoModelFactory): - - class Meta: - model = models.AccessRule - - mailbox = factory.SubFactory(MailboxFactory) - calendar = factory.SubFactory(UserCalendarFactory) diff --git a/modoboa/extensions/radicale/forms.py b/modoboa/extensions/radicale/forms.py deleted file mode 100644 index 14472ded1..000000000 --- a/modoboa/extensions/radicale/forms.py +++ /dev/null @@ -1,215 +0,0 @@ -""" -Radicale extension forms. -""" - -from django import forms -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _, ugettext_lazy - -from modoboa.extensions.admin.models import Domain, Mailbox -from modoboa.extensions.radicale.models import UserCalendar, SharedCalendar -from modoboa.lib.form_utils import WizardForm, TabForms, DynamicForm -from modoboa.lib.web_utils import render_to_json_response - - -class UserCalendarForm(forms.ModelForm): - - """User calendar form.""" - - class Meta: - model = UserCalendar - fields = ('name', 'mailbox', ) - widgets = { - 'mailbox': forms.widgets.Select( - attrs={ - "class": "selectpicker", "data-live-search": "true" - } - ) - } - - def __init__(self, user, *args, **kwargs): - """Custom constructor. - - We need the current user to filter the mailbox list. - """ - super(UserCalendarForm, self).__init__(*args, **kwargs) - if user.group == 'SimpleUsers': - del self.fields['mailbox'] - else: - self.fields['mailbox'].queryset = \ - Mailbox.objects.get_for_admin(user) - - -class SharedCalendarForm(forms.ModelForm): - - """Shared calendar form.""" - - class Meta: - model = SharedCalendar - widgets = { - "name": forms.TextInput(attrs={"class": "form-control"}), - "domain": forms.widgets.Select( - attrs={"class": "selectpicker", "data-live-search": "true"} - ) - } - - def __init__(self, user, *args, **kwargs): - """Custom constructor. - - We need the current user to filter the domain list. - """ - super(SharedCalendarForm, self).__init__(*args, **kwargs) - self.fields["domain"].queryset = Domain.objects.get_for_admin(user) - - -class RightsForm(forms.Form, DynamicForm): - - """Rights definition form.""" - - username = forms.CharField( - label="", required=False, widget=forms.widgets.TextInput( - attrs={"placeholder": ugettext_lazy("Username")} - ) - ) - read_access = forms.BooleanField( - initial=False, label=_("Read"), required=False - ) - write_access = forms.BooleanField( - initial=False, label=_("Write"), required=False - ) - - def __init__(self, *args, **kwargs): - from django.http import QueryDict - - if "instance" in kwargs: - self.calendar = kwargs["instance"] - del kwargs["instance"] - else: - self.calendar = None - super(RightsForm, self).__init__(*args, **kwargs) - - if self.calendar: - cpt = 1 - for rule in self.calendar.rules.all(): - self._create_field( - forms.EmailField, "username_%d" % cpt, - rule.mailbox.full_address - ) - self._create_field( - forms.BooleanField, "read_access_%d" % cpt, rule.read - ) - self._create_field( - forms.BooleanField, "write_access_%d" % cpt, rule.write - ) - cpt += 1 - - if args and isinstance(args[0], QueryDict): - self._load_from_qdict(args[0], "username", forms.EmailField) - self._load_from_qdict(args[0], "read_access", forms.BooleanField) - self._load_from_qdict(args[0], "write_access", forms.BooleanField) - - def save(self): - """Custom save method.""" - import re - from modoboa.lib.email_utils import split_mailbox - from modoboa.lib.exceptions import BadRequest - from modoboa.extensions.admin.models import Mailbox - from .models import AccessRule - - usernames = {} - for name, value in self.cleaned_data.iteritems(): - if not name.startswith("username") or not value: - continue - res = re.match(r"[^_]+_(\d+)$", name) - pos = int(res.group(1)) if res else None - usernames[value] = pos - for rule in self.calendar.rules.select_related().all(): - if rule.mailbox.full_address not in usernames: - rule.delete() - for username, pos in usernames.iteritems(): - local_part, domname = split_mailbox(username) - try: - mbox = Mailbox.objects.get( - address=local_part, domain__name=domname - ) - except Mailbox.DoesNotExist: - raise BadRequest(_("Mailbox %s does not exist")) - if pos: - raccess = self.cleaned_data.get("read_access_%d" % pos, False) - waccess = self.cleaned_data.get("write_access_%d" % pos, False) - else: - raccess = self.cleaned_data.get("read_access", False) - waccess = self.cleaned_data.get("write_access", False) - acr, created = AccessRule.objects.get_or_create( - mailbox=mbox, calendar=self.calendar - ) - acr.read = raccess - acr.write = waccess - acr.save() - - -class UserCalendarWizard(WizardForm): - - """Calendar creation wizard.""" - - def __init__(self, request): - super(UserCalendarWizard, self).__init__(request) - self.add_step(UserCalendarForm, _("General"), new_args=[request.user]) - self.add_step( - RightsForm, _("Rights"), formtpl="radicale/rightsform.html", - ) - - def extra_context(self, context): - context.update({ - "title": _("New calendar"), - "action": reverse("radicale:user_calendar_add"), - "formid": "newcal_form" - }) - - def done(self): - calendar = self.first_step.form.save(commit=False) - if self.request.user.group == 'SimpleUsers': - 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")) - - -class UserCalendarEditionForm(TabForms): - - """User calendar edition form.""" - - def __init__(self, request, *args, **kwargs): - self.forms = [] - self.forms.append({ - "id": "general", - "title": _("General"), - "cls": UserCalendarForm, - "mandatory": True, - "new_args": [request.user] - }) - self.forms.append({ - "id": "rights", - "title": _("Rights"), - "cls": RightsForm, - "formtpl": "radicale/rightsform.html", - "mandatory": True - }) - super(UserCalendarEditionForm, self).__init__(request, *args, **kwargs) - - def extra_context(self, context): - calendar = self.instances["general"] - context.update({ - "title": self.instances["general"].name, - "formid": "ucal_form", - "action": reverse("radicale:user_calendar", args=[calendar.id]) - }) - - def save(self): - """Custom save method.""" - calendar = self.forms[0]["instance"].save() - self.forms[1]["instance"].save() - - def done(self): - return render_to_json_response(_("Calendar updated")) diff --git a/modoboa/extensions/radicale/general_callbacks.py b/modoboa/extensions/radicale/general_callbacks.py deleted file mode 100644 index 9cfb78938..000000000 --- a/modoboa/extensions/radicale/general_callbacks.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -General callbacks. -""" - -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _ -from modoboa.lib import events - -PERMISSIONS = [ - ("radicale", "usercalendar", "add_usercalendar"), - ("radicale", "usercalendar", "change_usercalendar"), - ("radicale", "usercalendar", "delete_usercalendar"), - ("radicale", "sharedcalendar", "add_sharedcalendar"), - ("radicale", "sharedcalendar", "change_sharedcalendar"), - ("radicale", "sharedcalendar", "delete_sharedcalendar") -] - -ROLES_PERMISSIONS = { - "DomainAdmins": PERMISSIONS, - "Resellers": PERMISSIONS -} - - -@events.observe("GetExtraRolePermissions") -def extra_permissions(rolename): - """Extra permissions.""" - return ROLES_PERMISSIONS.get(rolename, []) - - -@events.observe("UserMenuDisplay") -def top_menu(target, user): - if target == "top_menu": - return [ - {"name": "radicale", - "label": _("Calendars"), - "url": reverse('radicale:index')} - ] - return [] diff --git a/modoboa/extensions/radicale/management/__init__.py b/modoboa/extensions/radicale/management/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/radicale/management/commands/__init__.py b/modoboa/extensions/radicale/management/commands/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/radicale/management/commands/generate_rights.py b/modoboa/extensions/radicale/management/commands/generate_rights.py deleted file mode 100644 index 3dd857c97..000000000 --- a/modoboa/extensions/radicale/management/commands/generate_rights.py +++ /dev/null @@ -1,116 +0,0 @@ -import os -import datetime -from optparse import make_option - -from django.core.management.base import BaseCommand - -from modoboa.core.management.commands import CloseConnectionMixin -from modoboa.core.models import User -from modoboa.lib import parameters -from modoboa.extensions.admin.models import Domain -from modoboa.extensions.radicale.models import ( - AccessRule -) - - -class Command(BaseCommand, CloseConnectionMixin): - help = "Generate Radicale rights file" - - option_list = BaseCommand.option_list + ( - make_option('--force', - action='store_true', - default=False, - help='Force generation of rights file'), - ) - - def _generate_acr(self, name, user, collection, perm="rw", comment=None): - """Write a new access control rule to the config file. - """ - if comment is not None: - self._cfgfile.write("\n# %s" % comment) - self._cfgfile.write(""" -[%s] -user = %s -collection = %s -permission = %s -""" % (name, user, collection, perm) - ) - - def _user_access_rules(self): - """Create user access rules. - """ - for acr in AccessRule.objects.select_related().all(): - section = "%s-to-%s-acr" % ( - acr.mailbox, acr.calendar - ) - permission = "" - if acr.read: - permission += "r" - if acr.write: - permission += "w" - self._generate_acr( - section, acr.mailbox.full_address, acr.calendar.path, - permission, - ) - - def _super_admin_rules(self): - """Generate access rules for super administrators. - """ - for sa in User.objects.filter(is_superuser=True): - section = "sa-%s-acr" % sa.username - self._generate_acr( - section, sa.username, ".*" - ) - - def _domain_admin_rules(self): - """Generate access rules for domain adminstrators. - """ - for da in User.objects.filter(groups__name="DomainAdmins"): - for domain in Domain.objects.get_for_admin(da): - section = "da-%s-to-%s-acr" % (da.email, domain.name) - self._generate_acr( - section, da.email, "%s/user/.*" % domain.name - ) - - def _generate_file(self, target): - """ - A user must not declare a rule for his direct admin! - """ - self._cfgfile = open(target, "w") - self._cfgfile.write("""# Rights management file for Radicale -# This file was generated by Modoboa on %s -# DO NOT EDIT MANUALLY! - """ % datetime.datetime.today()) - - allow_calendars_administration = parameters.get_admin( - "ALLOW_CALENDARS_ADMINISTRATION", app="radicale") - if allow_calendars_administration == "yes": - self._super_admin_rules() - self._domain_admin_rules() - - self._generate_acr( - "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() - - def handle(self, *args, **options): - """Command entry point.""" - path = parameters.get_admin("RIGHTS_FILE_PATH", app="radicale") - if not options["force"]: - try: - mtime = datetime.datetime.fromtimestamp( - int(os.path.getmtime(path)) - ) - except OSError: - pass - else: - if not AccessRule.objects.filter(last_update__gt=mtime).count(): - return - self._generate_file(path) diff --git a/modoboa/extensions/radicale/migrations/0001_initial.py b/modoboa/extensions/radicale/migrations/0001_initial.py deleted file mode 100644 index 8654a5fc0..000000000 --- a/modoboa/extensions/radicale/migrations/0001_initial.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('admin', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='AccessRule', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('read', models.BooleanField(default=False)), - ('write', models.BooleanField(default=False)), - ('last_update', models.DateTimeField(auto_now=True)), - ], - options={ - }, - bases=(models.Model,), - ), - migrations.CreateModel( - name='SharedCalendar', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=200)), - ('domain', models.ForeignKey(to='admin.Domain')), - ], - options={ - 'abstract': False, - }, - bases=(models.Model,), - ), - migrations.CreateModel( - name='UserCalendar', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=200)), - ('mailbox', models.ForeignKey(to='admin.Mailbox')), - ], - options={ - 'abstract': False, - }, - bases=(models.Model,), - ), - migrations.AddField( - model_name='accessrule', - name='calendar', - field=models.ForeignKey(related_name='rules', to='radicale.UserCalendar'), - preserve_default=True, - ), - migrations.AddField( - model_name='accessrule', - name='mailbox', - field=models.ForeignKey(to='admin.Mailbox'), - preserve_default=True, - ), - migrations.AlterUniqueTogether( - name='accessrule', - unique_together=set([('mailbox', 'calendar')]), - ), - ] diff --git a/modoboa/extensions/radicale/migrations/__init__.py b/modoboa/extensions/radicale/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/radicale/models.py b/modoboa/extensions/radicale/models.py deleted file mode 100644 index 23c325769..000000000 --- a/modoboa/extensions/radicale/models.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -Radicale extension models. -""" -from __future__ import unicode_literals - -import os - -from django.db import models -from django.utils.encoding import python_2_unicode_compatible -from django.utils.translation import ugettext as _ - -from modoboa.extensions.admin.models import Domain -from modoboa.lib import parameters - - -@python_2_unicode_compatible -class Calendar(models.Model): - - """Abstract calendar definition.""" - - name = models.CharField(max_length=200) - - class Meta: - abstract = True - - def __str__(self): - return self.name - - @property - def path(self): - """Return the calendar path.""" - raise NotImplementedError - - @property - def url(self): - """Return the calendar URL.""" - if not hasattr(self, "_url"): - self._url = os.path.join( - parameters.get_admin("SERVER_LOCATION"), - self.path - ) - return self._url - - @property - def tags(self): - """Return calendar tags.""" - raise NotImplementedError - - @property - def owner(self): - """Return calendar owner.""" - raise NotImplementedError - - -class UserCalendarManager(models.Manager): - - """Custom UserCalendar manager.""" - - def get_for_admin(self, admin): - """Return the list of calendars this admin can access. - - :param ``core.User`` admin: administrator - """ - domains = Domain.objects.get_for_admin(admin) - return self.get_query_set().filter(mailbox__domain__in=domains) - - -class UserCalendar(Calendar): - - """User calendar. - - We associate the calendar to a mailbox because we need to access - the related domain. - - """ - mailbox = models.ForeignKey("admin.Mailbox") - - objects = UserCalendarManager() - - @property - def path(self): - """Return the calendar path. - - /user// - """ - if not hasattr(self, "_path"): - self._path = "%s/user/%s/%s" % ( - self.mailbox.domain.name, self.mailbox.address, self.name - ) - return self._path - - @property - def tags(self): - return [{"name": "user", "label": _("User"), "type": "cal"}] - - @property - def owner(self): - return self.mailbox.user - - -class SharedCalendarManager(models.Manager): - - """Custom SharedCalendar manager.""" - - def get_for_admin(self, admin): - """Return the list of calendars this admin can access. - - :param ``core.User`` admin: administrator - """ - domains = Domain.objects.get_for_admin(admin) - return self.get_query_set().filter(domain__in=domains) - - -class SharedCalendar(Calendar): - - """Shared calendar. - - A shared calendar is associated to a domain and is readable and - writable by all domain members. - - """ - - domain = models.ForeignKey("admin.Domain") - - objects = SharedCalendarManager() - - @property - def path(self): - """Return the calendar path. - - /shared/ - """ - if not hasattr(self, "_path"): - self._path = "%s/shared/%s" % (self.domain.name, self.name) - return self._path - - @property - def tags(self): - return [{"name": "shared", "label": _("Shared"), "type": "cal"}] - - @property - def owner(self): - """Return calendar owner.""" - return self.domain - - -@python_2_unicode_compatible -class AccessRule(models.Model): - - """Access rules to user calendars.""" - - mailbox = models.ForeignKey("admin.Mailbox") - read = models.BooleanField(default=False) - write = models.BooleanField(default=False) - calendar = models.ForeignKey(UserCalendar, related_name="rules") - last_update = models.DateTimeField(auto_now=True) - - class Meta: - unique_together = ('mailbox', 'calendar') - - def __str__(self): - access = "r" if self.read else "" - access += "w" if self.write else "" - return "%s access rule to %s -> " \ - % (self.mailbox, self.calendar, access if access else "no access") diff --git a/modoboa/extensions/radicale/modo_extension.py b/modoboa/extensions/radicale/modo_extension.py deleted file mode 100644 index 02c9fb9dc..000000000 --- a/modoboa/extensions/radicale/modo_extension.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Radicale management frontend. - -""" - -from django.utils.translation import ugettext_lazy - -from modoboa.core.extensions import ModoExtension, exts_pool -from modoboa.lib import parameters - - -class Radicale(ModoExtension): - - """Radicale extension declaration.""" - - name = "radicale" - label = ugettext_lazy("Radicale management") - version = "1.0" - url = "calendars" - description = ugettext_lazy( - "Management frontend for Radicale, a simple calendar and contact " - "server." - ) - - def load(self): - """Plugin loading. - """ - from .app_settings import ParametersForm - - parameters.register(ParametersForm, "Radicale") - from modoboa.extensions.radicale import general_callbacks - -exts_pool.register_extension(Radicale) diff --git a/modoboa/extensions/radicale/static/radicale/css/radicale.css b/modoboa/extensions/radicale/static/radicale/css/radicale.css deleted file mode 100644 index 1be71507f..000000000 --- a/modoboa/extensions/radicale/static/radicale/css/radicale.css +++ /dev/null @@ -1,21 +0,0 @@ -#searchform { - margin-bottom: 10px; -} - -#original_row { - margin-left: 100px; -} - -.access-rule { - margin-top: 5px; - margin-left: 100px; -} - -.addrule, .delrule { - margin-left: 10px; -} - -table tr td[name=actions], -table tr th#actions { - text-align: right; -} \ No newline at end of file diff --git a/modoboa/extensions/radicale/static/radicale/js/jquery.dynamicrule.js b/modoboa/extensions/radicale/static/radicale/js/jquery.dynamicrule.js deleted file mode 100644 index cf94de18c..000000000 --- a/modoboa/extensions/radicale/static/radicale/js/jquery.dynamicrule.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @module jquery.dynamicrule - */ - -(function($) { - var DynamicRule = function(element, options) { - this.initialize(element, options); - }; - - DynamicRule.prototype = { - constructor: DynamicRule, - - /** - * Creates an instance of DynamicRule. - * - * @constructor - * @this {DynamicRule} - * @param {object} element - - * @param {dictionary} options - instance options - */ - initialize: function(element, options) { - this.$element = $(element); - this.options = $.extend({}, $.fn.dynamicrule.defaults, options); - this.rules_counter = 1; - - $(document).on( - "click", "a[class=addrule]", $.proxy(this.add_rule, this) - ); - $(document).on( - "click", "a[class=delrule]", $.proxy(this.delete_rule, this) - ); - }, - - /** - * Reset the current rule to default values. - */ - reset_original_rule: function() { - this.$element.find("#id_username").prop("value", ""); - this.$element.find("#id_read_access").prop("checked", ""); - this.$element.find("#id_write_access").prop("checked", ""); - }, - - /** - * Save the current rule to a new set of elements and reset - * the original ones. - */ - add_rule: function(event) { - var rulename = $("#id_username").prop("value"); - - event.preventDefault(); - if (rulename === "") { - return; - } - var $clone = this.$element.clone(); - var $btn = $clone.find("a"); - - $clone.attr("id", ""); - $btn.find("span").removeClass("fa-plus").addClass("fa-trash"); - $btn.removeClass("addrule").addClass("delrule"); - $clone.find("#id_username") - .attr("id", "id_username_" + this.rules_counter) - .attr("name", "username_" + this.rules_counter); - $clone.find("#id_read_access") - .attr("id", "id_read_access_" + this.rules_counter) - .attr("name", "read_access_" + this.rules_counter); - $clone.find("#id_write_access") - .attr("id", "id_write_access_" + this.rules_counter) - .attr("name", "write_access_" + this.rules_counter); - $clone.insertAfter(this.$element); - this.rules_counter++; - this.reset_original_rule(); - }, - - /** - * Delete a given rule. - * - * @param {object} event - event object - */ - delete_rule: function(event) { - event.preventDefault(); - var $link = get_target(event, "a"); - - $link.parent().remove(); - } - }; - - $.fn.dynamicrule = function(method) { - return this.each(function() { - var $this = $(this), - data = $this.data('dynamicrule'), - options = typeof method === "object" && method; - - if (!data) { - $this.data('dynamicrule', new DynamicRule(this, options)); - } - if (typeof method === "string") { - data[method](); - } - }); - }; - - $.fn.dynamicrule.defaults = { - }; - -})(jQuery); diff --git a/modoboa/extensions/radicale/static/radicale/js/radicale.js b/modoboa/extensions/radicale/static/radicale/js/radicale.js deleted file mode 100644 index a38393bcc..000000000 --- a/modoboa/extensions/radicale/static/radicale/js/radicale.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Creates an instance of Radicale. - * - * @constructor - * @param {Object} options - instance options - * @classdesc This class contains a set of methods used by the - * Radicale application. - */ -var Radicale = function(options) { - Listing.call(this, options); -}; - -Radicale.prototype = { - constructor: Radicale, - - defaults: { - deflocation: "list/", - main_table_id: "calendar_table", - eor_message: gettext("No more calendar to show") - }, - - initialize: function(options) { - this.options = $.extend({}, this.defaults, options); - this.options.defcallback = $.proxy(this.list_cb, this); - Listing.prototype.initialize.call(this, this.options); - this.options.navigation_params.push("calfilter"); - this.register_tag_handler("cal", this.generic_tag_handler); - $(document).on( - "click", "a[name=delcalendar]", $.proxy(this.del_calendar, this) - ); - }, - - list_cb: function(data) { - $("#{0} tbody".format(this.options.main_table_id)).html(data.rows); - this.update_listing(data); - }, - - /** - * Refresh the listing. - * - * @this Radicale - * @param {Object} data - the ajax call response (JSON) - */ - reload_listing: function(data) { - this.navobj.update(true); - if (data) { - $("body").notify("success", data, 2000); - } - }, - - /** - * Rights form initialization. - * - * @this Radicale - */ - 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) - }); - }, - - /** - * Retrieve a list of username from the server. - */ - get_username_list: function() { - var result; - - $.ajax({ - url: this.options.username_list_url, - dataType: "json", - async: false - }).done(function(data) { - result = data; - }); - return result; - }, - - edit_calendar_cb: function() { - this.rightsform_init(); - $('.submit').on('click', $.proxy(function(e) { - simple_ajax_form_post(e, { - formid: "ucal_form", - reload_on_success: false, - success_cb: $.proxy(this.reload_listing, this) - }); - }, this)); - }, - - shared_calendar_cb: function() { - $('.submit').on('click', $.proxy(function(e) { - simple_ajax_form_post(e, { - formid: "sharedcal_form", - reload_on_success: false, - success_cb: $.proxy(this.reload_listing, this) - }); - }, this)); - }, - - /** - * Delete a user calendar. - */ - del_calendar: function(event) { - event.preventDefault(); - var $link = get_target(event, "a"); - - if (!confirm($link.attr("title"))) { - return; - } - $.ajax({ - url: $link.attr("href"), - type: "DELETE" - }).done($.proxy(this.reload_listing, this)); - } -}; - -Radicale.prototype = $.extend({}, Listing.prototype, Radicale.prototype); diff --git a/modoboa/extensions/radicale/templates/radicale/accessrule.html b/modoboa/extensions/radicale/templates/radicale/accessrule.html deleted file mode 100644 index 5ac132826..000000000 --- a/modoboa/extensions/radicale/templates/radicale/accessrule.html +++ /dev/null @@ -1,9 +0,0 @@ -{% load i18n %} -{% load form_tags %} - -
- {% render_field username %} - - - -
diff --git a/modoboa/extensions/radicale/templates/radicale/calendar_detail.html b/modoboa/extensions/radicale/templates/radicale/calendar_detail.html deleted file mode 100644 index b5d5f2cb2..000000000 --- a/modoboa/extensions/radicale/templates/radicale/calendar_detail.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "common/generic_modal.html" %} - -{% load i18n %} - -{% block modalbody %} -

{% trans "To access this calendar, use the following address:" %} -

-{% endblock %} diff --git a/modoboa/extensions/radicale/templates/radicale/calendars.html b/modoboa/extensions/radicale/templates/radicale/calendars.html deleted file mode 100644 index c127ce396..000000000 --- a/modoboa/extensions/radicale/templates/radicale/calendars.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "twocols.html" %} -{% load i18n radicale_tags %} -{% load static %} - -{% block extra_css %} - - -{% endblock %} - -{% block extra_js %} - - - - - - - - - -{% endblock %} - -{% block leftcol %} - -{% endblock %} - -{% block apparea %} -
-
- {% include "admin/searchform.html" %} -
-
- -
-
-
- - - - - {% if with_owner %}{% endif %} - - - - - - - -
{% trans "Name" %}{% trans "Owner" %}{% trans "Tags" %}{% trans "Actions" %}
-
-{% endblock %} diff --git a/modoboa/extensions/radicale/templates/radicale/calendars_page.html b/modoboa/extensions/radicale/templates/radicale/calendars_page.html deleted file mode 100644 index cbe0dbe4e..000000000 --- a/modoboa/extensions/radicale/templates/radicale/calendars_page.html +++ /dev/null @@ -1,9 +0,0 @@ -{% load i18n lib_tags radicale_tags %} -{% for cal in calendars %} - - {% calendar_view_link cal %} - {% if with_owner %}{{ cal.owner }}{% endif %} - {% render_tags cal.tags %} - {% calendar_actions cal %} - -{% endfor %} diff --git a/modoboa/extensions/radicale/templates/radicale/rightsform.html b/modoboa/extensions/radicale/templates/radicale/rightsform.html deleted file mode 100644 index 6248509f6..000000000 --- a/modoboa/extensions/radicale/templates/radicale/rightsform.html +++ /dev/null @@ -1,8 +0,0 @@ -{% load form_tags radicale_tags %} -
- {% render_field form.username %} - - - -
-{% render_rule_fields form %} diff --git a/modoboa/extensions/radicale/templatetags/__init__.py b/modoboa/extensions/radicale/templatetags/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/radicale/templatetags/radicale_tags.py b/modoboa/extensions/radicale/templatetags/radicale_tags.py deleted file mode 100644 index 83bc07994..000000000 --- a/modoboa/extensions/radicale/templatetags/radicale_tags.py +++ /dev/null @@ -1,113 +0,0 @@ -""" -Custom template tags. -""" -from django import template -from django.core.urlresolvers import reverse -from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ - -from modoboa.lib.templatetags.lib_tags import render_link -from modoboa.lib.web_utils import render_actions - - -register = template.Library() - - -@register.simple_tag -def radicale_left_menu(user): - """Menu located inside the left column. - - :param ``User`` user: current user - :rtype: string - :return: the menu rendered as HTML code - """ - entries = [ - {"name": "newusercalendar", - "label": _("Add calendar"), - "img": "fa fa-plus", - "modal": True, - "modalcb": "radicale.add_calendar_cb", - "url": reverse("radicale:user_calendar_add")}, - ] - if user.group != "SimpleUsers": - entries += [ - {"name": "newsharedcalendar", - "label": _("Add shared calendar"), - "img": "fa fa-plus", - "modal": True, - "modalcb": "radicale.shared_calendar_cb", - "url": reverse("radicale:shared_calendar_add")}, - ] - return render_to_string('common/menulist.html', { - "entries": entries, - "user": user - }) - - -@register.simple_tag -def calendar_view_link(calendar): - """Render a link to view calendar detail.""" - linkdef = { - "label": calendar.name, "modal": True, - "title": _("View calendar detail") - } - if calendar.__class__.__name__ == "UserCalendar": - linkdef["url"] = reverse( - "radicale:user_calendar_detail", args=[calendar.pk] - ) - else: - linkdef["url"] = reverse( - "radicale:shared_calendar_detail", args=[calendar.pk] - ) - return render_link(linkdef) - - -@register.simple_tag -def calendar_actions(calendar): - """Render per-calendar actions.""" - actions = [ - {"name": "editcalendar", - "title": _("Edit %s" % calendar), - "modal": True, - "img": "fa fa-edit"}, - {"name": "delcalendar", - "title": _("Delete %s?" % calendar), - "img": "fa fa-trash"} - ] - if calendar.__class__.__name__ == 'UserCalendar': - actions[0]["url"] = reverse( - "radicale:user_calendar", args=[calendar.pk]) - actions[0]["modalcb"] = "radicale.edit_calendar_cb" - actions[1]["url"] = reverse( - "radicale:user_calendar", args=[calendar.id]) - else: - actions[0]["url"] = reverse( - "radicale:shared_calendar", args=[calendar.pk]) - actions[0]["modalcb"] = "radicale.shared_calendar_cb" - actions[1]["url"] = reverse( - "radicale:shared_calendar", args=[calendar.id]) - return render_actions(actions) - - -@register.simple_tag -def render_rule_fields(form): - """Render access rules for a given calendar.""" - from django.forms import forms - - cpt = 1 - result = "" - while True: - fname = "username_%d" % cpt - if fname not in form.fields: - break - rfieldname = "read_access_%d" % cpt - wfieldname = "write_access_%d" % cpt - result += render_to_string('radicale/accessrule.html', { - "username": forms.BoundField(form, form.fields[fname], fname), - "read_access": forms.BoundField( - form, form.fields[rfieldname], rfieldname), - "write_access": forms.BoundField( - form, form.fields[wfieldname], wfieldname) - }) - cpt += 1 - return result diff --git a/modoboa/extensions/radicale/tests.py b/modoboa/extensions/radicale/tests.py deleted file mode 100644 index 749364d3c..000000000 --- a/modoboa/extensions/radicale/tests.py +++ /dev/null @@ -1,265 +0,0 @@ -""" -Radicale extension unit tests. -""" -import os -import tempfile -from ConfigParser import SafeConfigParser - -from django.core.exceptions import ObjectDoesNotExist -from django.core.urlresolvers import reverse -from django.core import management - -from modoboa.lib import parameters -from modoboa.lib.tests import ModoTestCase -from modoboa.extensions.admin.factories import ( - MailboxFactory, populate_database -) -from modoboa.extensions.admin.models import ( - Domain, Mailbox -) - -from .factories import ( - UserCalendarFactory, SharedCalendarFactory, AccessRuleFactory -) -from .models import UserCalendar, SharedCalendar, AccessRule - - -class UserCalendarTestCase(ModoTestCase): - - def setUp(self): - super(UserCalendarTestCase, self).setUp() - populate_database() - - def assertRuleEqual(self, calname, username, read=False, write=False): - acr = AccessRule.objects.get( - mailbox__user__username=username, - calendar__name=calname) - self.assertEqual(acr.read, read) - self.assertEqual(acr.write, write) - - def test_add_calendar(self): - MailboxFactory( - address="polo", domain__name="test.com", - user__username="polo@test.com") - - # As a super administrator - mbox = Mailbox.objects.get(address='user', domain__name='test.com') - values = { - "name": "Test calendar", - "mailbox": mbox.pk, - "username": "admin@test.com", - "read_access": 1, - "stepid": "step2" - } - self.ajax_post( - reverse("radicale:user_calendar_add"), values) - self.clt.logout() - self.assertRuleEqual("Test calendar", "admin@test.com", read=True) - - # As a domain administrator - self.clt.login(username="admin@test.com", password="toto") - values = { - "name": "Test calendar 2", - "mailbox": mbox.pk, - "username": "admin@test.com", - "read_access": 1, - "write_access": 1, - "stepid": "step2" - } - self.ajax_post( - reverse("radicale:user_calendar_add"), values) - self.clt.logout() - self.assertRuleEqual( - "Test calendar 2", "admin@test.com", read=True, write=True - ) - - # As a user - self.clt.login(username="user@test.com", password="toto") - values = { - "name": "My calendar", - "username": "admin@test.com", - "read_access": 1, - "write_access": 1, - "username_1": "polo@test.com", - "write_access_1": 1, - "stepid": "step2" - } - self.ajax_post( - reverse("radicale:user_calendar_add"), values) - UserCalendar.objects.get(name="My calendar") - self.assertRuleEqual( - "My calendar", "admin@test.com", read=True, write=True) - self.assertRuleEqual("My calendar", "polo@test.com", write=True) - - def test_edit_calendar(self): - cal = UserCalendarFactory( - mailbox__user__username='test@modoboa.org', - mailbox__address='test', mailbox__domain__name='modoboa.org') - values = { - "name": "Modified", "mailbox": cal.mailbox.pk - } - self.ajax_post( - reverse("radicale:user_calendar", args=[cal.pk]), values - ) - - def test_del_calendar(self): - cal = UserCalendarFactory( - mailbox__user__username='test@modoboa.org', - mailbox__address='test', mailbox__domain__name='modoboa.org') - self.ajax_delete( - reverse("radicale:user_calendar", args=[cal.pk]) - ) - with self.assertRaises(ObjectDoesNotExist): - UserCalendar.objects.get(pk=cal.pk) - - def test_del_calendar_denied(self): - cal = UserCalendarFactory( - mailbox__user__username='test@modoboa.org', - mailbox__address='test', mailbox__domain__name='modoboa.org') - self.clt.logout() - self.clt.login(username="admin@test.com", password="toto") - self.ajax_delete( - reverse("radicale:user_calendar", args=[cal.pk]), status=403 - ) - - def test_add_calendar_denied(self): - self.clt.logout() - self.clt.login(username="admin@test.com", password="toto") - values = { - "name": "Test calendar", - "mailbox": Mailbox.objects.get( - address="user", domain__name="test2.com").pk, - "stepid": "step2" - } - self.ajax_post( - reverse("radicale:user_calendar_add"), values, status=400) - - -class SharedCalendarTestCase(ModoTestCase): - fixtures = ["initial_users.json"] - - def setUp(self): - super(SharedCalendarTestCase, self).setUp() - populate_database() - - def test_add_calendar(self): - # As a super administrator - domain = Domain.objects.get(name="test.com") - values = { - "name": "Test calendar", - "domain": domain.pk, - } - self.ajax_post( - reverse("radicale:shared_calendar_add"), values) - self.clt.logout() - - # As a domain administrator - self.clt.login(username="admin@test.com", password="toto") - values = { - "name": "Test calendar 2", - "domain": domain.pk - } - self.ajax_post( - reverse("radicale:shared_calendar_add"), values) - self.clt.logout() - - def test_add_calendar_denied(self): - self.clt.logout() - self.clt.login(username="admin@test.com", password="toto") - values = { - "name": "Test calendar", - "domain": Domain.objects.get(name="test2.com") - } - self.ajax_post( - reverse("radicale:shared_calendar_add"), values, status=400) - - def test_edit_calendar(self): - cal = SharedCalendarFactory( - domain__name='modoboa.org') - values = { - "name": "Modified", "domain": cal.domain.pk - } - self.ajax_post( - reverse("radicale:shared_calendar", args=[cal.pk]), values - ) - cal = SharedCalendar.objects.get(pk=cal.pk) - self.assertEqual(cal.name, "Modified") - - def test_del_calendar(self): - cal = SharedCalendarFactory(domain__name='modoboa.org') - self.ajax_delete( - reverse("radicale:shared_calendar", args=[cal.pk]) - ) - with self.assertRaises(ObjectDoesNotExist): - SharedCalendar.objects.get(pk=cal.pk) - - def test_del_calendar_denied(self): - cal = SharedCalendarFactory(domain__name='modoboa.org') - self.clt.logout() - self.clt.login(username="admin@test.com", password="toto") - self.ajax_delete( - reverse("radicale:shared_calendar", args=[cal.pk]), status=403 - ) - - -class AccessRuleTestCase(ModoTestCase): - fixtures = ["initial_users.json"] - - def setUp(self): - super(AccessRuleTestCase, self).setUp() - populate_database() - self.rights_file_path = tempfile.mktemp() - parameters.save_admin( - "RIGHTS_FILE_PATH", self.rights_file_path, app="radicale") - - def tearDown(self): - os.unlink(self.rights_file_path) - - def test_rights_file_generation(self): - mbox = Mailbox.objects.get(address="admin", domain__name="test.com") - cal = UserCalendarFactory(mailbox=mbox) - - AccessRuleFactory( - mailbox=Mailbox.objects.get( - address="user", domain__name="test.com"), - calendar=cal, read=True) - management.call_command("generate_rights", verbosity=False) - - cfg = SafeConfigParser() - with open(self.rights_file_path) as fpo: - cfg.readfp(fpo) - - # Check mandatory rules - self.assertTrue(cfg.has_section("domain-shared-calendars")) - self.assertTrue(cfg.has_section("owners-access")) - - # Check user-defined rules - section = "user@test.com-to-User calendar 1-acr" - self.assertTrue(cfg.has_section(section)) - self.assertEqual(cfg.get(section, "user"), "user@test.com") - self.assertEqual( - cfg.get(section, "collection"), - "test.com/user/admin/User calendar 1" - ) - self.assertEqual(cfg.get(section, "permission"), "r") - - def test_rights_file_generation_with_admin(self): - parameters.save_admin( - "ALLOW_CALENDARS_ADMINISTRATION", "yes", app="radicale") - management.call_command("generate_rights", verbosity=False) - cfg = SafeConfigParser() - with open(self.rights_file_path) as fpo: - cfg.readfp(fpo) - - # Check mandatory rules - self.assertTrue(cfg.has_section("domain-shared-calendars")) - self.assertTrue(cfg.has_section("owners-access")) - - # Super admin rules - section = "sa-admin-acr" - self.assertTrue(cfg.has_section(section)) - - # Domain admin rules - for section in ["da-admin@test.com-to-test.com-acr", - "da-admin@test2.com-to-test2.com-acr"]: - self.assertTrue(cfg.has_section(section)) diff --git a/modoboa/extensions/radicale/urls.py b/modoboa/extensions/radicale/urls.py deleted file mode 100644 index 6ae2542f6..000000000 --- a/modoboa/extensions/radicale/urls.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.conf.urls import url, patterns - -urlpatterns = patterns( - 'modoboa.extensions.radicale.views', - - url(r'^$', 'index', name="index"), - url(r'^list/$', 'calendars_page', name="calendars_page"), - url(r'^user/$', 'new_user_calendar', name='user_calendar_add'), - url(r'^user/(?P\d+)/$', 'user_calendar', - name='user_calendar'), - url(r'^user/(?P\d+)/detail/$', 'user_calendar_detail', - name='user_calendar_detail'), - url(r'^shared/$', 'new_shared_calendar', - name='shared_calendar_add'), - url(r'^shared/(?P\d+)/$', 'shared_calendar', - name='shared_calendar'), - url(r'^shared/(?P\d+)/detail/$', 'shared_calendar_detail', - name='shared_calendar_detail'), - url(r'^usernames/$', 'username_list', name='username_list'), -) diff --git a/modoboa/extensions/radicale/views.py b/modoboa/extensions/radicale/views.py deleted file mode 100644 index 619c41dde..000000000 --- a/modoboa/extensions/radicale/views.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -Radicale extension views. -""" -from itertools import chain - -from django.shortcuts import render -from django.core.urlresolvers import reverse -from django.contrib.auth.decorators import ( - login_required, permission_required, user_passes_test -) -from django.utils.translation import ugettext as _ - -from modoboa.lib.listing import get_sort_order, get_listing_page -from modoboa.lib.web_utils import ( - _render_to_string, render_to_json_response -) -from modoboa.lib.exceptions import NotFound, PermDeniedException - -from modoboa.extensions.radicale.forms import ( - UserCalendarWizard, SharedCalendarForm, UserCalendarEditionForm -) -from modoboa.extensions.radicale.models import UserCalendar, SharedCalendar - - -@login_required -def index(request): - """Calendar list entry point.""" - return render(request, "radicale/calendars.html", { - "selection": "radicale", - "with_owner": request.user.group != "SimpleUsers" - }) - - -def get_calendar_page(request, page_id=None): - """Return a page containing calendars.""" - sort_order, sort_dir = get_sort_order(request.GET, "name") - calfilter = request.GET.get("calfilter", None) - searchquery = request.GET.get("searchquery", None) - page_id = request.GET.get("page", 1) - if request.user.group == "SimpleUsers": - mbox = request.user.mailbox_set.all()[0] - cals = UserCalendar.objects.filter(mailbox=mbox) - if searchquery is not None: - cals = cals.filter(name__icontains=searchquery) - cals = cals.select_related().all() - else: - ucals = [] - if calfilter is None or calfilter == "user": - ucals = UserCalendar.objects.get_for_admin(request.user) - if searchquery is not None: - ucals = ucals.filter(name__icontains=searchquery) - scals = [] - if calfilter is None or calfilter == "shared": - scals = SharedCalendar.objects.get_for_admin(request.user) - if searchquery is not None: - scals = scals.filter(name__icontains=searchquery) - cals = chain(ucals, scals) - cals = sorted( - cals, key=lambda c: getattr(c, sort_order), reverse=sort_dir == '-' - ) - return get_listing_page(cals, page_id) - - -@login_required -def calendars_page(request, tplname="radicale/calendars_page.html"): - """Return a page of calendars. - - The content depends on current user's role. - """ - page = get_calendar_page(request) - if page is None: - context = {"length": 0} - else: - context = { - "rows": _render_to_string(request, tplname, { - "calendars": page.object_list, - "with_owner": request.user.group != "SimpleUsers" - }), - "page": page.number - } - return render_to_json_response(context) - - -@login_required -def new_user_calendar(request): - """Calendar creation view. - """ - return UserCalendarWizard(request).process() - - -@login_required -def user_calendar(request, pk): - """Edit or remove a calendar.""" - try: - 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": - ucal.delete() - return render_to_json_response(_("Calendar removed")) - return UserCalendarEditionForm(request, instances=instances).process() - - -@login_required -def user_calendar_detail(request, pk): - """Display user calendar's detail.""" - try: - 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 - return render(request, "radicale/calendar_detail.html", { - "title": ucal.name, "calendar": ucal - }) - - -@login_required -@permission_required("radicale.add_sharedcalendar") -def new_shared_calendar(request): - """Shared calendar creation view.""" - if request.method == "POST": - form = SharedCalendarForm(request.user, request.POST) - if form.is_valid(): - form.save() - return render_to_json_response(_("Calendar created")) - return render_to_json_response( - {"form_errors": form.errors}, status=400 - ) - form = SharedCalendarForm(request.user) - return render(request, "common/generic_modal_form.html", { - "form": form, - "formid": "sharedcal_form", - "title": _("New shared calendar"), - "action": reverse("radicale:shared_calendar_add"), - "action_classes": "submit", - "action_label": _("Submit") - }) - - -@login_required -@user_passes_test( - lambda u: u.has_perm("radicale.change_sharedcalendar") - or u.has_perm("radicale.delete_sharedcalendar") -) -def shared_calendar(request, pk): - """Edit or remove a shared calendar.""" - try: - 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": - form = SharedCalendarForm(request.user, request.POST, instance=scal) - if form.is_valid(): - form.save() - return render_to_json_response(_("Calendar updated")) - return render_to_json_response( - {"form_errors": form.errors}, status=400 - ) - form = SharedCalendarForm(request.user, instance=scal) - return render(request, "common/generic_modal_form.html", { - "form": form, - "formid": "sharedcal_form", - "title": scal.name, - "action": reverse("radicale:shared_calendar", args=[scal.pk]), - "action_classes": "submit", - "action_label": _("Submit") - }) - - -@login_required -@user_passes_test( - lambda u: u.has_perm("radicale.change_sharedcalendar") -) -def shared_calendar_detail(request, pk): - """Display shared calendar's detail.""" - try: - scal = SharedCalendar.objects.select_related().get(pk=pk) - except SharedCalendar.DoesNotExist: - raise NotFound - if not request.user.can_access(scal.domain): - raise PermDeniedException - return render(request, "radicale/calendar_detail.html", { - "title": scal.name, "calendar": scal - }) - - -@login_required -def username_list(request): - """Get the list of username the current user can see. - """ - from modoboa.extensions.admin.models import Domain, Mailbox - - result = [] - qset = Mailbox.objects.select_related("user") - if request.user.has_perm("admin.add_mailbox"): - qset = qset.filter( - domain__in=Domain.objects.get_for_admin(request.user) - ) - else: - user_domain = request.user.mailbox_set.all()[0].domain - qset = qset.filter(domain=user_domain) - for mbox in qset: - result.append(mbox.user.username) - return render_to_json_response(result)