From 051f9af1f7f23ced82dd325e75a82318ece10482 Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Mon, 8 Apr 2013 21:47:33 +0200 Subject: [PATCH 1/4] #436: New participant field 'title' --- openslides/participant/forms.py | 4 ++-- openslides/participant/models.py | 9 ++++++++- .../participant/templates/participant/overview.html | 2 ++ openslides/participant/views.py | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index 64a4f2b83..7d0d810c5 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -36,8 +36,8 @@ class UserCreateForm(forms.ModelForm, CssClassMixin): class Meta: model = User - fields = ('first_name', 'last_name', 'is_active', 'groups', 'structure_level', - 'gender', 'type', 'committee', 'about_me', 'comment', 'default_password') + fields = ('title', 'first_name', 'last_name', 'gender', 'groups', 'structure_level', + 'type', 'committee', 'about_me', 'comment', 'default_password', 'is_active') class UserUpdateForm(UserCreateForm): diff --git a/openslides/participant/models.py b/openslides/participant/models.py index bbb889329..d0c40a1fc 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -41,6 +41,9 @@ class User(PersonMixin, Person, SlideMixin, DjangoUser): structure_level = models.CharField( max_length=100, blank=True, default='', verbose_name=_("Structure level"), help_text=_('Will be shown after the name.')) + title = models.CharField( + max_length=50, blank=True, default='', verbose_name=_("Titel"), + help_text=_('Will be shown before the name.')) gender = models.CharField( max_length=50, choices=GENDER_CHOICES, blank=True, verbose_name=_("Gender"), help_text=_('Only for filtering the participant list.')) @@ -62,7 +65,11 @@ class User(PersonMixin, Person, SlideMixin, DjangoUser): @property def clean_name(self): - return self.get_full_name() or self.username + if self.title: + name = "%s %s" % (self.title, self.get_full_name()) + else: + name = self.get_full_name() + return name or self.username def get_name_suffix(self): return self.structure_level diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html index 08f4d182e..5420ac8dc 100644 --- a/openslides/participant/templates/participant/overview.html +++ b/openslides/participant/templates/participant/overview.html @@ -59,6 +59,7 @@ {% trans "Present" %} + {% trans "Title" %} {% trans "First Name" %} {% trans "Last Name" %} {% trans "Structure level" %} @@ -88,6 +89,7 @@ title="{% if user.is_active %}{% trans 'present' %}{% else %}{% trans 'absent' %}{% endif %}"> {% endif %} + {{ user.title }} {{ user.first_name }} {{ user.last_name }} {{ user.structure_level }} diff --git a/openslides/participant/views.py b/openslides/participant/views.py index 91218742d..cf9bd9056 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -184,7 +184,7 @@ class ParticipantsListPDF(PDFView): document_title = ugettext_lazy('List of Participants') def append_to_pdf(self, story): - data = [['#', _('Last Name'), _('First Name'), _('Group'), _('Type'), + data = [['#', _('Title'), _('Last Name'), _('First Name'), _('Group'), _('Type'), _('Committee')]] if config['participant_sort_users_by_first_name']: sort = 'first_name' @@ -195,6 +195,7 @@ class ParticipantsListPDF(PDFView): counter += 1 data.append([ counter, + Paragraph(user.title, stylesheet['Tablecell']), Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.structure_level, stylesheet['Tablecell']), From 2a97a61a148a4b87cfbd50adbbf7ccbe25266807 Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Tue, 9 Apr 2013 11:21:55 +0200 Subject: [PATCH 2/4] Remove participants field 'type'. Use 'group' field instead. Updated csv import, overview table and user detail view --- extras/csv-examples/participants-demo_de.csv | 27 ++++---- extras/csv-examples/participants-demo_en.csv | 27 ++++---- openslides/participant/api.py | 21 ++++++- openslides/participant/forms.py | 14 +++-- openslides/participant/models.py | 13 +--- .../templates/participant/import.html | 24 ++++--- .../templates/participant/overview.html | 15 +++-- .../templates/participant/user_detail.html | 63 +++++++++---------- openslides/participant/views.py | 12 ++-- openslides/static/styles/base.css | 14 ++++- 10 files changed, 135 insertions(+), 95 deletions(-) diff --git a/extras/csv-examples/participants-demo_de.csv b/extras/csv-examples/participants-demo_de.csv index 5a21169a1..f90ec012a 100644 --- a/extras/csv-examples/participants-demo_de.csv +++ b/extras/csv-examples/participants-demo_de.csv @@ -1,12 +1,15 @@ -"Vorname";"Nachname";"Geschlecht";"Gliederungsebene";"Typ";"Amt";"Kommentar" -"Angramain";"Aranea";"female";;"delegate";; -"Bastian";"Bux";"male";;"observer";"2. Vorsitzender"; -"Emma";"Dampf";"female";"Ortsverband Berlin-Mitte";"delegate";"AG Frauen"; -"David";"Delegierter";"male";"Ortsverband Berlin-Mitte";"delegate";"Haushaltsausschuss";"Demo-Account" -"Marta";"Grankvist";"female";"Ortsverband Köln";"delegate";"1. Vorsitzende"; -"Atréju";"Grün";"male";"Ortsverband Freiburg";"staff";"Versammlungsleitung"; -"Li Si";"Mandala";"female";;"staff";; -"Malin";"Melchersson";"male";"Gastredner e.V.";"guest";; -"Molly";"Tender";"female";"Ortsverband Berlin-Mitte";"delegate";; -"Dr. Karl";"Tur Tur";"male";;"observer";; -"Volker";"Versammlungsleitung";"male";"Ortsverband Hamburg";"delegate";"Versammlungsleitung";"Demo-Account" +"Titel";"Vorname";"Nachname";"Geschlecht";"E-Mail";"Gruppen-ID";"Gliederungsebene";"Amt";"Über mich";"Kommentar";"Aktiviert" +;"Angramain";"Aranea";"female";;;;;;;1 +;"Bastian";"Bux";"male";;;;"2. Vorsitzender";;;1 +;"Emma";"Dampf";"female";;3;"Ortsverband Berlin-Mitte";"AG Frauen";;;0 +"Dr.";"David";"Delegierter";"male";"david@example.com";3;"Ortsverband Berlin-Mitte";"Haushaltsausschuss";"Zu meiner Person: +A +B +C";"Demo-Account";1 +;"Marta";"Grankvist";"female";;3,4;"Ortsverband Köln";"1. Vorsitzende";;;0 +"Prof. Dr.";"Atréju";"Grün";"male";;4;"Ortsverband Freiburg";"Versammlungsleitung";;;1 +;"Li Si";"Mandala";"female";;4;;;;;1 +;"Malin";"Melchersson";"male";;;"Gastredner e.V.";;;;1 +;"Molly";"Tender";"female";;3;"Ortsverband Berlin-Mitte";;;;1 +"Dr. med.";"Karl";"Tur Tur";"male";;;;;;;1 +"Dipl.-Ing.";"Volker";"Versammlungsleitung";"male";"volker@example.com";3,4;"Ortsverband Hamburg";"Versammlungsleitung";;"Demo-Account";1 diff --git a/extras/csv-examples/participants-demo_en.csv b/extras/csv-examples/participants-demo_en.csv index 5c357b2ab..971eeaebd 100644 --- a/extras/csv-examples/participants-demo_en.csv +++ b/extras/csv-examples/participants-demo_en.csv @@ -1,12 +1,15 @@ -"First Name";"Last Name";"Gender";"Structure Level";"Type";"Committee";"Comment" -"Angramain";"Aranea";"female";;"delegate";; -"Bastian";"Bux";"male";;"observer";"2. Vorsitzender"; -"Emma";"Dampf";"female";"Ortsverband Berlin-Mitte";"delegate";"AG Frauen"; -"David";"Delegierter";"male";"Ortsverband Berlin-Mitte";"delegate";"Haushaltsausschuss";"Demo-Account" -"Marta";"Grankvist";"female";"Ortsverband Köln";"delegate";"1. Vorsitzende"; -"Atréju";"Grün";"male";"Ortsverband Freiburg";"staff";"Versammlungsleitung"; -"Li Si";"Mandala";"female";;"staff";; -"Malin";"Melchersson";"male";"Gastredner e.V.";"guest";; -"Molly";"Tender";"female";"Ortsverband Berlin-Mitte";"delegate";; -"Dr. Karl";"Tur Tur";"male";;"observer";; -"Volker";"Versammlungsleitung";"male";"Ortsverband Hamburg";"delegate";"Versammlungsleitung";"Demo-Account" +"First Name";"Last Name";"Gender";"Email";"Group id";"Structure Level";"Committee";"About me";"Comment";"Is active" +"Angramain";"Aranea";"female";;;;;;;1 +"Bastian";"Bux";"male";;;;"2. Vorsitzender";;;1 +"Emma";"Dampf";"female";;3;"Ortsverband Berlin-Mitte";"AG Frauen";;;0 +"David";"Delegierter";"male";"david@example.com";3;"Ortsverband Berlin-Mitte";"Haushaltsausschuss";"Zu meiner Person: +A +B +C";"Demo-Account";1 +"Marta";"Grankvist";"female";;3,4;"Ortsverband Köln";"1. Vorsitzende";;;0 +"Atréju";"Grün";"male";;4;"Ortsverband Freiburg";"Versammlungsleitung";;;1 +"Li Si";"Mandala";"female";;4;;;;;1 +"Malin";"Melchersson";"male";;;"Gastredner e.V.";;;;1 +"Molly";"Tender";"female";;3;"Ortsverband Berlin-Mitte";;;;1 +"Karl";"Tur Tur";"male";;;;;;;1 +"Volker";"Versammlungsleitung";"male";"volker@example.com";3,4;"Ortsverband Hamburg";"Versammlungsleitung";;"Demo-Account";1 diff --git a/openslides/participant/api.py b/openslides/participant/api.py index bf4310ca8..433dc2fc3 100644 --- a/openslides/participant/api.py +++ b/openslides/participant/api.py @@ -67,21 +67,38 @@ def import_users(csv_file): dialect=dialect)): if line_no: try: - (first_name, last_name, gender, structure_level, type, committee, comment) = line[:7] + (title, first_name, last_name, gender, email, groups, + structure_level, committee, about_me, comment, is_active) = line[:11] except ValueError: error_messages.append(_('Ignoring malformed line %d in import file.') % (line_no + 1)) continue user = User() + user.title = title user.last_name = last_name user.first_name = first_name user.username = gen_username(first_name, last_name) user.gender = gender + user.email = email user.structure_level = structure_level - user.type = type user.committee = committee + user.about_me = about_me user.comment = comment + if is_active == '1': + user.is_active = True + else: + user.is_active = False user.default_password = gen_password() user.save() + for groupid in groups: + try: + if groupid != ",": + Group.objects.get(pk=groupid).user_set.add(user) + except ValueError: + error_messages.append(_('Ignoring malformed group id in line %d.') % (line_no + 1)) + continue + except Group.DoesNotExist: + error_messages.append(_('Group id %s does not exists (line %d).') % (groupid, line_no + 1)) + continue user.reset_password() count_success += 1 except csv.Error: diff --git a/openslides/participant/forms.py b/openslides/participant/forms.py index 7d0d810c5..bab9ba92c 100644 --- a/openslides/participant/forms.py +++ b/openslides/participant/forms.py @@ -36,16 +36,17 @@ class UserCreateForm(forms.ModelForm, CssClassMixin): class Meta: model = User - fields = ('title', 'first_name', 'last_name', 'gender', 'groups', 'structure_level', - 'type', 'committee', 'about_me', 'comment', 'default_password', 'is_active') + fields = ('title', 'first_name', 'last_name', 'gender', 'email', + 'groups', 'structure_level', 'committee', 'about_me', 'comment', + 'is_active', 'default_password') class UserUpdateForm(UserCreateForm): class Meta: model = User - fields = ('username', 'first_name', 'last_name', 'is_active', 'groups', - 'structure_level', 'gender', 'type', 'committee', 'about_me', 'comment', - 'default_password') + fields = ('username', 'title', 'first_name', 'last_name', 'gender', 'email', + 'groups', 'structure_level', 'committee', 'about_me', 'comment', + 'is_active', 'default_password') class GroupForm(forms.ModelForm, CssClassMixin): @@ -106,7 +107,8 @@ class UsersettingsForm(forms.ModelForm, CssClassMixin): class Meta: model = User - fields = ('username', 'first_name', 'last_name', 'gender', 'email', 'committee', 'about_me') + fields = ('username', 'title', 'first_name', 'last_name', 'gender', 'email', + 'committee', 'about_me') class UserImportForm(forms.Form, CssClassMixin): diff --git a/openslides/participant/models.py b/openslides/participant/models.py index d0c40a1fc..37aa13c9d 100644 --- a/openslides/participant/models.py +++ b/openslides/participant/models.py @@ -30,16 +30,10 @@ class User(PersonMixin, Person, SlideMixin, DjangoUser): ('male', _('Male')), ('female', _('Female')), ) - TYPE_CHOICES = ( - ('delegate', _('Delegate')), - ('observer', _('Observer')), - ('staff', _('Staff')), - ('guest', _('Guest')), - ) django_user = models.OneToOneField(DjangoUser, editable=False, parent_link=True) structure_level = models.CharField( - max_length=100, blank=True, default='', verbose_name=_("Structure level"), + max_length=255, blank=True, default='', verbose_name=_("Structure level"), help_text=_('Will be shown after the name.')) title = models.CharField( max_length=50, blank=True, default='', verbose_name=_("Titel"), @@ -47,11 +41,8 @@ class User(PersonMixin, Person, SlideMixin, DjangoUser): gender = models.CharField( max_length=50, choices=GENDER_CHOICES, blank=True, verbose_name=_("Gender"), help_text=_('Only for filtering the participant list.')) - type = models.CharField( - max_length=100, choices=TYPE_CHOICES, blank=True, - verbose_name=_("Typ"), help_text=_('Only for filtering the participant list.')) committee = models.CharField( - max_length=100, blank=True, default='', verbose_name=_("Committee"), + max_length=255, blank=True, default='', verbose_name=_("Committee"), help_text=_('Only for filtering the participant list.')) about_me = models.TextField( blank=True, default='', verbose_name=_('About me'), diff --git a/openslides/participant/templates/participant/import.html b/openslides/participant/templates/participant/import.html index e5c8ce024..2d754b401 100644 --- a/openslides/participant/templates/participant/import.html +++ b/openslides/participant/templates/participant/import.html @@ -13,15 +13,21 @@

