Merge branch 'master' of github.com:OpenSlides/OpenSlides into sort_person_api

This commit is contained in:
Oskar Hahn 2012-11-22 16:35:26 +01:00
commit 8014f327a2
41 changed files with 563 additions and 545 deletions

View File

@ -98,13 +98,12 @@ II. Installation on GNU/Linux and MacOSX
OR
b) Clone development version from mercurial repository
http://hg.openslides.org. This requires Mercurial source control
management (hg):
b) Clone development version from OpenSlides' github repository
https://github.com/OpenSlides/OpenSlides.
This requires Git, see http://git-scm.com/.
Open command line (cmd) and run:
E.g. for Ubuntu run:
$ sudo apt-get install mercurial
$ hg clone http://hg.openslides.org OpenSlides
git clone git://github.com/OpenSlides/OpenSlides.git
3. Setup your virtual environment with virtualenv:

View File

@ -6,17 +6,11 @@ How to create a new portable Windows distribution of OpenSlides:
easy_install -Z django django-mptt reportlab pil
2.) Install OpenSlides by running in the top directory:
python setup.py install
NOTE: This step must be repeated whenever you make changes to OpenSlides.
3.) Run in the main directory of the OpenSlides checkout:
2.) Run in the main directory of the OpenSlides checkout:
python extras\win32-portable\prepare_portable.py
4.) The portable OpenSlides distribution is now ready as a zip archive
3.) The portable OpenSlides distribution is now ready as a zip archive
in the 'dist' directory

View File

