diff --git a/openslides/participant/static/javascript/participant.js b/openslides/participant/static/javascript/participant.js
index f02e6c3f6..bf17d5202 100644
--- a/openslides/participant/static/javascript/participant.js
+++ b/openslides/participant/static/javascript/participant.js
@@ -9,17 +9,20 @@ $(function() {
$('.status_link').click(function(event) {
event.preventDefault();
link = $(this);
+ group = $(this).parent();
$.ajax({
type: 'GET',
url: link.attr('href'),
dataType: 'json',
success: function(data) {
if (data.active) {
- link.addClass('active');
+ group.children('.status_link.deactivate').show();
+ group.children('.status_link.activate').hide();
} else {
- link.removeClass('active');
+ group.children('.status_link.deactivate').hide();
+ group.children('.status_link.activate').show();
}
}
});
});
-});
\ No newline at end of file
+});
diff --git a/openslides/participant/static/styles/participant.css b/openslides/participant/static/styles/participant.css
index 3d2820f49..0d656c9c8 100644
--- a/openslides/participant/static/styles/participant.css
+++ b/openslides/participant/static/styles/participant.css
@@ -4,14 +4,19 @@
* :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
* :license: GNU GPL, see LICENSE for more details.
*/
+
a.status_link span {
- background-image: url(../images/icons/off.png);
background-repeat: no-repeat;
background-position: center;
width: 16px;
height: 16px;
display: inline-block;
}
-a.status_link.active span {
+
+a.status_link.deactivate span {
background-image: url(../images/icons/on.png);
}
+
+a.status_link.activate span {
+ background-image: url(../images/icons/off.png);
+}
diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html
index 3cd529af4..4641d615a 100644
--- a/openslides/participant/templates/participant/overview.html
+++ b/openslides/participant/templates/participant/overview.html
@@ -90,15 +90,18 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
|
{% endif %}
diff --git a/openslides/participant/urls.py b/openslides/participant/urls.py
index 17efe5aac..61751402c 100644
--- a/openslides/participant/urls.py
+++ b/openslides/participant/urls.py
@@ -15,7 +15,7 @@ from django.core.urlresolvers import reverse
from openslides.participant.views import (
ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
- UserUpdateView, UserDeleteView)
+ UserUpdateView, UserDeleteView, SetUserStatusView)
urlpatterns = patterns('openslides.participant.views',
url(r'^$',
@@ -43,9 +43,22 @@ urlpatterns = patterns('openslides.participant.views',
name='user_delete',
),
- url(r'^(?P\d+)/status/$',
- 'user_set_status',
- name='user_status',
+ url(r'^(?P\d+)/status/toggle/$',
+ SetUserStatusView.as_view(),
+ {'action': 'toggle'},
+ name='user_status_toggle',
+ ),
+
+ url(r'^(?P\d+)/status/activate/$',
+ SetUserStatusView.as_view(),
+ {'action': 'activate'},
+ name='user_status_activate',
+ ),
+
+ url(r'^(?P\d+)/status/deactivate/$',
+ SetUserStatusView.as_view(),
+ {'action': 'deactivate'},
+ name='user_status_deactivate',
),
url(r'^import/$',
diff --git a/openslides/participant/views.py b/openslides/participant/views.py
index 48771d6bc..e0169ae5c 100644
--- a/openslides/participant/views.py
+++ b/openslides/participant/views.py
@@ -44,7 +44,8 @@ from openslides.utils.utils import (
template, permission_required, gen_confirm_form, ajax_request, decodedict,
encodedict, delete_default_permissions, html_strong)
from openslides.utils.views import (
- FormView, PDFView, TemplateView, CreateView, UpdateView, DeleteView)
+ FormView, PDFView, TemplateView, CreateView, UpdateView, DeleteView,
+ RedirectView, SingleObjectMixin, ListView)
from openslides.config.models import config
@@ -55,15 +56,15 @@ from openslides.participant.forms import (
UserImportForm, GroupForm, AdminPasswordChangeForm, ConfigForm)
-class Overview(TemplateView):
+class Overview(ListView):
"""
Show all participants.
"""
permission_required = 'participant.can_see_participant'
template_name = 'participant/overview.html'
+ context_object_name = 'users'
- def get_context_data(self, **kwargs):
- context = super(Overview, self).get_context_data(**kwargs)
+ def get_queryset(self):
try:
sortfilter = encodedict(parse_qs(
self.request.COOKIES['participant_sortfilter']))
@@ -81,19 +82,15 @@ class Overview(TemplateView):
else:
sortfilter[value] = [self.request.REQUEST[value]]
- query = User.objects
+ query = OpenSlidesUser.objects
if 'gender' in sortfilter:
- query = query.filter(
- openslidesuser__gender__iexact=sortfilter['gender'][0])
+ query = query.filter(gender__iexact=sortfilter['gender'][0])
if 'category' in sortfilter:
- query = query.filter(
- openslidesuser__category__iexact=sortfilter['category'][0])
+ query = query.filter(category__iexact=sortfilter['category'][0])
if 'type' in sortfilter:
- query = query.filter(
- openslidesuser__type__iexact=sortfilter['type'][0])
+ query = query.filter(type__iexact=sortfilter['type'][0])
if 'committee' in sortfilter:
- query = query.filter(
- openslidesuser__committee__iexact=sortfilter['committee'][0])
+ query = query.filter(committee__iexact=sortfilter['committee'][0])
if 'status' in sortfilter:
query = query.filter(is_active=sortfilter['status'][0])
if 'sort' in sortfilter:
@@ -109,15 +106,18 @@ class Overview(TemplateView):
if 'reverse' in sortfilter:
query = query.reverse()
- # list of filtered users
- users = query.all()
+ self.sortfilter = sortfilter
+
+ return query.all()
+
+ def get_context_data(self, **kwargs):
+ context = super(Overview, self).get_context_data(**kwargs)
- # list of all existing users
all_users = User.objects.count()
# quotient of selected users and all users
if all_users > 0:
- percent = float(len(users)) * 100 / float(all_users)
+ percent = self.object_list.count() * 100 / float(all_users)
else:
percent = 0
@@ -129,14 +129,13 @@ class Overview(TemplateView):
committees = [p['committee'] for p in OpenSlidesUser.objects.values('committee')
.exclude(committee='').distinct()]
context.update({
- 'users': users,
'allusers': all_users,
'percent': round(percent, 1),
'categories': categories,
'committees': committees,
- 'cookie': ['participant_sortfilter', urlencode(decodedict(sortfilter),
+ 'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
doseq=True)],
- 'sortfilter': sortfilter})
+ 'sortfilter': self.sortfilter})
return context
@@ -154,6 +153,8 @@ class UserCreateView(CreateView):
def manipulate_object(self, form):
self.object.username = gen_username(form.cleaned_data['first_name'], form.cleaned_data['last_name'])
+ if not self.object.firstpassword:
+ self.object.firstpassword = gen_password()
class UserUpdateView(UpdateView):
@@ -178,164 +179,125 @@ class UserDeleteView(DeleteView):
url = 'user_overview'
-@permission_required('participant.can_manage_participant')
-@template('confirm.html')
-def user_delete(request, user_id):
+class SetUserStatusView(RedirectView, SingleObjectMixin):
"""
- Delete an user.
+ Activate or deactivate an user.
"""
- user = User.objects.get(pk=user_id)
- if request.method == 'POST':
- user.delete()
- messages.success(request,
- _('Participant %s was successfully deleted.') % user)
- else:
- gen_confirm_form(request,
- _('Do you really want to delete %s?') % user,
- reverse('user_delete', args=[user_id]))
- return redirect(reverse('user_overview'))
+ permission_required = 'participant.can_manage_participant'
+ allow_ajax = True
+ url = 'user_overview'
+ model = OpenSlidesUser
+
+ def pre_redirect(self, request, *args, **kwargs):
+ self.object = self.get_object()
+ action = kwargs['action']
+ if action == 'activate':
+ self.object.is_active = True
+ elif action == 'deactivate':
+ self.object.is_active = False
+ elif action == 'toggle':
+ self.object.is_active = not self.object.is_active
+ self.object.save()
+ return super(SetUserStatusView, self).pre_redirect(request, *args, **kwargs)
+
+ def get_ajax_context(self, **kwargs):
+ context = super(SetUserStatusView, self).get_ajax_context(**kwargs)
+ context['active'] = self.object.is_active
+ return context
-@permission_required('participant.can_manage_participant')
-@template('confirm.html')
-def user_set_status(request, user_id):
+class ParticipantsListPDF(PDFView):
"""
- Set the status of an user.
+ Generate the userliste as PDF.
"""
- try:
- user = User.objects.get(pk=user_id)
- if user.is_active:
- user.is_active = False
- else:
- user.is_active = True
- user.save()
- except User.DoesNotExist:
- messages.error(request,
- _('Participant ID %d does not exist.') % int(user_id))
- return redirect(reverse('user_overview'))
+ permission_required = 'participant.can_see_participant'
+ filename = ugettext_lazy("Participant-list")
+ document_title = ugettext_lazy('List of Participants')
- if request.is_ajax():
- return ajax_request({'active': user.is_active})
- # set success messages for page reload only (= not ajax request)
- if user.is_active:
- messages.success(request, _('%s is now present.') % user)
- else:
- messages.success(request, _('%s is now absent.') % user)
- return redirect(reverse('user_overview'))
+ def append_to_pdf(self, story):
+ data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'),
+ _('Committee')]]
+ sort = 'last_name'
+ counter = 0
+ for user in OpenSlidesUser.objects.all().order_by(sort):
+ counter += 1
+ data.append([
+ counter,
+ Paragraph(user.last_name, stylesheet['Tablecell']),
+ Paragraph(user.first_name, stylesheet['Tablecell']),
+ Paragraph(user.category, stylesheet['Tablecell']),
+ Paragraph(user.type, stylesheet['Tablecell']),
+ Paragraph(user.committee, stylesheet['Tablecell'])
+ ])
+ t = LongTable(data,
+ style=[
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
+ ('LINEABOVE', (0, 0), (-1, 0), 2, colors.black),
+ ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
+ ('LINEBELOW', (0, -1), (-1, -1), 2, colors.black),
+ ('ROWBACKGROUNDS', (0, 1), (-1, -1),
+ (colors.white, (.9, .9, .9)))])
+ t._argW[0] = 0.75 * cm
+ story.append(t)
-@permission_required('participant.can_manage_participant')
-@template('participant/group_overview.html')
-def get_group_overview(request):
+class ParticipantsPasswordsPDF(PDFView):
"""
- Show all groups.
+ Generate the Welcomepaper for the users.
"""
- 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'
+ filename = ugettext_lazy("Participant-passwords")
+ top_space = 0
+ def get_template(self, buffer):
+ return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6,
+ leftMargin=0, rightMargin=0, showBoundary=False)
-@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()
+ def build_document(self, pdf_document, story):
+ pdf_document.build(story)
- 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()
+ def append_to_pdf(self, story):
+ data = []
+ participant_pdf_system_url = config["participant_pdf_system_url"]
+ participant_pdf_welcometext = config["participant_pdf_welcometext"]
+ for user in OpenSlidesUser.objects.all().order_by('last_name'):
+ cell = []
+ cell.append(Spacer(0, 0.8 * cm))
+ cell.append(Paragraph(_("Account for OpenSlides"),
+ stylesheet['Ballot_title']))
+ cell.append(Paragraph(_("for %s") % (user),
+ stylesheet['Ballot_subtitle']))
+ cell.append(Spacer(0, 0.5 * cm))
+ cell.append(Paragraph(_("User: %s") % (user.username),
+ stylesheet['Monotype']))
+ cell.append(Paragraph(_("Password: %s")
+ % (user.firstpassword), stylesheet['Monotype']))
+ cell.append(Spacer(0, 0.5 * cm))
+ cell.append(Paragraph(_("URL: %s")
+ % (participant_pdf_system_url),
+ stylesheet['Ballot_option']))
+ cell.append(Spacer(0, 0.5 * cm))
+ cell2 = []
+ cell2.append(Spacer(0, 0.8 * cm))
+ if participant_pdf_welcometext is not None:
+ cell2.append(Paragraph(
+ participant_pdf_welcometext.replace('\r\n', '
'),
+ stylesheet['Ballot_subtitle']))
- # 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
+ data.append([cell, cell2])
- # 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'))
+ # add empty table line if no participants available
+ if not data:
+ data.append(['', ''])
+ # build table
+ t = Table(data, 10.5 * cm, 7.42 * cm)
+ t.setStyle(TableStyle([
+ ('LINEBELOW', (0, 0), (-1, 0), 0.25, colors.grey),
+ ('LINEBELOW', (0, 1), (-1, 1), 0.25, colors.grey),
+ ('LINEBELOW', (0, 1), (-1, -1), 0.25, colors.grey),
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
+ ]))
+ story.append(t)
@login_required
@@ -582,121 +544,120 @@ def login(request):
return django_login(request, template_name='participant/login.html', extra_context=extra_content)
-def register_tab(request):
- """
- Register the participant tab.
- """
- selected = request.path.startswith('/participant/')
- return Tab(
- title=_('Participants'),
- url=reverse('user_overview'),
- permission=request.user.has_perm('participant.can_see_participant')
- or request.user.has_perm('participant.can_manage_participant'),
- selected=selected,
- )
-class ParticipantsListPDF(PDFView):
+@permission_required('participant.can_manage_participant')
+@template('participant/group_overview.html')
+def get_group_overview(request):
"""
- Generate the userliste as PDF.
+ Show all groups.
"""
- permission_required = 'participant.can_see_participant'
- filename = ugettext_lazy("Participant-list")
- document_title = ugettext_lazy('List of Participants')
+ if config['system_enable_anonymous']:
+ groups = Group.objects.all()
+ else:
+ groups = Group.objects.exclude(name='Anonymous')
+ return {
+ 'groups': groups,
+ }
- def append_to_pdf(self, story):
- data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'),
- _('Committee')]]
- sort = 'last_name'
- counter = 0
- for user in User.objects.all().order_by(sort):
+
+@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:
- counter += 1
- user.get_profile()
- data.append([
- counter,
- Paragraph(user.last_name, stylesheet['Tablecell']),
- Paragraph(user.first_name, stylesheet['Tablecell']),
- Paragraph(user.profile.group, stylesheet['Tablecell']),
- Paragraph(user.profile.get_type_display(),
- stylesheet['Tablecell']),
- Paragraph(user.profile.committee, stylesheet['Tablecell'])
- ])
- except Profile.DoesNotExist:
- counter -= 1
- pass
- t = LongTable(data,
- style=[
- ('VALIGN', (0, 0), (-1, -1), 'TOP'),
- ('LINEABOVE', (0, 0), (-1, 0), 2, colors.black),
- ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
- ('LINEBELOW', (0, -1), (-1, -1), 2, colors.black),
- ('ROWBACKGROUNDS', (0, 1), (-1, -1),
- (colors.white, (.9, .9, .9)))])
- t._argW[0] = 0.75 * cm
- story.append(t)
+ 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
+ }
-class ParticipantsPasswordsPDF(PDFView):
- """
- Generate the Welcomepaper for the users.
- """
- permission_required = 'participant.can_manage_participant'
- filename = ugettext_lazy("Participant-passwords")
- top_space = 0
-
- def get_template(self, buffer):
- return SimpleDocTemplate(buffer, topMargin=-6, bottomMargin=-6,
- leftMargin=0, rightMargin=0, showBoundary=False)
-
- def build_document(self, pdf_document, story):
- pdf_document.build(story)
-
- def append_to_pdf(self, story):
- data = []
- participant_pdf_system_url = config["participant_pdf_system_url"]
- participant_pdf_welcometext = config["participant_pdf_welcometext"]
- for user in User.objects.all().order_by('last_name'):
+ group = form.save()
try:
- user.get_profile()
- cell = []
- cell.append(Spacer(0, 0.8 * cm))
- cell.append(Paragraph(_("Account for OpenSlides"),
- stylesheet['Ballot_title']))
- cell.append(Paragraph(_("for %s") % (user.profile),
- stylesheet['Ballot_subtitle']))
- cell.append(Spacer(0, 0.5 * cm))
- cell.append(Paragraph(_("User: %s") % (user.username),
- stylesheet['Monotype']))
- cell.append(Paragraph(_("Password: %s")
- % (user.profile.firstpassword), stylesheet['Monotype']))
- cell.append(Spacer(0, 0.5 * cm))
- cell.append(Paragraph(_("URL: %s")
- % (participant_pdf_system_url),
- stylesheet['Ballot_option']))
- cell.append(Spacer(0, 0.5 * cm))
- cell2 = []
- cell2.append(Spacer(0, 0.8 * cm))
- if participant_pdf_welcometext is not None:
- cell2.append(Paragraph(
- participant_pdf_welcometext.replace('\r\n', '
'),
- stylesheet['Ballot_subtitle']))
+ 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()
- data.append([cell, cell2])
- except OpenSlidesUser.DoesNotExist:
- pass
- # add empty table line if no participants available
- if data == []:
- data.append(['', ''])
- # build table
- t = Table(data, 10.5 * cm, 7.42 * cm)
- t.setStyle(TableStyle([
- ('LINEBELOW', (0, 0), (-1, 0), 0.25, colors.grey),
- ('LINEBELOW', (0, 1), (-1, 1), 0.25, colors.grey),
- ('LINEBELOW', (0, 1), (-1, -1), 0.25, colors.grey),
- ('VALIGN', (0, 0), (-1, -1), 'TOP'),
- ]))
- story.append(t)
+ 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):
@@ -721,3 +682,17 @@ class Config(FormView):
messages.success(self.request,
_('Participants settings successfully saved.'))
return super(Config, self).form_valid(form)
+
+
+def register_tab(request):
+ """
+ Register the participant tab.
+ """
+ selected = request.path.startswith('/participant/')
+ return Tab(
+ title=_('Participants'),
+ url=reverse('user_overview'),
+ permission=request.user.has_perm('participant.can_see_participant')
+ or request.user.has_perm('participant.can_manage_participant'),
+ selected=selected,
+ )