{% trans 'Select a CSV file to import participants!' %}

- -

{% trans 'Required comma separated values' %}: - ({% trans 'first_name, last_name, gender, structure level, type, committee, comment' %}) -
- {% trans 'Required CSV file encoding: UTF-8 (Unicode).' %} -

- -

{% trans 'A CSV example file is available in OpenSlides Wiki.' %} -

+ +

{% trans 'Please note' %}:

+
{% csrf_token %} {% include "form.html" %} diff --git a/openslides/participant/templates/participant/overview.html b/openslides/participant/templates/participant/overview.html index 5420ac8dc..7c33a6677 100644 --- a/openslides/participant/templates/participant/overview.html +++ b/openslides/participant/templates/participant/overview.html @@ -59,11 +59,11 @@ {% trans "Present" %} - {% trans "Title" %} + {% trans "Title" %} {% trans "First Name" %} {% trans "Last Name" %} {% trans "Structure level" %} - {% trans "Type" %} + {% trans "Group" %} {% trans "Committee" %} {% if perms.participant.can_manage_participant %} {% trans "Comment" %} @@ -89,11 +89,18 @@ title="{% if user.is_active %}{% trans 'present' %}{% else %}{% trans 'absent' %}{% endif %}"> {% endif %} - {{ user.title }} + {{ user.title }} {{ user.first_name }} {{ user.last_name }} {{ user.structure_level }} - {{ user.get_type_display }} + + {% for group in user.groups.all %} + {% if group.name != 'Registered' %} + {{ group}} + {% if not forloop.last %}
{% endif %} + {% endif %} + {% endfor %} + {{ user.committee }} {% if perms.participant.can_manage_participant %} {{ user.comment|first_line }} diff --git a/openslides/participant/templates/participant/user_detail.html b/openslides/participant/templates/participant/user_detail.html index e31502b29..90fa33c4b 100644 --- a/openslides/participant/templates/participant/user_detail.html +++ b/openslides/participant/templates/participant/user_detail.html @@ -7,55 +7,50 @@ {% block content %} -