@ -18,8 +18,6 @@ import zipfile
import distutils.ccompiler
import distutils.sysconfig
from contextlib import nested
import pkg_resources
sys.path.insert(0, os.getcwd())
@ -80,10 +78,7 @@ SITE_PACKAGES = {
"pil": {
# NOTE: PIL is a special case, see copy_pil
"copy": [],
},
"openslides": {
"copy" : ["openslides"],
},
}
}
PY_DLLS = [
@ -297,9 +292,13 @@ def main():
raise
os.makedirs(odir)
out_site_packages = os.path.join(odir, "site-packages")
collect_lib(libdir, odir)
collect_site_packages(sitedir, os.path.join(odir, "site-packages"))
collect_site_packages(sitedir, out_site_packages)
exclude = get_pkg_exclude("openslides")
copy_dir_exclude(exclude, ".", "openslides", out_site_packages)
if not compile_openslides_launcher():
sys.stdout.write("Using prebuild openslides.exe\n")

View File

@ -3,7 +3,7 @@
"pk": 1,
"model": "auth.group",
"fields": {
"name": "Beobachter",
"name": "Beobachter/in",
"permissions": [
[
"can_see_agenda",
@ -57,7 +57,7 @@
"pk": 2,
"model": "auth.group",
"fields": {
"name": "Delegierter",
"name": "Delegierte/r",
"permissions": [
[
"can_see_agenda",

View File

@ -231,4 +231,4 @@ def get_widgets(request):
context={
'agenda': SLIDE['agenda'],
'items': Item.objects.all()},
permission_required='agenda.can_manage_agenda')]
permission_required='projector.can_manage_projector')]

View File

@ -85,7 +85,7 @@ class Assignment(models.Model, SlideMixin):
raise NameError(_('<b>%s</b> is already a candidate.') % candidate)
if not person.has_perm("assignment.can_manage_assignment") and self.status != 'sea':
raise NameError(_('The candidate list is already closed.'))
candidation = self.assignment_candidats.filter(person=candidate)
candidation = self.assignment_candidates.filter(person=candidate)
if candidation and candidate != person and \
not person.has_perm("assignment.can_manage_assignment"):
# if the candidation is blocked and anotherone tries to run the
@ -103,9 +103,8 @@ class Assignment(models.Model, SlideMixin):
stop running for a vote
"""
try:
candidation = self.assignment_candidats.get(person=candidate)
candidation = self.assignment_candidates.get(person=candidate)
except AssignmentCandidate.DoesNotExist:
# TODO: Use an OpenSlides Error
raise Exception(_('%s is no candidate') % candidate)
if not candidation.blocked:
@ -123,7 +122,7 @@ class Assignment(models.Model, SlideMixin):
return True, if person is a candidate.
"""
try:
return self.assignment_candidats.filter(person=person) \
return self.assignment_candidates.filter(person=person) \
.exclude(blocked=True).exists()
except AttributeError:
return False
@ -132,11 +131,11 @@ class Assignment(models.Model, SlideMixin):
"""
return True, if the person is blockt for candidation.
"""
return self.assignment_candidats.filter(person=person) \
return self.assignment_candidates.filter(person=person) \
.filter(blocked=True).exists()
@property
def assignment_candidats(self):
def assignment_candidates(self):
return AssignmentCandidate.objects.filter(assignment=self)
@property
@ -148,7 +147,7 @@ class Assignment(models.Model, SlideMixin):
return self.get_participants(only_elected=True)
def get_participants(self, only_elected=False, only_candidate=False):
candidates = self.assignment_candidats.exclude(blocked=True)
candidates = self.assignment_candidates.exclude(blocked=True)
assert not (only_elected and only_candidate)
@ -167,7 +166,7 @@ class Assignment(models.Model, SlideMixin):
def set_elected(self, person, value=True):
candidate = self.assignment_candidats.get(person=person)
candidate = self.assignment_candidates.get(person=person)
candidate.elected = value
candidate.save()
@ -293,7 +292,7 @@ class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin):
self.yesnoabstain = True
else:
# candidates <= available posts -> yes/no/abstain
if self.assignment.assignment_candidats.filter(elected=False).count() <= (self.assignment.posts):
if len(self.assignment.candidates) <= (self.assignment.posts - len(self.assignment.elected)):
self.yesnoabstain = True
else:
self.yesnoabstain = False

View File

@ -32,10 +32,11 @@
{% if assignment.active %}activeline{% endif %}">
<td><a href="{% url assignment_view assignment.id %}">{{ assignment }}</a></td>
<td>
{{ assignment.posts }} {% trans "posts" %} / {{ assignment.elected|length }} {% trans "elected" %}
{% blocktrans with posts=assignment.posts %}posts: {{ posts }}{% endblocktrans %}
{% if assignment.status != 'fin' %}
/ {{ assignment.candidates|length }} {% trans "candidates" %}
| {% blocktrans with candidates=assignment.get_participants|length %}candidates: {{ candidates }}{% endblocktrans %}
{% endif %}
| {% blocktrans with elected=assignment.elected|length %}elected: {{ elected }}{% endblocktrans %}
</td>
<td>{{ assignment.get_status_display }}</td>
<td>

View File

@ -33,9 +33,10 @@
<h1>{{ assignment }}</h1>
<p>{{ assignment.description|linebreaks }}</p>
{% if assignment.status != "fin" %}
<h3>{% trans "Candidates" %}</h3>
<ol>
{% for person in assignment.candidates %}
{% for person in assignment.get_participants %}
<li>
{{ person }}
{% if perms.assignment.can_manage_assignment %}
@ -43,6 +44,14 @@
<a href="{% url assignment_delother assignment.id person.person_id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Remove candidate' %}"></a>
{% endif %}
{% endif %}
{% if person in assignment.elected %}
| <b>{% trans "elected" %}</b>
{% if perms.assignment.can_manage_assignment %}
{% if assignment.status == "sea" or assignment.status == "vot" %}
<a href="{% url assignment_user_not_elected assignment.id person.person_id %}"><img src="{% static 'images/icons/dialog-cancel.png' %}" title="{% trans 'Mark candidate as not elected' %}"></a>
{% endif %}
{% endif %}
{% endif %}
</li>
{% empty %}
<li style="list-style: none outside none;"><i>{% trans "No candidates available." %}</i></li>
@ -85,27 +94,11 @@
</p>
{% endif %}
</form>
{% endif %}
{% endif %}
{% endif %}
<h3>{% trans "Elected Candidates" %}</h3>
<ul>
{% for person in assignment.elected %}
<li>
{{ person }}
{% if perms.assignment.can_manage_assignment %}
{% if assignment.status == "sea" or assignment.status == "vot" %}
<a href="{% url assignment_user_not_elected assignment.id person.person_id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Remove candidate' %}"></a>
{% endif %}
{% endif %}
</li>
{% empty %}
<li>{% trans "No elected candidates available." %}</li>
{% endfor %}
</ul>
{% if perms.assignment.can_manage_assignments %}
{% if perms.assignment.can_manage_assignments and blocked_candidates and assignment.status != "fin" %}
<h3>{% trans "Blocked Candidates" %}</h3>
<ul>
{% for person in blocked_candidates %}
@ -118,20 +111,11 @@
</ul>
{% endif %}
{% if assignment.status != "sea" or polls.exists %}
<h3>{% trans "Election results" %}</h3>
{% if polls.exists %}
<table id="election_table" style="width: auto;">
<tr>
<th></th>
{% with ballotnumber=polls.count %}
<th colspan="{{ ballotnumber|add:'1' }}" style="text-align: center;">
{% trans "ballot" %}
</th>
{% endwith %}
</tr>
<tr>
<th>{% trans "Candidates" %}</th>
{% for poll in polls %}
@ -161,7 +145,7 @@
</tr>
{% for candidate, poll_list in vote_results.items %}
<tr class="{% cycle 'odd' '' %}">
<tr class="{% cycle 'odd' '' as rowcolors %}">
<td class="candidate">
{% if candidate in assignment.elected %}
{% if perms.assignment.can_manage_assignment %}
@ -198,8 +182,7 @@
{% endif %}
</tr>
{% endfor %}
<tr>
<tr class="{% cycle rowcolors %}">
<td>{% trans 'Invalid votes' %}</td>
{% for poll in polls %}
{% if poll.published or perms.assignment.can_manage_assignment %}
@ -215,7 +198,6 @@
<td></td>
{% endif %}
</tr>
<tr class="total">
<td><strong>{% trans 'Votes cast' %}</strong></td>
{% for poll in polls %}
@ -233,11 +215,8 @@
{% endif %}
</tr>
</table>
{% else %}
<i>{% trans "No ballots available." %}</i>
<i>{% trans "No results available." %}</i>
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
<p><a href='{% url assignment_gen_poll assignment.id %}'>
<span class="button">
@ -245,9 +224,7 @@
</span>
</a></p>
{% endif %}
{% endif %}
{% endif %}
</div>
{% endblock %}

View File

@ -62,7 +62,7 @@
</tr>
{% for candidate, poll_list in vote_results.items %}
<tr class="{% cycle 'odd' '' %}">
<tr class="{% cycle 'odd' '' as rowcolors %}">
<td class="candidate{% if candidate in assignment.elected %} elected{% endif %}">
{% if candidate in assignment.elected %}
<a class="elected">
@ -92,8 +92,7 @@
{% endfor %}
</tr>
{% endfor %}
<tr>
<tr class="{% cycle rowcolors %}">
<td>{% trans 'Invalid votes' %}</td>
{% for poll in polls %}
<td style="white-space:nowrap;">
@ -105,7 +104,6 @@
{% endfor %}
</tr>
<tr class="total">
<td>
<strong>{% trans 'Votes cast' %}</strong>
@ -120,12 +118,6 @@
</td>
{% endfor %}
</tr>
</table>
{% elif some_polls_available %}
<i>{% trans "Vote results are not published yet." %}</i>
{% elif assignment.candidates %}
<i>{% trans "No ballots available." %}</i>
{% endif %}
<br>
{% endblock %}

View File

@ -101,7 +101,7 @@ def view(request, assignment_id=None):
vote_results = assignment.vote_results(only_published=False)
blocked_candidates = [candidate.person for candidate in \
assignment.assignment_candidats.filter(blocked=True)]
assignment.assignment_candidates.filter(blocked=True)]
return {
'assignment': assignment,
'blocked_candidates': blocked_candidates,
@ -170,6 +170,8 @@ def set_status(request, assignment_id=None, status=None):
messages.success(request, _('Election status was set to: <b>%s</b>.') % assignment.get_status_display())
except Assignment.DoesNotExist:
pass
except NameError, e:
messages.error(request, e)
return redirect(reverse('assignment_view', args=[assignment_id]))
@ -678,4 +680,4 @@ def get_widgets(request):
display_name=_('Elections'),
template='assignment/widget.html',
context={'assignments': Assignment.objects.all()},
permission_required='assignment.can_manage_assignment')]
permission_required='projector.can_manage_projector')]

