Merge pull request #27 from ostcar/master

A lot of fixes
This commit is contained in:
Oskar Hahn 2012-10-24 03:56:44 -07:00
commit 20e07c0af7
16 changed files with 1080 additions and 1025 deletions

View File

@ -11,14 +11,14 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_nominate_other", "can_nominate_other",
@ -44,6 +44,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -60,19 +65,19 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_support_application", "can_support_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_nominate_other", "can_nominate_other",
@ -98,6 +103,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -119,19 +129,19 @@
"item" "item"
], ],
[ [
"can_create_application", "can_create_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_manage_application", "can_manage_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_see_application", "can_see_motion",
"application", "motion",
"application" "motion"
], ],
[ [
"can_manage_assignment", "can_manage_assignment",
@ -177,6 +187,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }
@ -206,6 +221,11 @@
"can_see_projector", "can_see_projector",
"projector", "projector",
"projectorslide" "projectorslide"
],
[
"can_see_dashboard",
"projector",
"projectorslide"
] ]
] ]
} }

View File

@ -31,7 +31,7 @@
<div style="margin-right: 250px; min-width: 400px;"> <div style="margin-right: 250px; min-width: 400px;">
<h1>{{ assignment }}</h1> <h1>{{ assignment }}</h1>
<p>{{ assignment.description }}</p> <p>{{ assignment.description|linebreaks }}</p>
<h3>{% trans "Candidates" %}</h3> <h3>{% trans "Candidates" %}</h3>
<ol> <ol>

View File