{{ shown_user }} +

{{ shown_user.clean_name }} {% trans "Back to overview" %}

-

{{ shown_user.email }}

-

{% trans "Groups" %}

-

+ +

+ {% trans "Personal data" %} + + {{ shown_user.get_gender_display }} + + {{ shown_user.email }} + + {{ shown_user.about_me|linebreaks }} +
+ +
+ {% trans "Event data" %} + + {{ shown_user.structure_level }} + + {{ shown_user.committee }} + {% if shown_user.groups.all %} {{ shown_user.groups.all|join:", " }} {% else %} {% trans "The participant is not member of any group." %} {% endif %} -

- -{% if shown_user.get_gender_display %} -

{% trans "Gender" %}

-

{{ shown_user.get_gender_display }}

-{% endif %} - -{% if shown_user.get_type_display %} -

{% trans "Type" %}

-

{{ shown_user.get_type_display }}

-{% endif %} - -{% if shown_user.committee %} -

{% trans "Committee" %}

-

{{ shown_user.committee }}

-{% endif %} - -{% if shown_user.about_me %} -

{% trans "About me" %}

-

{{ shown_user.about_me }}

-{% endif %} +
{% if perms.participant.can_manage_participant %} - {% if shown_user.comment %} -

{% trans "Comment" %}