View File

@ -56,13 +56,13 @@ class GeneralConfigForm(forms.Form, CssClassMixin):
required=False,
)
frontpage_title = forms.CharField(
welcome_title = forms.CharField(
widget=forms.TextInput(),
label=_("Title"),
required=False,
)
frontpage_welcometext = forms.CharField(
welcome_text = forms.CharField(
widget=forms.Textarea(),
label=_("Welcome text"),
required=False,

View File

@ -86,8 +86,8 @@ def default_config(sender, key, **kwargs):
'event_location': '',
'event_organizer': '',
'presentation': '',
'frontpage_title': _('Welcome to OpenSlides'),
'frontpage_welcometext': _('[Place for your welcome text.]'),
'welcome_title': _('Welcome to OpenSlides'),
'welcome_text': _('[Place for your welcome text.]'),
'system_enable_anonymous': False,
}.get(key)

View File

@ -23,9 +23,9 @@
</fieldset>
<p></p>
<fieldset>
<legend>{% trans "Frontpage" %}</legend>
<legend>{% trans "Welcome Widget" %}</legend>
{% for field in form %}
{% if "id_frontpage" in field.label_tag %}
{% if "id_welcome" in field.label_tag %}
<p>
{{ field.errors }}
{{ field.required }}

View File

@ -41,8 +41,8 @@ class GeneralConfig(FormView):
'event_date': config['event_date'],
'event_location': config['event_location'],
'event_organizer': config['event_organizer'],
'frontpage_title': config['frontpage_title'],
'frontpage_welcometext': config['frontpage_welcometext'],
'welcome_title': config['welcome_title'],
'welcome_text': config['welcome_text'],
'system_enable_anonymous': config['system_enable_anonymous'],
}
@ -54,10 +54,9 @@ class GeneralConfig(FormView):
config['event_location'] = form.cleaned_data['event_location']
config['event_organizer'] = form.cleaned_data['event_organizer']
# frontpage
config['frontpage_title'] = form.cleaned_data['frontpage_title']
config['frontpage_welcometext'] = \
form.cleaned_data['frontpage_welcometext']
# welcome widget
config['welcome_title'] = form.cleaned_data['welcome_title']
config['welcome_text'] = form.cleaned_data['welcome_text']
# system
if form.cleaned_data['system_enable_anonymous']:

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,8 @@ from openslides.config.signals import default_config_value
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
CountInvalid, BaseVote)
from openslides.participant.models import User, Group
from openslides.projector.api import register_slidemodel
from openslides.projector.models import SlideMixin
@ -443,7 +445,10 @@ class Motion(models.Model, SlideMixin):
self.log = ""
self.log += u"%s | %s" % (datetime.now().strftime("%d.%m.%Y %H:%M:%S"), _propper_unicode(text))
if user is not None:
if isinstance(user, User):
self.log += u" (%s %s)" % (_("by"), _propper_unicode(user.username))
else:
self.log += u" (%s %s)" % (_("by"), _propper_unicode(str(user)))
self.log += "\n"
self.save()

