Merge lp:~sophron/postorius/create_users into lp:postorius

Proposed by George Chatzisofroniou
Status: Merged
Merged at revision: 93
Proposed branch: lp:~sophron/postorius/create_users
Merge into: lp:postorius
Diff against target: 273 lines (+187/-2)
9 files modified
src/postorius/forms.py (+35/-0)
src/postorius/templates/postorius/base.html (+1/-0)
src/postorius/templates/postorius/menu/mm_user_nav.html (+8/-0)
src/postorius/templates/postorius/users/index.html (+32/-0)
src/postorius/templates/postorius/users/new.html (+12/-0)
src/postorius/templates/postorius/users/summary.html (+17/-0)
src/postorius/urls.py (+6/-1)
src/postorius/views/generic.py (+22/-0)
src/postorius/views/views.py (+54/-1)
To merge this branch: bzr merge lp:~sophron/postorius/create_users
Reviewer Review Type Date Requested Status
Florian Fuchs Approve
Review via email: mp+129567@code.launchpad.net

Description of the change

I worked on this bug: https://bugs.launchpad.net/postorius/+bug/1058445

I added the feature to create a mailman user account, but in order to edit the basic user data via the web interface, some additions to mailman client are required. See, https://bugs.launchpad.net/mailman.client/+bug/1066352 and https://bugs.launchpad.net/mailman.client/+bug/1066343.

We also need an icon for the new entry on the menu: https://bugs.launchpad.net/postorius/+bug/1066340

I think it's better to divide the whole 'edit user' feature into smaller ones (delete user, register addresses to a user, basic data edit, etc).

To post a comment you must log in.
lp:~sophron/postorius/create_users updated
92. By George Chatzisofroniou

Added the required templates for users

Revision history for this message
Florian Fuchs (flo-fuchs) wrote :

Hi George,