-

{{ shown_user.comment }}

- {% endif %} - -

{% trans "Last Login" %}

+
+ {% trans "Administrative data" %} + + {{ shown_user.username }} + + {{ shown_user.comment|linebreaks }} + {% if shown_user.last_login > shown_user.date_joined %} -

{{ shown_user.last_login }}

+ {{ shown_user.last_login }} {% else %} -

{% trans "The participant has not logged in yet." %}

+ {% trans "The participant has not logged in yet." %} {% endif %} {% endif %} - {% endblock %} diff --git a/openslides/participant/views.py b/openslides/participant/views.py index cf9bd9056..fae0fe92f 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -184,8 +184,8 @@ class ParticipantsListPDF(PDFView): document_title = ugettext_lazy('List of Participants') def append_to_pdf(self, story): - data = [['#', _('Title'), _('Last Name'), _('First Name'), _('Group'), _('Type'), - _('Committee')]] + data = [['#', _('Title'), _('Last Name'), _('First Name'), + _('Structure level'), _('Group'), _('Committee')]] if config['participant_sort_users_by_first_name']: sort = 'first_name' else: @@ -193,13 +193,17 @@ class ParticipantsListPDF(PDFView): counter = 0 for user in User.objects.all().order_by(sort): counter += 1 + groups = '' + for group in user.groups.all(): + if unicode(group) != "Registered": + groups += "%s
" % unicode(group) data.append([ counter, Paragraph(user.title, stylesheet['Tablecell']), Paragraph(user.last_name, stylesheet['Tablecell']), Paragraph(user.first_name, stylesheet['Tablecell']), Paragraph(user.structure_level, stylesheet['Tablecell']), - Paragraph(user.get_type_display(), stylesheet['Tablecell']), + Paragraph(groups, stylesheet['Tablecell']), Paragraph(user.committee, stylesheet['Tablecell'])]) t = LongTable(data, style=[ ('VALIGN', (0, 0), (-1, -1), 'TOP'), @@ -293,7 +297,7 @@ class UserImportView(FormView): permission_required = 'participant.can_manage_participant' template_name = 'participant/import.html' form_class = UserImportForm - success_url_name = 'user_import' + success_url_name = 'user_overview' def form_valid(self, form): # check for valid encoding (will raise UnicodeDecodeError if not) diff --git a/openslides/static/styles/base.css b/openslides/static/styles/base.css index 05d137c98..13fc302e3 100644 --- a/openslides/static/styles/base.css +++ b/openslides/static/styles/base.css @@ -117,7 +117,19 @@ tr.total td { .optional { display: auto; } - +fieldset { + margin-bottom: 10px; +} +fieldset legend { + margin-bottom: 5px; +} +fieldset label { + font-weight: bold; + margin: 10px 0 0 0; +} +fieldset label:after { + content: ":"; +} /** Forms **/ input, textarea { From 9f6da9f33bc5a55237efe5b30d748a030ecb918c Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Tue, 9 Apr 2013 19:53:18 +0200 Subject: [PATCH 3/4] Reorder GroupDetailView code in view.py. --- openslides/participant/views.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openslides/participant/views.py b/openslides/participant/views.py index fae0fe92f..3e5a4551f 100644 --- a/openslides/participant/views.py +++ b/openslides/participant/views.py @@ -86,16 +86,6 @@ class UserDetailView(DetailView, PermissionMixin): context_object_name = 'shown_user' -class GroupDetailView(DetailView, PermissionMixin): - """ - Classed based view to show a specific group in the interface. - """ - permission_required = 'participant.can_manage_participant' - model = Group - template_name = 'participant/group_detail.html' - context_object_name = 'group' - - class UserCreateView(CreateView): """ Create a new participant. @@ -344,6 +334,16 @@ class GroupOverview(ListView): model = Group +class GroupDetailView(DetailView, PermissionMixin): + """ + Classed based view to show a specific group in the interface. + """ + permission_required = 'participant.can_manage_participant' + model = Group + template_name = 'participant/group_detail.html' + context_object_name = 'group' + + class GroupCreateView(CreateView): """ Create a new group. From 2c5bae7b0172f18e483c2356a06603b3d649a126 Mon Sep 17 00:00:00 2001 From: Emanuel Schuetze Date: Tue, 9 Apr 2013 20:12:57 +0200 Subject: [PATCH 4/4] #560 fixed: FormField to choose permissions is too small --- openslides/static/styles/base.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openslides/static/styles/base.css b/openslides/static/styles/base.css index 13fc302e3..cb2d854b3 100644 --- a/openslides/static/styles/base.css +++ b/openslides/static/styles/base.css @@ -156,7 +156,14 @@ form .required label:after { legend + .control-group { margin-top: 0px !important; } - +#id_permissions { + height: 310px; + width: auto; +} +#id_submitter, #id_supporter, #id_users { + height: 110px; + width: auto; +} /** Left sitebar navigation **/ .leftmenu ul {