View File

@ -8,7 +8,7 @@
<h1>{% trans "Import motions" %}</h1>
<p>{% trans 'Select a CSV file to import motions!' %}</p>
<p>{% trans 'Required comma separated values: <code>{number, title, text, reason, first_name, last_name}</code> (<code>number</code> and <code>reason</code> are optional and may be empty)' %}
<p>{% trans 'Required comma separated values: <code>{number, title, text, reason, first_name, last_name, is_group}</code> (<code>number</code>, <code>reason</code> and <code>is_group</code> are optional and may be empty)' %}
<br>
{% trans 'Required CSV file encoding: UTF-8 (Unicode).' %}
</p>

View File

@ -52,7 +52,7 @@ from openslides.projector.projector import Widget
from openslides.poll.views import PollFormView
from openslides.participant.api import gen_username, gen_password
from openslides.participant.models import User
from openslides.participant.models import User, Group
from openslides.agenda.models import Item
@ -579,6 +579,8 @@ def motion_import(request):
users_generated = 0
motions_generated = 0
motions_modified = 0
groups_assigned = 0
groups_generated = 0
with transaction.commit_on_success():
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
dialect = csv_ext.patchup(dialect)
@ -588,7 +590,11 @@ def motion_import(request):
if lno < 1:
continue
try:
(number, title, text, reason, first_name, last_name) = line[:6]
(number, title, text, reason, first_name, last_name, is_group) = line[:7]
if is_group.strip().lower() in ['y', 'j', 't', 'yes', 'ja', 'true', '1', 1]:
is_group = True
else:
is_group = False
except ValueError:
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
continue
@ -605,17 +611,43 @@ def motion_import(request):
except ValueError:
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
continue
if is_group:
# fetch existing groups or issue an error message
try:
user = Group.objects.get(name=last_name)
if user.group_as_person == False:
messages.error(request, _('Ignoring line %d because the assigned group may not act as a person.') % (lno + 1))
continue
else:
user = get_person(user.person_id)
groups_assigned += 1
except Group.DoesNotExist:
group = Group()
group.group_as_person = True
group.description = _('Created by motion import.')
group.name = last_name
group.save()
groups_generated += 1
user = get_person(group.person_id)
else:
# fetch existing users or create new users as needed
try:
user = User.objects.get(first_name=first_name, last_name=last_name)
except User.DoesNotExist:
user = None
if user is None:
if not first_name or not last_name:
messages.error(request, _('Ignoring line %d because it contains an incomplete first / last name pair.') % (lno + 1))
continue
user = User()
user.last_name = last_name
user.first_name = first_name
user.username = gen_username(first_name, last_name)
user.detail = ''
user.structure_level = ''
user.committee = ''
user.gender = ''
user.type = ''
@ -653,6 +685,12 @@ def motion_import(request):
'%d motions were successfully modified.', motions_modified) % motions_modified)
if users_generated:
messages.success(request, ungettext('%d new user was added.', '%d new users were added.', users_generated) % users_generated)
if groups_generated:
messages.success(request, ungettext('%d new group was added.', '%d new groups were added.', groups_generated) % groups_generated)
if groups_assigned:
messages.success(request, ungettext('%d group assigned to motions.', '%d groups assigned to motions.', groups_assigned) % groups_assigned)
return redirect(reverse('motion_overview'))
except csv.Error:
@ -928,4 +966,4 @@ def get_widgets(request):
display_name=_('Motions'),
template='motion/widget.html',
context={'motions': Motion.objects.all()},
permission_required='motion.can_manage_motion')]
permission_required='projector.can_manage_projector')]