thank you for your changes (and the bug reports)! I have just merged them to the trunk. I only made some very small changes and additions (adjusted the docstring in MailmanUserView, added the user icon, some PEP8 fixes...). I also made the user list and details only available to superusers (I don't think every user should be able to see who else is there...).

So now that we have a method to add new users to the core, we need a way to connect them to the users in the postorius database (the ones added through django.contrib.auth). I added some comment about that in the bug description:

https://bugs.launchpad.net/postorius/+bug/1058445

Cheers and thanks again
Florian

review: Approve
Revision history for this message
Richard Wackerbarth (wacky) wrote :

Isn't the visibility of the list members a per_list policy setting?

In any case, we will need to have list administrators (who are not the superuser) be able to see the membership on their list.

I think that Postorius will require a better model for roles.

Richard

On Oct 25, 2012, at 3:19 AM, Florian Fuchs <email address hidden> wrote:

> Review: Approve
>
> Hi George,
>
> thank you for your changes (and the bug reports)! I have just merged them to the trunk. I only made some very small changes and additions (adjusted the docstring in MailmanUserView, added the user icon, some PEP8 fixes...). I also made the user list and details only available to superusers (I don't think every user should be able to see who else is there...).

Revision history for this message
Florian Fuchs (flo-fuchs) wrote :

Hi Richard,

2012/10/25 Richard Wackerbarth <email address hidden>:
> Isn't the visibility of the list members a per_list policy setting?

Please not that users/index is not a list of members, but a list of
the users stored in Mailman's core database. The members of a list are
displayed for each list separately and can be accessed only by
superusers and list owners.

> In any case, we will need to have list administrators (who are not the superuser) be able to see the membership on their list.
>
> I think that Postorius will require a better model for roles.

Yes, this is already possible. There are two custom permission
decorators for view functions (list_owner_required and
list_moderator_required) that check if the currently logged-in user is
either the owner or the moderator of a list. Currently those
restrictions are in user on the list members page, the moderation
page, the list settings etc.

Next step is providing forms to make existing users owners and/or moderators.

Cheers
Florian

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/postorius/forms.py'
--- src/postorius/forms.py 2012-09-23 02:35:28 +0000
+++ src/postorius/forms.py 2012-10-13 18:25:24 +0000
@@ -534,6 +534,41 @@
534 "delivery_mode", "delivery_status"]]534 "delivery_mode", "delivery_status"]]
535535
536536
537class UserNew(FieldsetForm):
538 """
539 Form field to add a new user
540 """
541 display_name = forms.CharField(
542 label=_('User Name'),
543 required=True,
544 error_messages={'required': _('Please enter a display name.'),
545 'invalid': _('Please enter a valid display name.')})
546 email = forms.EmailField(
547 label=_("User's email address"),
548 error_messages={
549 'required': _("Please enter the user's email address.")},
550 required=True)
551 password = forms.CharField(
552 label=_('Password'),
553 required=True,
554 error_messages={'required': _('Please enter a password.')},
555 widget=forms.PasswordInput(render_value=False))
556 password_repeat = forms.CharField(
557 label=_('Repeat password'),
558 required=True,
559 error_messages={'required': _('Please repeat the password.')},
560 widget=forms.PasswordInput(render_value=False))
561
562 def clean(self):
563 cleaned_data = self.cleaned_data
564 password = cleaned_data.get("password")
565 password_repeat = cleaned_data.get("password_repeat")
566 if password != password_repeat:
567 raise forms.ValidationError("Passwords must be identical.")
568
569 return cleaned_data
570
571
537class UserSettings(FieldsetForm):572class UserSettings(FieldsetForm):
538 """Form handling the user settings.573 """Form handling the user settings.
539 """574 """
540575
=== modified file 'src/postorius/templates/postorius/base.html'
--- src/postorius/templates/postorius/base.html 2012-08-29 15:03:37 +0000
+++ src/postorius/templates/postorius/base.html 2012-10-13 18:25:24 +0000
@@ -24,6 +24,7 @@
24 <ul class="mm_metaNav">24 <ul class="mm_metaNav">
25 <li><a class="mm_lists" href="{% url list_index %}">Lists</a></li>25 <li><a class="mm_lists" href="{% url list_index %}">Lists</a></li>
26 {% if user.is_authenticated %}26 {% if user.is_authenticated %}
27 <li><a class="mm_users" href="{% url user_index %}">Users</a></li>
27 <li><a class="mm_todos" href="{% url user_todos %}">Todos</a></li>28 <li><a class="mm_todos" href="{% url user_todos %}">Todos</a></li>
28 {% endif %}29 {% endif %}
29 {% if user.is_superuser %}30 {% if user.is_superuser %}
3031
=== added file 'src/postorius/templates/postorius/menu/mm_user_nav.html'
--- src/postorius/templates/postorius/menu/mm_user_nav.html 1970-01-01 00:00:00 +0000
+++ src/postorius/templates/postorius/menu/mm_user_nav.html 2012-10-13 18:25:24 +0000
@@ -0,0 +1,8 @@
1{% load i18n %}
2<div class="mm_subHeader">
3 <span class="mm_context">{{ mm_user.address }}</span>
4 <ul class="mm_nav">
5 <li class="mm_user_summary"><a href="{% url user_summary mm_user.user_id %}">{% trans "Info" %}</a></li>
6 <li class="mm_new_user"><a class="btn btn-mini btn-success" href="{% url user_new %}">{% trans "New User" %}</a></li>
7 </ul>
8</div>
09
=== added directory 'src/postorius/templates/postorius/users'
=== added file 'src/postorius/templates/postorius/users/index.html'
--- src/postorius/templates/postorius/users/index.html 1970-01-01 00:00:00 +0000
+++ src/postorius/templates/postorius/users/index.html 2012-10-13 18:25:24 +0000
@@ -0,0 +1,32 @@
1{% extends "postorius/base.html" %}
2{% load i18n %}
3
4{% block main %}
5 {% if user.is_superuser %}
6 <ul class="mm_nav">
7 <li class="mm_new_user"><a class="btn btn-mini btn-success" href="{% url user_new %}">{% trans "New User" %}</a></li>
8 </ul>
9 {% endif %}
10 <h1>{% trans 'Users' %}</h1>
11
12 <table class="table table-bordered table-striped">
13 <thead>
14 <tr>
15 <th>{% trans 'Email' %}</th>
16 <th>{% trans 'Display name' %}</th>
17 </tr>
18 </thead>
19 <tbody>
20 {% for mm_user in mm_users %}
21 <tr>
22 <td>
23 <a href="{% url user_summary user_id=mm_user.user_id %}">{% for address in mm_user.addresses|slice:":1" %}{{ address }}{% endfor %}</a>
24 </td>
25 <td>
26 {{ mm_user.display_name }}
27 </td>
28 </tr>
29 {% endfor %}
30 </tbody>
31 </table>
32{% endblock main %}
033
=== added file 'src/postorius/templates/postorius/users/new.html'
--- src/postorius/templates/postorius/users/new.html 1970-01-01 00:00:00 +0000
+++ src/postorius/templates/postorius/users/new.html 2012-10-13 18:25:24 +0000
@@ -0,0 +1,12 @@
1{% extends extend_template %}
2{% load i18n %}
3
4{% block main %}
5 <h1>{% trans "Add a new User" %}</h1>
6 <form action="{% url user_new %}" method="post" class="well"> {% csrf_token %}
7 {{ form.as_p }}
8 <div class="field">
9 <button class="btn btn-success" type="submit">{% trans "Create User" %}</button>
10 </div>
11 </form>
12{% endblock main %}
013
=== added file 'src/postorius/templates/postorius/users/summary.html'
--- src/postorius/templates/postorius/users/summary.html 1970-01-01 00:00:00 +0000
+++ src/postorius/templates/postorius/users/summary.html 2012-10-13 18:25:24 +0000
@@ -0,0 +1,17 @@
1{% extends extend_template %}
2{% load i18n %}
3
4{% block main %}
5 {% include 'postorius/menu/mm_user_nav.html' %}
6 <h1>{% trans 'Mailman User' %}</h1>
7
8 <p><strong>Display name:</strong> {{ mm_user.display_name}}</p>
9
10 <h2>Valid email addresses for this account:</h2>
11 <ul>
12 {% for address in mm_user.addresses %}
13 <li>{{ address }}</li>
14 {% endfor %}
15 </ul>
16
17{% endblock main %}
018
=== modified file 'src/postorius/urls.py'
--- src/postorius/urls.py 2012-09-23 12:10:25 +0000
+++ src/postorius/urls.py 2012-10-13 18:25:24 +0000
@@ -26,7 +26,7 @@
2626
27urlpatterns = patterns(27urlpatterns = patterns(
28 'postorius.views',28 'postorius.views',
29 (r'^$', 'list_index'),29 (r'^$', 'list_index'),
30 # /account/30 # /account/
31 url(r'^accounts/login/$', 'user_login', name='user_login'),31 url(r'^accounts/login/$', 'user_login', name='user_login'),
32 url(r'^accounts/logout/$', 'user_logout', name='user_logout'),32 url(r'^accounts/logout/$', 'user_logout', name='user_logout'),
@@ -76,4 +76,9 @@
76 url(r'^lists/(?P<fqdn_listname>[^/]+)/settings/(?P<visible_section>[^/]+)?'76 url(r'^lists/(?P<fqdn_listname>[^/]+)/settings/(?P<visible_section>[^/]+)?'
77 '(?:/(?P<visible_option>.*))?$', 'list_settings',77 '(?:/(?P<visible_option>.*))?$', 'list_settings',
78 name='list_settings'),78 name='list_settings'),
79 # /users/
80 url(r'^users/$', 'user_index', name='user_index'),
81 url(r'^users/new/$', 'user_new', name='user_new'),
82 url(r'^users/(?P<user_id>[^/]+)/$',
83 UserSummaryView.as_view(), name='user_summary'),
79) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)84) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
8085
=== modified file 'src/postorius/views/generic.py'
--- src/postorius/views/generic.py 2012-09-26 21:13:41 +0000
+++ src/postorius/views/generic.py 2012-10-13 18:25:24 +0000
@@ -47,3 +47,25 @@
47 if 'template' in kwargs:47 if 'template' in kwargs:
48 self.template = kwargs['template']48 self.template = kwargs['template']
49 return super(MailingListView, self).dispatch(request, *args, **kwargs)49 return super(MailingListView, self).dispatch(request, *args, **kwargs)
50
51class MailmanUserView(TemplateView):
52 """A generic view for everything based on a mailman.client
53 list object.
54
55 Sets self.mailing_list to list object if fqdn_listname in **kwargs.
56 """
57
58 def _get_user(self, user_id):
59 return MailmanUser.objects.get_or_404(address=user_id)
60
61 def dispatch(self, request, *args, **kwargs):
62 # get the list object.
63 if 'user_id' in kwargs:
64 try:
65 self.mm_user = self._get_user(kwargs['user_id'])
66 except MailmanApiError:
67 return utils.render_api_error(request)
68 # set the template
69 if 'template' in kwargs:
70 self.template = kwargs['template']
71 return super(MailmanUserView, self).dispatch(request, *args, **kwargs)
5072
=== modified file 'src/postorius/views/views.py'
--- src/postorius/views/views.py 2012-09-26 21:07:54 +0000
+++ src/postorius/views/views.py 2012-10-13 18:25:24 +0000
@@ -44,7 +44,7 @@
44 MailmanApiError, Mailman404Error)44 MailmanApiError, Mailman404Error)
45from postorius.forms import *45from postorius.forms import *
46from postorius.auth.decorators import list_owner_required46from postorius.auth.decorators import list_owner_required
47from postorius.views.generic import MailingListView47from postorius.views.generic import MailingListView, MailmanUserView
4848
4949
50logger = logging.getLogger(__name__)50logger = logging.getLogger(__name__)
@@ -697,6 +697,59 @@
697 context_instance=RequestContext(request))697 context_instance=RequestContext(request))
698698
699699
700class UserSummaryView(MailmanUserView):
701 """Shows a summary of a user.
702 """
703
704 def get(self, request, user_id):
705 settingsform = MembershipSettings()
706 return render_to_response('postorius/users/summary.html',
707 {'mm_user': self.mm_user,
708 'settingsform': settingsform},
709 context_instance=RequestContext(request))
710
711
712@login_required
713def user_index(request, template='postorius/users/index.html'):
714 """Show a table of all users.
715 """
716 error = None
717 try:
718 mm_users = MailmanUser.objects.all()
719 except MailmanApiError:
720 return utils.render_api_error(request)
721 return render_to_response(template,
722 {'error': error,
723 'mm_users': mm_users},
724 context_instance=RequestContext(request))
725
726
727@login_required
728@user_passes_test(lambda u: u.is_superuser)
729def user_new(request):
730 message = None
731 if request.method == 'POST':
732 form = UserNew(request.POST)
733 if form.is_valid():
734 user = MailmanUser(display_name=form.cleaned_data['display_name'],
735 email=form.cleaned_data['email'],
736 password=form.cleaned_data['password'])
737 try:
738 user.save()
739 except MailmanApiError:
740 return utils.render_api_error(request)
741 except HTTPError, e:
742 messages.error(request, e)
743 else:
744 messages.success(request, _("New User registered"))
745 return redirect("user_index")
746 else:
747 form = UserNew()
748 return render_to_response('postorius/users/new.html',
749 {'form': form, 'message': message},
750 context_instance=RequestContext(request))
751
752
700def user_logout(request):753def user_logout(request):
701 logout(request)754 logout(request)
702 return redirect('user_login')755 return redirect('user_login')

Subscribers

People subscribed via source and target branches