Merge lp:~nkarageuzian/mailman/usermanagement into lp:mailman

Proposed by nicolask
Status: Rejected
Rejected by: Barry Warsaw
Proposed branch: lp:~nkarageuzian/mailman/usermanagement
Merge into: lp:mailman
Diff against target: 103 lines (+81/-3)
2 files modified
src/mailman/model/tests/test_usermanager.py (+67/-0)
src/mailman/model/usermanager.py (+14/-3)
To merge this branch: bzr merge lp:~nkarageuzian/mailman/usermanagement
Reviewer Review Type Date Requested Status
Mailman Coders Pending
Review via email: mp+200128@code.launchpad.net

Description of the change

solves the use case:
user sends a mail to the list without subscribing nor registering
admin accepts message
user wants to register to mailman through API but
create_user method fails as sender's address is registered.

and add tests for usermanager and the create_user function.

To post a comment you must log in.
Revision history for this message
Barry Warsaw (barry) wrote :
Download full text (5.0 KiB)

nicolask - thanks very much for the contribution to Mailman! I'm afraid I'm going to have to reject this merge proposal though because I think this issue needs to be solved at a different level. The model tries to be as simple as possible, and because the IUser object is a fundamental object, the IUserManager.create_user() method should not implement these additional semantics. On the mailing list, I outlined an approach that I think would be better.

In the hopes that you'll continue to contribute to Mailman, I'd like to offer some additional style feedback on your diff. Again, thanks for working on Mailman!

=== added file 'src/mailman/model/tests/test_usermanager.py'
--- src/mailman/model/tests/test_usermanager.py 1970-01-01 00:00:00 +0000
+++ src/mailman/model/tests/test_usermanager.py 2013-12-28 10:18:08 +0000
> +class TestUserManager(unittest.TestCase):
> + """Test usermanager."""
> +
> + layer = ConfigLayer
> +
> + def setUp(self):
> + self._mlist = create_list('<email address hidden>')
> + #getUtility(IAddress)('<email address hidden>','No one')

Of course, you can get rid of that commented out line, but also, since your
tests all use the IUserManager utility, it might be better to do something
like this in the setUp():

        self._user_manager = getUtility(IUserManager)

and then use self._user_manager instead of having to get the utility every
time.

> +
> + def test_create_user(self):
> + anne = getUtility(IUserManager).create_user(
> + '<email address hidden>', 'Anne Person')
> +
> + def test_create_user_existing_address_user(self):
> + anne = getUtility(IUserManager).create_user(
> + '<email address hidden>', 'Anne Person')
> + self.assertRaises(ExistingAddressError, getUtility(IUserManager).create_user,*(
> + '<email address hidden>', 'Anne Person'))

You'll want to make sure this line is less than 80 characters wide. Also, you
should need the * there. I think the following would work better:

        self.assertRaises(ExistingAddressError,
                          self._user_manager.create_user,
                          '<email address hidden>', 'Anne Person')

> +
> + def test_create_user_existing_address_no_user(self):
> + anne = getUtility(IUserManager).create_user(
> + '<email address hidden>', 'Anne Person')
> + noone = getUtility(IUserManager).create_user(
> + '<email address hidden>','No one')
> + self.assertTrue(anne.user_id != noone.user_id)

It would be better to use self.assertNotEqual() here, since the error message
is better should the test ever fail. (Also, remember, a single space comes
after commas in an argument list.)

https://docs.python.org/2.7/library/unittest.html?highlight=unittest#assert-methods

