mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-18 05:51:26 +02:00
wip: Radicale extension
Access rules definition works!
This commit is contained in:
@@ -344,15 +344,10 @@ class AccountForm(TabForms):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
self.user = request.user
|
||||
self.forms = [
|
||||
<<<<<<< HEAD
|
||||
dict(id="general", title=_("General"), cls=AccountFormGeneral,
|
||||
new_args=[self.user], mandatory=True),
|
||||
=======
|
||||
dict(id="general", title=_("General"),
|
||||
formtpl="admin/account_general_form.html",
|
||||
cls=AccountFormGeneral,
|
||||
new_args=[user], mandatory=True),
|
||||
>>>>>>> master
|
||||
new_args=[self.user], mandatory=True),
|
||||
dict(id="mail", title=_("Mail"), formtpl="admin/mailform.html",
|
||||
cls=AccountFormMail),
|
||||
dict(id="perms", title=_("Permissions"), formtpl="admin/permsform.html",
|
||||
|
||||
@@ -143,32 +143,6 @@ def editaccount(request, accountid, tplname="common/tabforms.html"):
|
||||
events.raiseEvent("FillAccountInstances", request.user, account, instances)
|
||||
return AccountForm(request, instances=instances).process()
|
||||
|
||||
# if request.method == "POST":
|
||||
# classes = {}
|
||||
# form = AccountForm(request.user, request.POST,
|
||||
# instances=instances, classes=classes)
|
||||
# account.oldgroup = account.group
|
||||
# if form.is_valid(mandatory_only=True):
|
||||
# form.save_general_form()
|
||||
# if form.is_valid(optional_only=True):
|
||||
# events.raiseEvent("AccountModified", account, form.account)
|
||||
# form.save()
|
||||
# return render_to_json_response(_("Account updated"))
|
||||
# return render_to_json_response({'form_errors': form.errors}, status=400)
|
||||
|
||||
# ctx = {
|
||||
# 'title': account.username,
|
||||
# 'formid': 'accountform',
|
||||
# 'action': reverse(editaccount, args=[accountid]),
|
||||
# 'action_label': _('Update'),
|
||||
# 'action_classes': 'submit',
|
||||
# 'tabs': AccountForm(request.user, instances=instances)
|
||||
# }
|
||||
# active_tab_id = request.GET.get("active_tab", "default")
|
||||
# if active_tab_id != "default":
|
||||
# ctx["tabs"].active_id = active_tab_id
|
||||
# return render(request, tplname, ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required("core.delete_user")
|
||||
|
||||
@@ -3,7 +3,7 @@ Radicale extension forms.
|
||||
"""
|
||||
from django import forms
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
from modoboa.lib.webutils import render_to_json_response
|
||||
from modoboa.lib.formutils import WizardForm, TabForms, DynamicForm
|
||||
from modoboa.extensions.radicale.models import UserCalendar, SharedCalendar
|
||||
@@ -29,9 +29,17 @@ class SharedCalendarForm(forms.ModelForm):
|
||||
class RightsForm(forms.Form, DynamicForm):
|
||||
"""
|
||||
"""
|
||||
username = forms.CharField(required=False)
|
||||
read_access = forms.BooleanField(initial=False, label=_("Read"))
|
||||
write_access = forms.BooleanField(initial=False, label=_("Write"))
|
||||
username = forms.CharField(
|
||||
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
|
||||
@@ -43,13 +51,65 @@ class RightsForm(forms.Form, DynamicForm):
|
||||
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 _create_field(self, typ, name, value=None, pos=None):
|
||||
def save(self):
|
||||
"""Custom save method.
|
||||
"""
|
||||
"""
|
||||
super(RightsForm, self)._create_field(typ, name, value, pos)
|
||||
import re
|
||||
from modoboa.lib.emailutils 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 not rule.mailbox.full_address 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):
|
||||
@@ -96,7 +156,18 @@ class UserCalendarEditionForm(TabForms):
|
||||
super(UserCalendarEditionForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def extra_context(self, context):
|
||||
calendar = self.instances["general"]
|
||||
context.update({
|
||||
"title": self.instances["general"].name,
|
||||
"formid": "ucal_form"
|
||||
"formid": "ucal_form",
|
||||
"action": reverse("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"))
|
||||
|
||||
@@ -115,7 +115,11 @@ class AccessRule(models.Model):
|
||||
mailbox = models.ForeignKey("admin.Mailbox")
|
||||
read = models.BooleanField(default=False)
|
||||
write = models.BooleanField(default=False)
|
||||
calendar = models.ForeignKey(UserCalendar)
|
||||
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 ""
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#original_row {
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.access-rule {
|
||||
margin-top: 5px;
|
||||
margin-left: 100px;
|
||||
}
|
||||
|
||||
.addrule, .delrule {
|
||||
margin-left: 10px;
|
||||
}
|
||||
@@ -52,11 +52,14 @@
|
||||
$btn.find("i").removeClass("icon-plus").addClass("icon-trash");
|
||||
$btn.removeClass("addrule").addClass("delrule");
|
||||
$clone.find("#id_username")
|
||||
.attr("id", "id_username_" + this.rules_counter);
|
||||
.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("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("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();
|
||||
@@ -69,7 +72,7 @@
|
||||
event.preventDefault();
|
||||
var $link = get_target(event, "a");
|
||||
|
||||
$link.parents("tr").remove();
|
||||
$link.parent().remove();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,13 @@ Radicale.prototype = {
|
||||
|
||||
edit_calendar_cb: function() {
|
||||
$("#original_row").dynamicrule();
|
||||
$('.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));
|
||||
},
|
||||
|
||||
add_shared_calendar_cb: function() {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{% load i18n %}
|
||||
<div class="form-inline access-rule">
|
||||
{{ username }}
|
||||
<label class="checkbox">{{ read_access }} {% trans "Read" %}</label>
|
||||
<label class="checkbox">{{ write_access }} {% trans "Write" %}</label>
|
||||
<a href="#" class="delrule"><i class="icon-trash"></i></a>
|
||||
</div>
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends "twocols.html" %}{% load i18n radicale_tags %}
|
||||
{% block html_head %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}radicale/css/radicale.css" />
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/jquery.sortable.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/history.js"></script>
|
||||
<script type="text/javascript" src="{{ STATIC_URL }}js/creation_wizard.js"></script>
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
{% load lib_tags %}
|
||||
{% load lib_tags radicale_tags %}
|
||||
{% if error %}<div class="alert alert-error">{{ error }}</div>{% endif %}
|
||||
<form action="{{ action }}" method="POST" id="{{ formid }}">
|
||||
{% csrf_token %}
|
||||
<table class="table table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ form.username.label }}</th>
|
||||
<th>{{ form.read_access.label }}</th>
|
||||
<th>{{ form.write_access.label }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="original_row">
|
||||
<td>{{ form.username }}</td>
|
||||
<td>{{ form.read_access }}</td>
|
||||
<td>{{ form.write_access }}</td>
|
||||
<td><a href="#" class="addrule"><i class="icon-plus"></i></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-inline" id="original_row">
|
||||
{{ form.username }}
|
||||
<label class="checkbox">{{ form.read_access }} {{ form.read_access.label }}</label>
|
||||
<label class="checkbox">{{ form.write_access }} {{ form.write_access.label }}</label>
|
||||
<a href="#" class="addrule"><i class="icon-plus"></i></a>
|
||||
</div>
|
||||
{% render_rule_fields form %}
|
||||
</form>
|
||||
|
||||
@@ -73,3 +73,28 @@ def calendar_actions(calendar):
|
||||
else:
|
||||
actions[0]["url"] = reverse("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 not fname 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
|
||||
|
||||
@@ -58,7 +58,7 @@ def user_calendar(request, pk):
|
||||
ucal = UserCalendar.objects.get(pk=pk)
|
||||
except UserCalendar.DoesNotExist:
|
||||
raise NotFound
|
||||
instances = {"general": ucal, "rights": None}
|
||||
instances = {"general": ucal, "rights": ucal}
|
||||
if request.method == "DELETE":
|
||||
# Check ownership
|
||||
ucal.delete()
|
||||
|
||||
@@ -8,7 +8,6 @@ from django.forms import ChoiceField
|
||||
from django.forms.widgets import RadioSelect, RadioInput
|
||||
from django.forms.fields import CharField, Field
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.html import conditional_escape
|
||||
@@ -67,7 +66,7 @@ class WizardStep(object):
|
||||
class WizardForm(object):
|
||||
"""Custom wizard.
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
template_name = "common/wizard_forms.html"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user