Merge branch 'master' into install
This commit is contained in:
commit
a2be848932
@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"pk": 2,
|
"pk": 1,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Beobachter",
|
"name": "Beobachter",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
@ -49,7 +49,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 3,
|
"pk": 2,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Delegierter",
|
"name": "Delegierter",
|
||||||
@ -92,7 +92,7 @@
|
|||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
@ -103,7 +103,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 4,
|
"pk": 3,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Versammlungsleitung",
|
"name": "Versammlungsleitung",
|
||||||
@ -161,12 +161,12 @@
|
|||||||
[
|
[
|
||||||
"can_manage_participant",
|
"can_manage_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_manage_projector",
|
"can_manage_projector",
|
||||||
@ -182,7 +182,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pk": 5,
|
"pk": 4,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Teilnehmerverwaltung",
|
"name": "Teilnehmerverwaltung",
|
||||||
@ -195,12 +195,12 @@
|
|||||||
[
|
[
|
||||||
"can_manage_participant",
|
"can_manage_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_participant",
|
"can_see_participant",
|
||||||
"participant",
|
"participant",
|
||||||
"openslidesuser"
|
"user"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"can_see_projector",
|
"can_see_projector",
|
||||||
|
@ -54,7 +54,7 @@ class Overview(TemplateView):
|
|||||||
context = self.get_context_data(**kwargs)
|
context = self.get_context_data(**kwargs)
|
||||||
if not request.user.has_perm('agenda.can_manage_agenda'):
|
if not request.user.has_perm('agenda.can_manage_agenda'):
|
||||||
messages.error(request,
|
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)
|
return self.render_to_response(context)
|
||||||
transaction.commit()
|
transaction.commit()
|
||||||
for item in Item.objects.all():
|
for item in Item.objects.all():
|
||||||
@ -167,69 +167,24 @@ class ItemDelete(DeleteView):
|
|||||||
model = Item
|
model = Item
|
||||||
url = 'item_overview'
|
url = 'item_overview'
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def get_answer_options(self):
|
||||||
self.object = self.get_object()
|
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)
|
self.object.delete(with_children=True)
|
||||||
messages.success(request,
|
messages.success(request,
|
||||||
_("Item %s and his children were successfully deleted.") \
|
_("Item %s and his children were successfully deleted.") \
|
||||||
% html_strong(self.object))
|
% html_strong(self.object))
|
||||||
else:
|
elif self.get_answer() == 'yes':
|
||||||
self.object.delete(with_children=False)
|
self.object.delete(with_children=False)
|
||||||
messages.success(request,
|
messages.success(request,
|
||||||
_("Item %s was successfully deleted.") \
|
_("Item %s was successfully deleted.") \
|
||||||
% html_strong(self.object))
|
% 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):
|
class AgendaPDF(PDFView):
|
||||||
"""
|
"""
|
||||||
|
@ -51,16 +51,16 @@ class ApplicationImportForm(forms.Form, CssClassMixin):
|
|||||||
)
|
)
|
||||||
import_permitted = forms.BooleanField(
|
import_permitted = forms.BooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Import applications with status \"permitted\""),
|
label=_("Import motions with status \"authorized\""),
|
||||||
help_text=_('Set the initial status for each application to '
|
help_text=_('Set the initial status for each motion to '
|
||||||
'"permitted"'),
|
'"authorized"'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConfigForm(forms.Form, CssClassMixin):
|
class ConfigForm(forms.Form, CssClassMixin):
|
||||||
application_min_supporters = forms.IntegerField(
|
application_min_supporters = forms.IntegerField(
|
||||||
widget=forms.TextInput(attrs={'class':'small-input'}),
|
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,
|
initial=4,
|
||||||
min_value=0,
|
min_value=0,
|
||||||
max_value=8,
|
max_value=8,
|
||||||
@ -69,7 +69,7 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
application_preamble = forms.CharField(
|
application_preamble = forms.CharField(
|
||||||
widget=forms.TextInput(),
|
widget=forms.TextInput(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Application preamble")
|
label=_("Motion preamble")
|
||||||
)
|
)
|
||||||
application_pdf_ballot_papers_selection = forms.ChoiceField(
|
application_pdf_ballot_papers_selection = forms.ChoiceField(
|
||||||
widget=forms.Select(),
|
widget=forms.Select(),
|
||||||
@ -90,17 +90,17 @@ class ConfigForm(forms.Form, CssClassMixin):
|
|||||||
application_pdf_title = forms.CharField(
|
application_pdf_title = forms.CharField(
|
||||||
widget=forms.TextInput(),
|
widget=forms.TextInput(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Title for PDF document (all applications)")
|
label=_("Title for PDF document (all motions)")
|
||||||
)
|
)
|
||||||
application_pdf_preamble = forms.CharField(
|
application_pdf_preamble = forms.CharField(
|
||||||
widget=forms.Textarea(),
|
widget=forms.Textarea(),
|
||||||
required=False,
|
required=False,
|
||||||
label=_("Preamble text for PDF document (all applications)")
|
label=_("Preamble text for PDF document (all motions)")
|
||||||
)
|
)
|
||||||
|
|
||||||
application_allow_trivial_change = forms.BooleanField(
|
application_allow_trivial_change = forms.BooleanField(
|
||||||
label=_("Allow trivial changes"),
|
label=_("Allow trivial changes"),
|
||||||
help_text=_('Warning: Trivial changes undermine the application ' \
|
help_text=_('Warning: Trivial changes undermine the motions '
|
||||||
'permission system.'),
|
'autorisation system.'),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Max
|
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.models import config
|
||||||
from openslides.config.signals import default_config_value
|
from openslides.config.signals import default_config_value
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
|
||||||
|
|
||||||
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
||||||
CountInvalid, BaseVote)
|
CountInvalid, BaseVote)
|
||||||
|
|
||||||
@ -53,7 +50,7 @@ class Application(models.Model, SlideMixin):
|
|||||||
('adj', _('Adjourned')),
|
('adj', _('Adjourned')),
|
||||||
('noc', _('Not Concerned')),
|
('noc', _('Not Concerned')),
|
||||||
('com', _('Commited a bill')),
|
('com', _('Commited a bill')),
|
||||||
('nop', _('Rejected (not permitted)')),
|
('nop', _('Rejected (not authorized)')),
|
||||||
('rev', _('Needs Review')), # Where is this status used?
|
('rev', _('Needs Review')), # Where is this status used?
|
||||||
#additional actions:
|
#additional actions:
|
||||||
# edit
|
# edit
|
||||||
@ -103,14 +100,14 @@ class Application(models.Model, SlideMixin):
|
|||||||
self.save(nonewversion=True)
|
self.save(nonewversion=True)
|
||||||
version.rejected = False
|
version.rejected = False
|
||||||
version.save()
|
version.save()
|
||||||
self.writelog(_("Version %d permitted") % (version.aid, ),
|
self.writelog(_("Version %d authorized") % (version.aid, ),
|
||||||
user)
|
user)
|
||||||
|
|
||||||
def reject_version(self, version, user = None):
|
def reject_version(self, version, user = None):
|
||||||
if version.id > self.permitted.id:
|
if version.id > self.permitted.id:
|
||||||
version.rejected = True
|
version.rejected = True
|
||||||
version.save()
|
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)
|
% (version.aid, ), user)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -141,9 +138,9 @@ class Application(models.Model, SlideMixin):
|
|||||||
if self.status == "pub" and not self.enough_supporters:
|
if self.status == "pub" and not self.enough_supporters:
|
||||||
note.append(_("Searching for supporters."))
|
note.append(_("Searching for supporters."))
|
||||||
if self.status == "pub" and self.permitted is None:
|
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:
|
elif self.unpermitted_changes and self.permitted:
|
||||||
note.append(_("Not yet permitted changes."))
|
note.append(_("Not yet authorized changes."))
|
||||||
return note
|
return note
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -309,7 +306,7 @@ class Application(models.Model, SlideMixin):
|
|||||||
self.set_number()
|
self.set_number()
|
||||||
self.permitted = aversion
|
self.permitted = aversion
|
||||||
self.save()
|
self.save()
|
||||||
self.writelog(_("Version %s permitted") % (aversion.aid), user)
|
self.writelog(_("Version %s authorized") % (aversion.aid), user)
|
||||||
return self.permitted
|
return self.permitted
|
||||||
|
|
||||||
def notpermit(self, user=None):
|
def notpermit(self, user=None):
|
||||||
@ -323,7 +320,7 @@ class Application(models.Model, SlideMixin):
|
|||||||
if self.number is None:
|
if self.number is None:
|
||||||
self.set_number()
|
self.set_number()
|
||||||
self.save()
|
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):
|
def set_status(self, user, status, force=False):
|
||||||
"""
|
"""
|
||||||
@ -335,19 +332,22 @@ class Application(models.Model, SlideMixin):
|
|||||||
error = False
|
error = False
|
||||||
break
|
break
|
||||||
if error:
|
if error:
|
||||||
|
#TODO: Use the Right Error
|
||||||
raise NameError(_('%s is not a valid status.') % status)
|
raise NameError(_('%s is not a valid status.') % status)
|
||||||
if self.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)
|
% self.status)
|
||||||
|
|
||||||
actions = []
|
actions = []
|
||||||
actions = self.get_allowed_actions(user)
|
actions = self.get_allowed_actions(user)
|
||||||
if status not in actions and not force:
|
if status not in actions and not force:
|
||||||
raise NameError(_('The application status is: \'%(currentstatus)s\'. '\
|
#TODO: Use the Right Error
|
||||||
|
raise NameError(_(
|
||||||
|
'The motion status is: \'%(currentstatus)s\'. '
|
||||||
'You can not set the status to \'%(newstatus)s\'.') % {
|
'You can not set the status to \'%(newstatus)s\'.') % {
|
||||||
'currentstatus': self.status,
|
'currentstatus': self.status,
|
||||||
'newstatus': status
|
'newstatus': status})
|
||||||
})
|
|
||||||
|
|
||||||
oldstatus = self.get_status_display()
|
oldstatus = self.get_status_display()
|
||||||
self.status = status
|
self.status = status
|
||||||
@ -360,15 +360,6 @@ class Application(models.Model, SlideMixin):
|
|||||||
Return a list of all the allowed status.
|
Return a list of all the allowed status.
|
||||||
"""
|
"""
|
||||||
actions = []
|
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
|
# check if user allowed to withdraw an application
|
||||||
if ((self.status == "pub"
|
if ((self.status == "pub"
|
||||||
@ -405,11 +396,10 @@ class Application(models.Model, SlideMixin):
|
|||||||
|
|
||||||
# Check if the user can delete the application (admin, manager, owner)
|
# Check if the user can delete the application (admin, manager, owner)
|
||||||
# reworked as requiered in #100
|
# reworked as requiered in #100
|
||||||
if is_admin \
|
if (user.has_perm("applicatoin.can_delete_all_applications") or
|
||||||
or (user.has_perm("application.can_manage_application") \
|
(user.has_perm("application.can_manage_application") and
|
||||||
and (self.status == "pub" or self.number is None)) \
|
self.number is None) or
|
||||||
or (self.submitter == user \
|
(self.submitter == user and self.number is None)):
|
||||||
and (self.status == "pub" or self.number is None)):
|
|
||||||
actions.append("delete")
|
actions.append("delete")
|
||||||
|
|
||||||
#For the rest, all actions need the manage permission
|
#For the rest, all actions need the manage permission
|
||||||
@ -463,7 +453,7 @@ class Application(models.Model, SlideMixin):
|
|||||||
|
|
||||||
def get_agenda_title_supplement(self):
|
def get_agenda_title_supplement(self):
|
||||||
number = self.number or '<i>[%s]</i>' % ugettext('no number')
|
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):
|
def __getattr__(self, name):
|
||||||
"""
|
"""
|
||||||
@ -539,10 +529,10 @@ class Application(models.Model, SlideMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = (
|
permissions = (
|
||||||
('can_see_application', ugettext_noop("Can see application")),
|
('can_see_application', ugettext_noop("Can see motions")),
|
||||||
('can_create_application', ugettext_noop("Can create application")),
|
('can_create_application', ugettext_noop("Can create motions")),
|
||||||
('can_support_application', ugettext_noop("Can support application")),
|
('can_support_application', ugettext_noop("Can support motions")),
|
||||||
('can_manage_application', ugettext_noop("Can manage application")),
|
('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_preamble': _('The Assembly may decide,'),
|
||||||
'application_pdf_ballot_papers_selection': 'CUSTOM_NUMBER',
|
'application_pdf_ballot_papers_selection': 'CUSTOM_NUMBER',
|
||||||
'application_pdf_ballot_papers_number': '8',
|
'application_pdf_ballot_papers_number': '8',
|
||||||
'application_pdf_title': _('Applications'),
|
'application_pdf_title': _('Motions'),
|
||||||
'application_pdf_preamble': '',
|
'application_pdf_preamble': '',
|
||||||
'application_allow_trivial_change': False,
|
'application_allow_trivial_change': False,
|
||||||
}.get(key)
|
}.get(key)
|
||||||
|
@ -6,16 +6,16 @@
|
|||||||
|
|
||||||
{% block submenu %}
|
{% block submenu %}
|
||||||
{% url application_overview as url_applicationoverview %}
|
{% url application_overview as url_applicationoverview %}
|
||||||
<h4>{% trans "Applications" %}</h4>
|
<h4>{% trans "Motions" %}</h4>
|
||||||
<ul>
|
<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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% if perms.application.can_manage_application %}
|
{% 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 %}
|
{% 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>
|
</ul>
|
||||||
|
|
||||||
{# second submenu #}
|
{# second submenu #}
|
||||||
@ -31,18 +31,18 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{# view application #}
|
{# view application #}
|
||||||
{% url application_view application.id as url_applicationview %}
|
{% 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 #}
|
{# edit application #}
|
||||||
{% if "edit" in actions %}
|
{% if "edit" in actions %}
|
||||||
{% url application_edit application.id as url_applicationedit %}
|
{% 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 %}
|
{% endif %}
|
||||||
{# delete application #}
|
{# delete application #}
|
||||||
{% if "delete" in actions %}
|
{% 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 %}
|
{% endif %}
|
||||||
{# PDF #}
|
{# 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 #}
|
{# activate and polls #}
|
||||||
{% if perms.projector.can_manage_projector %}
|
{% if perms.projector.can_manage_projector %}
|
||||||
<li>
|
<li>
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
{% block title %}
|
{% block title %}
|
||||||
{{ block.super }} –
|
{{ block.super }} –
|
||||||
{% if application %}
|
{% if application %}
|
||||||
{% trans "Edit application" %}
|
{% trans "Edit motion" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans "New application" %}
|
{% trans "New motion" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if application %}
|
{% if application %}
|
||||||
<h1>{% trans "Edit application" %}</h1>
|
<h1>{% trans "Edit motion" %}</h1>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h1>{% trans "New application" %}</h1>
|
<h1>{% trans "New motion" %}</h1>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form action="" method="post">{% csrf_token %}
|
<form action="" method="post">{% csrf_token %}
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{{ block.super }} – {% trans "Import applications" %} {% endblock %}
|
{% block title %}{{ block.super }} – {% trans "Import motions" %} {% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Import applications" %}</h1>
|
<h1>{% trans "Import motions" %}</h1>
|
||||||
<p>{% trans 'Select a CSV file to import applications!' %}</p>
|
<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)' %}
|
<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>
|
<br>
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{{ block.super }} – {% trans "Applications" %}{% endblock %}
|
{% block title %}{{ block.super }} – {% trans "Motions" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Applications" %}</h1>
|
<h1>{% trans "Motions" %}</h1>
|
||||||
<p><form action="{{request.url}}" name="filter" method="get">
|
<p><form action="{{ request.url }}" name="filter" method="get">
|
||||||
{% trans "Filter" %}:
|
{% trans "Filter" %}:
|
||||||
{% if min_supporters > 0 %}
|
{% if min_supporters > 0 %}
|
||||||
<input type="checkbox" name="needsup" onchange="document.forms['filter'].submit()"
|
<input type="checkbox" name="needsup" onchange="document.forms['filter'].submit()"
|
||||||
@ -19,21 +19,21 @@
|
|||||||
<input type="checkbox" name="status" onchange="document.forms['filter'].submit()"
|
<input type="checkbox" name="status" onchange="document.forms['filter'].submit()"
|
||||||
{% if 'on' in request.GET.status %}checked{% endif %}> {% trans "Status" %}:
|
{% 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 %}">
|
<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="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 "Permitted" %}</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="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="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>
|
<option value="rev" {% if 'rev' in request.GET.statusvalue %}selected{% endif %}>{% trans "Needs Review" %}</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
{{ applications|length }}
|
{{ applications|length }}
|
||||||
{% blocktrans count counter=applications|length %}application{% plural %}applications{% endblocktrans %}
|
{% blocktrans count counter=applications|length %}motion{% plural %}motions{% endblocktrans %}
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<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=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 %}
|
{% 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>
|
<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 %}
|
{% endif %}
|
||||||
@ -64,24 +64,24 @@
|
|||||||
<td>
|
<td>
|
||||||
<span style="width: 1px; white-space: nowrap;">
|
<span style="width: 1px; white-space: nowrap;">
|
||||||
{% if perms.projector.can_manage_projector %}
|
{% 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>
|
<span></span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.application.can_manage_application %}
|
{% 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 %}
|
{% 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 %}
|
||||||
{% 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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="7"><i>{% trans "No applications available." %}</i></td>
|
<td colspan="7"><i>{% trans "No motions available." %}</i></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{{ block.super }} – {% trans "Application" %} "{{ application.public_version.title }}"
|
{{ block.super }} – {% trans "Motion" %} "{{ application.public_version.title }}"
|
||||||
– {{ ballot }}. {% trans "Vote" %}
|
– {{ ballot }}. {% trans "Vote" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ application.public_version.title }} ({% trans "Application" %}
|
<h1>{{ application.public_version.title }} ({% trans "Motion" %}
|
||||||
{{ application.number }}) – {{ ballot }}. {% trans "Vote" %}</h1>
|
{{ application.number }}) – {{ ballot }}. {% trans "Vote" %}</h1>
|
||||||
<i class="helptext">{% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %}</i>
|
<i class="helptext">{% trans "Special values" %}: -1 = {% trans 'majority' %}; -2 = {% trans 'undocumented' %}</i>
|
||||||
<form action="" method="post" class="small-form">{% csrf_token %}
|
<form action="" method="post" class="small-form">{% csrf_token %}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{{ block.super }} – {% trans "Application" %} "{{ version.title }}"{% endblock %}
|
{% block title %}{{ block.super }} – {% trans "Motion" %} "{{ version.title }}"{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block submenu %}
|
{% block submenu %}
|
||||||
@ -143,7 +143,7 @@
|
|||||||
|
|
||||||
{% if perms.application.can_manage_application %}
|
{% if perms.application.can_manage_application %}
|
||||||
<div class="box">
|
<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 %}
|
{% if "pub" in actions or "per" in actions or "nop" in actions or "setnumber" in actions %}
|
||||||
<h4>{% trans "Formal validation" %}:</h4>
|
<h4>{% trans "Formal validation" %}:</h4>
|
||||||
@ -206,7 +206,7 @@
|
|||||||
<div id="main">
|
<div id="main">
|
||||||
<h1>
|
<h1>
|
||||||
{{ version.title }}
|
{{ version.title }}
|
||||||
({% trans "Application" %}
|
({% trans "Motion" %}
|
||||||
{% if application.number != None %}
|
{% if application.number != None %}
|
||||||
{{ application.number }})
|
{{ application.number }})
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -221,11 +221,11 @@
|
|||||||
{% if version == application.public_version %}
|
{% 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>
|
{% 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 %}
|
{% 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 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2>{% trans "Application" %}:</h2>
|
<h2>{% trans "Motion" %}:</h2>
|
||||||
|
|
||||||
{{ version.text|linebreaks }}
|
{{ version.text|linebreaks }}
|
||||||
|
|
||||||
@ -256,7 +256,7 @@
|
|||||||
<td style="white-space:nowrap;">
|
<td style="white-space:nowrap;">
|
||||||
{% if application.status != "pub" %}
|
{% if application.status != "pub" %}
|
||||||
{% if revision == application.permitted %}
|
{% 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 %}
|
{% else %}
|
||||||
{% if perms.application.can_manage_application %}
|
{% 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>
|
<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' %}">
|
<a href="{% model_url application 'view' %}">
|
||||||
{{ application.public_version.title }}
|
{{ application.public_version.title }}
|
||||||
</a>
|
</a>
|
||||||
({% trans 'Application' %}
|
({% trans "motion" %}
|
||||||
{% if application.number %}
|
{% if application.number %}
|
||||||
{{ application.number }})
|
{{ application.number }})
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -28,7 +28,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li>{% trans 'No applications available.' %}</li>
|
<li>{% trans 'No motion available.' %}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{{ block.super }} - {% trans "Application" %} {{ application.number }}{% endblock %}
|
{% block title %}{{ block.super }} - {% trans "Motion" %} {{ application.number }}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@ -60,9 +60,9 @@
|
|||||||
|
|
||||||
<h1>
|
<h1>
|
||||||
{% if application.number != None %}
|
{% if application.number != None %}
|
||||||
{% trans "Application No." %} {{ application.number }}
|
{% trans "Motion No." %} {{ application.number }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans "Application" %} <i>[{% trans "no number" %}]</i>
|
{% trans "Motion" %} <i>[{% trans "no number" %}]</i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
<b>{{ application.public_version.title }}</b>
|
<b>{{ application.public_version.title }}</b>
|
||||||
|
@ -12,15 +12,17 @@
|
|||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
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
|
from openslides.application.models import Application, AVersion
|
||||||
|
|
||||||
class ApplicationTest(TestCase):
|
class ApplicationTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.admin = User.objects.create_user('testadmin', '', 'default')
|
self.admin = User(username='testadmin')
|
||||||
self.anonym = User.objects.create_user('testanoym', '', 'default')
|
self.admin.save()
|
||||||
self.app1 = Application(submitter=self.admin.openslidesuser)
|
self.anonym = User(username='testanoym')
|
||||||
|
self.anonym.save()
|
||||||
|
self.app1 = Application(submitter=self.admin)
|
||||||
self.app1.save()
|
self.app1.save()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
|
@ -51,7 +51,7 @@ from openslides.projector.projector import Widget
|
|||||||
from openslides.poll.views import PollFormView
|
from openslides.poll.views import PollFormView
|
||||||
|
|
||||||
from openslides.participant.api import gen_username, gen_password
|
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
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ def overview(request):
|
|||||||
for (i, application) in enumerate(applications):
|
for (i, application) in enumerate(applications):
|
||||||
try:
|
try:
|
||||||
applications[i] = {
|
applications[i] = {
|
||||||
'actions' : application.get_allowed_actions(request.user.openslidesuser),
|
'actions' : application.get_allowed_actions(request.user),
|
||||||
'application' : application
|
'application' : application
|
||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
@ -152,8 +152,7 @@ def view(request, application_id, newest=False):
|
|||||||
else:
|
else:
|
||||||
version = application.public_version
|
version = application.public_version
|
||||||
revisions = application.versions
|
revisions = application.versions
|
||||||
user = request.user.openslidesuser
|
actions = application.get_allowed_actions(user=request.user)
|
||||||
actions = application.get_allowed_actions(user=user)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'application': application,
|
'application': application,
|
||||||
@ -178,16 +177,14 @@ def edit(request, application_id=None):
|
|||||||
|
|
||||||
if not is_manager \
|
if not is_manager \
|
||||||
and not request.user.has_perm('application.can_create_application'):
|
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'))
|
return redirect(reverse('application_overview'))
|
||||||
if application_id is not None:
|
if application_id is not None:
|
||||||
application = Application.objects.get(id=application_id)
|
application = Application.objects.get(id=application_id)
|
||||||
if (not hasattr(application.submitter, 'user') or
|
if not request.user == application.submitter and not is_manager:
|
||||||
not request.user.openslidesuser == application.submitter.user) \
|
messages.error(request, _("You can not edit this motion. You are not the submitter."))
|
||||||
and not is_manager:
|
|
||||||
messages.error(request, _("You can not edit this application. You are not the submitter."))
|
|
||||||
return redirect(reverse('application_view', args=[application.id]))
|
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:
|
else:
|
||||||
application = None
|
application = None
|
||||||
actions = None
|
actions = None
|
||||||
@ -221,7 +218,7 @@ def edit(request, application_id=None):
|
|||||||
original_supporters = []
|
original_supporters = []
|
||||||
application = managerform.save(commit=False)
|
application = managerform.save(commit=False)
|
||||||
elif application_id is None:
|
elif application_id is None:
|
||||||
application = Application(submitter=request.user.openslidesuser)
|
application = Application(submitter=request.user)
|
||||||
application.title = dataform.cleaned_data['title']
|
application.title = dataform.cleaned_data['title']
|
||||||
application.text = dataform.cleaned_data['text']
|
application.text = dataform.cleaned_data['text']
|
||||||
application.reason = dataform.cleaned_data['reason']
|
application.reason = dataform.cleaned_data['reason']
|
||||||
@ -231,7 +228,7 @@ def edit(request, application_id=None):
|
|||||||
and dataform.cleaned_data['trivial_change']
|
and dataform.cleaned_data['trivial_change']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
trivial_change = False
|
trivial_change = False
|
||||||
application.save(request.user.openslidesuser, trivial_change=trivial_change)
|
application.save(request.user, trivial_change=trivial_change)
|
||||||
if is_manager:
|
if is_manager:
|
||||||
try:
|
try:
|
||||||
new_supporters = set(managerform.cleaned_data['supporter'])
|
new_supporters = set(managerform.cleaned_data['supporter'])
|
||||||
@ -246,10 +243,11 @@ def edit(request, application_id=None):
|
|||||||
# remove old supporters
|
# remove old supporters
|
||||||
for supporter in old_supporters.difference(new_supporters):
|
for supporter in old_supporters.difference(new_supporters):
|
||||||
application.unsupport(supporter)
|
application.unsupport(supporter)
|
||||||
|
|
||||||
if application_id is None:
|
if application_id is None:
|
||||||
messages.success(request, _('New application was successfully created.'))
|
messages.success(request, _('New motion was successfully created.'))
|
||||||
else:
|
else:
|
||||||
messages.success(request, _('Application was successfully modified.'))
|
messages.success(request, _('Motion was successfully modified.'))
|
||||||
|
|
||||||
if not 'apply' in request.POST:
|
if not 'apply' in request.POST:
|
||||||
return redirect(reverse('application_view', args=[application.id]))
|
return redirect(reverse('application_view', args=[application.id]))
|
||||||
@ -263,9 +261,9 @@ def edit(request, application_id=None):
|
|||||||
else:
|
else:
|
||||||
if application.status == "pub" and application.supporters:
|
if application.status == "pub" and application.supporters:
|
||||||
if request.user.has_perm('application.can_manage_application'):
|
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:
|
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,
|
initial = {'title': application.title,
|
||||||
'text': application.text,
|
'text': application.text,
|
||||||
'reason': application.reason}
|
'reason': application.reason}
|
||||||
@ -273,7 +271,7 @@ def edit(request, application_id=None):
|
|||||||
dataform = formclass(initial=initial, prefix="data")
|
dataform = formclass(initial=initial, prefix="data")
|
||||||
if is_manager:
|
if is_manager:
|
||||||
if application_id is None:
|
if application_id is None:
|
||||||
initial = {'submitter': request.user.openslidesuser.person_id}
|
initial = {'submitter': request.user.person_id}
|
||||||
else:
|
else:
|
||||||
initial = {'submitter': application.submitter.person_id,
|
initial = {'submitter': application.submitter.person_id,
|
||||||
'supporter': [supporter.person_id for supporter in application.supporters]}
|
'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.
|
set a number for an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).set_number(user=request.user.openslidesuser)
|
Application.objects.get(pk=application_id).set_number(user=request.user)
|
||||||
messages.success(request, _("Application number was successfully set."))
|
messages.success(request, _("Motion number was successfully set."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
except NameError:
|
except NameError:
|
||||||
@ -312,8 +310,8 @@ def permit(request, application_id):
|
|||||||
permit an application.
|
permit an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).permit(user=request.user.openslidesuser)
|
Application.objects.get(pk=application_id).permit(user=request.user)
|
||||||
messages.success(request, _("Application was successfully permitted."))
|
messages.success(request, _("Motion was successfully authorized."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
except NameError, e:
|
except NameError, e:
|
||||||
@ -327,8 +325,8 @@ def notpermit(request, application_id):
|
|||||||
reject (not permit) an application.
|
reject (not permit) an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).notpermit(user=request.user.openslidesuser)
|
Application.objects.get(pk=application_id).notpermit(user=request.user)
|
||||||
messages.success(request, _("Application was successfully rejected."))
|
messages.success(request, _("Motion was successfully rejected."))
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
except NameError, e:
|
except NameError, e:
|
||||||
@ -343,8 +341,8 @@ def set_status(request, application_id=None, status=None):
|
|||||||
try:
|
try:
|
||||||
if status is not None:
|
if status is not None:
|
||||||
application = Application.objects.get(pk=application_id)
|
application = Application.objects.get(pk=application_id)
|
||||||
application.set_status(user=request.user.openslidesuser, status=status)
|
application.set_status(user=request.user, status=status)
|
||||||
messages.success(request, _("Application status was set to: <b>%s</b>.") % application.get_status_display())
|
messages.success(request, _("Motion status was set to: <b>%s</b>.") % application.get_status_display())
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
except NameError, e:
|
except NameError, e:
|
||||||
@ -359,8 +357,8 @@ def reset(request, application_id):
|
|||||||
reset an application.
|
reset an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).reset(user=request.user.openslides.user)
|
Application.objects.get(pk=application_id).reset(user=request.user)
|
||||||
messages.success(request, _("Application status was reset.") )
|
messages.success(request, _("Motion status was reset.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
return redirect(reverse('application_view', args=[application_id]))
|
return redirect(reverse('application_view', args=[application_id]))
|
||||||
@ -373,8 +371,8 @@ def support(request, application_id):
|
|||||||
support an application.
|
support an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).support(user=request.user.openslides.user)
|
Application.objects.get(pk=application_id).support(user=request.user)
|
||||||
messages.success(request, _("You have support the application successfully.") )
|
messages.success(request, _("You have support the motion successfully.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
return redirect(reverse('application_view', args=[application_id]))
|
return redirect(reverse('application_view', args=[application_id]))
|
||||||
@ -387,8 +385,8 @@ def unsupport(request, application_id):
|
|||||||
unsupport an application.
|
unsupport an application.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
Application.objects.get(pk=application_id).unsupport(user=request.user.openslidesuser)
|
Application.objects.get(pk=application_id).unsupport(user=request.user)
|
||||||
messages.success(request, _("You have unsupport the application successfully.") )
|
messages.success(request, _("You have unsupport the motion successfully.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
return redirect(reverse('application_view', args=[application_id]))
|
return redirect(reverse('application_view', args=[application_id]))
|
||||||
@ -401,7 +399,7 @@ def gen_poll(request, application_id):
|
|||||||
gen a poll for this application.
|
gen a poll for this application.
|
||||||
"""
|
"""
|
||||||
try:
|
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.") )
|
messages.success(request, _("New vote was successfully created.") )
|
||||||
except Application.DoesNotExist:
|
except Application.DoesNotExist:
|
||||||
pass # TODO: do not call poll after this excaption
|
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()
|
count = application.polls.filter(id__lte=poll_id).count()
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
poll.delete()
|
poll.delete()
|
||||||
application.writelog(_("Poll deleted"), request.user.openslidesuser)
|
application.writelog(_("Poll deleted"), request.user)
|
||||||
messages.success(request, _('Poll was successfully deleted.'))
|
messages.success(request, _('Poll was successfully deleted.'))
|
||||||
else:
|
else:
|
||||||
del_confirm_form(request, poll, name=_("the %s. poll") % count, delete_link=reverse('application_poll_delete', args=[poll_id]))
|
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):
|
if len(self.applications):
|
||||||
for application in self.applications:
|
for application in self.applications:
|
||||||
if not 'delete' in application.get_allowed_actions(user=request.user.openslidesuser):
|
if not 'delete' in application.get_allowed_actions(user=request.user):
|
||||||
messages.error(request, _("You can not delete application <b>%s</b>.") % application)
|
messages.error(request, _("You can not delete motion <b>%s</b>.") % application)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
title = application.title
|
title = application.title
|
||||||
application.delete(force=True)
|
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:
|
elif self.object:
|
||||||
if not 'delete' in self.object.get_allowed_actions(user=request.user.openslidesuser):
|
if not 'delete' in self.object.get_allowed_actions(user=request.user):
|
||||||
messages.error(request, _("You can not delete application <b>%s</b>.") % self.object)
|
messages.error(request, _("You can not delete motion <b>%s</b>.") % self.object)
|
||||||
else:
|
else:
|
||||||
title = self.object.title
|
title = self.object.title
|
||||||
self.object.delete(force=True)
|
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:
|
else:
|
||||||
messages.error(request, _("Invalid request"))
|
messages.error(request, _("Invalid request"))
|
||||||
|
|
||||||
@ -493,7 +491,7 @@ class ApplicationDelete(DeleteView):
|
|||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
|
|
||||||
if len(self.applications):
|
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:
|
else:
|
||||||
self.gen_confirm_form(request, _('Do you really want to delete <b>%s</b>?') % self.object, self.object.get_absolute_url('delete'))
|
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()
|
self.application = self.poll.get_application()
|
||||||
context['application'] = self.application
|
context['application'] = self.application
|
||||||
context['ballot'] = self.poll.get_ballot()
|
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
|
return context
|
||||||
|
|
||||||
def get_modelform_class(self):
|
def get_modelform_class(self):
|
||||||
cls = super(ViewPoll, self).get_modelform_class()
|
cls = super(ViewPoll, self).get_modelform_class()
|
||||||
user = self.request.user.openslidesuser
|
user = self.request.user
|
||||||
|
|
||||||
class ViewPollFormClass(cls):
|
class ViewPollFormClass(cls):
|
||||||
def save(self, commit = True):
|
def save(self, commit = True):
|
||||||
@ -535,10 +533,10 @@ def permit_version(request, aversion_id):
|
|||||||
aversion = AVersion.objects.get(pk=aversion_id)
|
aversion = AVersion.objects.get(pk=aversion_id)
|
||||||
application = aversion.application
|
application = aversion.application
|
||||||
if request.method == 'POST':
|
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))
|
messages.success(request, _("Version <b>%s</b> accepted.") % (aversion.aid))
|
||||||
else:
|
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]))
|
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)
|
aversion = AVersion.objects.get(pk=aversion_id)
|
||||||
application = aversion.application
|
application = aversion.application
|
||||||
if request.method == 'POST':
|
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))
|
messages.success(request, _("Version <b>%s</b> rejected.") % (aversion.aid))
|
||||||
else:
|
else:
|
||||||
messages.error(request, _("ERROR by rejecting the version.") )
|
messages.error(request, _("ERROR by rejecting the version.") )
|
||||||
@ -559,17 +557,6 @@ def reject_version(request, aversion_id):
|
|||||||
@permission_required('application.can_manage_application')
|
@permission_required('application.can_manage_application')
|
||||||
@template('application/import.html')
|
@template('application/import.html')
|
||||||
def application_import(request):
|
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':
|
if request.method == 'POST':
|
||||||
form = ApplicationImportForm(request.POST, request.FILES)
|
form = ApplicationImportForm(request.POST, request.FILES)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -652,11 +639,11 @@ def application_import(request):
|
|||||||
application.save(user, trivial_change=True)
|
application.save(user, trivial_change=True)
|
||||||
|
|
||||||
if applications_generated:
|
if applications_generated:
|
||||||
messages.success(request, ungettext('%d application was successfully imported.',
|
messages.success(request, ungettext('%d motion was successfully imported.',
|
||||||
'%d applications were successfully imported.', applications_generated) % applications_generated)
|
'%d motions were successfully imported.', applications_generated) % applications_generated)
|
||||||
if applications_modified:
|
if applications_modified:
|
||||||
messages.success(request, ungettext('%d application was successfully modified.',
|
messages.success(request, ungettext('%d motion was successfully modified.',
|
||||||
'%d applications were successfully modified.', applications_modified) % applications_modified)
|
'%d motions were successfully modified.', applications_modified) % applications_modified)
|
||||||
if users_generated:
|
if users_generated:
|
||||||
messages.success(request, ungettext('%d new user was added.', '%d new users were added.', users_generated) % 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'))
|
return redirect(reverse('application_overview'))
|
||||||
@ -668,8 +655,8 @@ def application_import(request):
|
|||||||
else:
|
else:
|
||||||
messages.error(request, _('Please check the form for errors.'))
|
messages.error(request, _('Please check the form for errors.'))
|
||||||
else:
|
else:
|
||||||
messages.warning(request, _("Attention: Existing applications will be modified if you import new applications with the same number."))
|
messages.warning(request, _("Attention: Existing motions will be modified if you import new motions with the same number."))
|
||||||
messages.warning(request, _("Attention: Importing an application without a number multiple times will create duplicates."))
|
messages.warning(request, _("Attention: Importing an motions without a number multiple times will create duplicates."))
|
||||||
form = ApplicationImportForm()
|
form = ApplicationImportForm()
|
||||||
return {
|
return {
|
||||||
'form': form,
|
'form': form,
|
||||||
@ -716,14 +703,14 @@ class ApplicationPDF(PDFView):
|
|||||||
story.append(Spacer(0,0.75*cm))
|
story.append(Spacer(0,0.75*cm))
|
||||||
applications = Application.objects.order_by('number')
|
applications = Application.objects.order_by('number')
|
||||||
if not applications: # No applications existing
|
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
|
else: # Print all Applications
|
||||||
# List of applications
|
# List of applications
|
||||||
for application in applications:
|
for application in applications:
|
||||||
if application.number:
|
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:
|
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)
|
# Applications details (each application on single page)
|
||||||
for application in applications:
|
for application in applications:
|
||||||
story.append(PageBreak())
|
story.append(PageBreak())
|
||||||
@ -735,9 +722,9 @@ class ApplicationPDF(PDFView):
|
|||||||
def get_application(self, application, story):
|
def get_application(self, application, story):
|
||||||
# application number
|
# application number
|
||||||
if 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:
|
else:
|
||||||
story.append(Paragraph(_("Application No."), stylesheet['Heading1']))
|
story.append(Paragraph(_("Motion No."), stylesheet['Heading1']))
|
||||||
|
|
||||||
# submitter
|
# submitter
|
||||||
cell1a = []
|
cell1a = []
|
||||||
@ -914,7 +901,7 @@ class Config(FormView):
|
|||||||
config['application_pdf_title'] = form.cleaned_data['application_pdf_title']
|
config['application_pdf_title'] = form.cleaned_data['application_pdf_title']
|
||||||
config['application_pdf_preamble'] = form.cleaned_data['application_pdf_preamble']
|
config['application_pdf_preamble'] = form.cleaned_data['application_pdf_preamble']
|
||||||
config['application_allow_trivial_change'] = form.cleaned_data['application_allow_trivial_change']
|
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)
|
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.config.models import config
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
from openslides.participant.models import User
|
||||||
|
|
||||||
from openslides.projector.projector import Widget
|
from openslides.projector.projector import Widget
|
||||||
|
|
||||||
@ -97,13 +97,12 @@ def view(request, assignment_id=None):
|
|||||||
polls = assignment.poll_set.all()
|
polls = assignment.poll_set.all()
|
||||||
vote_results = assignment.vote_results(only_published=False)
|
vote_results = assignment.vote_results(only_published=False)
|
||||||
|
|
||||||
user = request.user.openslidesuser
|
|
||||||
return {
|
return {
|
||||||
'assignment': assignment,
|
'assignment': assignment,
|
||||||
'form': form,
|
'form': form,
|
||||||
'vote_results': vote_results,
|
'vote_results': vote_results,
|
||||||
'polls': polls,
|
'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):
|
def run(request, assignment_id):
|
||||||
assignment = Assignment.objects.get(pk=assignment_id)
|
assignment = Assignment.objects.get(pk=assignment_id)
|
||||||
try:
|
try:
|
||||||
assignment.run(request.user.openslidesuser, request.user)
|
assignment.run(request.user, request.user)
|
||||||
messages.success(request, _('You have set your candidature successfully.') )
|
messages.success(request, _('You have set your candidature successfully.') )
|
||||||
except NameError, e:
|
except NameError, e:
|
||||||
messages.error(request, e)
|
messages.error(request, e)
|
||||||
@ -185,7 +184,7 @@ def delrun(request, assignment_id):
|
|||||||
assignment = Assignment.objects.get(pk=assignment_id)
|
assignment = Assignment.objects.get(pk=assignment_id)
|
||||||
try:
|
try:
|
||||||
if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"):
|
if assignment.status == 'sea' or user.has_perm("assignment.can_manage_assignment"):
|
||||||
assignment.delrun(request.user.openslidesuser)
|
assignment.delrun(request.user)
|
||||||
else:
|
else:
|
||||||
messages.error(request, _('The candidate list is already closed.'))
|
messages.error(request, _('The candidate list is already closed.'))
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
@ -81,7 +81,7 @@ def default_config(sender, key, **kwargs):
|
|||||||
return {
|
return {
|
||||||
'event_name': 'OpenSlides',
|
'event_name': 'OpenSlides',
|
||||||
'event_description':
|
'event_description':
|
||||||
_('Presentation system for agenda, applications and elections'),
|
_('Presentation system for agenda, motions and elections'),
|
||||||
'event_date': '',
|
'event_date': '',
|
||||||
'event_location': '',
|
'event_location': '',
|
||||||
'event_organizer': '',
|
'event_organizer': '',
|
||||||
|
@ -67,7 +67,7 @@ class GeneralConfig(FormView):
|
|||||||
anonymous = Group.objects.get(name='Anonymous')
|
anonymous = Group.objects.get(name='Anonymous')
|
||||||
except Group.DoesNotExist:
|
except Group.DoesNotExist:
|
||||||
default_perms = [u'can_see_agenda', u'can_see_projector',
|
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 = Group()
|
||||||
anonymous.name = 'Anonymous'
|
anonymous.name = 'Anonymous'
|
||||||
anonymous.save()
|
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
|
# calendars according to the current locale
|
||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
|
|
||||||
|
LOCALE_PATHS = (
|
||||||
|
_fs2unicode(os.path.join(SITE_ROOT, 'locale'))
|
||||||
|
)
|
||||||
|
|
||||||
# Absolute path to the directory that holds media.
|
# Absolute path to the directory that holds media.
|
||||||
# Example: "/home/media/media.lawrence.com/"
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
MEDIA_ROOT = _fs2unicode(os.path.join(SITE_ROOT, './static/'))
|
MEDIA_ROOT = _fs2unicode(os.path.join(SITE_ROOT, './static/'))
|
||||||
@ -89,7 +93,7 @@ MIDDLEWARE_CLASSES = (
|
|||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'openslides.participant.middleware.AuthenticationMiddleware',
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.locale.LocaleMiddleware',
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
)
|
)
|
||||||
|
@ -10,13 +10,19 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# for python 2.5 support
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
from random import choice
|
from random import choice
|
||||||
import string
|
import string
|
||||||
|
import csv
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from openslides.utils.person import get_person
|
from openslides.utils import csv_ext
|
||||||
from openslides.participant.models import OpenSlidesUser
|
|
||||||
|
from openslides.participant.models import User
|
||||||
|
|
||||||
|
|
||||||
def gen_password():
|
def gen_password():
|
||||||
@ -47,3 +53,44 @@ def gen_username(first_name, last_name):
|
|||||||
User.objects.get(username=testname)
|
User.objects.get(username=testname)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return testname
|
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,30 +11,21 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import AdminPasswordChangeForm
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.auth.models import User, Group, Permission
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
|
||||||
|
|
||||||
from openslides.utils.forms import (
|
from openslides.utils.forms import (
|
||||||
CssClassMixin, LocalizedModelMultipleChoiceField)
|
CssClassMixin, LocalizedModelMultipleChoiceField)
|
||||||
|
|
||||||
from openslides.participant.models import OpenSlidesUser
|
from openslides.participant.models import User, Group
|
||||||
|
|
||||||
|
|
||||||
USER_APPLICATION_IMPORT_OPTIONS = [
|
class UserCreateForm(forms.ModelForm, CssClassMixin):
|
||||||
('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"))
|
|
||||||
groups = forms.ModelMultipleChoiceField(
|
groups = forms.ModelMultipleChoiceField(
|
||||||
queryset=Group.objects.all(), label=_("User groups"), required=False)
|
queryset=Group.objects.exclude(name__iexact='anonymous'),
|
||||||
is_active = forms.BooleanField(
|
label=_("User groups"), required=False)
|
||||||
label=_("Active"), required=False, initial=True)
|
is_active = forms.BooleanField(label=_("Active"), required=False,
|
||||||
|
initial=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
@ -45,45 +36,74 @@ class UserNewForm(forms.ModelForm, CssClassMixin):
|
|||||||
class UserEditForm(forms.ModelForm, CssClassMixin):
|
class UserEditForm(forms.ModelForm, CssClassMixin):
|
||||||
first_name = forms.CharField(label=_("First name"))
|
first_name = forms.CharField(label=_("First name"))
|
||||||
last_name = forms.CharField(label=_("Last name"))
|
last_name = forms.CharField(label=_("Last name"))
|
||||||
groups = forms.ModelMultipleChoiceField(
|
groups = forms.ModelMultipleChoiceField(queryset=Group.objects.all(),
|
||||||
queryset=Group.objects.all(), label=_("User groups"), required=False)
|
label=_("User groups"), required=False)
|
||||||
is_active = forms.BooleanField(label=_("Active"), required=False)
|
is_active = forms.BooleanField(label=_("Active"), required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
exclude = ('password', 'is_staff', 'is_superuser', 'last_login',
|
fields = ('first_name', 'last_name', 'is_active', 'groups', 'category',
|
||||||
'date_joined', 'user_permissions')
|
'gender', 'type', 'committee', 'comment', 'default_password')
|
||||||
|
|
||||||
|
|
||||||
class UsernameForm(forms.ModelForm, CssClassMixin):
|
class UserUpdateForm(UserCreateForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
exclude = ('first_name', 'last_name', 'email', 'is_active',
|
fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
|
||||||
'is_superuser', 'groups', 'password', 'is_staff',
|
'category', 'gender', 'type', 'committee', 'comment',
|
||||||
'last_login', 'date_joined', 'user_permissions')
|
'default_password')
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesUserForm(forms.ModelForm, CssClassMixin):
|
|
||||||
class Meta:
|
|
||||||
model = OpenSlidesUser
|
|
||||||
|
|
||||||
|
|
||||||
class GroupForm(forms.ModelForm, CssClassMixin):
|
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(
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super(GroupForm, self).__init__(*args, **kwargs)
|
# Initial users
|
||||||
if kwargs.get('instance', None) is not None:
|
if kwargs.get('instance', None) is not None:
|
||||||
self.fields['permissions'].initial = (
|
initial = kwargs.setdefault('initial', {})
|
||||||
[p.pk for p in kwargs['instance'].permissions.all()])
|
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:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
exclude = ('permissions',)
|
|
||||||
|
|
||||||
|
|
||||||
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
||||||
@ -91,13 +111,9 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin):
|
|||||||
model = User
|
model = User
|
||||||
fields = ('username', 'first_name', 'last_name', 'email')
|
fields = ('username', 'first_name', 'last_name', 'email')
|
||||||
|
|
||||||
|
|
||||||
class UserImportForm(forms.Form, CssClassMixin):
|
class UserImportForm(forms.Form, CssClassMixin):
|
||||||
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
|
csvfile = forms.FileField(widget=forms.FileInput(attrs={'size': '50'}),
|
||||||
label=_("CSV File"))
|
label=_("CSV File"))
|
||||||
application_handling = forms.ChoiceField(
|
|
||||||
required=True, choices=USER_APPLICATION_IMPORT_OPTIONS,
|
|
||||||
label=_("For existing applications"))
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigForm(forms.Form, CssClassMixin):
|
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.
|
: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 import models
|
||||||
from django.db.models import Q, signals
|
from django.db.models import signals
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
from django.utils.translation import ugettext_lazy as _, ugettext_noop
|
||||||
|
|
||||||
from openslides.utils.person import PersonMixin
|
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
|
from openslides.config.signals import default_config_value
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesUser(models.Model, PersonMixin):
|
class User(DjangoUser, PersonMixin):
|
||||||
person_prefix = 'openslides_user'
|
person_prefix = 'user'
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
('male', _('Male')),
|
('male', _('Male')),
|
||||||
('female', _('Female')),
|
('female', _('Female')),
|
||||||
@ -35,10 +35,10 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
('guest', _('Guest')),
|
('guest', _('Guest')),
|
||||||
)
|
)
|
||||||
|
|
||||||
user = models.OneToOneField(User, unique=True, editable=False)
|
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
|
||||||
name_surfix = models.CharField(
|
category = models.CharField(
|
||||||
max_length=100, null=True, blank=True, verbose_name=_("Name Surfix"),
|
max_length=100, null=True, blank=True, verbose_name=_("Category"),
|
||||||
help_text=_('Shown behind the name.'))
|
help_text=_('Will be shown behind the name.'))
|
||||||
gender = models.CharField(
|
gender = models.CharField(
|
||||||
max_length=50, choices=GENDER_CHOICES, blank=True,
|
max_length=50, choices=GENDER_CHOICES, blank=True,
|
||||||
verbose_name=_("Gender"), help_text=_('Only for filter the userlist.'))
|
verbose_name=_("Gender"), help_text=_('Only for filter the userlist.'))
|
||||||
@ -51,21 +51,26 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
comment = models.TextField(
|
comment = models.TextField(
|
||||||
null=True, blank=True, verbose_name=_('Comment'),
|
null=True, blank=True, verbose_name=_('Comment'),
|
||||||
help_text=_('Only for notes.'))
|
help_text=_('Only for notes.'))
|
||||||
firstpassword = models.CharField(
|
default_password = models.CharField(
|
||||||
max_length=100, null=True, blank=True,
|
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):
|
def reset_password(self, password=None):
|
||||||
"""
|
"""
|
||||||
Reset the password for the user to his default-password.
|
Reset the password for the user to his default-password.
|
||||||
"""
|
"""
|
||||||
if password is None:
|
if password is None:
|
||||||
password = self.firstpassword
|
password = self.default_password
|
||||||
self.user.set_password(password)
|
self.set_password(password)
|
||||||
self.user.save()
|
self.save()
|
||||||
|
|
||||||
def has_perm(self, perm):
|
|
||||||
return self.user.has_perm(perm)
|
|
||||||
|
|
||||||
@models.permalink
|
@models.permalink
|
||||||
def get_absolute_url(self, link='edit'):
|
def get_absolute_url(self, link='edit'):
|
||||||
@ -77,14 +82,15 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
* delete
|
* delete
|
||||||
"""
|
"""
|
||||||
if link == 'edit':
|
if link == 'edit':
|
||||||
return ('user_edit', [str(self.user.id)])
|
return ('user_edit', [str(self.id)])
|
||||||
if link == 'delete':
|
if link == 'delete':
|
||||||
return ('user_delete', [str(self.user.id)])
|
return ('user_delete', [str(self.id)])
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if self.name_surfix:
|
name = self.get_full_name() or self.username
|
||||||
return "%s (%s)" % (self.user.get_full_name(), self.name_surfix)
|
if self.name_suffix:
|
||||||
return "%s" % self.user.get_full_name()
|
return u"%s (%s)" % (name, self.name_suffix)
|
||||||
|
return u"%s" % name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
# Rename permissions
|
# Rename permissions
|
||||||
@ -95,46 +101,63 @@ class OpenSlidesUser(models.Model, PersonMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesGroup(models.Model, PersonMixin):
|
class Group(DjangoGroup, PersonMixin):
|
||||||
person_prefix = 'openslides_group'
|
person_prefix = 'group'
|
||||||
|
|
||||||
group = models.OneToOneField(Group)
|
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
|
||||||
group_as_person = models.BooleanField(default=False)
|
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):
|
def __unicode__(self):
|
||||||
return unicode(self.group)
|
return unicode(self.name)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesUsersConnecter(object):
|
class UsersConnector(object):
|
||||||
def __init__(self, person_prefix=None, id=None):
|
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||||
self.person_prefix = person_prefix
|
self.person_prefix_filter = person_prefix_filter
|
||||||
self.id = id
|
self.id_filter = id_filter
|
||||||
|
self.users = User.objects.all()
|
||||||
|
self.groups = Group.objects.filter(group_as_person=True)
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
if (not self.person_prefix or
|
if (not self.person_prefix_filter or
|
||||||
self.person_prefix == OpenSlidesUser.person_prefix):
|
self.person_prefix_filter == User.person_prefix):
|
||||||
if self.id:
|
if self.id_filter:
|
||||||
yield OpenSlidesUser.objects.get(pk=self.id)
|
yield self.users.get(pk=self.id_filter)
|
||||||
else:
|
else:
|
||||||
for user in OpenSlidesUser.objects.all():
|
for user in self.users:
|
||||||
yield user
|
yield user
|
||||||
|
|
||||||
if (not self.person_prefix or
|
if (not self.person_prefix_filter or
|
||||||
self.person_prefix == OpenSlidesGroup.person_prefix):
|
self.person_prefix_filter == Group.person_prefix):
|
||||||
if self.id:
|
if self.id_filter:
|
||||||
yield OpenSlidesGroup.objects.get(pk=self.id)
|
yield self.groups.get(pk=self.id_filter)
|
||||||
else:
|
else:
|
||||||
for group in OpenSlidesGroup.objects.all():
|
for group in self.groups:
|
||||||
yield group
|
yield group
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return OpenSlidesUser.objects.get(pk=key)
|
return User.objects.get(pk=key)
|
||||||
|
|
||||||
|
|
||||||
@receiver(receiv_persons, dispatch_uid="participant")
|
@receiver(receive_persons, dispatch_uid="participant")
|
||||||
def receiv_persons(sender, **kwargs):
|
def receive_persons(sender, **kwargs):
|
||||||
return OpenSlidesUsersConnecter(person_prefix=kwargs['person_prefix'],
|
return UsersConnector(person_prefix_filter=kwargs['person_prefix_filter'],
|
||||||
id=kwargs['id'])
|
id_filter=kwargs['id_filter'])
|
||||||
|
|
||||||
|
|
||||||
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
@receiver(default_config_value, dispatch_uid="participant_default_config")
|
||||||
@ -150,7 +173,17 @@ def default_config(sender, key, **kwargs):
|
|||||||
}.get(key)
|
}.get(key)
|
||||||
|
|
||||||
|
|
||||||
@receiver(signals.post_save, sender=User)
|
@receiver(signals.post_save, sender=DjangoUser)
|
||||||
def user_post_save(sender, instance, signal, *args, **kwargs):
|
def user_post_save(sender, instance, signal, *args, **kwargs):
|
||||||
# Creates OpenSlidesUser
|
try:
|
||||||
profile, new = OpenSlidesUser.objects.get_or_create(user=instance)
|
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,15 +9,18 @@ $(function() {
|
|||||||
$('.status_link').click(function(event) {
|
$('.status_link').click(function(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
link = $(this);
|
link = $(this);
|
||||||
|
group = $(this).parent();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
url: link.attr('href'),
|
url: link.attr('href'),
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if (data.active) {
|
if (data.active) {
|
||||||
link.addClass('active');
|
group.children('.status_link.deactivate').show();
|
||||||
|
group.children('.status_link.activate').hide();
|
||||||
} else {
|
} 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.
|
* :copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
||||||
* :license: GNU GPL, see LICENSE for more details.
|
* :license: GNU GPL, see LICENSE for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
a.status_link span {
|
a.status_link span {
|
||||||
background-image: url(../images/icons/off.png);
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
a.status_link.active span {
|
|
||||||
|
a.status_link.deactivate span {
|
||||||
background-image: url(../images/icons/on.png);
|
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 title %}
|
||||||
{{ block.super }} –
|
{{ block.super }} –
|
||||||
{% if edituser %}
|
{% if edit_user %}
|
||||||
{% trans "Edit participant" %}
|
{% trans "Edit participant" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans "New participant" %}
|
{% trans "New participant" %}
|
||||||
@ -13,17 +13,18 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if edituser %}
|
{% if edit_user %}
|
||||||
<h1>{% trans "Edit participant" %}</h1>
|
<h1>{% trans "Edit participant" %}</h1>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h1>{% trans "New participant" %}</h1>
|
<h1>{% trans "New participant" %}</h1>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form action="" method="post">{% csrf_token %}
|
<form action="" method="post">{% csrf_token %}
|
||||||
{{ userform.as_p }}
|
{{ form.as_p }}
|
||||||
{{ profileform.as_p }}
|
{% if edit_user %}
|
||||||
{% if edituser %}
|
<p>
|
||||||
<p><a href="{% url user_reset_password edituser.id %}">{% trans 'Reset to First Password' %}</a></p>
|
<a href="{% url user_reset_password edit_user.id %}">{% trans 'Reset to First Password' %}</a>
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<button class="button" type="submit">
|
<button class="button" type="submit">
|
||||||
|
@ -13,58 +13,59 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Participants" %}</h1>
|
<h1>{% trans "Participants" %}</h1>
|
||||||
|
|
||||||
<p><form action="{{request.url}}" name="filter" method="post">
|
<p>
|
||||||
{% csrf_token %}
|
<form action="" name="filter" method="get">
|
||||||
{% trans "Filter" %}:
|
{% trans "Filter" %}:
|
||||||
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="gender" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Gender" %} --</option>
|
<option value="---">-- {% trans "Gender" %} --</option>
|
||||||
<option value="male" {% if 'male' in sortfilter.gender %}selected{% endif %}>{% trans "Male" %}</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="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option>
|
||||||
<option value="" {% if '' in sortfilter.gender %}selected{% endif %}>{% trans "Not specified" %}</option>
|
<option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="group" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="category" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Group" %} --</option>
|
<option value="---">-- {% trans "Category" %} --</option>
|
||||||
{% for group in groups %}
|
{% for category in categories %}
|
||||||
<option value="{{ group }}" {% if group in sortfilter.group %}selected{% endif %}>
|
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}>
|
||||||
{{ group }}</option>
|
{{ category }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Type" %} --</option>
|
<option value="---">-- {% trans "Type" %} --</option>
|
||||||
<option value="delegate" {% if 'delegate' in sortfilter.type %}selected{% endif %}>{% trans "Delegate" %}</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="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="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="guest"{% if 'guest' in sortfilter.type %} selected{% endif %}>{% trans "Guest" %}</option>
|
||||||
<option value="" {% if '' in sortfilter.type %}selected{% endif %}>{% trans "Not specified" %}</option>
|
<option value=""{% if '' in sortfilter.type %} selected{% endif %}>{% trans "Not specified" %}</option>
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="committee" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Committee" %} --</option>
|
<option value="---">-- {% trans "Committee" %} --</option>
|
||||||
{% for committee in committees %}
|
{% for committee in committees %}
|
||||||
<option value="{{ committee }}" {% if committee in sortfilter.committee %}selected{% endif %}>
|
<option value="{{ committee }}"{% if committee in sortfilter.committee %} selected{% endif %}>
|
||||||
{{ committee }}</option>
|
{{ committee }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="status" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Status" %} --</option>
|
<option value="---">-- {% trans "Status" %} --</option>
|
||||||
<option value="1" {% if '1' in sortfilter.status %}selected{% endif %}>{% trans "Active" %}</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>
|
<option value="0"{% if '0' in sortfilter.status %} selected{% endif %}>{% trans "Inactive" %}</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
{% if users|length == allusers|length %}
|
{% if users.count == allusers %}
|
||||||
{{ users|length }}
|
{{ users.count }}
|
||||||
{% blocktrans count counter=users|length %}participant{% plural %}participants{% endblocktrans %}
|
{% blocktrans count counter=users.count %}participant{% plural %}participants{% endblocktrans %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ users|length }} {% trans "of" %} {{ allusers|length }} {% trans "Participants" %} (= {{ percent }} %)
|
{{ users.count }} {% trans "of" %} {{ allusers }} {% trans "Participants" %} (= {{ percent }} %)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<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=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=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=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>
|
<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 %}
|
{% if perms.participant.can_manage_participant %}
|
||||||
@ -77,20 +78,28 @@
|
|||||||
<tr class="{% cycle '' 'odd' %}">
|
<tr class="{% cycle '' 'odd' %}">
|
||||||
<td>{{ user.first_name }}</td>
|
<td>{{ user.first_name }}</td>
|
||||||
<td>{{ user.last_name }}</td>
|
<td>{{ user.last_name }}</td>
|
||||||
<td>{{ user.openslidesuser.name_surfix }}</td>
|
<td>{{ user.category }}</td>
|
||||||
<td>{{ user.openslidesuser.get_type_display }}</td>
|
<td>{{ user.get_type_display }}</td>
|
||||||
<td>{{ user.openslidesuser.committee }}</td>
|
<td>{{ user.committee }}</td>
|
||||||
{% if perms.participant.can_manage_participant %}
|
{% if perms.participant.can_manage_participant %}
|
||||||
<td>{{ user.openslidesuser.comment|first_line }}</td>
|
<td>{{ user.comment|first_line }}</td>
|
||||||
<td>{% if user.last_login > user.date_joined %}
|
<td>
|
||||||
|
{% if user.last_login > user.date_joined %}
|
||||||
{{ user.last_login }}
|
{{ user.last_login }}
|
||||||
{% endif %}</td>
|
{% endif %}
|
||||||
<td><span style="width: 1px; white-space: nowrap;">
|
</td>
|
||||||
<a href="{% url user_edit user.id %}"><img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}"></a>
|
<td>
|
||||||
<a href="{% url user_delete user.id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}"></a>
|
<span style="width: 1px; white-space: nowrap;">
|
||||||
<a class="status_link {% if user.is_active %}active{% endif %}"
|
<a href="{% url user_edit user.id %}">
|
||||||
href="{% url user_status user.id %}"
|
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
|
||||||
title="{% trans 'Change status (active/inactive)' %}">
|
</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>
|
<span></span>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -12,61 +12,65 @@
|
|||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import Client
|
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 django.contrib.auth.hashers import check_password
|
||||||
|
|
||||||
from openslides.utils.person import get_person, Persons
|
from openslides.utils.person import get_person, Persons
|
||||||
from openslides.participant.api import gen_username, gen_password
|
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):
|
def setUp(self):
|
||||||
self.user1 = User(first_name=u'Max', last_name=u'Mustermann')
|
self.user1 = User()
|
||||||
self.user1.username = gen_username(self.user1.first_name, self.user1.last_name)
|
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.user1.save()
|
||||||
self.openslidesuser1 = self.user1.openslidesuser
|
self.django_user1 = self.user1.django_user
|
||||||
self.openslidesuser1.firstpassword = gen_password()
|
|
||||||
self.openslidesuser1.save()
|
|
||||||
self.user1 = self.openslidesuser1.user
|
|
||||||
|
|
||||||
def test_participant_user(self):
|
def test_participant_user(self):
|
||||||
self.assertEqual(self.user1.openslidesuser, self.openslidesuser1)
|
self.assertEqual(self.django_user1.user, self.user1)
|
||||||
self.assertEqual(self.user1, self.openslidesuser1.user)
|
self.assertEqual(self.django_user1, self.user1.django_user)
|
||||||
|
|
||||||
def test_repr(self):
|
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):
|
def test_name_surfix(self):
|
||||||
self.openslidesuser1.name_surfix = u'München'
|
self.user1.category = u'München'
|
||||||
self.openslidesuser1.save()
|
self.user1.save()
|
||||||
self.assertEqual(unicode(self.openslidesuser1), u'Max Mustermann (München)')
|
self.assertEqual(unicode(self.user1), u'Max Mustermann (München)')
|
||||||
|
|
||||||
def test_reset_password(self):
|
def test_reset_password(self):
|
||||||
self.assertIsInstance(self.openslidesuser1.firstpassword, basestring)
|
self.assertIsInstance(self.user1.default_password, basestring)
|
||||||
self.assertEqual(len(self.openslidesuser1.firstpassword), 8)
|
self.assertEqual(len(self.user1.default_password), 8)
|
||||||
self.user1.set_unusable_password()
|
self.user1.set_unusable_password()
|
||||||
self.assertFalse(self.user1.check_password(self.openslidesuser1.firstpassword))
|
self.assertFalse(self.user1.check_password(self.user1.default_password))
|
||||||
self.openslidesuser1.reset_password()
|
self.user1.reset_password()
|
||||||
self.assertTrue(self.user1.check_password(self.openslidesuser1.firstpassword))
|
self.assertTrue(self.user1.check_password(self.user1.default_password))
|
||||||
|
|
||||||
def test_person_api(self):
|
def test_person_api(self):
|
||||||
self.assertTrue(hasattr(self.openslidesuser1, 'person_id'))
|
self.assertTrue(hasattr(self.user1, 'person_id'))
|
||||||
self.assertEqual(self.openslidesuser1.person_id, 'openslides_user:1')
|
self.assertEqual(self.user1.person_id, 'user:1')
|
||||||
self.assertEqual(get_person('openslides_user:1'), self.openslidesuser1)
|
self.assertEqual(get_person('user:1'), self.user1)
|
||||||
self.assertEqual(len(Persons()), 1)
|
self.assertEqual(len(Persons(person_prefix_filter='user')), 1)
|
||||||
|
|
||||||
|
|
||||||
class OpenSlidesGroupTest(TestCase):
|
class GroupTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.group1 = Group.objects.create(name='Test Group')
|
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):
|
def test_group_group(self):
|
||||||
self.assertEqual(self.openslidesgroup1.group, self.group1)
|
self.assertEqual(self.group1.django_group, self.django_group1)
|
||||||
|
self.assertEqual(self.group1, self.django_group1.group)
|
||||||
|
|
||||||
def test_person_api(self):
|
def test_person_api(self):
|
||||||
self.assertTrue(hasattr(self.openslidesgroup1, 'person_id'))
|
self.assertTrue(hasattr(self.group1, 'person_id'))
|
||||||
self.assertEqual(self.openslidesgroup1.person_id, 'openslides_group:1')
|
person_id = "group:%d" % self.group1.id
|
||||||
self.assertEqual(get_person('openslides_group:1'), self.openslidesgroup1)
|
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.conf.urls.defaults import url, patterns
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from openslides.participant.views import (ParticipantsListPDF,
|
from openslides.participant.views import (
|
||||||
ParticipantsPasswordsPDF)
|
ParticipantsListPDF, ParticipantsPasswordsPDF, Overview, UserCreateView,
|
||||||
|
UserUpdateView, UserDeleteView, SetUserStatusView, UserImportView,
|
||||||
|
ResetPasswordView, GroupOverviewView, GroupCreateView, GroupUpdateView,
|
||||||
|
GroupDeleteView)
|
||||||
|
|
||||||
urlpatterns = patterns('openslides.participant.views',
|
urlpatterns = patterns('openslides.participant.views',
|
||||||
url(r'^$',
|
url(r'^$',
|
||||||
'get_overview',
|
Overview.as_view(),
|
||||||
name='user_overview',
|
name='user_overview',
|
||||||
),
|
),
|
||||||
|
|
||||||
url(r'^new/$',
|
url(r'^new/$',
|
||||||
'edit',
|
UserCreateView.as_view(),
|
||||||
name='user_new',
|
name='user_new',
|
||||||
),
|
),
|
||||||
|
|
||||||
url(r'^(?P<user_id>\d+)/edit/$',
|
url(r'^(?P<pk>\d+)/edit/$',
|
||||||
'edit',
|
UserUpdateView.as_view(),
|
||||||
name='user_edit',
|
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/$',
|
url(r'^print/$',
|
||||||
ParticipantsListPDF.as_view(),
|
ParticipantsListPDF.as_view(),
|
||||||
name='user_print',
|
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/$',
|
url(r'^passwords/print/$',
|
||||||
ParticipantsPasswordsPDF.as_view(),
|
ParticipantsPasswordsPDF.as_view(),
|
||||||
name='print_passwords',
|
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('',
|
urlpatterns += patterns('',
|
||||||
(r'^500/$', 'openslides.utils.views.server_error'),
|
|
||||||
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
|
||||||
|
|
||||||
url(r'^login/$',
|
url(r'^login/$',
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
: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.api import generate_person_id, get_person, Persons
|
||||||
from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField
|
from openslides.utils.person.forms import PersonFormField, MultiplePersonFormField
|
||||||
from openslides.utils.person.models import PersonField, PersonMixin
|
from openslides.utils.person.models import PersonField, PersonMixin
|
||||||
|
@ -10,16 +10,16 @@
|
|||||||
:license: GNU GPL, see LICENSE for more details.
|
: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):
|
class Persons(object):
|
||||||
"""
|
"""
|
||||||
A Storage for a multiplicity of different Person-Objects.
|
A Storage for a multiplicity of different Person-Objects.
|
||||||
"""
|
"""
|
||||||
def __init__(self, person_prefix=None, id=None):
|
def __init__(self, person_prefix_filter=None, id_filter=None):
|
||||||
self.person_prefix = person_prefix
|
self.person_prefix_filter = person_prefix_filter
|
||||||
self.id = id
|
self.id_filter = id_filter
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
try:
|
try:
|
||||||
@ -35,14 +35,16 @@ class Persons(object):
|
|||||||
|
|
||||||
def iter_persons(self):
|
def iter_persons(self):
|
||||||
self._cache = list()
|
self._cache = list()
|
||||||
for receiver, persons in receiv_persons.send(
|
for receiver, persons in receive_persons.send(
|
||||||
sender='persons', person_prefix=self.person_prefix, id=self.id):
|
sender='persons', person_prefix_filter=self.person_prefix_filter, id_filter=self.id_filter):
|
||||||
for person in persons:
|
for person in persons:
|
||||||
self._cache.append(person)
|
self._cache.append(person)
|
||||||
yield person
|
yield person
|
||||||
|
|
||||||
|
|
||||||
def generate_person_id(prefix, id):
|
def generate_person_id(prefix, id):
|
||||||
|
assert prefix is not None
|
||||||
|
assert id is not None
|
||||||
if ':' in prefix:
|
if ':' in prefix:
|
||||||
raise ValueError("':' is not allowed in a the 'person_prefix'")
|
raise ValueError("':' is not allowed in a the 'person_prefix'")
|
||||||
return "%s:%d" % (prefix, id)
|
return "%s:%d" % (prefix, id)
|
||||||
@ -61,4 +63,4 @@ def get_person(person_id):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
from openslides.utils.person import EmtyPerson
|
from openslides.utils.person import EmtyPerson
|
||||||
return 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:
|
try:
|
||||||
return generate_person_id(self.person_prefix, self.pk)
|
return generate_person_id(self.person_prefix, self.pk)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError("%s has to have a attribute 'user_prefix'"
|
raise AttributeError("%s has to have a attribute 'person_prefix'"
|
||||||
% self)
|
% self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
from django.dispatch import Signal
|
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.dispatch import receiver
|
||||||
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponseServerError, HttpResponse, HttpResponseRedirect
|
||||||
from django.utils.decorators import method_decorator
|
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.utils.importlib import import_module
|
||||||
from django.template import loader, RequestContext
|
from django.template import loader, RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -105,6 +105,50 @@ class AjaxMixin(object):
|
|||||||
return HttpResponse(json.dumps(self.get_ajax_context(**kwargs)))
|
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):
|
class TemplateView(PermissionMixin, _TemplateView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(TemplateView, self).get_context_data(**kwargs)
|
context = super(TemplateView, self).get_context_data(**kwargs)
|
||||||
@ -208,21 +252,32 @@ class CreateView(PermissionMixin, _CreateView):
|
|||||||
messages.error(self.request, _('Please check the form for errors.'))
|
messages.error(self.request, _('Please check the form for errors.'))
|
||||||
return super(CreateView, self).form_invalid(form)
|
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):
|
def get_success_message(self):
|
||||||
return _('%s was successfully created.') % html_strong(self.object)
|
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)
|
return _('Do you really want to delete %s?') % html_strong(self.object)
|
||||||
|
|
||||||
def get_success_message(self):
|
def get_success_message(self):
|
||||||
return _('%s was successfully deleted.') % html_strong(self.object)
|
return _('%s was successfully deleted.') % html_strong(self.object)
|
||||||
|
|
||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
self.confirm_form(request, self.object)
|
self.confirm_form()
|
||||||
|
|
||||||
def pre_post_redirect(self, request, *args, **kwargs):
|
def pre_post_redirect(self, request, *args, **kwargs):
|
||||||
|
if self.get_answer().lower() == 'yes':
|
||||||
self.object.delete()
|
self.object.delete()
|
||||||
messages.success(request, self.get_success_message())
|
messages.success(request, self.get_success_message())
|
||||||
|
|
||||||
@ -230,20 +285,8 @@ class DeleteView(RedirectView, SingleObjectMixin):
|
|||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
return super(DeleteView, self).get(request, *args, **kwargs)
|
return super(DeleteView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def confirm_form(self, request, object):
|
def get_answer_url(self):
|
||||||
self.gen_confirm_form(request, self.get_confirm_question(),
|
return self.object.get_absolute_url('delete')
|
||||||
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")))
|
|
||||||
|
|
||||||
|
|
||||||
class DetailView(TemplateView, SingleObjectMixin):
|
class DetailView(TemplateView, SingleObjectMixin):
|
||||||
|
Loading…
Reference in New Issue
Block a user