=== modified file 'src/mailman/model/usermanager.py'
--- src/mailman/model/usermanager.py 2013-01-01 14:05:42 +0000
+++ src/mailman/model/usermanager.py 2013-12-28 10:18:08 +0000
> @@ -40,13 +40,24 @@
> @implementer(IUserManager)
> class UserManager:
> """See `IUserManager`."""
> -
> - def create_user(self, email=None, display_name=None):
> + @dbconnection
> + def create_user(s...

Read more...

Revision history for this message
nicolask (nkarageuzian) wrote :

barry,

No problems and many thanks for the time you spent for writing style hints.

I've read #1312884 and plan to contribute on it as I agree with the aproach proposed.
I guess I could get one more hint (file ref) to dive quickly in test writings for that.

Revision history for this message
Barry Warsaw (barry) wrote :

Writing tests for the REST API is actually pretty easy. In general, the
doctests in docs/ should be used to document how to use the API for the common
cases, and it should only document good-path uses (i.e. not error or corner
conditions). Use unittests for bad-path, error condition, or corner cases.

I think good examples of these are the user tests.

Here's the unittests: http://tinyurl.com/mldysb2

And the doctests: http://tinyurl.com/mqtacm9

Hope that helps and don't worry; I'll do a thorough review and help you get
your contribution landed. Thanks again!

Unmerged revisions

7232. By nicolask

improve usermanagement : allow create_user method even if an address is known (mail sent to the list without subscribing).

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'src/mailman/model/tests/test_usermanager.py'
--- src/mailman/model/tests/test_usermanager.py 1970-01-01 00:00:00 +0000
+++ src/mailman/model/tests/test_usermanager.py 2013-12-28 10:18:08 +0000
@@ -0,0 +1,67 @@
1# Copyright (C) 2011-2013 by the Free Software Foundation, Inc.
2#
3# This file is part of GNU Mailman.
4#
5# GNU Mailman is free software: you can redistribute it and/or modify it under
6# the terms of the GNU General Public License as published by the Free
7# Software Foundation, either version 3 of the License, or (at your option)
8# any later version.
9#
10# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13# more details.
14#
15# You should have received a copy of the GNU General Public License along with
16# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
17
18"""Test usermanager."""
19
20from __future__ import absolute_import, unicode_literals
21
22__metaclass__ = type
23__all__ = [
24 'TestUserManager',
25 ]
26
27
28import unittest
29
30from zope.component import getUtility
31
32from mailman.app.lifecycle import create_list
33from mailman.interfaces.usermanager import IUserManager
34from mailman.interfaces.address import ExistingAddressError
35from mailman.interfaces.address import IAddress
36from mailman.testing.layers import ConfigLayer
37from mailman.utilities.datetime import now
38
39
40
041
42class TestUserManager(unittest.TestCase):
43 """Test usermanager."""
44
45 layer = ConfigLayer
46
47 def setUp(self):
48 self._mlist = create_list('test@example.com')
49 #getUtility(IAddress)('no_one@example.com','No one')
50
51 def test_create_user(self):
52 anne = getUtility(IUserManager).create_user(
53 'anne@example.com', 'Anne Person')
54
55 def test_create_user_existing_address_user(self):
56 anne = getUtility(IUserManager).create_user(
57 'anne@example.com', 'Anne Person')
58 self.assertRaises(ExistingAddressError, getUtility(IUserManager).create_user,*(
59 'anne@example.com', 'Anne Person'))
60
61 def test_create_user_existing_address_no_user(self):
62 anne = getUtility(IUserManager).create_user(
63 'anne@example.com', 'Anne Person')
64 noone = getUtility(IUserManager).create_user(
65 'no_one@example.com','No one')
66 self.assertTrue(anne.user_id != noone.user_id)
67
68
169
=== modified file 'src/mailman/model/usermanager.py'
--- src/mailman/model/usermanager.py 2013-01-01 14:05:42 +0000
+++ src/mailman/model/usermanager.py 2013-12-28 10:18:08 +0000
@@ -40,13 +40,24 @@
40@implementer(IUserManager)40@implementer(IUserManager)
41class UserManager:41class UserManager:
42 """See `IUserManager`."""42 """See `IUserManager`."""
4343 @dbconnection
44 def create_user(self, email=None, display_name=None):44 def create_user(self, store, email=None, display_name=None):
45 """See `IUserManager`."""45 """See `IUserManager`."""
46 user = User(display_name, Preferences())46 user = User(display_name, Preferences())
47 if email:47 if email:
48 address = self.create_address(email, display_name)48 address = None
49 try:
50 address = self.create_address(email, display_name)
51 except:
52 addresses = store.find(Address, email=email.lower())
53 if addresses.count() == 0:
54 raise Exception("inconsistent results")
55 if addresses.one().user == None:
56 address = addresses.one()
57 else:
58 raise ExistingAddressError(email)
49 user.link(address)59 user.link(address)
60 store.add(user)
50 return user61 return user
5162
52 @dbconnection63 @dbconnection