Merge branch 'master' of github.com:OpenSlides/OpenSlides into sort_person_api
This commit is contained in:
commit
8014f327a2
11
INSTALL.txt
11
INSTALL.txt
@ -98,13 +98,12 @@ II. Installation on GNU/Linux and MacOSX
|
|||||||
|
|
||||||
OR
|
OR
|
||||||
|
|
||||||
b) Clone development version from mercurial repository
|
b) Clone development version from OpenSlides' github repository
|
||||||
http://hg.openslides.org. This requires Mercurial source control
|
https://github.com/OpenSlides/OpenSlides.
|
||||||
management (hg):
|
This requires Git, see http://git-scm.com/.
|
||||||
|
Open command line (cmd) and run:
|
||||||
|
|
||||||
E.g. for Ubuntu run:
|
git clone git://github.com/OpenSlides/OpenSlides.git
|
||||||
$ sudo apt-get install mercurial
|
|
||||||
$ hg clone http://hg.openslides.org OpenSlides
|
|
||||||
|
|
||||||
3. Setup your virtual environment with virtualenv:
|
3. Setup your virtual environment with virtualenv:
|
||||||
|
|
||||||
|
@ -6,17 +6,11 @@ How to create a new portable Windows distribution of OpenSlides:
|
|||||||
|
|
||||||
easy_install -Z django django-mptt reportlab pil
|
easy_install -Z django django-mptt reportlab pil
|
||||||
|
|
||||||
2.) Install OpenSlides by running in the top directory:
|
2.) Run in the main directory of the OpenSlides checkout:
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
python extras\win32-portable\prepare_portable.py
|
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
|
in the 'dist' directory
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@ import zipfile
|
|||||||
import distutils.ccompiler
|
import distutils.ccompiler
|
||||||
import distutils.sysconfig
|
import distutils.sysconfig
|
||||||
|
|
||||||
from contextlib import nested
|
|
||||||
|
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
sys.path.insert(0, os.getcwd())
|
||||||
@ -80,10 +78,7 @@ SITE_PACKAGES = {
|
|||||||
"pil": {
|
"pil": {
|
||||||
# NOTE: PIL is a special case, see copy_pil
|
# NOTE: PIL is a special case, see copy_pil
|
||||||
"copy": [],
|
"copy": [],
|
||||||
},
|
}
|
||||||
"openslides": {
|
|
||||||
"copy" : ["openslides"],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PY_DLLS = [
|
PY_DLLS = [
|
||||||
@ -297,9 +292,13 @@ def main():
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
os.makedirs(odir)
|
os.makedirs(odir)
|
||||||
|
out_site_packages = os.path.join(odir, "site-packages")
|
||||||
|
|
||||||
collect_lib(libdir, odir)
|
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():
|
if not compile_openslides_launcher():
|
||||||
sys.stdout.write("Using prebuild openslides.exe\n")
|
sys.stdout.write("Using prebuild openslides.exe\n")
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"pk": 1,
|
"pk": 1,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Beobachter",
|
"name": "Beobachter/in",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
[
|
[
|
||||||
"can_see_agenda",
|
"can_see_agenda",
|
||||||
@ -57,7 +57,7 @@
|
|||||||
"pk": 2,
|
"pk": 2,
|
||||||
"model": "auth.group",
|
"model": "auth.group",
|
||||||
"fields": {
|
"fields": {
|
||||||
"name": "Delegierter",
|
"name": "Delegierte/r",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
[
|
[
|
||||||
"can_see_agenda",
|
"can_see_agenda",
|
||||||
|
@ -231,4 +231,4 @@ def get_widgets(request):
|
|||||||
context={
|
context={
|
||||||
'agenda': SLIDE['agenda'],
|
'agenda': SLIDE['agenda'],
|
||||||
'items': Item.objects.all()},
|
'items': Item.objects.all()},
|
||||||
permission_required='agenda.can_manage_agenda')]
|
permission_required='projector.can_manage_projector')]
|
||||||
|
@ -85,7 +85,7 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
raise NameError(_('<b>%s</b> is already a candidate.') % candidate)
|
raise NameError(_('<b>%s</b> is already a candidate.') % candidate)
|
||||||
if not person.has_perm("assignment.can_manage_assignment") and self.status != 'sea':
|
if not person.has_perm("assignment.can_manage_assignment") and self.status != 'sea':
|
||||||
raise NameError(_('The candidate list is already closed.'))
|
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 \
|
if candidation and candidate != person and \
|
||||||
not person.has_perm("assignment.can_manage_assignment"):
|
not person.has_perm("assignment.can_manage_assignment"):
|
||||||
# if the candidation is blocked and anotherone tries to run the
|
# 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
|
stop running for a vote
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
candidation = self.assignment_candidats.get(person=candidate)
|
candidation = self.assignment_candidates.get(person=candidate)
|
||||||
except AssignmentCandidate.DoesNotExist:
|
except AssignmentCandidate.DoesNotExist:
|
||||||
# TODO: Use an OpenSlides Error
|
|
||||||
raise Exception(_('%s is no candidate') % candidate)
|
raise Exception(_('%s is no candidate') % candidate)
|
||||||
|
|
||||||
if not candidation.blocked:
|
if not candidation.blocked:
|
||||||
@ -123,7 +122,7 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
return True, if person is a candidate.
|
return True, if person is a candidate.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return self.assignment_candidats.filter(person=person) \
|
return self.assignment_candidates.filter(person=person) \
|
||||||
.exclude(blocked=True).exists()
|
.exclude(blocked=True).exists()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return False
|
||||||
@ -132,11 +131,11 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
"""
|
"""
|
||||||
return True, if the person is blockt for candidation.
|
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()
|
.filter(blocked=True).exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def assignment_candidats(self):
|
def assignment_candidates(self):
|
||||||
return AssignmentCandidate.objects.filter(assignment=self)
|
return AssignmentCandidate.objects.filter(assignment=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -148,7 +147,7 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
return self.get_participants(only_elected=True)
|
return self.get_participants(only_elected=True)
|
||||||
|
|
||||||
def get_participants(self, only_elected=False, only_candidate=False):
|
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)
|
assert not (only_elected and only_candidate)
|
||||||
|
|
||||||
@ -167,7 +166,7 @@ class Assignment(models.Model, SlideMixin):
|
|||||||
|
|
||||||
|
|
||||||
def set_elected(self, person, value=True):
|
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.elected = value
|
||||||
candidate.save()
|
candidate.save()
|
||||||
|
|
||||||
@ -293,7 +292,7 @@ class AssignmentPoll(BasePoll, CountInvalid, CountVotesCast, PublishPollMixin):
|
|||||||
self.yesnoabstain = True
|
self.yesnoabstain = True
|
||||||
else:
|
else:
|
||||||
# candidates <= available posts -> yes/no/abstain
|
# 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
|
self.yesnoabstain = True
|
||||||
else:
|
else:
|
||||||
self.yesnoabstain = False
|
self.yesnoabstain = False
|
||||||
|
@ -32,10 +32,11 @@
|
|||||||
{% if assignment.active %}activeline{% endif %}">
|
{% if assignment.active %}activeline{% endif %}">
|
||||||
<td><a href="{% url assignment_view assignment.id %}">{{ assignment }}</a></td>
|
<td><a href="{% url assignment_view assignment.id %}">{{ assignment }}</a></td>
|
||||||
<td>
|
<td>
|
||||||
{{ assignment.posts }} {% trans "posts" %} / {{ assignment.elected|length }} {% trans "elected" %}
|
{% blocktrans with posts=assignment.posts %}posts: {{ posts }}{% endblocktrans %}
|
||||||
{% if assignment.status != 'fin' %}
|
{% if assignment.status != 'fin' %}
|
||||||
/ {{ assignment.candidates|length }} {% trans "candidates" %}
|
| {% blocktrans with candidates=assignment.get_participants|length %}candidates: {{ candidates }}{% endblocktrans %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
| {% blocktrans with elected=assignment.elected|length %}elected: {{ elected }}{% endblocktrans %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ assignment.get_status_display }}</td>
|
<td>{{ assignment.get_status_display }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -33,9 +33,10 @@
|
|||||||
<h1>{{ assignment }}</h1>
|
<h1>{{ assignment }}</h1>
|
||||||
<p>{{ assignment.description|linebreaks }}</p>
|
<p>{{ assignment.description|linebreaks }}</p>
|
||||||
|
|
||||||
|
{% if assignment.status != "fin" %}
|
||||||
<h3>{% trans "Candidates" %}</h3>
|
<h3>{% trans "Candidates" %}</h3>
|
||||||
<ol>
|
<ol>
|
||||||
{% for person in assignment.candidates %}
|
{% for person in assignment.get_participants %}
|
||||||
<li>
|
<li>
|
||||||
{{ person }}
|
{{ person }}
|
||||||
{% if perms.assignment.can_manage_assignment %}
|
{% 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>
|
<a href="{% url assignment_delother assignment.id person.person_id %}"><img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Remove candidate' %}"></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% 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>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li style="list-style: none outside none;"><i>{% trans "No candidates available." %}</i></li>
|
<li style="list-style: none outside none;"><i>{% trans "No candidates available." %}</i></li>
|
||||||
@ -85,27 +94,11 @@
|
|||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h3>{% trans "Elected Candidates" %}</h3>
|
{% if perms.assignment.can_manage_assignments and blocked_candidates and assignment.status != "fin" %}
|
||||||
<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 %}
|
|
||||||
<h3>{% trans "Blocked Candidates" %}</h3>
|
<h3>{% trans "Blocked Candidates" %}</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for person in blocked_candidates %}
|
{% for person in blocked_candidates %}
|
||||||
@ -118,20 +111,11 @@
|
|||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if assignment.status != "sea" or polls.exists %}
|
||||||
<h3>{% trans "Election results" %}</h3>
|
<h3>{% trans "Election results" %}</h3>
|
||||||
|
|
||||||
{% if polls.exists %}
|
{% if polls.exists %}
|
||||||
<table id="election_table" style="width: auto;">
|
<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>
|
<tr>
|
||||||
<th>{% trans "Candidates" %}</th>
|
<th>{% trans "Candidates" %}</th>
|
||||||
{% for poll in polls %}
|
{% for poll in polls %}
|
||||||
@ -161,7 +145,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for candidate, poll_list in vote_results.items %}
|
{% for candidate, poll_list in vote_results.items %}
|
||||||
<tr class="{% cycle 'odd' '' %}">
|
<tr class="{% cycle 'odd' '' as rowcolors %}">
|
||||||
<td class="candidate">
|
<td class="candidate">
|
||||||
{% if candidate in assignment.elected %}
|
{% if candidate in assignment.elected %}
|
||||||
{% if perms.assignment.can_manage_assignment %}
|
{% if perms.assignment.can_manage_assignment %}
|
||||||
@ -198,8 +182,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<tr class="{% cycle rowcolors %}">
|
||||||
<tr>
|
|
||||||
<td>{% trans 'Invalid votes' %}</td>
|
<td>{% trans 'Invalid votes' %}</td>
|
||||||
{% for poll in polls %}
|
{% for poll in polls %}
|
||||||
{% if poll.published or perms.assignment.can_manage_assignment %}
|
{% if poll.published or perms.assignment.can_manage_assignment %}
|
||||||
@ -215,7 +198,6 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="total">
|
<tr class="total">
|
||||||
<td><strong>{% trans 'Votes cast' %}</strong></td>
|
<td><strong>{% trans 'Votes cast' %}</strong></td>
|
||||||
{% for poll in polls %}
|
{% for poll in polls %}
|
||||||
@ -233,11 +215,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
{% else %}
|
||||||
{% else %}
|
<i>{% trans "No results available." %}</i>
|
||||||
|
|
||||||
<i>{% trans "No ballots available." %}</i>
|
|
||||||
|
|
||||||
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
|
{% if assignment.candidates and perms.assignment.can_manage_assignment and assignment.status == "vot" %}
|
||||||
<p><a href='{% url assignment_gen_poll assignment.id %}'>
|
<p><a href='{% url assignment_gen_poll assignment.id %}'>
|
||||||
<span class="button">
|
<span class="button">
|
||||||
@ -245,9 +224,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</a></p>
|
</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% for candidate, poll_list in vote_results.items %}
|
{% 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 %}">
|
<td class="candidate{% if candidate in assignment.elected %} elected{% endif %}">
|
||||||
{% if candidate in assignment.elected %}
|
{% if candidate in assignment.elected %}
|
||||||
<a class="elected">
|
<a class="elected">
|
||||||
@ -92,8 +92,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<tr class="{% cycle rowcolors %}">
|
||||||
<tr>
|
|
||||||
<td>{% trans 'Invalid votes' %}</td>
|
<td>{% trans 'Invalid votes' %}</td>
|
||||||
{% for poll in polls %}
|
{% for poll in polls %}
|
||||||
<td style="white-space:nowrap;">
|
<td style="white-space:nowrap;">
|
||||||
@ -105,7 +104,6 @@
|
|||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="total">
|
<tr class="total">
|
||||||
<td>
|
<td>
|
||||||
<strong>{% trans 'Votes cast' %}</strong>
|
<strong>{% trans 'Votes cast' %}</strong>
|
||||||
@ -120,12 +118,6 @@
|
|||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
{% elif some_polls_available %}
|
|
||||||
<i>{% trans "Vote results are not published yet." %}</i>
|
|
||||||
{% elif assignment.candidates %}
|
|
||||||
<i>{% trans "No ballots available." %}</i>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<br>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -101,7 +101,7 @@ def view(request, assignment_id=None):
|
|||||||
vote_results = assignment.vote_results(only_published=False)
|
vote_results = assignment.vote_results(only_published=False)
|
||||||
|
|
||||||
blocked_candidates = [candidate.person for candidate in \
|
blocked_candidates = [candidate.person for candidate in \
|
||||||
assignment.assignment_candidats.filter(blocked=True)]
|
assignment.assignment_candidates.filter(blocked=True)]
|
||||||
return {
|
return {
|
||||||
'assignment': assignment,
|
'assignment': assignment,
|
||||||
'blocked_candidates': blocked_candidates,
|
'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())
|
messages.success(request, _('Election status was set to: <b>%s</b>.') % assignment.get_status_display())
|
||||||
except Assignment.DoesNotExist:
|
except Assignment.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
except NameError, e:
|
||||||
|
messages.error(request, e)
|
||||||
return redirect(reverse('assignment_view', args=[assignment_id]))
|
return redirect(reverse('assignment_view', args=[assignment_id]))
|
||||||
|
|
||||||
|
|
||||||
@ -678,4 +680,4 @@ def get_widgets(request):
|
|||||||
display_name=_('Elections'),
|
display_name=_('Elections'),
|
||||||
template='assignment/widget.html',
|
template='assignment/widget.html',
|
||||||
context={'assignments': Assignment.objects.all()},
|
context={'assignments': Assignment.objects.all()},
|
||||||
permission_required='assignment.can_manage_assignment')]
|
permission_required='projector.can_manage_projector')]
|
||||||
|
@ -56,13 +56,13 @@ class GeneralConfigForm(forms.Form, CssClassMixin):
|
|||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
frontpage_title = forms.CharField(
|
welcome_title = forms.CharField(
|
||||||
widget=forms.TextInput(),
|
widget=forms.TextInput(),
|
||||||
label=_("Title"),
|
label=_("Title"),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
frontpage_welcometext = forms.CharField(
|
welcome_text = forms.CharField(
|
||||||
widget=forms.Textarea(),
|
widget=forms.Textarea(),
|
||||||
label=_("Welcome text"),
|
label=_("Welcome text"),
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -86,8 +86,8 @@ def default_config(sender, key, **kwargs):
|
|||||||
'event_location': '',
|
'event_location': '',
|
||||||
'event_organizer': '',
|
'event_organizer': '',
|
||||||
'presentation': '',
|
'presentation': '',
|
||||||
'frontpage_title': _('Welcome to OpenSlides'),
|
'welcome_title': _('Welcome to OpenSlides'),
|
||||||
'frontpage_welcometext': _('[Place for your welcome text.]'),
|
'welcome_text': _('[Place for your welcome text.]'),
|
||||||
'system_enable_anonymous': False,
|
'system_enable_anonymous': False,
|
||||||
}.get(key)
|
}.get(key)
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<p></p>
|
<p></p>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "Frontpage" %}</legend>
|
<legend>{% trans "Welcome Widget" %}</legend>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
{% if "id_frontpage" in field.label_tag %}
|
{% if "id_welcome" in field.label_tag %}
|
||||||
<p>
|
<p>
|
||||||
{{ field.errors }}
|
{{ field.errors }}
|
||||||
{{ field.required }}
|
{{ field.required }}
|
||||||
|
@ -41,8 +41,8 @@ class GeneralConfig(FormView):
|
|||||||
'event_date': config['event_date'],
|
'event_date': config['event_date'],
|
||||||
'event_location': config['event_location'],
|
'event_location': config['event_location'],
|
||||||
'event_organizer': config['event_organizer'],
|
'event_organizer': config['event_organizer'],
|
||||||
'frontpage_title': config['frontpage_title'],
|
'welcome_title': config['welcome_title'],
|
||||||
'frontpage_welcometext': config['frontpage_welcometext'],
|
'welcome_text': config['welcome_text'],
|
||||||
'system_enable_anonymous': config['system_enable_anonymous'],
|
'system_enable_anonymous': config['system_enable_anonymous'],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,10 +54,9 @@ class GeneralConfig(FormView):
|
|||||||
config['event_location'] = form.cleaned_data['event_location']
|
config['event_location'] = form.cleaned_data['event_location']
|
||||||
config['event_organizer'] = form.cleaned_data['event_organizer']
|
config['event_organizer'] = form.cleaned_data['event_organizer']
|
||||||
|
|
||||||
# frontpage
|
# welcome widget
|
||||||
config['frontpage_title'] = form.cleaned_data['frontpage_title']
|
config['welcome_title'] = form.cleaned_data['welcome_title']
|
||||||
config['frontpage_welcometext'] = \
|
config['welcome_text'] = form.cleaned_data['welcome_text']
|
||||||
form.cleaned_data['frontpage_welcometext']
|
|
||||||
|
|
||||||
# system
|
# system
|
||||||
if form.cleaned_data['system_enable_anonymous']:
|
if form.cleaned_data['system_enable_anonymous']:
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,8 @@ from openslides.config.signals import default_config_value
|
|||||||
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
from openslides.poll.models import (BaseOption, BasePoll, CountVotesCast,
|
||||||
CountInvalid, BaseVote)
|
CountInvalid, BaseVote)
|
||||||
|
|
||||||
|
from openslides.participant.models import User, Group
|
||||||
|
|
||||||
from openslides.projector.api import register_slidemodel
|
from openslides.projector.api import register_slidemodel
|
||||||
from openslides.projector.models import SlideMixin
|
from openslides.projector.models import SlideMixin
|
||||||
|
|
||||||
@ -443,7 +445,10 @@ class Motion(models.Model, SlideMixin):
|
|||||||
self.log = ""
|
self.log = ""
|
||||||
self.log += u"%s | %s" % (datetime.now().strftime("%d.%m.%Y %H:%M:%S"), _propper_unicode(text))
|
self.log += u"%s | %s" % (datetime.now().strftime("%d.%m.%Y %H:%M:%S"), _propper_unicode(text))
|
||||||
if user is not None:
|
if user is not None:
|
||||||
self.log += u" (%s %s)" % (_("by"), _propper_unicode(user.username))
|
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.log += "\n"
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<h1>{% trans "Import motions" %}</h1>
|
<h1>{% trans "Import motions" %}</h1>
|
||||||
<p>{% trans 'Select a CSV file to import motions!' %}</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, is_group}</code> (<code>number</code>, <code>reason</code> and <code>is_group</code> are optional and may be empty)' %}
|
||||||
<br>
|
<br>
|
||||||
{% trans 'Required CSV file encoding: UTF-8 (Unicode).' %}
|
{% trans 'Required CSV file encoding: UTF-8 (Unicode).' %}
|
||||||
</p>
|
</p>
|
||||||
|
@ -52,7 +52,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 User
|
from openslides.participant.models import User, Group
|
||||||
|
|
||||||
from openslides.agenda.models import Item
|
from openslides.agenda.models import Item
|
||||||
|
|
||||||
@ -579,6 +579,8 @@ def motion_import(request):
|
|||||||
users_generated = 0
|
users_generated = 0
|
||||||
motions_generated = 0
|
motions_generated = 0
|
||||||
motions_modified = 0
|
motions_modified = 0
|
||||||
|
groups_assigned = 0
|
||||||
|
groups_generated = 0
|
||||||
with transaction.commit_on_success():
|
with transaction.commit_on_success():
|
||||||
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
|
dialect = csv.Sniffer().sniff(request.FILES['csvfile'].readline())
|
||||||
dialect = csv_ext.patchup(dialect)
|
dialect = csv_ext.patchup(dialect)
|
||||||
@ -588,7 +590,11 @@ def motion_import(request):
|
|||||||
if lno < 1:
|
if lno < 1:
|
||||||
continue
|
continue
|
||||||
try:
|
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:
|
except ValueError:
|
||||||
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
||||||
continue
|
continue
|
||||||
@ -605,24 +611,50 @@ def motion_import(request):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
messages.error(request, _('Ignoring malformed line %d in import file.') % (lno + 1))
|
||||||
continue
|
continue
|
||||||
# fetch existing users or create new users as needed
|
|
||||||
try:
|
if is_group:
|
||||||
user = User.objects.get(first_name=first_name, last_name=last_name)
|
# fetch existing groups or issue an error message
|
||||||
except User.DoesNotExist:
|
try:
|
||||||
user = None
|
user = Group.objects.get(name=last_name)
|
||||||
if user is None:
|
if user.group_as_person == False:
|
||||||
user = User()
|
messages.error(request, _('Ignoring line %d because the assigned group may not act as a person.') % (lno + 1))
|
||||||
user.last_name = last_name
|
continue
|
||||||
user.first_name = first_name
|
else:
|
||||||
user.username = gen_username(first_name, last_name)
|
user = get_person(user.person_id)
|
||||||
user.detail = ''
|
|
||||||
user.committee = ''
|
groups_assigned += 1
|
||||||
user.gender = ''
|
except Group.DoesNotExist:
|
||||||
user.type = ''
|
group = Group()
|
||||||
user.default_password = gen_password()
|
group.group_as_person = True
|
||||||
user.save()
|
group.description = _('Created by motion import.')
|
||||||
user.reset_password()
|
group.name = last_name
|
||||||
users_generated += 1
|
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.structure_level = ''
|
||||||
|
user.committee = ''
|
||||||
|
user.gender = ''
|
||||||
|
user.type = ''
|
||||||
|
user.default_password = gen_password()
|
||||||
|
user.save()
|
||||||
|
user.reset_password()
|
||||||
|
users_generated += 1
|
||||||
# create / modify the motion
|
# create / modify the motion
|
||||||
motion = None
|
motion = None
|
||||||
if number:
|
if number:
|
||||||
@ -653,6 +685,12 @@ def motion_import(request):
|
|||||||
'%d motions were successfully modified.', motions_modified) % motions_modified)
|
'%d motions were successfully modified.', motions_modified) % motions_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)
|
||||||
|
|
||||||
|
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'))
|
return redirect(reverse('motion_overview'))
|
||||||
|
|
||||||
except csv.Error:
|
except csv.Error:
|
||||||
@ -928,4 +966,4 @@ def get_widgets(request):
|
|||||||
display_name=_('Motions'),
|
display_name=_('Motions'),
|
||||||
template='motion/widget.html',
|
template='motion/widget.html',
|
||||||
context={'motions': Motion.objects.all()},
|
context={'motions': Motion.objects.all()},
|
||||||
permission_required='motion.can_manage_motion')]
|
permission_required='projector.can_manage_projector')]
|
||||||
|
@ -71,7 +71,7 @@ def import_users(csv_file):
|
|||||||
dialect=dialect)):
|
dialect=dialect)):
|
||||||
if line_no:
|
if line_no:
|
||||||
try:
|
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:
|
except ValueError:
|
||||||
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
|
error_messages.append(_('Ignoring malformed line %d in import file.') % line_no + 1)
|
||||||
continue
|
continue
|
||||||
@ -80,7 +80,7 @@ def import_users(csv_file):
|
|||||||
user.first_name = first_name
|
user.first_name = first_name
|
||||||
user.username = gen_username(first_name, last_name)
|
user.username = gen_username(first_name, last_name)
|
||||||
user.gender = gender
|
user.gender = gender
|
||||||
user.detail = detail
|
user.structure_level = structure_level
|
||||||
user.type = type
|
user.type = type
|
||||||
user.committee = committee
|
user.committee = committee
|
||||||
user.comment = comment
|
user.comment = comment
|
||||||
|
@ -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', 'detail',
|
fields = ('first_name', 'last_name', 'is_active', 'groups', 'structure_level',
|
||||||
'gender', 'type', 'committee', 'about_me', 'comment', 'default_password')
|
'gender', 'type', 'committee', 'about_me', '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',
|
||||||
'detail', 'gender', 'type', 'committee', 'about_me', 'comment',
|
'structure_level', 'gender', 'type', 'committee', 'about_me', 'comment',
|
||||||
'default_password')
|
'default_password')
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,8 +40,8 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
|
django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True)
|
||||||
detail = models.CharField(
|
structure_level = models.CharField(
|
||||||
max_length=100, blank=True, default='', verbose_name=_("Detail"),
|
max_length=100, blank=True, default='', verbose_name=_("Structure level"),
|
||||||
help_text=_('Will be shown after the name.'))
|
help_text=_('Will be shown after the name.'))
|
||||||
gender = models.CharField(
|
gender = models.CharField(
|
||||||
max_length=50, choices=GENDER_CHOICES, blank=True,
|
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
|
return self.get_full_name() or self.username
|
||||||
|
|
||||||
def get_name_suffix(self):
|
def get_name_suffix(self):
|
||||||
return self.detail
|
return self.structure_level
|
||||||
|
|
||||||
def set_name_suffix(self, value):
|
def set_name_suffix(self, value):
|
||||||
self.detail = value
|
self.structure_level = value
|
||||||
|
|
||||||
name_suffix = property(get_name_suffix, set_name_suffix)
|
name_suffix = property(get_name_suffix, set_name_suffix)
|
||||||
|
|
||||||
@ -131,7 +131,8 @@ class User(DjangoUser, PersonMixin, Person, SlideMixin):
|
|||||||
|
|
||||||
register_slidemodel(User)
|
register_slidemodel(User)
|
||||||
|
|
||||||
class Group(DjangoGroup, PersonMixin, Person):
|
class Group(DjangoGroup, PersonMixin, Person, SlideMixin):
|
||||||
|
prefix = 'group' # This is for the slides
|
||||||
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)
|
||||||
@ -161,6 +162,16 @@ class Group(DjangoGroup, PersonMixin, Person):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('name',)
|
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):
|
class UsersAndGroupsToPersons(object):
|
||||||
"""
|
"""
|
||||||
|
@ -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="detail" onchange="document.forms['filter'].submit()">
|
<select class="default-input" name="structure_level" onchange="document.forms['filter'].submit()">
|
||||||
<option value="---">-- {% trans "Detail" %} --</option>
|
<option value="---">-- {% trans "Structure level" %} --</option>
|
||||||
{% for detail in details %}
|
{% for level in structure_levels %}
|
||||||
<option value="{{ detail }}"{% if detail in sortfilter.detail %} selected{% endif %}>
|
<option value="{{ level }}"{% if level in sortfilter.structure_level %} selected{% endif %}>
|
||||||
{{ detail }}</option>
|
{{ level }}</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=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=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><a href="{% model_url user 'view' %}">{{ user.first_name }}</a></td>
|
<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><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.get_type_display }}</td>
|
||||||
<td>{{ user.committee }}</td>
|
<td>{{ user.committee }}</td>
|
||||||
{% if perms.participant.can_manage_participant %}
|
{% if perms.participant.can_manage_participant %}
|
||||||
@ -93,10 +93,12 @@
|
|||||||
<a href="{% url user_edit user.id %}">
|
<a href="{% url user_edit user.id %}">
|
||||||
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
|
<img src="{% static 'images/icons/edit.png' %}" title="{% trans 'Edit participant' %}">
|
||||||
</a>
|
</a>
|
||||||
{% if user != request_user and not user.is_superuser %}
|
{% if user != request_user %}
|
||||||
<a href="{% url user_delete user.id %}">
|
<a href="{% url user_delete user.id %}">
|
||||||
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
|
<img src="{% static 'images/icons/delete.png' %}" title="{% trans 'Delete participant' %}">
|
||||||
</a>
|
</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 %}>
|
<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>
|
<span></span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li>{% trans "None" %}</li>
|
<li><i>{% trans "None" %}</i></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -33,7 +33,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li>{% trans "None" %}</li>
|
<li><i>{% trans "None" %}</i></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -44,6 +44,6 @@
|
|||||||
{% for assignment in assignments %}
|
{% for assignment in assignments %}
|
||||||
<li><a href="{% model_url assignment 'view' %}">{{ assignment }}</a></li>
|
<li><a href="{% model_url assignment 'view' %}">{{ assignment }}</a></li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li>{% trans "None" %}</li>
|
<li><i>{% trans "None" %}</i></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
|
|
||||||
<h2>{% trans "Groups" %}</h2>
|
<h2>{% trans "Groups" %}</h2>
|
||||||
<p>
|
<p>
|
||||||
{% for group in shown_user.groups.all %}
|
{% if shown_user.groups.all %}
|
||||||
{{ group }},
|
{{ shown_user.groups.all|join:", " }}
|
||||||
{% empty %}
|
{% else %}
|
||||||
{% trans "The participant is not member of any group." %}
|
{% trans "The participant is not member of any group." %}
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% if shown_user.get_gender_display %}
|
{% if shown_user.get_gender_display %}
|
||||||
|
24
openslides/participant/templates/projector/GroupSlide.html
Normal file
24
openslides/participant/templates/projector/GroupSlide.html
Normal 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 %}
|
@ -6,38 +6,16 @@
|
|||||||
{% block title %}{{ block.super }} - {{ title }}{% endblock %}
|
{% block title %}{{ block.super }} - {{ title }}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="item_fullscreen">{{ shown_user }}
|
||||||
<div id='sidebar'>
|
<span>
|
||||||
<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 %}
|
|
||||||
|
|
||||||
{% if shown_user.committee %}
|
{% if shown_user.committee %}
|
||||||
<p><strong>{% trans "Committee" %}</strong><br />{{ shown_user.committee }}</p>
|
<p>{{ shown_user.committee }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<p>
|
||||||
|
{% if shown_user.groups.all %}
|
||||||
|
{{ shown_user.groups.all|join:", " }}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1>{{ shown_user }}</h1>
|
|
||||||
<p>{{ shown_user.email }}</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scrollcontent %}
|
|
||||||
<p>
|
|
||||||
<div class="text">{{ shown_user.about_me|linebreaks }}</div>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -38,7 +38,7 @@ class UserTest(TestCase):
|
|||||||
self.assertEqual(unicode(self.user1), 'Max Mustermann')
|
self.assertEqual(unicode(self.user1), 'Max Mustermann')
|
||||||
|
|
||||||
def test_name_suffix(self):
|
def test_name_suffix(self):
|
||||||
self.user1.detail = 'München'
|
self.user1.structure_level = 'München'
|
||||||
self.user1.save()
|
self.user1.save()
|
||||||
self.assertEqual(unicode(self.user1), 'Max Mustermann (München)')
|
self.assertEqual(unicode(self.user1), 'Max Mustermann (München)')
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class UserOverview(ListView):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
sortfilter = {}
|
sortfilter = {}
|
||||||
|
|
||||||
for value in ['gender', 'detail', 'type', 'committee', 'status',
|
for value in ['gender', 'structure_level', 'type', 'committee', 'status',
|
||||||
'sort', '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] == '---':
|
||||||
@ -85,8 +85,8 @@ class UserOverview(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 'detail' in sortfilter:
|
if 'structure_level' in sortfilter:
|
||||||
query = query.filter(detail__iexact=sortfilter['detail'][0])
|
query = query.filter(structure_level__iexact=sortfilter['structure_level'][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:
|
||||||
@ -97,7 +97,7 @@ class UserOverview(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
|
||||||
['detail', 'type', 'committee', 'comment']):
|
['structure_level', 'type', 'committee', 'comment']):
|
||||||
query = query.order_by(
|
query = query.order_by(
|
||||||
'%s' % sortfilter['sort'][0])
|
'%s' % sortfilter['sort'][0])
|
||||||
else:
|
else:
|
||||||
@ -125,8 +125,8 @@ class UserOverview(ListView):
|
|||||||
percent = 0
|
percent = 0
|
||||||
|
|
||||||
# list of all existing categories
|
# list of all existing categories
|
||||||
details = [p['detail'] for p in User.objects.values('detail')
|
structure_levels = [p['structure_level'] for p in User.objects.values('structure_level')
|
||||||
.exclude(detail='').distinct()]
|
.exclude(structure_level='').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')
|
||||||
.exclude(committee='').distinct()]
|
.exclude(committee='').distinct()]
|
||||||
@ -135,7 +135,7 @@ class UserOverview(ListView):
|
|||||||
'allusers': all_users,
|
'allusers': all_users,
|
||||||
'request_user': self.request.user,
|
'request_user': self.request.user,
|
||||||
'percent': round(percent, 1),
|
'percent': round(percent, 1),
|
||||||
'details': details,
|
'structure_levels': structure_levels,
|
||||||
'committees': committees,
|
'committees': committees,
|
||||||
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
|
'cookie': ['participant_sortfilter', urlencode(decodedict(self.sortfilter),
|
||||||
doseq=True)],
|
doseq=True)],
|
||||||
@ -208,8 +208,6 @@ class UserDeleteView(DeleteView):
|
|||||||
def pre_redirect(self, request, *args, **kwargs):
|
def pre_redirect(self, request, *args, **kwargs):
|
||||||
if self.get_object() == self.request.user:
|
if self.get_object() == self.request.user:
|
||||||
messages.error(request, _("You can not delete yourself."))
|
messages.error(request, _("You can not delete yourself."))
|
||||||
elif self.get_object().is_superuser:
|
|
||||||
messages.error(request, _("You can not delete the administrator."))
|
|
||||||
else:
|
else:
|
||||||
super(DeleteView, self).pre_redirect(request, *args, **kwargs)
|
super(DeleteView, self).pre_redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
@ -268,8 +266,8 @@ 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.detail, stylesheet['Tablecell']),
|
Paragraph(user.structure_level, stylesheet['Tablecell']),
|
||||||
Paragraph(user.type, stylesheet['Tablecell']),
|
Paragraph(user.get_type_display(), stylesheet['Tablecell']),
|
||||||
Paragraph(user.committee, stylesheet['Tablecell'])])
|
Paragraph(user.committee, stylesheet['Tablecell'])])
|
||||||
t = LongTable(data, style=[
|
t = LongTable(data, style=[
|
||||||
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
('VALIGN', (0, 0), (-1, -1), 'TOP'),
|
||||||
|
@ -155,6 +155,10 @@ body{
|
|||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.item_fullscreen span
|
||||||
|
{
|
||||||
|
font-size: 50%; font-weight:normal;
|
||||||
|
}
|
||||||
|
|
||||||
/* items in a list*/
|
/* items in a list*/
|
||||||
.itemlist li
|
.itemlist li
|
||||||
|
@ -15,27 +15,6 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans 'Dashboard' %}</h1>
|
<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">
|
<div class="column" id="col1">
|
||||||
{% for name, widget in widgets.items %}
|
{% for name, widget in widgets.items %}
|
||||||
|
@ -4,6 +4,5 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% get_config 'frontpage_title' %}</h1>
|
<div class="item_fullscreen">{% get_config 'welcome_title' %}</div>
|
||||||
{% get_config 'frontpage_welcometext' %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,7 +1,36 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load tags %}
|
{% 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">
|
<a href="{% url projector_show %}" target="_blank">
|
||||||
<div id="iframewrapper">
|
<div id="iframewrapper">
|
||||||
<iframe id="iframe" src="{% url projector_show %}" frameborder="0"></iframe>
|
<iframe id="iframe" src="{% url projector_show %}" frameborder="0"></iframe>
|
||||||
|
@ -1 +0,0 @@
|
|||||||
{{ welcometext|safe|linebreaks }}
|
|
@ -22,6 +22,7 @@ from django.db import transaction
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.template import RequestContext
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
@ -396,10 +397,10 @@ def get_widgets(request):
|
|||||||
|
|
||||||
# welcome widget
|
# welcome widget
|
||||||
context = {
|
context = {
|
||||||
'welcometext': config['frontpage_welcometext']}
|
'welcometext': config['welcome_text']}
|
||||||
widgets.append(Widget(
|
widgets.append(Widget(
|
||||||
name='welcome',
|
name='welcome',
|
||||||
display_name=config['frontpage_title'],
|
display_name=config['welcome_title'],
|
||||||
template='projector/welcome_widget.html',
|
template='projector/welcome_widget.html',
|
||||||
context=context,
|
context=context,
|
||||||
permission_required='projector.can_see_dashboard',
|
permission_required='projector.can_see_dashboard',
|
||||||
@ -410,6 +411,7 @@ def get_widgets(request):
|
|||||||
name='live_view',
|
name='live_view',
|
||||||
display_name=_('Projector live view'),
|
display_name=_('Projector live view'),
|
||||||
template='projector/live_view_widget.html',
|
template='projector/live_view_widget.html',
|
||||||
|
context = RequestContext(request, {}),
|
||||||
permission_required='projector.can_see_projector',
|
permission_required='projector.can_see_projector',
|
||||||
default_column=2))
|
default_column=2))
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ input[type="submit"], input[type="button"] {
|
|||||||
padding:4px 10px !important;
|
padding:4px 10px !important;
|
||||||
margin: 2px 0 2px 0;
|
margin: 2px 0 2px 0;
|
||||||
}
|
}
|
||||||
#id_permissions {
|
#id_permissions, #id_users {
|
||||||
height: 310px;
|
height: 310px;
|
||||||
}
|
}
|
||||||
.button {
|
.button {
|
||||||
|
@ -76,7 +76,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<small>
|
<small>
|
||||||
© 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.
|
© 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>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 %}
|
|
@ -16,14 +16,13 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
|||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.importlib import import_module
|
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'
|
handler500 = 'openslides.utils.views.server_error'
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
# frontpage
|
# Redirect to dashboard URL
|
||||||
(r'^$', FrontPage.as_view()),
|
url(r'^$', RedirectView.as_view(url='dashboard'), name='home',),
|
||||||
|
|
||||||
(r'^agenda/', include('openslides.agenda.urls')),
|
(r'^agenda/', include('openslides.agenda.urls')),
|
||||||
(r'^motion/', include('openslides.motion.urls')),
|
(r'^motion/', include('openslides.motion.urls')),
|
||||||
|
@ -20,6 +20,7 @@ from reportlab.pdfbase.ttfonts import TTFont
|
|||||||
from reportlab.rl_config import defaultPageSize
|
from reportlab.rl_config import defaultPageSize
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils import formats
|
||||||
# Import gettext for python 2.5 support
|
# Import gettext for python 2.5 support
|
||||||
from django.utils.translation import ugettext as _, gettext
|
from django.utils.translation import ugettext as _, gettext
|
||||||
|
|
||||||
@ -222,8 +223,8 @@ def firstPage(canvas, doc):
|
|||||||
|
|
||||||
# time
|
# time
|
||||||
canvas.setFont('Ubuntu', 7)
|
canvas.setFont('Ubuntu', 7)
|
||||||
time = datetime.now().strftime(gettext("%Y-%m-%d %H:%Mh"))
|
time = formats.date_format(datetime.now(), 'DATETIME_FORMAT')
|
||||||
canvas.drawString(15 * cm, 28 * cm, _("Printed: %s") % time)
|
canvas.drawString(15 * cm, 28 * cm, _("As of: %s") % time)
|
||||||
|
|
||||||
# title
|
# title
|
||||||
if doc.title:
|
if doc.title:
|
||||||
|
@ -358,33 +358,6 @@ class PDFView(PermissionMixin, View):
|
|||||||
return self.render_to_response(self.get_filename())
|
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'):
|
def server_error(request, template_name='500.html'):
|
||||||
"""
|
"""
|
||||||
500 error handler.
|
500 error handler.
|
||||||
|
Loading…
Reference in New Issue
Block a user