diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index 7da694a58..f766c247b 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -18,14 +18,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop from openslides.utils.forms import ( CssClassMixin, LocalizedModelMultipleChoiceField) -from openslides.participant.models import OpenSlidesUser - - -USER_APPLICATION_IMPORT_OPTIONS = [ - ('REASSIGN', _('Keep applications, try to reassign submitter')), - ('INREVIEW', _('Keep applications, set status to "needs review"')), - ('DISCARD', _('Discard applications')) -] +from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup class UserCreateForm(forms.ModelForm, CssClassMixin): @@ -50,25 +43,10 @@ class UserUpdateForm(UserCreateForm): 'firstpassword') -class UsernameForm(forms.ModelForm, CssClassMixin): - class Meta: - model = User - exclude = ('first_name', 'last_name', 'email', 'is_active', - 'is_superuser', 'groups', 'password', 'is_staff', - 'last_login', 'date_joined', 'user_permissions') - - -class OpenSlidesUserForm(forms.ModelForm, CssClassMixin): - class Meta: - model = OpenSlidesUser - - class GroupForm(forms.ModelForm, CssClassMixin): - as_user = forms.BooleanField( - initial=False, required=False, label=_("Treat Group as User"), - help_text=_("The Group will appear on any place, other user does.")) permissions = LocalizedModelMultipleChoiceField( - queryset=Permission.objects.all(), label=_("Persmissions")) + queryset=Permission.objects.all(), label=_("Persmissions"), + required=False) def __init__(self, *args, **kwargs): super(GroupForm, self).__init__(*args, **kwargs) @@ -76,9 +54,22 @@ class GroupForm(forms.ModelForm, CssClassMixin): self.fields['permissions'].initial = ( [p.pk for p in kwargs['instance'].permissions.all()]) + def clean_name(self): + data = self.cleaned_data['name'] + if self.instance.name.lower() == 'anonymous': + # Editing the anonymous-user + if self.instance.name.lower() != data.lower(): + raise forms.ValidationError( + _('You can not edit the name for the anonymous user')) + else: + if data.lower() == 'anonymous': + raise forms.ValidationError( + _('Group name "%s" is reserved for internal use.') % data) + return data + + class Meta: - model = Group - exclude = ('permissions',) + model = OpenSlidesGroup class UsersettingsForm(forms.ModelForm, CssClassMixin): diff --git a/openslides/participant/models.py b/openslides/participant/models.py index 09d2adbdf..625a82ec9 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -35,7 +35,7 @@ class OpenSlidesUser(User, PersonMixin): ('guest', _('Guest')), ) - user = models.OneToOneField(User, unique=True, editable=False, parent_link=True) + user = models.OneToOneField(User, editable=False, parent_link=True) category = models.CharField( max_length=100, null=True, blank=True, verbose_name=_("Category"), help_text=_('Will be shown behind the name.')) @@ -85,9 +85,9 @@ class OpenSlidesUser(User, PersonMixin): * delete """ if link == 'edit': - return ('user_edit', [str(self.user.id)]) + return ('user_edit', [str(self.id)]) if link == 'delete': - return ('user_delete', [str(self.user.id)]) + return ('user_delete', [str(self.id)]) def __unicode__(self): if self.name_surfix: @@ -103,13 +103,27 @@ class OpenSlidesUser(User, PersonMixin): ) -class OpenSlidesGroup(models.Model, PersonMixin): +class OpenSlidesGroup(Group, PersonMixin): person_prefix = 'openslides_group' - group = models.OneToOneField(Group) + group = models.OneToOneField(Group, editable=False, parent_link=True) group_as_person = models.BooleanField(default=False) description = models.TextField(blank=True) + @models.permalink + def get_absolute_url(self, link='edit'): + """ + Return the URL to this user. + + link can be: + * edit + * delete + """ + if link == 'edit': + return ('user_group_edit', [str(self.id)]) + if link == 'delete': + return ('user_group_delete', [str(self.id)]) + def __unicode__(self): return unicode(self.group) @@ -169,5 +183,7 @@ def user_post_save(sender, instance, signal, *args, **kwargs): @receiver(signals.post_save, sender=Group) def group_post_save(sender, instance, signal, *args, **kwargs): - # Creates OpenSlidesGroup - openslidesgroup, new = OpenSlidesGroup.objects.get_or_create(group=instance) + try: + instance.openslidesgroup + except OpenSlidesGroup.DoesNotExist: + OpenSlidesGroup(group=instance).save_base(raw=True) diff --git a/openslides/participant/urls.py b/openslides/participant/urls.py index 584f880e7..f55c30756 100644 --- a/openslides/participant/urls.py +++ b/openslides/participant/urls.py @@ -16,7 +16,8 @@ from django.core.urlresolvers import reverse from openslides.participant.views import ( ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView, UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView, - ResetPasswordView) + ResetPasswordView, GroupOverviewView, GroupCreateView, GroupUpdateView, + GroupDeleteView) urlpatterns = patterns('openslides.participant.views', url(r'^$', @@ -44,11 +45,6 @@ urlpatterns = patterns('openslides.participant.views', name='user_reset_password', ), - url(r'^print/$', - ParticipantsListPDF.as_view(), - name='user_print', - ), - url(r'^(?P\d+)/status/toggle/$', SetUserStatusView.as_view(), {'action': 'toggle'}, @@ -73,25 +69,30 @@ urlpatterns = patterns('openslides.participant.views', ), url(r'^group/$', - 'get_group_overview', + GroupOverviewView.as_view(), name='user_group_overview', ), url(r'^group/new/$', - 'group_edit', + GroupCreateView.as_view(), name='user_group_new', ), - url(r'^group/(?P\d+)/edit/$', - 'group_edit', + url(r'^group/(?P\d+)/edit/$', + GroupUpdateView.as_view(), name='user_group_edit', ), - url(r'^group/(?P\d+)/del/$', - 'group_delete', + url(r'^group/(?P\d+)/del/$', + GroupDeleteView.as_view(), name='user_group_delete', ), + url(r'^print/$', + ParticipantsListPDF.as_view(), + name='user_print', + ), + url(r'^passwords/print/$', ParticipantsPasswordsPDF.as_view(), name='print_passwords', diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 15e4e9eba..4854c29af 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -52,7 +52,7 @@ from openslides.config.models import config from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup from openslides.participant.api import gen_username, gen_password, import_users from openslides.participant.forms import ( - UserCreateForm, UserUpdateForm, OpenSlidesUserForm, UsersettingsForm, + UserCreateForm, UserUpdateForm, UsersettingsForm, UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm) @@ -113,7 +113,7 @@ class Overview(ListView): def get_context_data(self, **kwargs): context = super(Overview, self).get_context_data(**kwargs) - all_users = User.objects.count() + all_users = OpenSlidesUser.objects.count() # quotient of selected users and all users if all_users > 0: @@ -347,6 +347,84 @@ class ResetPasswordView(RedirectView, SingleObjectMixin, QuestionMixin): return reverse('user_reset_password', args=[self.object.id]) +class GroupOverviewView(ListView): + """ + Overview over all groups. + """ + permission_required = 'participant.can_manage_participant' + template_name = 'participant/group_overview.html' + context_object_name = 'groups' + model = OpenSlidesGroup + + +class GroupEditMixin(object): + """ + Methodes for the GroupCreateView and GroupUpdateView. + """ + def get_form_class(self): + delete_default_permissions() + return self.form_class + + +class GroupCreateView(CreateView, GroupEditMixin): + """ + Create a new group. + """ + permission_required = 'participant.can_manage_participant' + template_name = 'participant/group_edit.html' + context_object_name = 'group' + model = OpenSlidesGroup + form_class = GroupForm + success_url = 'user_group_overview' + apply_url = 'user_group_edit' + + +class GroupUpdateView(UpdateView, GroupEditMixin): + """ + Update an existing group. + """ + permission_required = 'participant.can_manage_participant' + template_name = 'participant/group_edit.html' + model = OpenSlidesGroup + context_object_name = 'group' + form_class = GroupForm + success_url = 'user_group_overview' + apply_url = 'user_group_edit' + + +class GroupDeleteView(DeleteView): + """ + Delete a Group. + """ + permission_required = 'participant.can_manage_participant' + model = OpenSlidesGroup + url = 'user_group_overview' + + +class Config(FormView): + """ + Config page for the participant app. + """ + permission_required = 'config.can_manage_config' + form_class = ConfigForm + template_name = 'participant/config.html' + + def get_initial(self): + return { + 'participant_pdf_system_url': config['participant_pdf_system_url'], + 'participant_pdf_welcometext': config['participant_pdf_welcometext'] + } + + def form_valid(self, form): + config['participant_pdf_system_url'] = \ + form.cleaned_data['participant_pdf_system_url'] + config['participant_pdf_welcometext'] = \ + form.cleaned_data['participant_pdf_welcometext'] + messages.success(self.request, + _('Participants settings successfully saved.')) + return super(Config, self).form_valid(form) + + @login_required @template('participant/settings.html') def user_settings(request): @@ -391,7 +469,6 @@ def user_settings_password(request): } - def login(request): extra_content = {} try: @@ -411,146 +488,6 @@ def login(request): return django_login(request, template_name='participant/login.html', extra_context=extra_content) - - -@permission_required('participant.can_manage_participant') -@template('participant/group_overview.html') -def get_group_overview(request): - """ - Show all groups. - """ - if config['system_enable_anonymous']: - groups = Group.objects.all() - else: - groups = Group.objects.exclude(name='Anonymous') - return { - 'groups': groups, - } - - -@permission_required('participant.can_manage_participant') -@template('participant/group_edit.html') -def group_edit(request, group_id=None): - """ - Edit a group. - """ - if group_id is not None: - try: - group = Group.objects.get(id=group_id) - except Group.DoesNotExist: - # TODO: return a 404 Object - raise NameError("There is no group %d" % group_id) - else: - group = None - delete_default_permissions() - - if request.method == 'POST': - form = GroupForm(request.POST, instance=group) - if form.is_valid(): - # TODO: This can be done inside the form - group_name = form.cleaned_data['name'].lower() - - # TODO: Why is this code called on any request and not only, if the - # anonymous_group is edited? - try: - anonymous_group = Group.objects.get(name='Anonymous') - except Group.DoesNotExist: - anonymous_group = None - - # special handling for anonymous auth - # TODO: This code should be a form validator. - if group is None and group_name.strip().lower() == 'anonymous': - # don't allow to create this group - messages.error(request, - _('Group name "%s" is reserved for internal use.') - % group_name) - return { - 'form': form, - 'group': group - } - - group = form.save() - try: - openslides_group = OpenSlidesGroup.objects.get(group=group) - except OpenSlidesGroup.DoesNotExist: - django_group = None - if form.cleaned_data['as_user'] and django_group is None: - OpenSlidesGroup(group=group).save() - elif not form.cleaned_data['as_user'] and django_group: - django_group.delete() - - if anonymous_group is not None and \ - anonymous_group.id == group.id: - # prevent name changes - - # XXX: I'm sure this could be done as *one* group.save() - group.name = 'Anonymous' - group.save() - - if group_id is None: - messages.success(request, - _('New group was successfully created.')) - else: - messages.success(request, _('Group was successfully modified.')) - if not 'apply' in request.POST: - return redirect(reverse('user_group_overview')) - if group_id is None: - return redirect(reverse('user_group_edit', args=[group.id])) - else: - messages.error(request, _('Please check the form for errors.')) - else: - if group and OpenSlidesGroup.objects.filter(group=group).exists(): - initial = {'as_user': True} - else: - initial = {'as_user': False} - - form = GroupForm(instance=group, initial=initial) - return { - 'form': form, - 'group': group, - } - - -@permission_required('participant.can_manage_participant') -def group_delete(request, group_id): - """ - Delete a group. - """ - group = Group.objects.get(pk=group_id) - if request.method == 'POST': - group.delete() - messages.success(request, - _('Group %s was successfully deleted.') % group) - else: - gen_confirm_form(request, - _('Do you really want to delete %s?') % group, - reverse('user_group_delete', args=[group_id])) - return redirect(reverse('user_group_overview')) - - -class Config(FormView): - """ - Config page for the participant app. - """ - permission_required = 'config.can_manage_config' - form_class = ConfigForm - template_name = 'participant/config.html' - - def get_initial(self): - return { - 'participant_pdf_system_url': config['participant_pdf_system_url'], - 'participant_pdf_welcometext': config['participant_pdf_welcometext'] - } - - def form_valid(self, form): - config['participant_pdf_system_url'] = \ - form.cleaned_data['participant_pdf_system_url'] - config['participant_pdf_welcometext'] = \ - form.cleaned_data['participant_pdf_welcometext'] - messages.success(self.request, - _('Participants settings successfully saved.')) - return super(Config, self).form_valid(form) - - def register_tab(request): """ Register the participant tab.