View File

@ -71,7 +71,7 @@ def import_users(csv_file):
dialect=dialect)):
if line_no:
try:
(first_name, last_name, gender, detail, type, committee, comment) = line[:7]
(first_name, last_name, gender, structure_level, type, committee, comment) = line[:7]
except ValueError:
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
continue
@ -80,7 +80,7 @@ def import_users(csv_file):
user.first_name = first_name
user.username = gen_username(first_name, last_name)
user.gender = gender
user.detail = detail
user.structure_level = structure_level
user.type = type
user.committee = committee
user.comment = comment

View File

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

View File

@ -40,8 +40,8 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
)
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
detail = models.CharField(
max_length=100, blank=True, default='', verbose_name=_("Detail"),
structure_level = models.CharField(
max_length=100, blank=True, default='', verbose_name=_("Structure level"),
help_text=_('Will be shown after the name.'))
gender = models.CharField(
max_length=50, choices=GENDER_CHOICES, blank=True,
@ -67,10 +67,10 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
return self.get_full_name() or self.username
def get_name_suffix(self):
return self.detail
return self.structure_level
def set_name_suffix(self, value):
self.detail = value
self.structure_level = value
name_suffix = property(get_name_suffix, set_name_suffix)
@ -131,7 +131,8 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
register_slidemodel(User)
class Group(DjangoGroup, PersonMixin, Person):
class Group(DjangoGroup, PersonMixin, Person, SlideMixin):
prefix = 'group' # This is for the slides
person_prefix = 'group'
django_group = models.OneToOneField(DjangoGroup, editable=False, parent_link=True)
@ -161,6 +162,16 @@ class Group(DjangoGroup, PersonMixin, Person):
class Meta:
ordering = ('name',)
def slide(self):
"""
Returns a map with the data for the slides.
"""
return {
'group': self,
'title': self.name,
'template': 'projector/GroupSlide.html'}
register_slidemodel(Group)
class UsersAndGroupsToPersons(object):
"""

View File

@ -26,11 +26,11 @@
<option value="female"{% if 'female' in sortfilter.gender %} selected{% endif %}>{% trans "Female" %}</option>
<option value=""{% if '' in sortfilter.gender %} selected{% endif %}>{% trans "Not specified" %}</option>
</select>
<select class="default-input" name="detail" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Detail" %} --</option>
{% for detail in details %}
<option value="{{ detail }}"{% if detail in sortfilter.detail %} selected{% endif %}>
{{ detail }}</option>
<select class="default-input" name="structure_level" onchange="document.forms['filter'].submit()">
<option value="---">-- {% trans "Structure level" %} --</option>
{% for level in structure_levels %}
<option value="{{ level }}"{% if level in sortfilter.structure_level %} selected{% endif %}>
{{ level }}</option>
{% endfor %}
</select>
<select class="default-input" name="type" onchange="document.forms['filter'].submit()">
@ -65,7 +65,7 @@
<tr>
<th><a href="?sort=first_name&reverse={% if 'first_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "First Name" %}</a></th>
<th><a href="?sort=last_name&reverse={% if 'last_name' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Last Name" %}</a></th>
<th><a href="?sort=detail&reverse={% if 'detail' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Detail" %}</a></th>
<th><a href="?sort=structure_level&reverse={% if 'structure_level' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Structure level" %}</a></th>
<th><a href="?sort=type&reverse={% if 'type' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Type" %}</a></th>
<th><a href="?sort=committee&reverse={% if 'committee' in sortfilter.sort and 'reverse' not in sortfilter %}1{% else %}---{%endif%}">{% trans "Committee" %}</a></th>
{% if perms.participant.can_manage_participant %}
@ -78,7 +78,7 @@
<tr class="{% cycle '' 'odd' %}">
<td><a href="{% model_url user 'view' %}">{{ user.first_name }}</a></td>
<td><a href="{% model_url user 'view' %}">{{ user.last_name }}</a></td>
<td>{{ user.detail }}</td>
<td>{{ user.structure_level }}</td>
<td>{{ user.get_type_display }}</td>
<td>{{ user.committee }}</td>
{% if perms.participant.can_manage_participant %}
@ -93,10 +93,12 @@
<a href="{% url user_edit user.id %}">
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
</a>
{% if user != request_user and not user.is_superuser %}
{% if user != request_user %}
<a href="{% url user_delete user.id %}">
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
</a>
{% endif %}
{% if user != request_user and not user.is_superuser %}
<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>

View File

@ -14,7 +14,7 @@
{% endif %}
</li>
{% empty %}
<li>{% trans "None" %}</li>
<li><i>{% trans "None" %}</i></li>
{% endfor %}
</ul>
@ -33,7 +33,7 @@
{% endif %}
</li>
{% empty %}
<li>{% trans "None" %}</li>
<li><i>{% trans "None" %}</i></li>
{% endfor %}
</ul>
{% endif %}
@ -44,6 +44,6 @@
{% for assignment in assignments %}
<li><a href="{% model_url assignment 'view' %}">{{ assignment }}</a></li>
{% empty %}
<li>{% trans "None" %}</li>
<li><i>{% trans "None" %}</i></li>
{% endfor %}
</ul>

View File

@ -13,11 +13,11 @@
<h2>{% trans "Groups" %}</h2>
<p>
{% for group in shown_user.groups.all %}
{{ group }},
{% empty %}
{% if shown_user.groups.all %}
{{ shown_user.groups.all|join:", " }}
{% else %}
{% trans "The participant is not member of any group." %}
{% endfor %}
{% endif %}
</p>
{% if shown_user.get_gender_display %}

View File

@ -0,0 +1,24 @@
{% extends "base-projector.html" %}
{% load i18n %}
{% load tags %}
{% block title %}{{ block.super }} - {{ title }}{% endblock %}
{% block content %}
<div class="item_fullscreen">{{ group }}
<span>
<p><i>{{ group.user_set.all.count }} {% trans "participants" %}:</i></p>
<p>
{% if group.user_set.all %}
{{ group.user_set.all|join:", " }}
{% endif %}
</p>
</span>
</div>
{% endblock %}
{% block scrollcontent %}
{% endblock %}

View File

@ -6,38 +6,16 @@
{% block title %}{{ block.super }} - {{ title }}{% endblock %}
{% block content %}
<div id='sidebar'>
<div class='box'>
<p><strong>{% trans "Groups" %}</strong><br />
{% for group in shown_user.groups.all %}
{{ group }},
{% empty %}
{% trans "The participant is not member of any group." %}
{% endfor %}
</p>
{% if shown_user.get_gender_display %}
<p><strong>{% trans "Gender" %}</strong><br />{{ shown_user.get_gender_display }}</p>
{% endif %}
{% if shown_user.get_type_display %}
<p><strong>{% trans "Type" %}</strong><br />{{ shown_user.get_type_display }}</p>
{% endif %}
<div class="item_fullscreen">{{ shown_user }}
<span>
{% if shown_user.committee %}
<p><strong>{% trans "Committee" %}</strong><br />{{ shown_user.committee }}</p>
<p>{{ shown_user.committee }}</p>
{% endif %}
</div>
</div>
<h1>{{ shown_user }}</h1>
<p>{{ shown_user.email }}</p>
{% endblock %}
{% block scrollcontent %}
<p>
<div class="text">{{ shown_user.about_me|linebreaks }}</div>
{% if shown_user.groups.all %}
{{ shown_user.groups.all|join:", " }}
{% endif %}
</p>
</span>
</div>
{% endblock %}

View File

@ -38,7 +38,7 @@ class UserTest(TestCase):
self.assertEqual(unicode(self.user1), 'Max Mustermann')
def test_name_suffix(self):
self.user1.detail = 'München'
self.user1.structure_level = 'München'
self.user1.save()
self.assertEqual(unicode(self.user1), 'Max Mustermann (München)')

View File

@ -71,7 +71,7 @@ class UserOverview(ListView):
except KeyError:
sortfilter = {}
for value in ['gender', 'detail', 'type', 'committee', 'status',
for value in ['gender', 'structure_level', 'type', 'committee', 'status',
'sort', 'reverse']:
if value in self.request.REQUEST:
if self.request.REQUEST[value] == '---':
@ -85,8 +85,8 @@ class UserOverview(ListView):
query = User.objects
if 'gender' in sortfilter:
query = query.filter(gender__iexact=sortfilter['gender'][0])
if 'detail' in sortfilter:
query = query.filter(detail__iexact=sortfilter['detail'][0])
if 'structure_level' in sortfilter:
query = query.filter(structure_level__iexact=sortfilter['structure_level'][0])
if 'type' in sortfilter:
query = query.filter(type__iexact=sortfilter['type'][0])
if 'committee' in sortfilter:
@ -97,7 +97,7 @@ class UserOverview(ListView):
if sortfilter['sort'][0] in ['first_name', 'last_name', 'last_login']:
query = query.order_by(sortfilter['sort'][0])
elif (sortfilter['sort'][0] in
['detail', 'type', 'committee', 'comment']):
['structure_level', 'type', 'committee', 'comment']):
query = query.order_by(
'%s' % sortfilter['sort'][0])
else:
@ -125,8 +125,8 @@ class UserOverview(ListView):
percent = 0
# list of all existing categories
details = [p['detail'] for p in User.objects.values('detail')
.exclude(detail='').distinct()]
structure_levels = [p['structure_level'] for p in User.objects.values('structure_level')
.exclude(structure_level='').distinct()]
# list of all existing committees
committees = [p['committee'] for p in User.objects.values('committee')
.exclude(committee='').distinct()]
@ -135,7 +135,7 @@ class UserOverview(ListView):
'allusers': all_users,
'request_user': self.request.user,
'percent': round(percent, 1),
'details': details,
'structure_levels': structure_levels,
'committees': committees,
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
doseq=True)],
@ -208,8 +208,6 @@ class UserDeleteView(DeleteView):
def pre_redirect(self, request, *args, **kwargs):
if self.get_object() == self.request.user:
messages.error(request, _("You can not delete yourself."))
elif self.get_object().is_superuser:
messages.error(request, _("You can not delete the administrator."))
else:
super(DeleteView, self).pre_redirect(request, *args, **kwargs)
@ -268,8 +266,8 @@ class ParticipantsListPDF(PDFView):
counter,
Paragraph(user.last_name, stylesheet['Tablecell']),
Paragraph(user.first_name, stylesheet['Tablecell']),
Paragraph(user.detail, stylesheet['Tablecell']),
Paragraph(user.type, stylesheet['Tablecell']),
Paragraph(user.structure_level, stylesheet['Tablecell']),
Paragraph(user.get_type_display(), stylesheet['Tablecell']),
Paragraph(user.committee, stylesheet['Tablecell'])])
t = LongTable(data, style=[
('VALIGN', (0, 0), (-1, -1), 'TOP'),

View File

@ -155,6 +155,10 @@ body{
font-weight:bold;
text-align: center;
}
.item_fullscreen span
{
font-size: 50%; font-weight:normal;
}
/* items in a list*/
.itemlist li

View File

@ -15,27 +15,6 @@
{% block content %}
<h1>{% trans 'Dashboard' %}</h1>
{% if perms.projector.can_manage_projector %}
<div style="text-align: right; padding: 0 10px 5px 0; margin-top:-20px;">
<!-- control projector view -->
{% trans "Adjust projector view" %}:
<a class="projector_edit" href="{% url projector_bigger %}" title="{% trans 'Zoom in' %}">
<img src="{% static 'images/icons/zoom-in.png' %}" />
</a>
<a class="projector_edit" href="{% url projector_smaller %}" title="{% trans 'Zoom out' %}">
<img src="{% static 'images/icons/zoom-out.png' %}" />
</a>
<a class="projector_edit" href="{% url projector_up %}" title="{% trans 'Scroll text up' %}">
<img src="{% static 'images/icons/go-up.png' %}" />
</a>
<a class="projector_edit" href="{% url projector_down %}" title="{% trans 'Scroll text down' %}">
<img src="{% static 'images/icons/go-down.png' %}" />
</a>
<a class="projector_edit" href="{% url projector_clean %}" title="{% trans 'Reset projector view' %}">
<img src="{% static 'images/icons/view-reset.png' %}" />
</a>
</div>
{% endif %}
<div class="column" id="col1">
{% for name, widget in widgets.items %}

View File

@ -4,6 +4,5 @@
{% load i18n %}
{% block content %}
<h1>{% get_config 'frontpage_title' %}</h1>
{% get_config 'frontpage_welcometext' %}
<div class="item_fullscreen">{% get_config 'welcome_title' %}</div>
{% endblock %}

View File

@ -1,7 +1,36 @@
{% load i18n %}
{% load tags %}
{% load staticfiles %}
<!-- projector control buttons -->
{% if perms.projector.can_manage_projector %}
<div style="float: right;">
<p>
<a class="projector_edit" href="{% url projector_bigger %}" title="{% trans 'Zoom in' %}">
<img src="{% static 'images/icons/zoom-in.png' %}" />
</a><br>
<a class="projector_edit" href="{% url projector_smaller %}" title="{% trans 'Zoom out' %}">
<img src="{% static 'images/icons/zoom-out.png' %}" />
</a>
</p>
<p>
<a class="projector_edit" href="{% url projector_up %}" title="{% trans 'Scroll text up' %}">
<img src="{% static 'images/icons/go-up.png' %}" />
</a><br>
<a class="projector_edit" href="{% url projector_down %}" title="{% trans 'Scroll text down' %}">
<img src="{% static 'images/icons/go-down.png' %}" />
</a>
</p>
<p>
<a class="projector_edit" href="{% url projector_clean %}" title="{% trans 'Reset projector view' %}">
<img src="{% static 'images/icons/view-reset.png' %}" />
</a>
</p>
</div>
{% endif %}
<!-- projector view -->
<a href="{% url projector_show %}" target="_blank">
<div id="iframewrapper">
<iframe id="iframe" src="{% url projector_show %}" frameborder="0"></iframe>

View File

@ -1 +0,0 @@
{{ welcometext|safe|linebreaks }}

View File

@ -22,6 +22,7 @@ from django.db import transaction
from django.db.models import Q
from django.dispatch import receiver
from django.shortcuts import redirect
from django.template import RequestContext
from django.utils.datastructures import SortedDict
from django.utils.importlib import import_module
from django.utils.translation import ugettext_lazy as _
@ -396,10 +397,10 @@ def get_widgets(request):
# welcome widget
context = {
'welcometext': config['frontpage_welcometext']}
'welcometext': config['welcome_text']}
widgets.append(Widget(
name='welcome',
display_name=config['frontpage_title'],
display_name=config['welcome_title'],
template='projector/welcome_widget.html',
context=context,
permission_required='projector.can_see_dashboard',
@ -410,6 +411,7 @@ def get_widgets(request):
name='live_view',
display_name=_('Projector live view'),
template='projector/live_view_widget.html',
context = RequestContext(request, {}),
permission_required='projector.can_see_projector',
default_column=2))

View File

@ -316,7 +316,7 @@ input[type="submit"], input[type="button"] {
padding:4px 10px !important;
margin: 2px 0 2px 0;
}
#id_permissions {
#id_permissions, #id_users {
height: 310px;
}
.button {

View File

@ -76,7 +76,7 @@
{% endblock %}
<div id="footer">
<small>
&copy; Copyright 2011-2012 | Powered by <a href="http://openslides.org" target="_blank">OpenSlides</a> | Get <a href="http://openslides.org/support" target="_blank">professional support</a> for OpenSlides.
&copy; Copyright 2011-2012 | Powered by <a href="http://openslides.org" target="_blank">OpenSlides</a> | {% trans "Get <a href='http://openslides.org/support' target='_blank'>professional support</a> for OpenSlides." %}
</small>
</div>
</div>

View File

@ -1,29 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ block.super }} {% trans "Home" %}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p>{{ welcometext|safe|linebreaks }}</p>
{% trans "You have access to the following pages:" %}
<ul>
{% for app in apps %}
<li><a href="{{ app.url }}">{{ app.title }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% block submenu %}
{% if perms.projector.can_see_projector %}
<h4 class="sectiontitle">{% trans "Home" %}</h4>
<ul>
<li>
<a href="{% url projector_show %}"><img src="{% static 'images/icons/projector.png' %}"> {% trans 'Projector view' %}</a>
</li>
</ul>
{% endif %}
{% endblock %}

View File

@ -16,14 +16,13 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.shortcuts import redirect
from django.utils.importlib import import_module
from openslides.utils.views import FrontPage
from openslides.utils.views import RedirectView
handler500 = 'openslides.utils.views.server_error'
urlpatterns = patterns('',
# frontpage
(r'^$', FrontPage.as_view()),
# Redirect to dashboard URL
url(r'^$', RedirectView.as_view(url='dashboard'), name='home',),
(r'^agenda/', include('openslides.agenda.urls')),
(r'^motion/', include('openslides.motion.urls')),

View File

@ -20,6 +20,7 @@ from reportlab.pdfbase.ttfonts import TTFont
from reportlab.rl_config import defaultPageSize
from django.conf import settings
from django.utils import formats
# Import gettext for python 2.5 support
from django.utils.translation import ugettext as _, gettext
@ -222,8 +223,8 @@ def firstPage(canvas, doc):
# time
canvas.setFont('Ubuntu', 7)
time = datetime.now().strftime(gettext("%Y-%m-%d %H:%Mh"))
canvas.drawString(15 * cm, 28 * cm, _("Printed: %s") % time)
time = formats.date_format(datetime.now(), 'DATETIME_FORMAT')
canvas.drawString(15 * cm, 28 * cm, _("As of: %s") % time)
# title
if doc.title:

View File

@ -358,33 +358,6 @@ class PDFView(PermissionMixin, View):
return self.render_to_response(self.get_filename())
class FrontPage(TemplateView):
template_name = 'front_page.html'
def has_permission(self, request):
if request.user.is_authenticated() or config['system_enable_anonymous']:
return True
return False
def get_context_data(self, **kwargs):
context = super(FrontPage, self).get_context_data(**kwargs)
apps = []
for app in settings.INSTALLED_APPS:
try:
mod = import_module(app + '.views')
tab = mod.register_tab(self.request)
except (ImportError, AttributeError):
continue
if tab.permission:
apps.append(tab)
context.update({
'apps': apps,
'title': config['frontpage_title'],
'welcometext': config['frontpage_welcometext'],
})
return context
def server_error(request, template_name='500.html'):
"""
500 error handler.