Implement rights for anonymous as requested by #45

This commit is contained in:
rene 2011-11-14 16:37:12 +01:00
parent 40dc6f56df
commit 9f50863439
12 changed files with 227 additions and 52 deletions

View File

@ -323,7 +323,7 @@ class Application(models.Model):
if self.status == "pub" \
and user != self.submitter \
and user not in self.supporter.all() \
and user.profile:
and getattr(user, 'profile', None):
actions.append("support")
except Profile.DoesNotExist:
pass

View File

@ -9,9 +9,9 @@
:copyright: 2011 by the OpenSlides team, see AUTHORS.
:license: GNU GPL, see LICENSE for more details.
"""
from __future__ import with_statement
import csv
from django.shortcuts import redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
@ -441,6 +441,9 @@ def application_import(request):
return redirect(reverse('application_overview'))
except Profile.DoesNotExist:
pass
except AttributeError:
# AnonymousUser
pass
if request.method == 'POST':
form = ApplicationImportForm(request.POST, request.FILES)

View File

@ -18,6 +18,7 @@ DEBUG = True
TEMPLATE_DEBUG = DEBUG
AUTH_PROFILE_MODULE = 'participant.Profile'
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend', 'openslides.system.auth.AnonymousAuth',)
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/agenda/'
@ -137,4 +138,5 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.core.context_processors.i18n',
'utils.utils.revision',
'openslides.system.auth.anonymous_context_additions',
)

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-11-09 22:57+0100\n"
"POT-Creation-Date: 2011-11-10 23:13+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,11 +17,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: default.settings.py:59 settings.py:59
#: default.settings.py:60 settings.py:60
msgid "German"
msgstr "Deutsch"
#: default.settings.py:60 settings.py:60
#: default.settings.py:61 settings.py:61
msgid "English"
msgstr "Englisch"
@ -53,7 +53,7 @@ msgstr "Ja, mit allen Kindelementen."
msgid "No"
msgstr "Nein"
#: agenda/api.py:67 participant/views.py:164 participant/views.py:242
#: agenda/api.py:67 participant/views.py:165 participant/views.py:268
#: utils/utils.py:40
#, python-format
msgid "Do you really want to delete <b>%s</b>?"
@ -145,9 +145,9 @@ msgstr "Eintrag wurde erfolgreich geändert."
msgid "Agenda item modified"
msgstr "Tagesordnungseintrag geändert"
#: agenda/views.py:283 application/views.py:526 participant/views.py:141
#: participant/views.py:227 participant/views.py:256 participant/views.py:313
#: system/views.py:32 system/views.py:74
#: agenda/views.py:283 application/views.py:526 participant/views.py:142
#: participant/views.py:253 participant/views.py:282 participant/views.py:339
#: system/views.py:48 system/views.py:91
msgid "Please check the form for errors."
msgstr "Bitte kontrollieren Sie das Formular nach Fehlern."
@ -727,7 +727,7 @@ msgstr "FEHLER beim Zurückweisen der Version."
msgid "Do you really want to reject version <b>%s</b>?"
msgstr "Soll Version <b>%s</b> wirklich zurückgewiesen werden?"
#: application/views.py:440 participant/views.py:272
#: application/views.py:440 participant/views.py:298
msgid ""
"The import function is available for the superuser (without user profile) "
"only."
@ -1359,62 +1359,67 @@ msgstr "Amt"
msgid "First Password"
msgstr "Erstes Passwort"
#: participant/views.py:133
#: participant/views.py:134
msgid "New participant was successfully created."
msgstr "Neue/r Teilnehmer/in wurde erfolgreich angelegt."
#: participant/views.py:135
#: participant/views.py:136
msgid "Participant was successfully modified."
msgstr "Teilnehmer/in wurde erfolgreich geändert."
#: participant/views.py:162
#: participant/views.py:163
#, python-format
msgid "Participant <b>%s</b> was successfully deleted."
msgstr "Teilnehmer/in <b>%s</b> wurde erfolgreich gelöscht."
#: participant/views.py:174
#: participant/views.py:175
#, python-format
msgid "Participant <b>%s</b> is now a normal user."
msgstr "Teilnehmer/in <b>%s</b> ist jetzt ein normaler Nutzer."
#: participant/views.py:178
#: participant/views.py:179
#, python-format
msgid "Participant <b>%s</b> is now administrator."
msgstr "Teilnehmer/in <b>%s</b> ist jetzt ein Administrator."
#: participant/views.py:188
#: participant/views.py:189
#, python-format
msgid "Participant <b>%s</b> was successfully deactivated."
msgstr "Teilnehmer/in <b>%s</b> wurde erfolgreich deaktiviert."
#: participant/views.py:192
#: participant/views.py:193
#, python-format
msgid "Participant <b>%s</b> was successfully activated."
msgstr "Teilnehmer/in <b>%s</b> wurde erfolgreich aktiviert."
#: participant/views.py:219
#: participant/views.py:231
#, python-format
msgid "Group name \"%s\" is reserved for internal use."
msgstr "Der Gruppenname \"%s\" ist für interne Verwendung reserviert."
#: participant/views.py:245
msgid "New group was successfully created."
msgstr "Neue Gruppe wurde erfolgreich angelegt."
#: participant/views.py:221
#: participant/views.py:247
msgid "Group was successfully modified."
msgstr "Gruppe wurde erfolgreich geändert."
#: participant/views.py:240
#: participant/views.py:266
#, python-format
msgid "Group <b>%s</b> was successfully deleted."
msgstr "Gruppe <b>%s</b> wurde erfolgreich gelöscht."
#: participant/views.py:254
#: participant/views.py:280
msgid "User settings successfully saved."
msgstr "Nutzereinstellungen wurden erfolgreich gespeichert."
#: participant/views.py:311
#: participant/views.py:337
#, python-format
msgid "%d new participants were successfully imported."
msgstr "%d neue Teilnehmer/innen wurden erfolgreich importiert."
#: participant/views.py:315
#: participant/views.py:341
msgid ""
"Attention: All existing participants will be removed if you import new "
"participants."
@ -1422,14 +1427,14 @@ msgstr ""
"Achtung: Alle existierenden Teilnehmer/innen werden gelöscht, wenn Sie neue "
"Teilnehmer/innen importieren."
#: participant/views.py:326
#: participant/views.py:352
#, python-format
msgid "%s Password was successfully generated."
msgid_plural "%s Passwords were successfully generated."
msgstr[0] "Es wurde %s Passwort erfolgreich generiert."
msgstr[1] "Es wurden %s Passwörter erfolgreich generiert."
#: participant/views.py:328
#: participant/views.py:354
msgid ""
"There are no participants which need a first time password. No passwords "
"generated."
@ -1437,12 +1442,12 @@ msgstr ""
"Es sind keine Teilnehmer/innen ohne Erst-Passwort vorhanden. Es wurden keine "
"Passwörter generiert."
#: participant/views.py:337
#: participant/views.py:363
#, python-format
msgid "The Password for <b>%s</b> was successfully reset."
msgstr "Das Passwort für <b>%s</b> wurde erfolgreich zurückgesetzt."
#: participant/views.py:339
#: participant/views.py:365
#, python-format
msgid "Do you really want to reset the password for <b>%s</b>?"
msgstr "Soll das Passwort für <b>%s</b> wirklich zurückgesetzt werden?"
@ -1528,11 +1533,11 @@ msgstr "Aktionen"
msgid "Edit group"
msgstr "Benutzergruppe bearbeiten"
#: participant/templates/participant/group_overview.html:15
#: participant/templates/participant/group_overview.html:16
msgid "Delete group"
msgstr "Benutzergruppe löschen"
#: participant/templates/participant/group_overview.html:20
#: participant/templates/participant/group_overview.html:22
#: participant/templates/participant/overview.html:84
msgid "No participants available."
msgstr "Keine Teilnehmer/innen vorhanden."
@ -1551,7 +1556,7 @@ msgstr ""
#: participant/templates/participant/login.html:5
#: participant/templates/participant/login.html:13
#: participant/templates/participant/login.html:43 templates/base.html:26
#: participant/templates/participant/login.html:42 templates/base.html:26
msgid "Login"
msgstr "Anmelden"
@ -1564,6 +1569,10 @@ msgid "Your username and password didn't match. Please try again."
msgstr ""
"Benutzername und Passwort stimmen nicht überein. Bitte noch einmal versuchen."
#: participant/templates/participant/login.html:46
msgid "Continue as guest"
msgstr "Weiter als Gast"
#: participant/templates/participant/overview.html:42 utils/pdf.py:263
msgid "First Name"
msgstr "Vorname"
@ -1637,79 +1646,95 @@ msgstr "System URL"
msgid "Welcome text (for password PDF)"
msgstr "Willkommenstext (für Passwort-PDF-Liste)"
#: system/forms.py:29
#: system/forms.py:24
msgid "Access for anonymous / guest users"
msgstr "Zugriff für anonyme oder Gast-Nutzer"
#: system/forms.py:24
msgid "Allow access for guest users"
msgstr "Zugriff für Gast-Nutzer aktivieren"
#: system/forms.py:30
msgid "Event name"
msgstr "Veranstaltungsname"
#: system/forms.py:30
#: system/forms.py:31
msgid "Short description of event"
msgstr "Kurzbeschreibung der Veranstaltung"
#: system/forms.py:31
#: system/forms.py:32
msgid "Event date"
msgstr "Veranstaltungszeitraum"
#: system/forms.py:32
#: system/forms.py:33
msgid "Event location"
msgstr "Veranstaltungsort"
#: system/forms.py:33
#: system/forms.py:34
msgid "Event organizer"
msgstr "Veranstalter"
#: system/forms.py:39
#: system/forms.py:40
msgid "Countdown (in seconds)"
msgstr "Countdown (in Sekunden)"
#: system/forms.py:45
#: system/forms.py:46
msgid "Number of (minimum) required supporters for a application"
msgstr "Mindestanzahl erforderlicher Unterstützer/innen für einen Antrag"
#: system/forms.py:46
#: system/forms.py:47
msgid "Application preamble"
msgstr "Antragseinleitung"
#: system/forms.py:47 system/forms.py:58
#: system/forms.py:48 system/forms.py:59
msgid "Number of ballot papers (selection)"
msgstr "Anzahl der Wahlscheine (Vorauswahl)"
#: system/forms.py:47 system/forms.py:58
#: system/forms.py:48 system/forms.py:59
msgid "Number of all delegates"
msgstr "Anzahl aller Delegierten"
#: system/forms.py:47 system/forms.py:58
#: system/forms.py:48 system/forms.py:59
msgid "Number of all participants"
msgstr "Anzahl aller Teilnehmer/innen"
#: system/forms.py:47 system/forms.py:58
#: system/forms.py:48 system/forms.py:59
msgid "Use the following custum number"
msgstr "Verwende die folgende benutzerdefinierte Anzahl"
#: system/forms.py:48 system/forms.py:59
#: system/forms.py:49 system/forms.py:60
msgid "Custom number of ballot papers"
msgstr "Benutzerdefinierte Anzahl von Wahlscheinen"
#: system/forms.py:49
#: system/forms.py:50
msgid "Title for PDF document (all applications)"
msgstr "Titel für PDF-Dokuemt (alle Anträge)"
#: system/forms.py:50
#: system/forms.py:51
msgid "Preamble text for PDF document (all applications)"
msgstr "Einleitungstext für PDF-Dokument (alle Anträge)"
#: system/forms.py:56
#: system/forms.py:57
msgid "Title for PDF document (all elections)"
msgstr "Titel für PDF-Dokument (alle Wahlen)"
#: system/forms.py:57
#: system/forms.py:58
msgid "Preamble text for PDF document (all elections)"
msgstr "Einleitungstext für PDF-Dokument (alle Wahlen) "
#: system/views.py:30
#: system/views.py:42
msgid ""
"Anonymous access enabled. Please modify the \"Anonymous\" group to fit your "
"required permissions."
msgstr ""
"Anonymer Zugriff aktiviert. Bitte setzen Sie die Rechte der Gruppe \"Anonymous\" "
"passend zum gewünschten Zugriffslevel."
#: system/views.py:46
msgid "System settings successfully saved."
msgstr "Systemeinstellungen erfolgreich gespeichert."
#: system/views.py:72
#: system/views.py:89
msgid "General settings successfully saved."
msgstr "Allgemeine Einstellungen erfolgreich gespeichert."

View File

@ -12,7 +12,9 @@
<tr class="{% cycle '' 'odd' %}">
<td>{{ group.name }}</td>
<td><a href="{% url user_group_edit group.id %}"><img src="/static/images/icons/document-edit.png" title="{%trans 'Edit group' %}"></a>
{% if group.name != 'Anonymous' %}
<a href="{% url user_group_delete group.id %}"><img src="/static/images/icons/edit-delete.png" title="{%trans 'Delete group' %}"></a>
{% endif %}
</td>
</tr>
{% empty %}

View File

@ -25,7 +25,6 @@
});
</script>
{% endif %}
<form method="post" action="{% url user_login %}">
{% csrf_token %}
<table>
@ -42,7 +41,20 @@
<button type="submit">
<span class="icon ok">{%trans 'Login' %}</span>
</button>
{% if os_enable_anonymous_login %}
<button id="anonymous_login">
<span class="icon ok">{%trans 'Continue as guest' %}</span>
</button>
{% endif %}
<input type="hidden" name="next" value="{{ next }}" />
</p>
</form>
{% if os_enable_anonymous_login %}
<script>
$("#anonymous_login").live('click', function () {
window.location.href = '{% url item_overview %}';
return false;
});
</script>
{% endif %}
{% endblock %}

View File

@ -32,6 +32,7 @@ from participant.api import gen_username
from participant.forms import UserNewForm, UserEditForm, ProfileForm, UsersettingsForm, UserImportForm, GroupForm, AdminPasswordChangeForm
from utils.utils import template, permission_required, gen_confirm_form
from utils.pdf import print_userlist, print_passwords
from system.api import config_get
from django.db.models import Avg, Max, Min, Count
@ -195,7 +196,10 @@ def user_set_active(request, user_id):
@permission_required('participant.can_manage_participant')
@template('participant/group_overview.html')
def get_group_overview(request):
groups = Group.objects.all()
if config_get('system_enable_anonymous', False):
groups = Group.objects.all()
else:
groups = Group.objects.exclude(name='Anonymous')
return {
'groups': groups,
}
@ -214,7 +218,29 @@ def group_edit(request, group_id=None):
if request.method == 'POST':
form = GroupForm(request.POST, instance=group)
if form.is_valid():
group_name = form.cleaned_data['name'].lower()
try:
anonymous_group = Group.objects.get(name='Anonymous')
except Group.DoesNotExist:
anonymous_group = None
# special handling for anonymous auth
if group is None and group_name.strip().lower() == 'anonymous':
# don't allow to create this group
messages.error(request, _('Group name "%s" is reserved for internal use.') % group_name)
return {
'form' : form,
'group': group
}
group = form.save()
if anonymous_group is not None and \
anonymous_group.id == group.id:
# prevent name changes - XXX: I'm sure this could be done as *one* group.save()
group.name = 'Anonymous'
group.save()
if group_id is None:
messages.success(request, _('New group was successfully created.'))
else:
@ -273,6 +299,9 @@ def user_import(request):
return redirect(reverse('user_overview'))
except Profile.DoesNotExist:
pass
except AttributeError:
# AnonymousUser
pass
if request.method == 'POST':
form = UserImportForm(request.POST, request.FILES)

View File

@ -0,0 +1,82 @@
from django.contrib.auth.models import Permission
from openslides.system.api import config_get
class AnonymousAuth(object):
"""
Authenticates the AnonymousUser against the Permission-Group 'Anonymous'.
No rights are granted unless the group is defined and contains them.
"""
supports_anonymous_user = True
supports_inactive_user = True
supports_object_permissions = False
def authenticate(self, username=None, password=None):
"""
Authenticate a user based in username / password.
- always return None as anonymous can't login..
"""
return None
def get_group_permissions(self, user_obj, obj=None):
"""
Return the permissions a user is graneted by his group membership(s).
- try to return the permissions for the 'Anonymous' group
"""
if not user_obj.is_anonymous() or obj is not None or \
not config_get('system_enable_anonymous', False):
return set()
perms = Permission.objects.filter(group__name='Anonymous')
if perms is None:
return set()
perms = perms.values_list('content_type__app_label', 'codename').order_by()
return set([u'%s.%s' % (ct, name) for ct, name in perms])
def get_all_permissions(self, user_obj, obj=None):
"""
Return all permissions a user is granted including goup permissions.
- for anonymous it's identical to get_group_permissions
"""
return self.get_group_permissions(user_obj, obj)
def has_perm(self, user_obj, perm, obj=None):
"""
Check if the user as a specific permission
"""
if not user_obj.is_anonymous() or obj is not None or \
not config_get('system_enable_anonymous', False):
return False
return (perm in self.get_all_permissions(user_obj))
def has_module_perm(self, user_obj, app_label):
"""
Check if the user has permissions on the module app_label
"""
if not user_obj.is_anonymous() or \
not config_get('system_enable_anonymous', False):
return False
for perm in self.get_all_permissions(user_obj):
if perm[:perm.index('.')] == app_label:
return True
return False
def get_user(self, user_id):
"""
Return the User object for user_id
- for anonymous it's always None
"""
return None
def anonymous_context_additions(RequestContext):
"""
Add a variable to the request context that will indicate
if anonymous login is possible at all.
"""
return { 'os_enable_anonymous_login' : config_get('system_enable_anonymous', False) }

View File

@ -0,0 +1 @@
from AnonymousAuth import *

View File

@ -21,6 +21,7 @@ class SystemConfigForm(Form):
#user_registration = BooleanField(label=_("User registration"), required=False)
system_url = CharField(widget=TextInput(), required=False, label=_("System URL"))
system_welcometext = CharField(widget=Textarea(), required=False, label=_("Welcome text (for password PDF)"))
system_enable_anonymous = BooleanField(required=False, label=_("Access for anonymous / guest users"), help_text=_("Allow access for guest users"))
class EventConfigForm(Form):
error_css_class = 'error'
@ -58,4 +59,4 @@ class AssignmentConfigForm(Form):
assignment_pdf_ballot_papers_selection = ChoiceField(widget=Select(), required=False, label=_("Number of ballot papers (selection)"), choices=[("1", _("Number of all delegates")),("2", _("Number of all participants")),("0", _("Use the following custum number"))])
assignment_pdf_ballot_papers_number = IntegerField(widget=TextInput(attrs={'class':'small-input'}), required=False, min_value=1, label=_("Custom number of ballot papers"))

View File

@ -13,6 +13,7 @@
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.contrib.auth.models import Group, Permission
from django.utils.translation import ugettext as _
from utils.utils import template
from utils.utils import template, permission_required
@ -27,6 +28,22 @@ def get_system_config(request):
if form.is_valid():
config_set('system_url', form.cleaned_data['system_url'])
config_set('system_welcometext', form.cleaned_data['system_welcometext'])
if form.cleaned_data['system_enable_anonymous']:
config_set('system_enable_anonymous', True)
# check for Anonymous group and (re)create it as needed
try:
anonymous = Group.objects.get(name='Anonymous')
except Group.DoesNotExist:
default_perms = [u'can_see_agenda', u'can_see_projector', u'can_see_application']
anonymous = Group()
anonymous.name = 'Anonymous'
anonymous.save()
anonymous.permissions = Permission.objects.filter(codename__in=default_perms)
anonymous.save()
messages.success(request, _('Anonymous access enabled. Please modify the "Anonymous" group to fit your required permissions.'))
else:
# use '' - False will evaluate to uniced(False) => True..
config_set('system_enable_anonymous', '')
messages.success(request, _('System settings successfully saved.'))
else:
messages.error(request, _('Please check the form for errors.'))
@ -35,6 +52,7 @@ def get_system_config(request):
form = SystemConfigForm(initial={
'system_url': config_get('system_url'),
'system_welcometext': config_get('system_welcometext'),
'system_enable_anonymous': config_get('system_enable_anonymous'),
})
return {
'form': form,