Merge branch 'master' into install
This commit is contained in:
commit
a2be848932
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"pk": 2,
|
||||
"pk": 1,
|
||||
"model": "auth.group",
|
||||
"fields": {
|
||||
"name": "Beobachter",
|
||||
@ -38,7 +38,7 @@
|
||||
[
|
||||
"can_see_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_see_projector",
|
||||
@ -49,7 +49,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 3,
|
||||
"pk": 2,
|
||||
"model": "auth.group",
|
||||
"fields": {
|
||||
"name": "Delegierter",
|
||||
@ -92,7 +92,7 @@
|
||||
[
|
||||
"can_see_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_see_projector",
|
||||
@ -103,7 +103,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 4,
|
||||
"pk": 3,
|
||||
"model": "auth.group",
|
||||
"fields": {
|
||||
"name": "Versammlungsleitung",
|
||||
@ -161,12 +161,12 @@
|
||||
[
|
||||
"can_manage_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_see_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_manage_projector",
|
||||
@ -182,7 +182,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 5,
|
||||
"pk": 4,
|
||||
"model": "auth.group",
|
||||
"fields": {
|
||||
"name": "Teilnehmerverwaltung",
|
||||
@ -195,12 +195,12 @@
|
||||
[
|
||||
"can_manage_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_see_participant",
|
||||
"participant",
|
||||
"openslidesuser"
|
||||
"user"
|
||||
],
|
||||
[
|
||||
"can_see_projector",
|
||||
|
@ -54,7 +54,7 @@ class Overview(TemplateView):
|
||||
context = self.get_context_data(**kwargs)
|
||||
if not request.user.has_perm('agenda.can_manage_agenda'):
|
||||
messages.error(request,
|
||||
_('You are not permitted to manage the agenda.'))
|
||||
_('You are not authorized to manage the agenda.'))
|
||||
return self.render_to_response(context)
|
||||
transaction.commit()
|
||||
for item in Item.objects.all():
|
||||
@ -167,69 +167,24 @@ class ItemDelete(DeleteView):
|
||||
model = Item
|
||||
url = 'item_overview'
|
||||
|
||||
def pre_post_redirect(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
def get_answer_options(self):
|
||||
if self.object.children.exists():
|
||||
return [('all', _("Yes, with all child items."))] + self.answer_options
|
||||
else:
|
||||
return self.answer_options
|
||||
|
||||
if 'all' in request.POST:
|
||||
def pre_post_redirect(self, request, *args, **kwargs):
|
||||
if self.get_answer() == 'all':
|
||||
self.object.delete(with_children=True)
|
||||
messages.success(request,
|
||||
_("Item %s and his children were successfully deleted.") \
|
||||
% html_strong(self.object))
|
||||
else:
|
||||
elif self.get_answer() == 'yes':
|
||||
self.object.delete(with_children=False)
|
||||
messages.success(request,
|
||||
_("Item %s was successfully deleted.") \
|
||||
% html_strong(self.object))
|
||||
|
||||
def gen_confirm_form(self, request, message, url, singleitem=False):
|
||||
if singleitem:
|
||||
messages.warning(
|
||||
request,
|
||||
"""
|
||||
%s
|
||||
<form action="%s" method="post">
|
||||
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
||||
<input type="submit" value="%s">
|
||||
<input type="button" value="%s">
|
||||
</form>
|
||||
"""
|
||||
% (message, url, csrf(request)['csrf_token'], _("Yes"),
|
||||
_("No"))
|
||||
)
|
||||
else:
|
||||
messages.warning(
|
||||
request,
|
||||
"""
|
||||
%s
|
||||
<form action="%s" method="post">
|
||||
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
||||
<input type="submit" value="%s">
|
||||
<input type="submit" name="all" value="%s">
|
||||
<input type="button" value="%s">
|
||||
</form>
|
||||
"""
|
||||
% (message, url, csrf(request)['csrf_token'], _("Yes"),
|
||||
_("Yes, with all child items."), _("No"))
|
||||
)
|
||||
|
||||
def confirm_form(self, request, object, item=None):
|
||||
if item is None:
|
||||
item = object
|
||||
if item.get_children():
|
||||
self.gen_confirm_form(
|
||||
request,
|
||||
_('Do you really want to delete %s?') % html_strong(item),
|
||||
item.get_absolute_url('delete'),
|
||||
False,
|
||||
)
|
||||
else:
|
||||
self.gen_confirm_form(
|
||||
request,
|
||||
_('Do you really want to delete %s?') % html_strong(item),
|
||||
item.get_absolute_url('delete'),
|
||||
True,
|
||||
)
|
||||
|
||||
|
||||
class AgendaPDF(PDFView):
|
||||
"""
|
||||
|
@ -51,16 +51,16 @@ class ApplicationImportForm(forms.Form, CssClassMixin):
|
||||
)
|
||||
import_permitted = forms.BooleanField(
|
||||
required=False,
|
||||
label=_("Import applications with status \"permitted\""),
|
||||
help_text=_('Set the initial status for each application to '
|
||||
'"permitted"'),
|
||||
label=_("Import motions with status \"authorized\""),
|
||||
help_text=_('Set the initial status for each motion to '
|
||||
'"authorized"'),
|
||||
)
|
||||
|
||||
|
||||
class ConfigForm(forms.Form, CssClassMixin):
|
||||
application_min_supporters = forms.IntegerField(
|
||||
widget=forms.TextInput(attrs={'class':'small-input'}),
|
||||
label=_("Number of (minimum) required supporters for a application"),
|
||||
label=_("Number of (minimum) required supporters for a motion"),
|
||||
initial=4,
|
||||
min_value=0,
|
||||
max_value=8,
|
||||
@ -69,7 +69,7 @@ class ConfigForm(forms.Form, CssClassMixin):
|
||||
application_preamble = forms.CharField(
|
||||
widget=forms.TextInput(),
|
||||
required=False,
|
||||
label=_("Application preamble")
|
||||
label=_("Motion preamble")
|
||||
)
|
||||
application_pdf_ballot_papers_selection = forms.ChoiceField(
|
||||
widget=forms.Select(),
|
||||
@ -90,17 +90,17 @@ class ConfigForm(forms.Form, CssClassMixin):
|
||||
application_pdf_title = forms.CharField(
|
||||
widget=forms.TextInput(),
|
||||
required=False,
|
||||
label=_("Title for PDF document (all applications)")
|
||||
label=_("Title for PDF document (all motions)")
|
||||
)
|
||||
application_pdf_preamble = forms.CharField(
|
||||
widget=forms.Textarea(),
|
||||
required=False,
|
||||
label=_("Preamble text for PDF document (all applications)")
|
||||
label=_("Preamble text for PDF document (all motions)")
|
||||
)
|
||||
|
||||
application_allow_trivial_change = forms.BooleanField(
|
||||
label=_("Allow trivial changes"),
|
||||
help_text=_('Warning: Trivial changes undermine the application ' \
|
||||
'permission system.'),
|
||||
help_text=_('Warning: Trivial changes undermine the motions '
|
||||
'autorisation system.'),
|
||||
required=False,
|
||||
)
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import Max
|
||||
@ -26,8 +25,6 @@ from openslides.utils.person import PersonField
|
||||
from openslides.config.models import config
|
||||
from openslides.config.signals import default_config_value
|
||||
|
||||
from openslides.participant.models import OpenSlidesUser
|
||||
|
||||
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
||||
CountInvalid, BaseVote)
|
||||
|
||||
@ -53,7 +50,7 @@ class Application(models.Model, SlideMixin):
|
||||
('adj', _('Adjourned')),
|
||||
('noc', _('Not Concerned')),
|
||||
('com', _('Commited a bill')),
|
||||
('nop', _('Rejected (not permitted)')),
|
||||
('nop', _('Rejected (not authorized)')),
|
||||
('rev', _('Needs Review')), # Where is this status used?
|
||||
#additional actions:
|
||||
# edit
|
||||
@ -103,14 +100,14 @@ class Application(models.Model, SlideMixin):
|
||||
self.save(nonewversion=True)
|
||||
version.rejected = False
|
||||
version.save()
|
||||
self.writelog(_("Version %d permitted") % (version.aid, ),
|
||||
self.writelog(_("Version %d authorized") % (version.aid, ),
|
||||
user)
|
||||
|
||||
def reject_version(self, version, user = None):
|
||||
if version.id > self.permitted.id:
|
||||
version.rejected = True
|
||||
version.save()
|
||||
self.writelog(pgettext("Rejected means not permitted", "Version %d rejected")
|
||||
self.writelog(pgettext("Rejected means not authorized", "Version %d rejected")
|
||||
% (version.aid, ), user)
|
||||
return True
|
||||
return False
|
||||
@ -141,9 +138,9 @@ class Application(models.Model, SlideMixin):
|
||||
if self.status == "pub" and not self.enough_supporters:
|
||||
note.append(_("Searching for supporters."))
|
||||
if self.status == "pub" and self.permitted is None:
|
||||
note.append(_("Not yet permitted."))
|
||||
note.append(_("Not yet authorized."))
|
||||
elif self.unpermitted_changes and self.permitted:
|
||||
note.append(_("Not yet permitted changes."))
|
||||
note.append(_("Not yet authorized changes."))
|
||||
return note
|
||||
|
||||
@property
|
||||
@ -309,7 +306,7 @@ class Application(models.Model, SlideMixin):
|
||||
self.set_number()
|
||||
self.permitted = aversion
|
||||
self.save()
|
||||
self.writelog(_("Version %s permitted") % (aversion.aid), user)
|
||||
self.writelog(_("Version %s authorized") % (aversion.aid), user)
|
||||
return self.permitted
|
||||
|
||||
def notpermit(self, user=None):
|
||||
@ -323,7 +320,7 @@ class Application(models.Model, SlideMixin):
|
||||
if self.number is None:
|
||||
self.set_number()
|
||||
self.save()
|
||||
self.writelog(_("Version %s not permitted") % (self.last_version.aid), user)
|
||||
self.writelog(_("Version %s not authorized") % (self.last_version.aid), user)
|
||||
|
||||
def set_status(self, user, status, force=False):
|
||||
"""
|
||||
@ -335,19 +332,22 @@ class Application(models.Model, SlideMixin):
|
||||
error = False
|
||||
break
|
||||
if error:
|
||||
#TODO: Use the Right Error
|
||||
raise NameError(_('%s is not a valid status.') % status)
|
||||
if self.status == status:
|
||||
raise NameError(_('The application status is already \'%s.\'') \
|
||||
#TODO: Use the Right Error
|
||||
raise NameError(_('The motion status is already \'%s.\'') \
|
||||
% self.status)
|
||||
|
||||
actions = []
|
||||
actions = self.get_allowed_actions(user)
|
||||
if status not in actions and not force:
|
||||
raise NameError(_('The application status is: \'%(currentstatus)s\'. '\
|
||||
'You can not set the status to \'%(newstatus)s\'.') % {
|
||||
'currentstatus': self.status,
|
||||
'newstatus': status
|
||||
})
|
||||
#TODO: Use the Right Error
|
||||
raise NameError(_(
|
||||
'The motion status is: \'%(currentstatus)s\'. '
|
||||
'You can not set the status to \'%(newstatus)s\'.') % {
|
||||
'currentstatus': self.status,
|
||||
'newstatus': status})
|
||||
|
||||
oldstatus = self.get_status_display()
|
||||
self.status = status
|
||||
@ -360,15 +360,6 @@ class Application(models.Model, SlideMixin):
|
||||
Return a list of all the allowed status.
|
||||
"""
|
||||
actions = []
|
||||
is_admin = False
|
||||
if user:
|
||||
try:
|
||||
user = user.openslidesuser
|
||||
except OpenSlidesUser.DoesNotExist:
|
||||
is_admin = True
|
||||
except AttributeError:
|
||||
# For the anonymous-user
|
||||
pass
|
||||
|
||||
# check if user allowed to withdraw an application
|
||||
if ((self.status == "pub"
|
||||
@ -405,11 +396,10 @@ class Application(models.Model, SlideMixin):
|
||||
|
||||
# Check if the user can delete the application (admin, manager, owner)
|
||||
# reworked as requiered in #100
|
||||
if is_admin \
|
||||
or (user.has_perm("application.can_manage_application") \
|
||||
and (self.status == "pub" or self.number is None)) \
|
||||
or (self.submitter == user \
|
||||
and (self.status == "pub" or self.number is None)):
|
||||
if (user.has_perm("applicatoin.can_delete_all_applications") or
|
||||
(user.has_perm("application.can_manage_application") and
|
||||
self.number is None) or
|
||||
(self.submitter == user and self.number is None)):
|
||||
actions.append("delete")
|
||||
|
||||
#For the rest, all actions need the manage permission
|
||||
@ -463,7 +453,7 @@ class Application(models.Model, SlideMixin):
|
||||
|
||||
def get_agenda_title_supplement(self):
|
||||
number = self.number or '<i>[%s]</i>' % ugettext('no number')
|
||||
return '(%s %s)' % (ugettext('Application'), number)
|
||||
return '(%s %s)' % (ugettext('motion'), number)
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
@ -539,10 +529,10 @@ class Application(models.Model, SlideMixin):
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
('can_see_application', ugettext_noop("Can see application")),
|
||||
('can_create_application', ugettext_noop("Can create application")),
|
||||
('can_support_application', ugettext_noop("Can support application")),
|
||||
('can_manage_application', ugettext_noop("Can manage application")),
|
||||
('can_see_application', ugettext_noop("Can see motions")),
|
||||
('can_create_application', ugettext_noop("Can create motions")),
|
||||
('can_support_application', ugettext_noop("Can support motions")),
|
||||
('can_manage_application', ugettext_noop("Can manage motions")),
|
||||
)
|
||||
|
||||
|
||||
@ -611,7 +601,7 @@ def default_config(sender, key, **kwargs):
|
||||
'application_preamble': _('The Assembly may decide,'),
|
||||
'application_pdf_ballot_papers_selection': 'CUSTOM_NUMBER',
|
||||
'application_pdf_ballot_papers_number': '8',
|
||||
'application_pdf_title': _('Applications'),
|
||||
'application_pdf_title': _('Motions'),
|
||||
'application_pdf_preamble': '',
|
||||
'application_allow_trivial_change': False,
|
||||
}.get(key)
|
||||
|
@ -6,16 +6,16 @@
|
||||
|
||||
{% block submenu %}
|
||||
{% url application_overview as url_applicationoverview %}
|
||||
<h4>{% trans "Applications" %}</h4>
|
||||
<h4>{% trans "Motions" %}</h4>
|
||||
<ul>
|
||||
<li class="{% if request.path == url_applicationoverview %}selected{% endif %}"><a href="{% url application_overview %}">{% trans "All applications" %}</a></li>
|
||||
<li class="{% if request.path == url_applicationoverview %}selected{% endif %}"><a href="{% url application_overview %}">{% trans "All motions" %}</a></li>
|
||||
{% if perms.application.can_create_application or perms.application.can_manage_application %}
|
||||
<li class="{% active request '/application/new' %}"><a href="{% url application_new %}">{% trans "New application" %}</a></li>
|
||||
<li class="{% active request '/application/new' %}"><a href="{% url application_new %}">{% trans "New motion" %}</a></li>
|
||||
{% endif %}
|
||||
{% if perms.application.can_manage_application %}
|
||||
<li class="{% active request '/application/import' %}"><a href="{% url application_import %}">{% trans 'Import applications' %}</a></li>
|
||||
<li class="{% active request '/application/import' %}"><a href="{% url application_import %}">{% trans 'Import motions' %}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url print_applications %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'All applications as PDF' %}</a></li>
|
||||
<li><a href="{% url print_applications %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'All motions as PDF' %}</a></li>
|
||||
</ul>
|
||||
|
||||
{# second submenu #}
|
||||
@ -31,18 +31,18 @@
|
||||
<ul>
|
||||
{# view application #}
|
||||
{% url application_view application.id as url_applicationview %}
|
||||
<li class="{% if request.path == url_applicationview %}selected{% endif %}"><a href="{% url application_view application.id %}">{% trans 'View application' %}</a></li>
|
||||
<li class="{% if request.path == url_applicationview %}selected{% endif %}"><a href="{% url application_view application.id %}">{% trans 'View motion' %}</a></li>
|
||||
{# edit application #}
|
||||
{% if "edit" in actions %}
|
||||
{% url application_edit application.id as url_applicationedit %}
|
||||
<li class="{% if request.path == url_applicationedit %}selected{% endif %}"><a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}"> {% trans 'Edit application' %}</a></li>
|
||||
<li class="{% if request.path == url_applicationedit %}selected{% endif %}"><a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}"> {% trans 'Edit motion' %}</a></li>
|
||||
{% endif %}
|
||||
{# delete application #}
|
||||
{% if "delete" in actions %}
|
||||
<li><a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}"> {% trans 'Delete application' %}</a></li>
|
||||
<li><a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}"> {% trans 'Delete motion' %}</a></li>
|
||||
{% endif %}
|
||||
{# PDF #}
|
||||
<li><a href="{% url print_application application.id %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'Application as PDF' %}</a></li>
|
||||
<li><a href="{% url print_application application.id %}"><img src="{% static 'images/icons/pdf.png' %}"> {% trans 'Motion as PDF' %}</a></li>
|
||||
{# activate and polls #}
|
||||
{% if perms.projector.can_manage_projector %}
|
||||
<li>
|
||||
|
@ -5,17 +5,17 @@
|
||||
{% block title %}
|
||||
{{ block.super }} –
|
||||
{% if application %}
|
||||
{% trans "Edit application" %}
|
||||
{% trans "Edit motion" %}
|
||||
{% else %}
|
||||
{% trans "New application" %}
|
||||
{% trans "New motion" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if application %}
|
||||
<h1>{% trans "Edit application" %}</h1>
|
||||
<h1>{% trans "Edit motion" %}</h1>
|
||||
{% else %}
|
||||
<h1>{% trans "New application" %}</h1>
|
||||
<h1>{% trans "New motion" %}</h1>
|
||||
{% endif %}
|
||||
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ block.super }} – {% trans "Import applications" %} {% endblock %}
|
||||
{% block title %}{{ block.super }} – {% trans "Import motions" %} {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Import applications" %}</h1>
|
||||
<p>{% trans 'Select a CSV file to import applications!' %}</p>
|
||||
<h1>{% trans "Import motions" %}</h1>
|
||||
<p>{% trans 'Select a CSV file to import motions!' %}</p>
|
||||
|
||||
<p>{% trans 'Required comma separated values: <code>{number, title, text, reason, first_name, last_name}</code> (<code>number</code> and <code>reason</code> are optional and may be empty)' %}
|
||||
<br>
|
||||
|
@ -4,11 +4,11 @@
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}{{ block.super }} – {% trans "Applications" %}{% endblock %}
|
||||
{% block title %}{{ block.super }} – {% trans "Motions" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Applications" %}</h1>
|
||||
<p><form action="{{request.url}}" name="filter" method="get">
|
||||
<h1>{% trans "Motions" %}</h1>
|
||||
<p><form action="{{ request.url }}" name="filter" method="get">
|
||||
{% trans "Filter" %}:
|
||||
{% if min_supporters > 0 %}
|
||||
<input type="checkbox" name="needsup" onchange="document.forms['filter'].submit()"
|
||||
@ -19,21 +19,21 @@
|
||||
<input type="checkbox" name="status" onchange="document.forms['filter'].submit()"
|
||||
{% if 'on' in request.GET.status %}checked{% endif %}> {% trans "Status" %}:
|
||||
<select class="default-input" name="statusvalue" onchange="{% if 'on' in request.GET.status %}document.forms['filter'].submit(){% endif %}">
|
||||
<option value="pub" {% if 'pub' in request.GET.statusvalue %}selected{% endif %}>{% trans "Not yet permitted" %}</option>
|
||||
<option value="per" {% if 'on' in request.GET.status and 'per' in request.GET.statusvalue %}selected{% endif %}>{% trans "Permitted" %}</option>
|
||||
<option value="pub" {% if 'pub' in request.GET.statusvalue %}selected{% endif %}>{% trans "Not yet authorized" %}</option>
|
||||
<option value="per" {% if 'on' in request.GET.status and 'per' in request.GET.statusvalue %}selected{% endif %}>{% trans "Authorized" %}</option>
|
||||
<option value="acc" {% if 'on' in request.GET.status and 'acc' in request.GET.statusvalue %}selected{% endif %}>{% trans "Accepted" %}</option>
|
||||
<option value="rej" {% if 'on' in request.GET.status and 'rej' in request.GET.statusvalue %}selected{% endif %}>{% trans "Rejected" %}</option>
|
||||
<option value="wit" {% if 'on' in request.GET.status and 'wit' in request.GET.statusvalue %}selected{% endif %}>{% trans "Withdrawed (by submitter)" %}</option>
|
||||
<option value="wit" {% if 'on' in request.GET.status and 'wit' in request.GET.statusvalue %}selected{% endif %}>{% trans "Withdrawen (by submitter)" %}</option>
|
||||
<option value="rev" {% if 'rev' in request.GET.statusvalue %}selected{% endif %}>{% trans "Needs Review" %}</option>
|
||||
</select>
|
||||
</form>
|
||||
</p>
|
||||
{{ applications|length }}
|
||||
{% blocktrans count counter=applications|length %}application{% plural %}applications{% endblocktrans %}
|
||||
{% blocktrans count counter=applications|length %}motion{% plural %}motions{% endblocktrans %}
|
||||
<table>
|
||||
<tr>
|
||||
<th><a href="?sort=number{% if 'number' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Number" %}</a></th>
|
||||
<th><a href="?sort=title{% if 'title' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Application title" %}</a></th>
|
||||
<th><a href="?sort=title{% if 'title' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Motion title" %}</a></th>
|
||||
{% if min_supporters > 0 %}
|
||||
<th><a href="?sort=supporter{% if 'supporter' in request.GET.sort and 'reverse' not in request.GET %}&reverse{%endif%}">{% trans "Number of supporters" %}</a></th>
|
||||
{% endif %}
|
||||
@ -64,24 +64,24 @@
|
||||
<td>
|
||||
<span style="width: 1px; white-space: nowrap;">
|
||||
{% if perms.projector.can_manage_projector %}
|
||||
<a class="activate_link {% if application.active %}active{% endif %}" href="{% url projector_activate_slide application.sid %}" title="{% trans 'Activate application' %}">
|
||||
<a class="activate_link {% if application.active %}active{% endif %}" href="{% url projector_activate_slide application.sid %}" title="{% trans 'Activate motion' %}">
|
||||
<span></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.application.can_manage_application %}
|
||||
<a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit application' %}"></a>
|
||||
<a href="{% url application_edit application.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit motion' %}"></a>
|
||||
{% if "delete" in useractions %}
|
||||
<a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete application' %}"></a>
|
||||
<a href="{% url application_delete application.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete motion' %}"></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<a href="{% url print_application application.id %}" title="{% trans 'Application as PDF' %}"><img src="{% static 'images/icons/pdf.png' %}"></a>
|
||||
<a href="{% url print_application application.id %}" title="{% trans 'Motion as PDF' %}"><img src="{% static 'images/icons/pdf.png' %}"></a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="7"><i>{% trans "No applications available." %}</i></td>
|
||||
<td colspan="7"><i>{% trans "No motions available." %}</i></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
@ -4,12 +4,12 @@
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}
|
||||
{{ block.super }} – {% trans "Application" %} "{{ application.public_version.title }}"
|
||||
{{ block.super }} – {% trans "Motion" %} "{{ application.public_version.title }}"
|
||||
– {{ ballot }}. {% trans "Vote" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ application.public_version.title }} ({% trans "Application" %}
|
||||
<h1>{{ application.public_version.title }} ({% trans "Motion" %}
|
||||
{{ application.number }}) – {{ ballot }}. {% trans "Vote" %}</h1>
|
||||
<i class="helptext">{% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %}</i>
|
||||
<form action="" method="post" class="small-form">{% csrf_token %}
|
||||
|
@ -4,7 +4,7 @@
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}{{ block.super }} – {% trans "Application" %} "{{ version.title }}"{% endblock %}
|
||||
{% block title %}{{ block.super }} – {% trans "Motion" %} "{{ version.title }}"{% endblock %}
|
||||
|
||||
|
||||
{% block submenu %}
|
||||
@ -143,7 +143,7 @@
|
||||
|
||||
{% if perms.application.can_manage_application %}
|
||||
<div class="box">
|
||||
<h4><b>{% trans "Manage application" %}</b></h4>
|
||||
<h4><b>{% trans "Manage motion" %}</b></h4>
|
||||
|
||||
{% if "pub" in actions or "per" in actions or "nop" in actions or "setnumber" in actions %}
|
||||
<h4>{% trans "Formal validation" %}:</h4>
|
||||
@ -206,7 +206,7 @@
|
||||
<div id="main">
|
||||
<h1>
|
||||
{{ version.title }}
|
||||
({% trans "Application" %}
|
||||
({% trans "Motion" %}
|
||||
{% if application.number != None %}
|
||||
{{ application.number }})
|
||||
{% else %}
|
||||
@ -221,11 +221,11 @@
|
||||
{% if version == application.public_version %}
|
||||
{% trans "This is not the newest version." %} <a href="{% url application_view_newest application.id %}">{% trans "Go to version" %} {{ application.last_version.aid }}.</a>
|
||||
{% else %}
|
||||
{% trans "This is not the permitted version." %} <a href="{% url application_view application.id %}">{% trans "Go to version" %} {{ application.public_version.aid }}.</a>
|
||||
{% trans "This is not the authorized version." %} <a href="{% url application_view application.id %}">{% trans "Go to version" %} {{ application.public_version.aid }}.</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans "Application" %}:</h2>
|
||||
<h2>{% trans "Motion" %}:</h2>
|
||||
|
||||
{{ version.text|linebreaks }}
|
||||
|
||||
@ -256,7 +256,7 @@
|
||||
<td style="white-space:nowrap;">
|
||||
{% if application.status != "pub" %}
|
||||
{% if revision == application.permitted %}
|
||||
<img title="{% trans 'Version permitted' %}" src="{% static 'images/icons/accept.png' %}">
|
||||
<img title="{% trans 'Version authorized' %}" src="{% static 'images/icons/accept.png' %}">
|
||||
{% else %}
|
||||
{% if perms.application.can_manage_application %}
|
||||
<a href="{% url application_version_permit revision.id %}"><img title="{% trans 'Permit Version' %}" src="{% static 'images/icons/accept-grey.png' %}"></a>
|
||||
|
@ -20,7 +20,7 @@
|
||||
<a href="{% model_url application 'view' %}">
|
||||
{{ application.public_version.title }}
|
||||
</a>
|
||||
({% trans 'Application' %}
|
||||
({% trans "motion" %}
|
||||
{% if application.number %}
|
||||
{{ application.number }})
|
||||
{% else %}
|
||||
@ -28,7 +28,7 @@
|
||||
{% endif %}
|
||||
</li>
|
||||
{% empty %}
|
||||
<li>{% trans 'No applications available.' %}</li>
|
||||
<li>{% trans 'No motion available.' %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}{{ block.super }} - {% trans "Application" %} {{ application.number }}{% endblock %}
|
||||
{% block title %}{{ block.super }} - {% trans "Motion" %} {{ application.number }}{% endblock %}
|
||||
{% block content %}
|
||||
<div id="sidebar">
|
||||
<div class="box">
|
||||
@ -60,9 +60,9 @@
|
||||
|
||||
<h1>
|
||||
{% if application.number != None %}
|
||||
{% trans "Application No." %} {{ application.number }}
|
||||
{% trans "Motion No." %} {{ application.number }}
|
||||
{% else %}
|
||||
{% trans "Application" %} <i>[{% trans "no number" %}]</i>
|
||||
{% trans "Motion" %} <i>[{% trans "no number" %}]</i>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<b>{{ application.public_version.title }}</b>
|
||||
|
@ -12,15 +12,17 @@
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from openslides.participant.models import User
|
||||
from openslides.application.models import Application, AVersion
|
||||
|
||||
class ApplicationTest(TestCase):
|
||||
def setUp(self):
|
||||
self.admin = User.objects.create_user('testadmin', '', 'default')
|
||||
self.anonym = User.objects.create_user('testanoym', '', 'default')
|
||||
self.app1 = Application(submitter=self.admin.openslidesuser)
|
||||
self.admin = User(username='testadmin')
|
||||
self.admin.save()
|
||||
self.anonym = User(username='testanoym')
|
||||
self.anonym.save()
|
||||
self.app1 = Application(submitter=self.admin)
|
||||
self.app1.save()
|
||||
|
||||
def refresh(self):
|
||||
|
@ -51,7 +51,7 @@ from openslides.projector.projector import Widget
|
||||
from openslides.poll.views import PollFormView
|
||||
|
||||
from openslides.participant.api import gen_username, gen_password
|
||||
from openslides.participant.models import OpenSlidesUser
|
||||
from openslides.participant.models import User
|
||||
|
||||
from openslides.agenda.models import Item
|
||||
|
||||
@ -124,7 +124,7 @@ def overview(request):
|
||||
for (i, application) in enumerate(applications):
|
||||
try:
|
||||
applications[i] = {
|
||||
'actions' : application.get_allowed_actions(request.user.openslidesuser),
|
||||
'actions' : application.get_allowed_actions(request.user),
|
||||
'application' : application
|
||||
}
|
||||
except:
|
||||
@ -152,8 +152,7 @@ def view(request, application_id, newest=False):
|
||||
else:
|
||||
version = application.public_version
|
||||
revisions = application.versions
|
||||
user = request.user.openslidesuser
|
||||
actions = application.get_allowed_actions(user=user)
|
||||
actions = application.get_allowed_actions(user=request.user)
|
||||
|
||||
return {
|
||||
'application': application,
|
||||
@ -178,16 +177,14 @@ def edit(request, application_id=None):
|
||||
|
||||
if not is_manager \
|
||||
and not request.user.has_perm('application.can_create_application'):
|
||||
messages.error(request, _("You have not the necessary rights to create or edit applications."))
|
||||
messages.error(request, _("You have not the necessary rights to create or edit motions."))
|
||||
return redirect(reverse('application_overview'))
|
||||
if application_id is not None:
|
||||
application = Application.objects.get(id=application_id)
|
||||
if (not hasattr(application.submitter, 'user') or
|
||||
not request.user.openslidesuser == application.submitter.user) \
|
||||
and not is_manager:
|
||||
messages.error(request, _("You can not edit this application. You are not the submitter."))
|
||||
if not request.user == application.submitter and not is_manager:
|
||||
messages.error(request, _("You can not edit this motion. You are not the submitter."))
|
||||
return redirect(reverse('application_view', args=[application.id]))
|
||||
actions = application.get_allowed_actions(user=request.user.openslidesuser)
|
||||
actions = application.get_allowed_actions(user=request.user)
|
||||
else:
|
||||
application = None
|
||||
actions = None
|
||||
@ -221,7 +218,7 @@ def edit(request, application_id=None):
|
||||
original_supporters = []
|
||||
application = managerform.save(commit=False)
|
||||
elif application_id is None:
|
||||
application = Application(submitter=request.user.openslidesuser)
|
||||
application = Application(submitter=request.user)
|
||||
application.title = dataform.cleaned_data['title']
|
||||
application.text = dataform.cleaned_data['text']
|
||||
application.reason = dataform.cleaned_data['reason']
|
||||
@ -231,7 +228,7 @@ def edit(request, application_id=None):
|
||||
and dataform.cleaned_data['trivial_change']
|
||||
except KeyError:
|
||||
trivial_change = False
|
||||
application.save(request.user.openslidesuser, trivial_change=trivial_change)
|
||||
application.save(request.user, trivial_change=trivial_change)
|
||||
if is_manager:
|
||||
try:
|
||||
new_supporters = set(managerform.cleaned_data['supporter'])
|
||||
@ -246,10 +243,11 @@ def edit(request, application_id=None):
|
||||
# remove old supporters
|
||||
for supporter in old_supporters.difference(new_supporters):
|
||||
application.unsupport(supporter)
|
||||
|
||||
if application_id is None:
|
||||
messages.success(request, _('New application was successfully created.'))
|
||||
messages.success(request, _('New motion was successfully created.'))
|
||||
else:
|
||||
messages.success(request, _('Application was successfully modified.'))
|
||||
messages.success(request, _('Motion was successfully modified.'))
|
||||
|
||||
if not 'apply' in request.POST:
|
||||
return redirect(reverse('application_view', args=[application.id]))
|
||||
@ -263,9 +261,9 @@ def edit(request, application_id=None):
|
||||
else:
|
||||
if application.status == "pub" and application.supporters:
|
||||
if request.user.has_perm('application.can_manage_application'):
|
||||
messages.warning(request, _("Attention: Do you really want to edit this application? The supporters will <b>not</b> be removed automatically because you can manage applications. Please check if the supports are valid after your changing!"))
|
||||
messages.warning(request, _("Attention: Do you really want to edit this motion? The supporters will <b>not</b> be removed automatically because you can manage motions. Please check if the supports are valid after your changing!"))
|
||||
else:
|
||||
messages.warning(request, _("Attention: Do you really want to edit this application? All <b>%s</b> supporters will be removed! Try to convince the supporters again.") % len(application.supporters) )
|
||||
messages.warning(request, _("Attention: Do you really want to edit this motion? All <b>%s</b> supporters will be removed! Try to convince the supporters again.") % application.supporter.count() )
|
||||
initial = {'title': application.title,
|
||||
'text': application.text,
|
||||
'reason': application.reason}
|
||||
@ -273,7 +271,7 @@ def edit(request, application_id=None):
|
||||
dataform = formclass(initial=initial, prefix="data")
|
||||
if is_manager:
|
||||
if application_id is None:
|
||||
initial = {'submitter': request.user.openslidesuser.person_id}
|
||||
initial = {'submitter': request.user.person_id}
|
||||
else:
|
||||
initial = {'submitter': application.submitter.person_id,
|
||||
'supporter': [supporter.person_id for supporter in application.supporters]}
|
||||
@ -296,8 +294,8 @@ def set_number(request, application_id):
|
||||
set a number for an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).set_number(user=request.user.openslidesuser)
|
||||
messages.success(request, _("Application number was successfully set."))
|
||||
Application.objects.get(pk=application_id).set_number(user=request.user)
|
||||
messages.success(request, _("Motion number was successfully set."))
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
except NameError:
|
||||
@ -312,8 +310,8 @@ def permit(request, application_id):
|
||||
permit an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).permit(user=request.user.openslidesuser)
|
||||
messages.success(request, _("Application was successfully permitted."))
|
||||
Application.objects.get(pk=application_id).permit(user=request.user)
|
||||
messages.success(request, _("Motion was successfully authorized."))
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
except NameError, e:
|
||||
@ -327,8 +325,8 @@ def notpermit(request, application_id):
|
||||
reject (not permit) an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).notpermit(user=request.user.openslidesuser)
|
||||
messages.success(request, _("Application was successfully rejected."))
|
||||
Application.objects.get(pk=application_id).notpermit(user=request.user)
|
||||
messages.success(request, _("Motion was successfully rejected."))
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
except NameError, e:
|
||||
@ -343,8 +341,8 @@ def set_status(request, application_id=None, status=None):
|
||||
try:
|
||||
if status is not None:
|
||||
application = Application.objects.get(pk=application_id)
|
||||
application.set_status(user=request.user.openslidesuser, status=status)
|
||||
messages.success(request, _("Application status was set to: <b>%s</b>.") % application.get_status_display())
|
||||
application.set_status(user=request.user, status=status)
|
||||
messages.success(request, _("Motion status was set to: <b>%s</b>.") % application.get_status_display())
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
except NameError, e:
|
||||
@ -359,8 +357,8 @@ def reset(request, application_id):
|
||||
reset an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).reset(user=request.user.openslides.user)
|
||||
messages.success(request, _("Application status was reset.") )
|
||||
Application.objects.get(pk=application_id).reset(user=request.user)
|
||||
messages.success(request, _("Motion status was reset.") )
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
return redirect(reverse('application_view', args=[application_id]))
|
||||
@ -373,8 +371,8 @@ def support(request, application_id):
|
||||
support an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).support(user=request.user.openslides.user)
|
||||
messages.success(request, _("You have support the application successfully.") )
|
||||
Application.objects.get(pk=application_id).support(user=request.user)
|
||||
messages.success(request, _("You have support the motion successfully.") )
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
return redirect(reverse('application_view', args=[application_id]))
|
||||
@ -387,8 +385,8 @@ def unsupport(request, application_id):
|
||||
unsupport an application.
|
||||
"""
|
||||
try:
|
||||
Application.objects.get(pk=application_id).unsupport(user=request.user.openslidesuser)
|
||||
messages.success(request, _("You have unsupport the application successfully.") )
|
||||
Application.objects.get(pk=application_id).unsupport(user=request.user)
|
||||
messages.success(request, _("You have unsupport the motion successfully.") )
|
||||
except Application.DoesNotExist:
|
||||
pass
|
||||
return redirect(reverse('application_view', args=[application_id]))
|
||||
@ -401,7 +399,7 @@ def gen_poll(request, application_id):
|
||||
gen a poll for this application.
|
||||
"""
|
||||
try:
|
||||
poll = Application.objects.get(pk=application_id).gen_poll(user=request.user.openslidesuser)
|
||||
poll = Application.objects.get(pk=application_id).gen_poll(user=request.user)
|
||||
messages.success(request, _("New vote was successfully created.") )
|
||||
except Application.DoesNotExist:
|
||||
pass # TODO: do not call poll after this excaption
|
||||
@ -418,7 +416,7 @@ def delete_poll(request, poll_id):
|
||||
count = application.polls.filter(id__lte=poll_id).count()
|
||||
if request.method == 'POST':
|
||||
poll.delete()
|
||||
application.writelog(_("Poll deleted"), request.user.openslidesuser)
|
||||
application.writelog(_("Poll deleted"), request.user)
|
||||
messages.success(request, _('Poll was successfully deleted.'))
|
||||
else:
|
||||
del_confirm_form(request, poll, name=_("the %s. poll") % count, delete_link=reverse('application_poll_delete', args=[poll_id]))
|
||||
@ -458,21 +456,21 @@ class ApplicationDelete(DeleteView):
|
||||
|
||||
if len(self.applications):
|
||||
for application in self.applications:
|
||||
if not 'delete' in application.get_allowed_actions(user=request.user.openslidesuser):
|
||||
messages.error(request, _("You can not delete application <b>%s</b>.") % application)
|
||||
if not 'delete' in application.get_allowed_actions(user=request.user):
|
||||
messages.error(request, _("You can not delete motion <b>%s</b>.") % application)
|
||||
continue
|
||||
|
||||
title = application.title
|
||||
application.delete(force=True)
|
||||
messages.success(request, _("Application <b>%s</b> was successfully deleted.") % title)
|
||||
messages.success(request, _("Motion <b>%s</b> was successfully deleted.") % title)
|
||||
|
||||
elif self.object:
|
||||
if not 'delete' in self.object.get_allowed_actions(user=request.user.openslidesuser):
|
||||
messages.error(request, _("You can not delete application <b>%s</b>.") % self.object)
|
||||
if not 'delete' in self.object.get_allowed_actions(user=request.user):
|
||||
messages.error(request, _("You can not delete motion <b>%s</b>.") % self.object)
|
||||
else:
|
||||
title = self.object.title
|
||||
self.object.delete(force=True)
|
||||
messages.success(request, _("Application <b>%s</b> was successfully deleted.") % title)
|
||||
messages.success(request, _("Motion <b>%s</b> was successfully deleted.") % title)
|
||||
else:
|
||||
messages.error(request, _("Invalid request"))
|
||||
|
||||
@ -493,7 +491,7 @@ class ApplicationDelete(DeleteView):
|
||||
self.object = self.get_object()
|
||||
|
||||
if len(self.applications):
|
||||
self.gen_confirm_form(request, _('Do you really want to delete multiple applications?') % self.object.get_absolute_url('delete'))
|
||||
self.gen_confirm_form(request, _('Do you really want to delete multiple motions?') % self.object.get_absolute_url('delete'))
|
||||
else:
|
||||
self.gen_confirm_form(request, _('Do you really want to delete <b>%s</b>?') % self.object, self.object.get_absolute_url('delete'))
|
||||
|
||||
@ -508,12 +506,12 @@ class ViewPoll(PollFormView):
|
||||
self.application = self.poll.get_application()
|
||||
context['application'] = self.application
|
||||
context['ballot'] = self.poll.get_ballot()
|
||||
context['actions'] = self.application.get_allowed_actions(user=self.request.user.openslidesuser)
|
||||
context['actions'] = self.application.get_allowed_actions(user=self.request.user)
|
||||
return context
|
||||
|
||||
def get_modelform_class(self):
|
||||
cls = super(ViewPoll, self).get_modelform_class()
|
||||
user = self.request.user.openslidesuser
|
||||
user = self.request.user
|
||||
|
||||
class ViewPollFormClass(cls):
|
||||
def save(self, commit = True):
|
||||
@ -535,10 +533,10 @@ def permit_version(request, aversion_id):
|
||||
aversion = AVersion.objects.get(pk=aversion_id)
|
||||
application = aversion.application
|
||||
if request.method == 'POST':
|
||||
application.accept_version(aversion, user=request.user.openslidesuser)
|
||||
application.accept_version(aversion, user=request.user)
|
||||
messages.success(request, _("Version <b>%s</b> accepted.") % (aversion.aid))
|
||||
else:
|
||||
gen_confirm_form(request, _('Do you really want to permit version <b>%s</b>?') % aversion.aid, reverse('application_version_permit', args=[aversion.id]))
|
||||
gen_confirm_form(request, _('Do you really want to authorize version <b>%s</b>?') % aversion.aid, reverse('application_version_permit', args=[aversion.id]))
|
||||
return redirect(reverse('application_view', args=[application.id]))
|
||||
|
||||
|
||||
@ -547,7 +545,7 @@ def reject_version(request, aversion_id):
|
||||
aversion = AVersion.objects.get(pk=aversion_id)
|
||||
application = aversion.application
|
||||
if request.method == 'POST':
|
||||
if application.reject_version(aversion, user=request.user.openslidesuser):
|
||||
if application.reject_version(aversion, user=request.user):
|
||||
messages.success(request, _("Version <b>%s</b> rejected.") % (aversion.aid))
|
||||
else:
|
||||
messages.error(request, _("ERROR by rejecting the version.") )
|
||||
@ -559,17 +557,6 @@ def reject_version(request, aversion_id):
|
||||
@permission_required('application.can_manage_application')
|
||||
@template('application/import.html')
|
||||
def application_import(request):
|
||||
try:
|
||||
request.user.openslidesuser
|
||||
except OpenSlidesUser.DoesNotExist:
|
||||
pass
|
||||
except AttributeError:
|
||||
# AnonymousUser
|
||||
pass
|
||||
else:
|
||||
messages.error(request, _('The import function is available for the admin (without user profile) only.'))
|
||||
return redirect(reverse('application_overview'))
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ApplicationImportForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
@ -652,11 +639,11 @@ def application_import(request):
|
||||
application.save(user, trivial_change=True)
|
||||
|
||||
if applications_generated:
|
||||
messages.success(request, ungettext('%d application was successfully imported.',
|
||||
'%d applications were successfully imported.', applications_generated) % applications_generated)
|
||||
messages.success(request, ungettext('%d motion was successfully imported.',
|
||||
'%d motions were successfully imported.', applications_generated) % applications_generated)
|
||||
if applications_modified:
|
||||
messages.success(request, ungettext('%d application was successfully modified.',
|
||||
'%d applications were successfully modified.', applications_modified) % applications_modified)
|
||||
messages.success(request, ungettext('%d motion was successfully modified.',
|
||||
'%d motions were successfully modified.', applications_modified) % applications_modified)
|
||||
if users_generated:
|
||||
messages.success(request, ungettext('%d new user was added.', '%d new users were added.', users_generated) % users_generated)
|
||||
return redirect(reverse('application_overview'))
|
||||
@ -668,8 +655,8 @@ def application_import(request):
|
||||
else:
|
||||
messages.error(request, _('Please check the form for errors.'))
|
||||
else:
|
||||
messages.warning(request, _("Attention: Existing applications will be modified if you import new applications with the same number."))
|
||||
messages.warning(request, _("Attention: Importing an application without a number multiple times will create duplicates."))
|
||||
messages.warning(request, _("Attention: Existing motions will be modified if you import new motions with the same number."))
|
||||
messages.warning(request, _("Attention: Importing an motions without a number multiple times will create duplicates."))
|
||||
form = ApplicationImportForm()
|
||||
return {
|
||||
'form': form,
|
||||
@ -716,14 +703,14 @@ class ApplicationPDF(PDFView):
|
||||
story.append(Spacer(0,0.75*cm))
|
||||
applications = Application.objects.order_by('number')
|
||||
if not applications: # No applications existing
|
||||
story.append(Paragraph(_("No applications available."), stylesheet['Heading3']))
|
||||
story.append(Paragraph(_("No motions available."), stylesheet['Heading3']))
|
||||
else: # Print all Applications
|
||||
# List of applications
|
||||
for application in applications:
|
||||
if application.number:
|
||||
story.append(Paragraph(_("Application No.")+" %s: %s" % (application.number, application.title), stylesheet['Heading3']))
|
||||
story.append(Paragraph(_("Motion No.")+" %s: %s" % (application.number, application.title), stylesheet['Heading3']))
|
||||
else:
|
||||
story.append(Paragraph(_("Application No.")+" : %s" % (application.title), stylesheet['Heading3']))
|
||||
story.append(Paragraph(_("Motion No.")+" : %s" % (application.title), stylesheet['Heading3']))
|
||||
# Applications details (each application on single page)
|
||||
for application in applications:
|
||||
story.append(PageBreak())
|
||||
@ -735,9 +722,9 @@ class ApplicationPDF(PDFView):
|
||||
def get_application(self, application, story):
|
||||
# application number
|
||||
if application.number:
|
||||
story.append(Paragraph(_("Application No.")+" %s" % application.number, stylesheet['Heading1']))
|
||||
story.append(Paragraph(_("Motion No.")+" %s" % application.number, stylesheet['Heading1']))
|
||||
else:
|
||||
story.append(Paragraph(_("Application No."), stylesheet['Heading1']))
|
||||
story.append(Paragraph(_("Motion No."), stylesheet['Heading1']))
|
||||
|
||||
# submitter
|
||||
cell1a = []
|
||||
@ -914,7 +901,7 @@ class Config(FormView):
|
||||
config['application_pdf_title'] = form.cleaned_data['application_pdf_title']
|
||||
config['application_pdf_preamble'] = form.cleaned_data['application_pdf_preamble']
|
||||
config['application_allow_trivial_change'] = form.cleaned_data['application_allow_trivial_change']
|
||||
messages.success(self.request, _('Application settings successfully saved.'))
|
||||
messages.success(self.request, _('Motion settings successfully saved.'))
|
||||
return super(Config, self).form_valid(form)
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@ from openslides.utils.person import get_person
|
||||
|
||||
from openslides.config.models import config
|
||||
|
||||
from openslides.participant.models import OpenSlidesUser
|
||||
from openslides.participant.models import User
|
||||
|
||||
from openslides.projector.projector import Widget
|
||||
|
||||
@ -97,13 +97,12 @@ def view(request, assignment_id=None):
|
||||
polls = assignment.poll_set.all()
|
||||
vote_results = assignment.vote_results(only_published=False)
|
||||
|
||||
user = request.user.openslidesuser
|
||||
return {
|
||||
'assignment': assignment,
|
||||
'form': form,
|
||||
'vote_results': vote_results,
|
||||
'polls': polls,
|
||||
'user_is_candidate': assignment.is_candidate(user)
|
||||
'user_is_candidate': assignment.is_candidate(request.user)
|
||||
}
|
||||
|
||||
|
||||
@ -173,7 +172,7 @@ def set_status(request, assignment_id=None, status=None):
|
||||
def run(request, assignment_id):
|
||||
assignment = Assignment.objects.get(pk=assignment_id)
|
||||
try:
|
||||
assignment.run(request.user.openslidesuser, request.user)
|
||||
assignment.run(request.user, request.user)
|
||||
messages.success(request, _('You have set your candidature successfully.') )
|
||||
except NameError, e:
|
||||
messages.error(request, e)
|
||||
@ -185,7 +184,7 @@ def delrun(request, assignment_id):
|
||||
assignment = Assignment.objects.get(pk=assignment_id)
|
||||
try:
|
||||
if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"):
|
||||
assignment.delrun(request.user.openslidesuser)
|
||||
assignment.delrun(request.user)
|
||||
else:
|
||||
messages.error(request, _('The candidate list is already closed.'))
|
||||
except Exception, e:
|
||||
|
@ -81,7 +81,7 @@ def default_config(sender, key, **kwargs):
|
||||
return {
|
||||
'event_name': 'OpenSlides',
|
||||
'event_description':
|
||||
_('Presentation system for agenda, applications and elections'),
|
||||
_('Presentation system for agenda, motions and elections'),
|
||||
'event_date': '',
|
||||
'event_location': '',
|
||||
'event_organizer': '',
|
||||
|
@ -67,7 +67,7 @@ class GeneralConfig(FormView):
|
||||
anonymous = Group.objects.get(name='Anonymous')
|
||||
except Group.DoesNotExist:
|
||||
default_perms = [u'can_see_agenda', u'can_see_projector',
|
||||
u'can_see_application', 'can_see_assignment']
|
||||
u'can_see_application', u'can_see_assignment']
|
||||
anonymous = Group()
|
||||
anonymous.name = 'Anonymous'
|
||||
anonymous.save()
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -46,6 +46,10 @@ USE_I18N = True
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
LOCALE_PATHS = (
|
||||
_fs2unicode(os.path.join(SITE_ROOT, 'locale'))
|
||||
)
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = _fs2unicode(os.path.join(SITE_ROOT, './static/'))
|
||||
@ -89,7 +93,7 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'openslides.participant.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
)
|
||||
|
@ -10,13 +10,19 @@
|
||||
:license: GNU GPL, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
# for python 2.5 support
|
||||
from __future__ import with_statement
|
||||
|
||||
from random import choice
|
||||
import string
|
||||
import csv
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
|
||||
from openslides.utils.person import get_person
|
||||
from openslides.participant.models import OpenSlidesUser
|
||||
from openslides.utils import csv_ext
|
||||
|
||||
from openslides.participant.models import User
|
||||
|
||||
|
||||
def gen_password():
|
||||
@ -47,3 +53,44 @@ def gen_username(first_name, last_name):
|
||||
User.objects.get(username=testname)
|
||||
except User.DoesNotExist:
|
||||
return testname
|
||||
|
||||
|
||||
def import_users(csv_file):
|
||||
error_messages = []
|
||||
count_success = 0
|
||||
try:
|
||||
# check for valid encoding (will raise UnicodeDecodeError if not)
|
||||
csv_file.read().decode('utf-8')
|
||||
csv_file.seek(0)
|
||||
|
||||
with transaction.commit_on_success():
|
||||
dialect = csv.Sniffer().sniff(csv_file.readline())
|
||||
dialect = csv_ext.patchup(dialect)
|
||||
csv_file.seek(0)
|
||||
|
||||
for (line_no, line) in enumerate(csv.reader(csv_file,
|
||||
dialect=dialect)):
|
||||
if line_no:
|
||||
try:
|
||||
(first_name, last_name, gender, category, type, committee, comment) = line[:7]
|
||||
except ValueError:
|
||||
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
|
||||
continue
|
||||
user = User()
|
||||
user.last_name = last_name
|
||||
user.first_name = first_name
|
||||
user.username = gen_username(first_name, last_name)
|
||||
user.gender = gender
|
||||
user.category = category
|
||||
user.type = type
|
||||
user.committee = committee
|
||||
user.comment = comment
|
||||
user.firstpassword = gen_password()
|
||||
user.save()
|
||||
user.reset_password()
|
||||
count_success += 1
|
||||
except csv.Error:
|
||||
error_messages.appen(_('Import aborted because of severe errors in the input file.'))
|
||||
except UnicodeDecodeError:
|
||||
error_messages.appen(_('Import file has wrong character encoding, only UTF-8 is supported!'))
|
||||
return (count_success, error_messages)
|
||||
|
@ -11,79 +11,99 @@
|
||||
"""
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth.forms import AdminPasswordChangeForm
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from openslides.utils.forms import (
|
||||
CssClassMixin, LocalizedModelMultipleChoiceField)
|
||||
|
||||
from openslides.participant.models import OpenSlidesUser
|
||||
from openslides.participant.models import User, Group
|
||||
|
||||
|
||||
USER_APPLICATION_IMPORT_OPTIONS = [
|
||||
('REASSIGN', _('Keep applications, try to reassign submitter')),
|
||||
('INREVIEW', _('Keep applications, set status to "needs review"')),
|
||||
('DISCARD', _('Discard applications'))
|
||||
]
|
||||
|
||||
|
||||
class UserNewForm(forms.ModelForm, CssClassMixin):
|
||||
first_name = forms.CharField(label=_("First name"))
|
||||
last_name = forms.CharField(label=_("Last name"))
|
||||
class UserCreateForm(forms.ModelForm, CssClassMixin):
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
queryset=Group.objects.all(), label=_("User groups"), required=False)
|
||||
is_active = forms.BooleanField(
|
||||
label=_("Active"), required=False, initial=True)
|
||||
queryset=Group.objects.exclude(name__iexact='anonymous'),
|
||||
label=_("User groups"), required=False)
|
||||
is_active = forms.BooleanField(label=_("Active"), required=False,
|
||||
initial=True)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
exclude = ('username', 'password', 'is_staff', 'is_superuser',
|
||||
'last_login', 'date_joined', 'user_permissions')
|
||||
'last_login', 'date_joined', 'user_permissions')
|
||||
|
||||
|
||||
class UserEditForm(forms.ModelForm, CssClassMixin):
|
||||
first_name = forms.CharField(label=_("First name"))
|
||||
last_name = forms.CharField(label=_("Last name"))
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
queryset=Group.objects.all(), label=_("User groups"), required=False)
|
||||
groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),
|
||||
label=_("User groups"), required=False)
|
||||
is_active = forms.BooleanField(label=_("Active"), required=False)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
exclude = ('password', 'is_staff', 'is_superuser', 'last_login',
|
||||
'date_joined', 'user_permissions')
|
||||
fields = ('first_name', 'last_name', 'is_active', 'groups', 'category',
|
||||
'gender', 'type', 'committee', 'comment', 'default_password')
|
||||
|
||||
|
||||
class UsernameForm(forms.ModelForm, CssClassMixin):
|
||||
class UserUpdateForm(UserCreateForm):
|
||||
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
|
||||
fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
|
||||
'category', 'gender', 'type', 'committee', 'comment',
|
||||
'default_password')
|
||||
|
||||
|
||||
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)
|
||||
users = forms.ModelMultipleChoiceField(
|
||||
queryset=User.objects.all(), label=_("Users"), required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GroupForm, self).__init__(*args, **kwargs)
|
||||
# Initial users
|
||||
if kwargs.get('instance', None) is not None:
|
||||
self.fields['permissions'].initial = (
|
||||
[p.pk for p in kwargs['instance'].permissions.all()])
|
||||
initial = kwargs.setdefault('initial', {})
|
||||
initial['users'] = [django_user.user.pk for django_user in kwargs['instance'].user_set.all()]
|
||||
|
||||
super(GroupForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def save(self, commit=True):
|
||||
instance = forms.ModelForm.save(self, False)
|
||||
|
||||
old_save_m2m = self.save_m2m
|
||||
def save_m2m():
|
||||
old_save_m2m()
|
||||
|
||||
instance.user_set.clear()
|
||||
for user in self.cleaned_data['users']:
|
||||
instance.user_set.add(user)
|
||||
self.save_m2m = save_m2m
|
||||
|
||||
if commit:
|
||||
instance.save()
|
||||
self.save_m2m()
|
||||
|
||||
return instance
|
||||
|
||||
def clean_name(self):
|
||||
# Do not allow to change the name "anonymous" or give another group
|
||||
# this name
|
||||
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',)
|
||||
|
||||
|
||||
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
||||
@ -91,13 +111,9 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
||||
model = User
|
||||
fields = ('username', 'first_name', 'last_name', 'email')
|
||||
|
||||
|
||||
class UserImportForm(forms.Form, CssClassMixin):
|
||||
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
|
||||
label=_("CSV File"))
|
||||
application_handling = forms.ChoiceField(
|
||||
required=True, choices=USER_APPLICATION_IMPORT_OPTIONS,
|
||||
label=_("For existing applications"))
|
||||
|
||||
|
||||
class ConfigForm(forms.Form, CssClassMixin):
|
||||
|
22
openslides/participant/middleware.py
Normal file
22
openslides/participant/middleware.py
Normal file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
openslides.utils.middleware
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Additional definitions for OpenSlides forms.
|
||||
|
||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
||||
:license: GNU GPL, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.middleware import AuthenticationMiddleware as _AuthenticationMiddleware
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
||||
|
||||
class AuthenticationMiddleware(_AuthenticationMiddleware):
|
||||
def process_request(self, request):
|
||||
super(AuthenticationMiddleware, self).process_request(request)
|
||||
|
||||
if not isinstance(request.user, AnonymousUser):
|
||||
request.user = request.user.user
|
@ -10,20 +10,20 @@
|
||||
:license: GNU GPL, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.contrib.auth.models import User as DjangoUser, Group as DjangoGroup
|
||||
from django.db import models
|
||||
from django.db.models import Q, signals
|
||||
from django.db.models import signals
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
||||
|
||||
from openslides.utils.person import PersonMixin
|
||||
from openslides.utils.person.signals import receiv_persons
|
||||
from openslides.utils.person.signals import receive_persons
|
||||
|
||||
from openslides.config.signals import default_config_value
|
||||
|
||||
|
||||
class OpenSlidesUser(models.Model, PersonMixin):
|
||||
person_prefix = 'openslides_user'
|
||||
class User(DjangoUser, PersonMixin):
|
||||
person_prefix = 'user'
|
||||
GENDER_CHOICES = (
|
||||
('male', _('Male')),
|
||||
('female', _('Female')),
|
||||
@ -35,10 +35,10 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
||||
('guest', _('Guest')),
|
||||
)
|
||||
|
||||
user = models.OneToOneField(User, unique=True, editable=False)
|
||||
name_surfix = models.CharField(
|
||||
max_length=100, null=True, blank=True, verbose_name=_("Name Surfix"),
|
||||
help_text=_('Shown behind the name.'))
|
||||
django_user = models.OneToOneField(DjangoUser, 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.'))
|
||||
gender = models.CharField(
|
||||
max_length=50, choices=GENDER_CHOICES, blank=True,
|
||||
verbose_name=_("Gender"), help_text=_('Only for filter the userlist.'))
|
||||
@ -51,21 +51,26 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
||||
comment = models.TextField(
|
||||
null=True, blank=True, verbose_name=_('Comment'),
|
||||
help_text=_('Only for notes.'))
|
||||
firstpassword = models.CharField(
|
||||
default_password = models.CharField(
|
||||
max_length=100, null=True, blank=True,
|
||||
verbose_name=_("First Password"))
|
||||
verbose_name=_("Default password"))
|
||||
|
||||
def get_name_suffix(self):
|
||||
return self.category
|
||||
|
||||
def set_name_suffix(self, value):
|
||||
self.category = value
|
||||
|
||||
name_suffix = property(get_name_suffix, set_name_suffix)
|
||||
|
||||
def reset_password(self, password=None):
|
||||
"""
|
||||
Reset the password for the user to his default-password.
|
||||
"""
|
||||
if password is None:
|
||||
password = self.firstpassword
|
||||
self.user.set_password(password)
|
||||
self.user.save()
|
||||
|
||||
def has_perm(self, perm):
|
||||
return self.user.has_perm(perm)
|
||||
password = self.default_password
|
||||
self.set_password(password)
|
||||
self.save()
|
||||
|
||||
@models.permalink
|
||||
def get_absolute_url(self, link='edit'):
|
||||
@ -77,14 +82,15 @@ class OpenSlidesUser(models.Model, 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:
|
||||
return "%s (%s)" % (self.user.get_full_name(), self.name_surfix)
|
||||
return "%s" % self.user.get_full_name()
|
||||
name = self.get_full_name() or self.username
|
||||
if self.name_suffix:
|
||||
return u"%s (%s)" % (name, self.name_suffix)
|
||||
return u"%s" % name
|
||||
|
||||
class Meta:
|
||||
# Rename permissions
|
||||
@ -95,46 +101,63 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
||||
)
|
||||
|
||||
|
||||
class OpenSlidesGroup(models.Model, PersonMixin):
|
||||
person_prefix = 'openslides_group'
|
||||
class Group(DjangoGroup, PersonMixin):
|
||||
person_prefix = 'group'
|
||||
|
||||
group = models.OneToOneField(Group)
|
||||
django_group = models.OneToOneField(DjangoGroup, 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)
|
||||
return unicode(self.name)
|
||||
|
||||
|
||||
class OpenSlidesUsersConnecter(object):
|
||||
def __init__(self, person_prefix=None, id=None):
|
||||
self.person_prefix = person_prefix
|
||||
self.id = id
|
||||
class UsersConnector(object):
|
||||
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||
self.person_prefix_filter = person_prefix_filter
|
||||
self.id_filter = id_filter
|
||||
self.users = User.objects.all()
|
||||
self.groups = Group.objects.filter(group_as_person=True)
|
||||
|
||||
def __iter__(self):
|
||||
if (not self.person_prefix or
|
||||
self.person_prefix == OpenSlidesUser.person_prefix):
|
||||
if self.id:
|
||||
yield OpenSlidesUser.objects.get(pk=self.id)
|
||||
if (not self.person_prefix_filter or
|
||||
self.person_prefix_filter == User.person_prefix):
|
||||
if self.id_filter:
|
||||
yield self.users.get(pk=self.id_filter)
|
||||
else:
|
||||
for user in OpenSlidesUser.objects.all():
|
||||
for user in self.users:
|
||||
yield user
|
||||
|
||||
if (not self.person_prefix or
|
||||
self.person_prefix == OpenSlidesGroup.person_prefix):
|
||||
if self.id:
|
||||
yield OpenSlidesGroup.objects.get(pk=self.id)
|
||||
if (not self.person_prefix_filter or
|
||||
self.person_prefix_filter == Group.person_prefix):
|
||||
if self.id_filter:
|
||||
yield self.groups.get(pk=self.id_filter)
|
||||
else:
|
||||
for group in OpenSlidesGroup.objects.all():
|
||||
for group in self.groups:
|
||||
yield group
|
||||
|
||||
def __getitem__(self, key):
|
||||
return OpenSlidesUser.objects.get(pk=key)
|
||||
return User.objects.get(pk=key)
|
||||
|
||||
|
||||
@receiver(receiv_persons, dispatch_uid="participant")
|
||||
def receiv_persons(sender, **kwargs):
|
||||
return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'],
|
||||
id=kwargs['id'])
|
||||
@receiver(receive_persons, dispatch_uid="participant")
|
||||
def receive_persons(sender, **kwargs):
|
||||
return UsersConnector(person_prefix_filter=kwargs['person_prefix_filter'],
|
||||
id_filter=kwargs['id_filter'])
|
||||
|
||||
|
||||
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
||||
@ -150,7 +173,17 @@ def default_config(sender, key, **kwargs):
|
||||
}.get(key)
|
||||
|
||||
|
||||
@receiver(signals.post_save, sender=User)
|
||||
@receiver(signals.post_save, sender=DjangoUser)
|
||||
def user_post_save(sender, instance, signal, *args, **kwargs):
|
||||
# Creates OpenSlidesUser
|
||||
profile, new = OpenSlidesUser.objects.get_or_create(user=instance)
|
||||
try:
|
||||
instance.user
|
||||
except User.DoesNotExist:
|
||||
User(django_user=instance).save_base(raw=True)
|
||||
|
||||
|
||||
@receiver(signals.post_save, sender=DjangoGroup)
|
||||
def group_post_save(sender, instance, signal, *args, **kwargs):
|
||||
try:
|
||||
instance.group
|
||||
except Group.DoesNotExist:
|
||||
Group(django_group=instance).save_base(raw=True)
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
{% block title %}
|
||||
{{ block.super }} –
|
||||
{% if edituser %}
|
||||
{% if edit_user %}
|
||||
{% trans "Edit participant" %}
|
||||
{% else %}
|
||||
{% trans "New participant" %}
|
||||
@ -13,30 +13,31 @@
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% if edituser %}
|
||||
{% if edit_user %}
|
||||
<h1>{% trans "Edit participant" %}</h1>
|
||||
{% else %}
|
||||
<h1>{% trans "New participant" %}</h1>
|
||||
{% endif %}
|
||||
|
||||
<form action="" method="post">{% csrf_token %}
|
||||
{{ userform.as_p }}
|
||||
{{ profileform.as_p }}
|
||||
{% if edituser %}
|
||||
<p><a href="{% url user_reset_password edituser.id %}">{% trans 'Reset to First Password' %}</a></p>
|
||||
{{ form.as_p }}
|
||||
{% if edit_user %}
|
||||
<p>
|
||||
<a href="{% url user_reset_password edit_user.id %}">{% trans 'Reset to First Password' %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>
|
||||
<button class="button" type="submit">
|
||||
<span class="icon ok">{% trans 'Save' %}</span>
|
||||
</button>
|
||||
<button class="button" type="submit" name="apply">
|
||||
<span class="icon apply">{% trans 'Apply' %}</span>
|
||||
</button>
|
||||
<a href='{% url user_overview %}'>
|
||||
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
|
||||
<span class="icon cancel">{% trans 'Cancel' %}</span>
|
||||
</button>
|
||||
</a>
|
||||
<button class="button" type="submit">
|
||||
<span class="icon ok">{% trans 'Save' %}</span>
|
||||
</button>
|
||||
<button class="button" type="submit" name="apply">
|
||||
<span class="icon apply">{% trans 'Apply' %}</span>
|
||||
</button>
|
||||
<a href='{% url user_overview %}'>
|
||||
<button class="button" type="button" onclick="window.location='{% url user_overview %}'">
|
||||
<span class="icon cancel">{% trans 'Cancel' %}</span>
|
||||
</button>
|
||||
</a>
|
||||
</p>
|
||||
<small>* {% trans "required" %}</small>
|
||||
</form>
|
||||
|
@ -8,99 +8,108 @@
|
||||
|
||||
{% block header %}
|
||||
{% if perms.agenda.can_manage_agenda %}
|
||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
|
||||
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
|
||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/participant.css' %}" />
|
||||
<script type="text/javascript" src="{% static 'javascript/participant.js' %}"></script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Participants" %}</h1>
|
||||
|
||||
<p><form action="{{request.url}}" name="filter" method="post">
|
||||
{% csrf_token %}
|
||||
{% trans "Filter" %}:
|
||||
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Gender" %} --</option>
|
||||
<option value="male" {% if 'male' in sortfilter.gender %}selected{% endif %}>{% trans "Male" %}</option>
|
||||
<option value="female" {% if 'female' in sortfilter.gender %}selected{% endif %}>{% trans "Female" %}</option>
|
||||
<option value="" {% if '' in sortfilter.gender %}selected{% endif %}>{% trans "Not specified" %}</option>
|
||||
</select>
|
||||
<select class="default-input" name="group" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Group" %} --</option>
|
||||
{% for group in groups %}
|
||||
<option value="{{ group }}" {% if group in sortfilter.group %}selected{% endif %}>
|
||||
{{ group }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Type" %} --</option>
|
||||
<option value="delegate" {% if 'delegate' in sortfilter.type %}selected{% endif %}>{% trans "Delegate" %}</option>
|
||||
<option value="observer" {% if 'observer' in sortfilter.type %}selected{% endif %}>{% trans "Observer" %}</option>
|
||||
<option value="staff" {% if 'staff' in sortfilter.type %}selected{% endif %}>{% trans "Staff" %}</option>
|
||||
<option value="guest" {% if 'guest' in sortfilter.type %}selected{% endif %}>{% trans "Guest" %}</option>
|
||||
<option value="" {% if '' in sortfilter.type %}selected{% endif %}>{% trans "Not specified" %}</option>
|
||||
</select>
|
||||
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Committee" %} --</option>
|
||||
{% for committee in committees %}
|
||||
<option value="{{ committee }}" {% if committee in sortfilter.committee %}selected{% endif %}>
|
||||
{{ committee }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Status" %} --</option>
|
||||
<option value="1" {% if '1' in sortfilter.status %}selected{% endif %}>{% trans "Active" %}</option>
|
||||
<option value="0" {% if '0' in sortfilter.status %}selected{% endif %}>{% trans "Inactive" %}</option>
|
||||
</select>
|
||||
<p>
|
||||
<form action="" name="filter" method="get">
|
||||
{% trans "Filter" %}:
|
||||
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Gender" %} --</option>
|
||||
<option value="male"{% if 'male' in sortfilter.gender %} selected{% endif %}>{% trans "Male" %}</option>
|
||||
<option value="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option>
|
||||
<option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||
</select>
|
||||
<select class="default-input" name="category" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Category" %} --</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}>
|
||||
{{ category }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Type" %} --</option>
|
||||
<option value="delegate"{% if 'delegate' in sortfilter.type %} selected{% endif %}>{% trans "Delegate" %}</option>
|
||||
<option value="observer"{% if 'observer' in sortfilter.type %} selected{% endif %}>{% trans "Observer" %}</option>
|
||||
<option value="staff"{% if 'staff' in sortfilter.type %} selected{% endif %}>{% trans "Staff" %}</option>
|
||||
<option value="guest"{% if 'guest' in sortfilter.type %} selected{% endif %}>{% trans "Guest" %}</option>
|
||||
<option value=""{% if '' in sortfilter.type %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||
</select>
|
||||
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Committee" %} --</option>
|
||||
{% for committee in committees %}
|
||||
<option value="{{ committee }}"{% if committee in sortfilter.committee %} selected{% endif %}>
|
||||
{{ committee }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
||||
<option value="---">-- {% trans "Status" %} --</option>
|
||||
<option value="1"{% if '1' in sortfilter.status %} selected{% endif %}>{% trans "Active" %}</option>
|
||||
<option value="0"{% if '0' in sortfilter.status %} selected{% endif %}>{% trans "Inactive" %}</option>
|
||||
</select>
|
||||
</form>
|
||||
</p>
|
||||
{% if users|length == allusers|length %}
|
||||
{{ users|length }}
|
||||
{% blocktrans count counter=users|length %}participant{% plural %}participants{% endblocktrans %}
|
||||
{% if users.count == allusers %}
|
||||
{{ users.count }}
|
||||
{% blocktrans count counter=users.count %}participant{% plural %}participants{% endblocktrans %}
|
||||
{% else %}
|
||||
{{ users|length }} {% trans "of" %} {{ allusers|length }} {% trans "Participants" %} (= {{ percent }} %)
|
||||
{{ users.count }} {% trans "of" %} {{ allusers }} {% trans "Participants" %} (= {{ percent }} %)
|
||||
{% endif %}
|
||||
<table>
|
||||
<tr>
|
||||
<th><a href="?sort=first_name&reverse={% if 'first_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "First Name" %}</a></th>
|
||||
<th><a href="?sort=last_name&reverse={% if 'last_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Name" %}</a></th>
|
||||
<th><a href="?sort=group&reverse={% if 'group' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Group" %}</a></th>
|
||||
<th><a href="?sort=group&reverse={% if 'category' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Category" %}</a></th>
|
||||
<th><a href="?sort=type&reverse={% if 'type' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Type" %}</a></th>
|
||||
<th><a href="?sort=committee&reverse={% if 'committee' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Committee" %}</a></th>
|
||||
{% if perms.participant.can_manage_participant %}
|
||||
<th><a href="?sort=comment&reverse={% if 'comment' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Comment" %}</a></th>
|
||||
<th><a href="?sort=last_login&reverse={% if 'last_login' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Login" %}</a></th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
<th><a href="?sort=comment&reverse={% if 'comment' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Comment" %}</a></th>
|
||||
<th><a href="?sort=last_login&reverse={% if 'last_login' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Login" %}</a></th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for user in users %}
|
||||
<tr class="{% cycle '' 'odd' %}">
|
||||
<td>{{ user.first_name }}</td>
|
||||
<td>{{ user.last_name }}</td>
|
||||
<td>{{ user.openslidesuser.name_surfix }}</td>
|
||||
<td>{{ user.openslidesuser.get_type_display }}</td>
|
||||
<td>{{ user.openslidesuser.committee }}</td>
|
||||
{% if perms.participant.can_manage_participant %}
|
||||
<td>{{ user.openslidesuser.comment|first_line }}</td>
|
||||
<td>{% if user.last_login > user.date_joined %}
|
||||
{{ user.last_login }}
|
||||
{% endif %}</td>
|
||||
<td><span style="width: 1px; white-space: nowrap;">
|
||||
<a href="{% url user_edit user.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}"></a>
|
||||
<a href="{% url user_delete user.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}"></a>
|
||||
<a class="status_link {% if user.is_active %}active{% endif %}"
|
||||
href="{% url user_status user.id %}"
|
||||
title="{% trans 'Change status (active/inactive)' %}">
|
||||
<span></span>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for user in users %}
|
||||
<tr class="{% cycle '' 'odd' %}">
|
||||
<td>{{ user.first_name }}</td>
|
||||
<td>{{ user.last_name }}</td>
|
||||
<td>{{ user.category }}</td>
|
||||
<td>{{ user.get_type_display }}</td>
|
||||
<td>{{ user.committee }}</td>
|
||||
{% if perms.participant.can_manage_participant %}
|
||||
<td>{{ user.comment|first_line }}</td>
|
||||
<td>
|
||||
{% if user.last_login > user.date_joined %}
|
||||
{{ user.last_login }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<span style="width: 1px; white-space: nowrap;">
|
||||
<a href="{% url user_edit user.id %}">
|
||||
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
|
||||
</a>
|
||||
<a href="{% url user_delete user.id %}">
|
||||
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
|
||||
</a>
|
||||
<a class="status_link deactivate" href="{% url user_status_deactivate user.id %}" title="{% trans 'Change status to inactive' %}"{% if not user.is_active %} style="display:none"{% endif %}>
|
||||
<span></span>
|
||||
</a>
|
||||
<a class="status_link activate" href="{% url user_status_activate user.id %}" title="{% trans 'Change status to active' %}"{% if user.is_active %} style="display:none"{% endif %}>
|
||||
<span></span>
|
||||
</a>
|
||||
</span>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="9"><i>{% trans "No participants available." %}</i></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
@ -12,61 +12,65 @@
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.db.models.query import EmptyQuerySet
|
||||
from django.contrib.auth.hashers import check_password
|
||||
|
||||
from openslides.utils.person import get_person, Persons
|
||||
from openslides.participant.api import gen_username, gen_password
|
||||
from openslides.participant.models import OpenSlidesUser, OpenSlidesGroup
|
||||
from openslides.participant.models import User, Group
|
||||
|
||||
|
||||
class OpenSlidesUserTest(TestCase):
|
||||
class UserTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user1 = User(first_name=u'Max', last_name=u'Mustermann')
|
||||
self.user1.username = gen_username(self.user1.first_name, self.user1.last_name)
|
||||
self.user1 = User()
|
||||
self.user1.first_name = u'Max'
|
||||
self.user1.last_name = u'Mustermann'
|
||||
self.user1.username = gen_username(
|
||||
self.user1.first_name, self.user1.last_name)
|
||||
self.user1.default_password = gen_password()
|
||||
self.user1.save()
|
||||
self.openslidesuser1 = self.user1.openslidesuser
|
||||
self.openslidesuser1.firstpassword = gen_password()
|
||||
self.openslidesuser1.save()
|
||||
self.user1 = self.openslidesuser1.user
|
||||
self.django_user1 = self.user1.django_user
|
||||
|
||||
def test_participant_user(self):
|
||||
self.assertEqual(self.user1.openslidesuser, self.openslidesuser1)
|
||||
self.assertEqual(self.user1, self.openslidesuser1.user)
|
||||
self.assertEqual(self.django_user1.user, self.user1)
|
||||
self.assertEqual(self.django_user1, self.user1.django_user)
|
||||
|
||||
def test_repr(self):
|
||||
self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann')
|
||||
self.assertEqual(unicode(self.user1), u'Max Mustermann')
|
||||
|
||||
def test_name_surfix(self):
|
||||
self.openslidesuser1.name_surfix = u'München'
|
||||
self.openslidesuser1.save()
|
||||
self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann (München)')
|
||||
self.user1.category = u'München'
|
||||
self.user1.save()
|
||||
self.assertEqual(unicode(self.user1), u'Max Mustermann (München)')
|
||||
|
||||
def test_reset_password(self):
|
||||
self.assertIsInstance(self.openslidesuser1.firstpassword, basestring)
|
||||
self.assertEqual(len(self.openslidesuser1.firstpassword), 8)
|
||||
self.assertIsInstance(self.user1.default_password, basestring)
|
||||
self.assertEqual(len(self.user1.default_password), 8)
|
||||
self.user1.set_unusable_password()
|
||||
self.assertFalse(self.user1.check_password(self.openslidesuser1.firstpassword))
|
||||
self.openslidesuser1.reset_password()
|
||||
self.assertTrue(self.user1.check_password(self.openslidesuser1.firstpassword))
|
||||
self.assertFalse(self.user1.check_password(self.user1.default_password))
|
||||
self.user1.reset_password()
|
||||
self.assertTrue(self.user1.check_password(self.user1.default_password))
|
||||
|
||||
def test_person_api(self):
|
||||
self.assertTrue(hasattr(self.openslidesuser1, 'person_id'))
|
||||
self.assertEqual(self.openslidesuser1.person_id, 'openslides_user:1')
|
||||
self.assertEqual(get_person('openslides_user:1'), self.openslidesuser1)
|
||||
self.assertEqual(len(Persons()), 1)
|
||||
self.assertTrue(hasattr(self.user1, 'person_id'))
|
||||
self.assertEqual(self.user1.person_id, 'user:1')
|
||||
self.assertEqual(get_person('user:1'), self.user1)
|
||||
self.assertEqual(len(Persons(person_prefix_filter='user')), 1)
|
||||
|
||||
|
||||
class OpenSlidesGroupTest(TestCase):
|
||||
class GroupTest(TestCase):
|
||||
def setUp(self):
|
||||
self.group1 = Group.objects.create(name='Test Group')
|
||||
self.openslidesgroup1 = OpenSlidesGroup.objects.create(group=self.group1)
|
||||
self.django_group1 = self.group1.django_group
|
||||
|
||||
def test_group_openslidesgroup(self):
|
||||
self.assertEqual(self.openslidesgroup1.group, self.group1)
|
||||
def test_group_group(self):
|
||||
self.assertEqual(self.group1.django_group, self.django_group1)
|
||||
self.assertEqual(self.group1, self.django_group1.group)
|
||||
|
||||
def test_person_api(self):
|
||||
self.assertTrue(hasattr(self.openslidesgroup1, 'person_id'))
|
||||
self.assertEqual(self.openslidesgroup1.person_id, 'openslides_group:1')
|
||||
self.assertEqual(get_person('openslides_group:1'), self.openslidesgroup1)
|
||||
self.assertTrue(hasattr(self.group1, 'person_id'))
|
||||
person_id = "group:%d" % self.group1.id
|
||||
self.assertEqual(self.group1.person_id, person_id)
|
||||
self.assertRaises(Group.DoesNotExist)
|
||||
self.group1.group_as_person = True
|
||||
self.group1.save()
|
||||
self.assertEqual(get_person(person_id), self.group1)
|
||||
|
@ -13,70 +13,86 @@
|
||||
from django.conf.urls.defaults import url, patterns
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from openslides.participant.views import (ParticipantsListPDF,
|
||||
ParticipantsPasswordsPDF)
|
||||
from openslides.participant.views import (
|
||||
ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
|
||||
UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView,
|
||||
ResetPasswordView, GroupOverviewView, GroupCreateView, GroupUpdateView,
|
||||
GroupDeleteView)
|
||||
|
||||
urlpatterns = patterns('openslides.participant.views',
|
||||
url(r'^$',
|
||||
'get_overview',
|
||||
Overview.as_view(),
|
||||
name='user_overview',
|
||||
),
|
||||
|
||||
url(r'^new/$',
|
||||
'edit',
|
||||
UserCreateView.as_view(),
|
||||
name='user_new',
|
||||
),
|
||||
|
||||
url(r'^(?P<user_id>\d+)/edit/$',
|
||||
'edit',
|
||||
url(r'^(?P<pk>\d+)/edit/$',
|
||||
UserUpdateView.as_view(),
|
||||
name='user_edit',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/del/$',
|
||||
UserDeleteView.as_view(),
|
||||
name='user_delete',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/reset_password/$',
|
||||
ResetPasswordView.as_view(),
|
||||
name='user_reset_password',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/status/toggle/$',
|
||||
SetUserStatusView.as_view(),
|
||||
{'action': 'toggle'},
|
||||
name='user_status_toggle',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/status/activate/$',
|
||||
SetUserStatusView.as_view(),
|
||||
{'action': 'activate'},
|
||||
name='user_status_activate',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/status/deactivate/$',
|
||||
SetUserStatusView.as_view(),
|
||||
{'action': 'deactivate'},
|
||||
name='user_status_deactivate',
|
||||
),
|
||||
|
||||
url(r'^import/$',
|
||||
UserImportView.as_view(),
|
||||
name='user_import',
|
||||
),
|
||||
|
||||
url(r'^group/$',
|
||||
GroupOverviewView.as_view(),
|
||||
name='user_group_overview',
|
||||
),
|
||||
|
||||
url(r'^group/new/$',
|
||||
GroupCreateView.as_view(),
|
||||
name='user_group_new',
|
||||
),
|
||||
|
||||
url(r'^group/(?P<pk>\d+)/edit/$',
|
||||
GroupUpdateView.as_view(),
|
||||
name='user_group_edit',
|
||||
),
|
||||
|
||||
url(r'^group/(?P<pk>\d+)/del/$',
|
||||
GroupDeleteView.as_view(),
|
||||
name='user_group_delete',
|
||||
),
|
||||
|
||||
url(r'^print/$',
|
||||
ParticipantsListPDF.as_view(),
|
||||
name='user_print',
|
||||
),
|
||||
|
||||
url(r'^(?P<user_id>\d+)/del/$',
|
||||
'user_delete',
|
||||
name='user_delete',
|
||||
),
|
||||
|
||||
url(r'^(?P<user_id>\d+)/status/$',
|
||||
'user_set_status',
|
||||
name='user_status',
|
||||
),
|
||||
|
||||
url(r'^import/$',
|
||||
'user_import',
|
||||
name='user_import',
|
||||
),
|
||||
|
||||
url(r'^group/$',
|
||||
'get_group_overview',
|
||||
name='user_group_overview',
|
||||
),
|
||||
|
||||
url(r'^group/new/$',
|
||||
'group_edit',
|
||||
name='user_group_new',
|
||||
),
|
||||
|
||||
url(r'^group/(?P<group_id>\d+)/edit/$',
|
||||
'group_edit',
|
||||
name='user_group_edit',
|
||||
),
|
||||
|
||||
url(r'^group/(?P<group_id>\d+)/del/$',
|
||||
'group_delete',
|
||||
name='user_group_delete',
|
||||
),
|
||||
|
||||
url(r'^resetpassword/(?P<user_id>\d+)/$',
|
||||
'reset_password',
|
||||
name='user_reset_password',
|
||||
),
|
||||
|
||||
url(r'^passwords/print/$',
|
||||
ParticipantsPasswordsPDF.as_view(),
|
||||
name='print_passwords',
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,6 @@ for plugin in settings.INSTALLED_PLUGINS:
|
||||
|
||||
|
||||
urlpatterns += patterns('',
|
||||
(r'^500/$', 'openslides.utils.views.server_error'),
|
||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
||||
|
||||
url(r'^login/$',
|
||||
|
@ -10,7 +10,7 @@
|
||||
:license: GNU GPL, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from openslides.utils.person.signals import receiv_persons
|
||||
from openslides.utils.person.signals import receive_persons
|
||||
from openslides.utils.person.api import generate_person_id, get_person, Persons
|
||||
from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField
|
||||
from openslides.utils.person.models import PersonField, PersonMixin
|
||||
|
@ -10,16 +10,16 @@
|
||||
:license: GNU GPL, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from openslides.utils.person.signals import receiv_persons
|
||||
from openslides.utils.person.signals import receive_persons
|
||||
|
||||
|
||||
class Persons(object):
|
||||
"""
|
||||
A Storage for a multiplicity of different Person-Objects.
|
||||
"""
|
||||
def __init__(self, person_prefix=None, id=None):
|
||||
self.person_prefix = person_prefix
|
||||
self.id = id
|
||||
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||
self.person_prefix_filter = person_prefix_filter
|
||||
self.id_filter = id_filter
|
||||
|
||||
def __iter__(self):
|
||||
try:
|
||||
@ -35,14 +35,16 @@ class Persons(object):
|
||||
|
||||
def iter_persons(self):
|
||||
self._cache = list()
|
||||
for receiver, persons in receiv_persons.send(
|
||||
sender='persons', person_prefix=self.person_prefix, id=self.id):
|
||||
for receiver, persons in receive_persons.send(
|
||||
sender='persons', person_prefix_filter=self.person_prefix_filter, id_filter=self.id_filter):
|
||||
for person in persons:
|
||||
self._cache.append(person)
|
||||
yield person
|
||||
|
||||
|
||||
def generate_person_id(prefix, id):
|
||||
assert prefix is not None
|
||||
assert id is not None
|
||||
if ':' in prefix:
|
||||
raise ValueError("':' is not allowed in a the 'person_prefix'")
|
||||
return "%s:%d" % (prefix, id)
|
||||
@ -61,4 +63,4 @@ def get_person(person_id):
|
||||
except TypeError:
|
||||
from openslides.utils.person import EmtyPerson
|
||||
return EmtyPerson()
|
||||
return Persons(person_prefix=person_prefix, id=id)[0]
|
||||
return Persons(person_prefix_filter=person_prefix, id_filter=id)[0]
|
||||
|
@ -57,7 +57,7 @@ class PersonMixin(object):
|
||||
try:
|
||||
return generate_person_id(self.person_prefix, self.pk)
|
||||
except AttributeError:
|
||||
raise AttributeError("%s has to have a attribute 'user_prefix'"
|
||||
raise AttributeError("%s has to have a attribute 'person_prefix'"
|
||||
% self)
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -12,4 +12,4 @@
|
||||
|
||||
from django.dispatch import Signal
|
||||
|
||||
receiv_persons = Signal(providing_args=['person_prefix', 'id'])
|
||||
receive_persons = Signal(providing_args=['person_prefix_filter', 'id_filter'])
|
||||
|
@ -34,7 +34,7 @@ from django.conf import settings
|
||||
from django.dispatch import receiver
|
||||
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext as _, ugettext_noop, ugettext_lazy
|
||||
from django.utils.importlib import import_module
|
||||
from django.template import loader, RequestContext
|
||||
from django.template.loader import render_to_string
|
||||
@ -105,6 +105,50 @@ class AjaxMixin(object):
|
||||
return HttpResponse(json.dumps(self.get_ajax_context(**kwargs)))
|
||||
|
||||
|
||||
class QuestionMixin(object):
|
||||
question = ugettext_lazy('Are you sure?')
|
||||
success_message = ugettext_lazy('Thank you for your answer')
|
||||
answer_options = [('yes', ugettext_lazy("Yes")), ('no', ugettext_lazy("No"))]
|
||||
|
||||
def get_answer_options(self):
|
||||
return self.answer_options
|
||||
|
||||
def get_question(self):
|
||||
return unicode(self.question)
|
||||
|
||||
def get_answer(self):
|
||||
for option in self.get_answer_options():
|
||||
if option[0] in self.request.POST:
|
||||
return option[0]
|
||||
return None
|
||||
|
||||
def get_answer_url(self):
|
||||
return self.answer_url
|
||||
|
||||
def confirm_form(self):
|
||||
option_fields = "\n".join([
|
||||
'<input type="submit" name="%s" value="%s">' % (option[0], unicode(option[1]))
|
||||
for option in self.get_answer_options()])
|
||||
messages.warning(self.request,
|
||||
"""
|
||||
%(message)s
|
||||
<form action="%(url)s" method="post">
|
||||
<input type="hidden" value="%(csrf)s" name="csrfmiddlewaretoken">
|
||||
%(option_fields)s
|
||||
</form>
|
||||
""" % {
|
||||
'message': self.get_question(),
|
||||
'url': self.get_answer_url(),
|
||||
'csrf': csrf(self.request)['csrf_token'],
|
||||
'option_fields': option_fields})
|
||||
|
||||
def pre_redirect(self, request, *args, **kwargs):
|
||||
self.confirm_form(request, self.object)
|
||||
|
||||
def pre_post_redirect(self, request, *args, **kwargs):
|
||||
messages.success(request)
|
||||
|
||||
|
||||
class TemplateView(PermissionMixin, _TemplateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(TemplateView, self).get_context_data(**kwargs)
|
||||
@ -208,42 +252,41 @@ class CreateView(PermissionMixin, _CreateView):
|
||||
messages.error(self.request, _('Please check the form for errors.'))
|
||||
return super(CreateView, self).form_invalid(form)
|
||||
|
||||
def form_valid(self, form):
|
||||
self.object = form.save(commit=False)
|
||||
self.manipulate_object(form)
|
||||
self.object.save()
|
||||
form.save_m2m()
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
def get_success_message(self):
|
||||
return _('%s was successfully created.') % html_strong(self.object)
|
||||
|
||||
def manipulate_object(self, form):
|
||||
pass
|
||||
|
||||
class DeleteView(RedirectView, SingleObjectMixin):
|
||||
def get_confirm_question(self):
|
||||
|
||||
class DeleteView(RedirectView, SingleObjectMixin, QuestionMixin):
|
||||
def get_question(self):
|
||||
return _('Do you really want to delete %s?') % html_strong(self.object)
|
||||
|
||||
def get_success_message(self):
|
||||
return _('%s was successfully deleted.') % html_strong(self.object)
|
||||
|
||||
def pre_redirect(self, request, *args, **kwargs):
|
||||
self.confirm_form(request, self.object)
|
||||
self.confirm_form()
|
||||
|
||||
def pre_post_redirect(self, request, *args, **kwargs):
|
||||
self.object.delete()
|
||||
messages.success(request, self.get_success_message())
|
||||
if self.get_answer().lower() == 'yes':
|
||||
self.object.delete()
|
||||
messages.success(request, self.get_success_message())
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super(DeleteView, self).get(request, *args, **kwargs)
|
||||
|
||||
def confirm_form(self, request, object):
|
||||
self.gen_confirm_form(request, self.get_confirm_question(),
|
||||
object.get_absolute_url('delete'))
|
||||
|
||||
def gen_confirm_form(self, request, message, url):
|
||||
messages.warning(request,
|
||||
"""
|
||||
%s
|
||||
<form action="%s" method="post">
|
||||
<input type="hidden" value="%s" name="csrfmiddlewaretoken">
|
||||
<input type="submit" value="%s">
|
||||
<input type="button" value="%s">
|
||||
</form>
|
||||
""" % (message, url, csrf(request)['csrf_token'], _("Yes"), _("No")))
|
||||
def get_answer_url(self):
|
||||
return self.object.get_absolute_url('delete')
|
||||
|
||||
|
||||
class DetailView(TemplateView, SingleObjectMixin):
|
||||
|
Loading…
Reference in New Issue
Block a user