@ -430,11 +430,11 @@ class AssignmentPDF(PDFView):
for candidate, poll_list in vote_results.iteritems(): for candidate, poll_list in vote_results.iteritems():
row = [] row = []
candidate_string = candidate.user.get_full_name() candidate_string = candidate.clean_name
if candidate in elected_candidates: if candidate in elected_candidates:
candidate_string = "* " + candidate_string candidate_string = "* " + candidate_string
if candidate.category: if candidate.name_suffix:
candidate_string += "\n(%s)" % candidate.category candidate_string += "\n(%s)" % candidate.name_suffix
row.append(candidate_string) row.append(candidate_string)
for vote in poll_list: for vote in poll_list:
if vote == None: if vote == None:
@ -565,7 +565,7 @@ class AssignmentPollPDF(PDFView):
if self.poll.yesnoabstain: if self.poll.yesnoabstain:
for option in options: for option in options:
candidate = option.candidate candidate = option.candidate
cell.append(Paragraph(candidate.user.get_full_name(), cell.append(Paragraph(candidate.clean_name,
stylesheet['Ballot_option_name'])) stylesheet['Ballot_option_name']))
if candidate.name_suffix: if candidate.name_suffix:
cell.append(Paragraph("(%s)" % candidate.name_suffix, cell.append(Paragraph("(%s)" % candidate.name_suffix,
@ -591,10 +591,10 @@ class AssignmentPollPDF(PDFView):
else: else:
for option in options: for option in options:
candidate = option.candidate candidate = option.candidate
cell.append(Paragraph(circle + candidate.user.get_full_name(), cell.append(Paragraph(circle + candidate.clean_name,
stylesheet['Ballot_option_name'])) stylesheet['Ballot_option_name']))
if candidate.category: if candidate.name_suffix:
cell.append(Paragraph("(%s)" % candidate.category, cell.append(Paragraph("(%s)" % candidate.name_suffix,
stylesheet['Ballot_option_group_right'])) stylesheet['Ballot_option_group_right']))
else: else:
cell.append(Paragraph("&nbsp;", cell.append(Paragraph("&nbsp;",

View File

@ -66,8 +66,9 @@ class GeneralConfig(FormView):
try: try:
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 = ['can_see_agenda', 'can_see_projector',
u'can_see_motion', u'can_see_assignment'] 'can_see_motion', 'can_see_assignment',
'can_see_dashboard']
anonymous = Group() anonymous = Group()
anonymous.name = 'Anonymous' anonymous.name = 'Anonymous'
anonymous.save() anonymous.save()

File diff suppressed because it is too large Load Diff

View File

@ -426,10 +426,13 @@ class MotionDelete(DeleteView):
""" """
Delete one or more Motions. Delete one or more Motions.
""" """
permission_required = 'motion.can_manage_motion'
model = Motion model = Motion
url = 'motion_overview' url = 'motion_overview'
def has_permission(self, request, *args, **kwargs):
self.kwargs = kwargs
return self.get_object().get_allowed_actions(request.user)
def get_object(self): def get_object(self):
self.motions = [] self.motions = []

View File

@ -27,7 +27,7 @@ class UserCreateForm(forms.ModelForm, CssClassMixin):
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'is_active', 'groups', 'category', fields = ('first_name', 'last_name', 'is_active', 'groups', 'detail',
'gender', 'type', 'committee', 'comment', 'default_password') 'gender', 'type', 'committee', 'comment', 'default_password')
@ -35,7 +35,7 @@ class UserUpdateForm(UserCreateForm):
class Meta: class Meta:
model = User model = User
fields = ('username', 'first_name', 'last_name', 'is_active', 'groups', fields = ('username', 'first_name', 'last_name', 'is_active', 'groups',
'category', 'gender', 'type', 'committee', 'comment', 'detail', 'gender', 'type', 'committee', 'comment',
'default_password') 'default_password')

View File

@ -16,14 +16,14 @@ 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, Person
from openslides.utils.person.signals import receive_persons from openslides.utils.person.signals import receive_persons
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
class User(DjangoUser, PersonMixin): class User(DjangoUser, PersonMixin, Person):
person_prefix = 'user' person_prefix = 'user'
GENDER_CHOICES = ( GENDER_CHOICES = (
('male', _('Male')), ('male', _('Male')),
@ -37,8 +37,8 @@ class User(DjangoUser, PersonMixin):
) )
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True) django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
category = models.CharField( detail = models.CharField(
max_length=100, null=True, blank=True, verbose_name=_("Category"), max_length=100, blank=True, default='', verbose_name=_("Detail"),
help_text=_('Will be 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,
@ -47,20 +47,24 @@ class User(DjangoUser, PersonMixin):
max_length=100, choices=TYPE_CHOICES, blank=True, max_length=100, choices=TYPE_CHOICES, blank=True,
verbose_name=_("Typ"), help_text=_('Only for filter the userlist.')) verbose_name=_("Typ"), help_text=_('Only for filter the userlist.'))
committee = models.CharField( committee = models.CharField(
max_length=100, null=True, blank=True, verbose_name=_("Committee"), max_length=100, blank=True, default='', verbose_name=_("Committee"),
help_text=_('Only for filter the userlist.')) help_text=_('Only for filter the userlist.'))
comment = models.TextField( comment = models.TextField(
null=True, blank=True, verbose_name=_('Comment'), blank=True, default='', verbose_name=_('Comment'),
help_text=_('Only for notes.')) help_text=_('Only for notes.'))
default_password = models.CharField( default_password = models.CharField(
max_length=100, null=True, blank=True, max_length=100, blank=True, default='',
verbose_name=_("Default password")) verbose_name=_("Default password"))
@property
def clean_name(self):
return self.get_full_name() or self.username
def get_name_suffix(self): def get_name_suffix(self):
return self.category return self.detail
def set_name_suffix(self, value): def set_name_suffix(self, value):
self.category = value self.detail = value
name_suffix = property(get_name_suffix, set_name_suffix) name_suffix = property(get_name_suffix, set_name_suffix)
@ -88,10 +92,9 @@ class User(DjangoUser, PersonMixin):
return ('user_delete', [str(self.id)]) return ('user_delete', [str(self.id)])
def __unicode__(self): def __unicode__(self):
name = self.get_full_name() or self.username
if self.name_suffix: if self.name_suffix:
return u"%s (%s)" % (name, self.name_suffix) return u"%s (%s)" % (self.clean_name, self.name_suffix)
return u"%s" % name return u"%s" % self.clean_name
class Meta: class Meta:
# Rename permissions # Rename permissions
@ -103,7 +106,7 @@ class User(DjangoUser, PersonMixin):
ordering = ('last_name',) ordering = ('last_name',)
class Group(DjangoGroup, PersonMixin): class Group(DjangoGroup, PersonMixin, Person):
person_prefix = 'group' person_prefix = 'group'
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True) django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)

View File

@ -26,11 +26,11 @@
<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="category" onchange="document.forms['filter'].submit()"> <select class="default-input" name="detail" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Category" %} --</option> <option value="---">-- {% trans "Detail" %} --</option>
{% for category in categories %} {% for detail in details %}
<option value="{{ category }}"{% if category in sortfilter.category %} selected{% endif %}> <option value="{{ detail }}"{% if detail in sortfilter.detail %} selected{% endif %}>
{{ category }}</option> {{ detail }}</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()">
@ -65,7 +65,7 @@
<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=category&reverse={% if 'category' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Category" %}</a></th> <th><a href="?sort=detail&reverse={% if 'detail' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Detail" %}</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 %}
@ -78,7 +78,7 @@
<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.category }}</td> <td>{{ user.detail }}</td>
<td>{{ user.get_type_display }}</td> <td>{{ user.get_type_display }}</td>
<td>{{ user.committee }}</td> <td>{{ user.committee }}</td>
{% if perms.participant.can_manage_participant %} {% if perms.participant.can_manage_participant %}

View File

@ -35,12 +35,12 @@ class UserTest(TestCase):
self.assertEqual(self.django_user1, self.user1.django_user) self.assertEqual(self.django_user1, self.user1.django_user)
def test_repr(self): def test_repr(self):
self.assertEqual(unicode(self.user1), u'Max Mustermann') self.assertEqual(unicode(self.user1), 'Max Mustermann')
def test_name_surfix(self): def test_name_surfix(self):
self.user1.category = u'München' self.user1.detail = 'München'
self.user1.save() self.user1.save()
self.assertEqual(unicode(self.user1), u'Max Mustermann (München)') self.assertEqual(unicode(self.user1), 'Max Mustermann (München)')
def test_reset_password(self): def test_reset_password(self):
self.assertIsInstance(self.user1.default_password, basestring) self.assertIsInstance(self.user1.default_password, basestring)

View File

@ -66,8 +66,8 @@ class Overview(ListView):
except KeyError: except KeyError:
sortfilter = {} sortfilter = {}
for value in [u'gender', u'category', u'type', u'committee', u'status', for value in ['gender', 'detail', 'type', 'committee', 'status',
u'sort', u'reverse']: 'sort', 'reverse']:
if value in self.request.REQUEST: if value in self.request.REQUEST:
if self.request.REQUEST[value] == '---': if self.request.REQUEST[value] == '---':
try: try:
@ -80,8 +80,8 @@ class Overview(ListView):
query = User.objects query = User.objects
if 'gender' in sortfilter: if 'gender' in sortfilter:
query = query.filter(gender__iexact=sortfilter['gender'][0]) query = query.filter(gender__iexact=sortfilter['gender'][0])
if 'category' in sortfilter: if 'detail' in sortfilter:
query = query.filter(category__iexact=sortfilter['category'][0]) query = query.filter(detail__iexact=sortfilter['detail'][0])
if 'type' in sortfilter: if 'type' in sortfilter:
query = query.filter(type__iexact=sortfilter['type'][0]) query = query.filter(type__iexact=sortfilter['type'][0])
if 'committee' in sortfilter: if 'committee' in sortfilter:
@ -92,7 +92,7 @@ class Overview(ListView):
if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']: if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']:
query = query.order_by(sortfilter['sort'][0]) query = query.order_by(sortfilter['sort'][0])
elif (sortfilter['sort'][0] in elif (sortfilter['sort'][0] in
['category', 'type', 'committee', 'comment']): ['detail', 'type', 'committee', 'comment']):
query = query.order_by( query = query.order_by(
'%s' % sortfilter['sort'][0]) '%s' % sortfilter['sort'][0])
else: else:
@ -118,8 +118,8 @@ class Overview(ListView):
percent = 0 percent = 0
# list of all existing categories # list of all existing categories
categories = [p['category'] for p in User.objects.values('category') details = [p['detail'] for p in User.objects.values('detail')
.exclude(category='').distinct()] .exclude(detail='').distinct()]
# list of all existing committees # list of all existing committees
committees = [p['committee'] for p in User.objects.values('committee') committees = [p['committee'] for p in User.objects.values('committee')
@ -127,7 +127,7 @@ class Overview(ListView):
context.update({ context.update({
'allusers': all_users, 'allusers': all_users,
'percent': round(percent, 1), 'percent': round(percent, 1),
'categories': categories, 'details': details,
'committees': committees, 'committees': committees,
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter), 'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
doseq=True)], doseq=True)],
@ -223,7 +223,7 @@ class ParticipantsListPDF(PDFView):
counter, counter,
Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.last_name, stylesheet['Tablecell']),
Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']),
Paragraph(user.category, stylesheet['Tablecell']), Paragraph(user.detail, stylesheet['Tablecell']),
Paragraph(user.type, stylesheet['Tablecell']), Paragraph(user.type, stylesheet['Tablecell']),
Paragraph(user.committee, stylesheet['Tablecell'])]) Paragraph(user.committee, stylesheet['Tablecell'])])
t = LongTable(data, style=[ t = LongTable(data, style=[

View File

@ -11,7 +11,8 @@
""" """
from openslides.utils.person.signals import receive_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,
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

View File

@ -13,6 +13,37 @@
from openslides.utils.person.signals import receive_persons from openslides.utils.person.signals import receive_persons
class Person(object):
"""
Meta-class for all person objects
"""
def person_id(self):
"""
Return an id for representation of ths person. Has to be unique.
"""
raise NotImplementedError('Any person object needs a person_id')
def __repr__(self):
"""
Return a string for this person.
"""
return str(self.person_id)
@property
def clean_name(self):
"""
Return the name of this person without a suffix
"""
return unicode(self)
@property
def name_suffix(self):
"""
Return a suffix for the person-name.
"""
return ''
class Persons(object): class Persons(object):
""" """
A Storage for a multiplicity of different Person-Objects. A Storage for a multiplicity of different Person-Objects.

View File

@ -101,13 +101,13 @@ def permission_required(perm, login_url=None):
if request.user.has_perm(perm): if request.user.has_perm(perm):
return func(request, *args, **kw) return func(request, *args, **kw)
if request.user.is_authenticated(): if request.user.is_authenticated():
return render_to_forbitten(request) return render_to_forbidden(request)
return redirect(reverse('user_login')) return redirect(reverse('user_login'))
return wrapper return wrapper
return renderer return renderer
def render_to_forbitten(request, error= def render_to_forbidden(request, error=
ugettext_lazy("Sorry, you have no rights to see this page.")): ugettext_lazy("Sorry, you have no rights to see this page.")):
return HttpResponseForbidden(render_to_string('403.html', return HttpResponseForbidden(render_to_string('403.html',
{'error': error}, context_instance=RequestContext(request))) {'error': error}, context_instance=RequestContext(request)))

View File

@ -52,7 +52,7 @@ from django.views.generic.list import TemplateResponseMixin
from openslides.config.models import config from openslides.config.models import config
from openslides.utils.utils import render_to_forbitten, html_strong from openslides.utils.utils import render_to_forbidden, html_strong
from openslides.utils.signals import template_manipulation from openslides.utils.signals import template_manipulation
from openslides.utils.pdf import firstPage, laterPages from openslides.utils.pdf import firstPage, laterPages
@ -80,20 +80,20 @@ class LoginMixin(object):
class PermissionMixin(object): class PermissionMixin(object):
permission_required = NO_PERMISSION_REQUIRED permission_required = NO_PERMISSION_REQUIRED
def has_permission(self, request): def has_permission(self, request, *args, **kwargs):
if self.permission_required == NO_PERMISSION_REQUIRED: if self.permission_required == NO_PERMISSION_REQUIRED:
return True return True
else: else:
return request.user.has_perm(self.permission_required) return request.user.has_perm(self.permission_required)
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not self.has_permission(request): if not self.has_permission(request, *args, **kwargs):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
path = request.get_full_path() path = request.get_full_path()
return HttpResponseRedirect("%s?next=%s" % (settings.LOGIN_URL, return HttpResponseRedirect("%s?next=%s" % (settings.LOGIN_URL,
path)) path))
else: else:
return render_to_forbitten(request) return render_to_forbidden(request)
return _View.dispatch(self, request, *args, **kwargs) return _View.dispatch(self, request, *args, **kwargs)