pyramid-fullauth 0.4.0__py3.3.egg

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. EGG-INFO/PKG-INFO +184 -0
  2. EGG-INFO/SOURCES.txt +93 -0
  3. EGG-INFO/dependency_links.txt +1 -0
  4. EGG-INFO/not-zip-safe +1 -0
  5. EGG-INFO/requires.txt +13 -0
  6. EGG-INFO/top_level.txt +2 -0
  7. pyramid_fullauth/__init__.py +106 -0
  8. pyramid_fullauth/__pycache__/__init__.cpython-33.pyc +0 -0
  9. pyramid_fullauth/__pycache__/auth.cpython-33.pyc +0 -0
  10. pyramid_fullauth/__pycache__/events.cpython-33.pyc +0 -0
  11. pyramid_fullauth/__pycache__/exceptions.cpython-33.pyc +0 -0
  12. pyramid_fullauth/__pycache__/request.cpython-33.pyc +0 -0
  13. pyramid_fullauth/__pycache__/tools.cpython-33.pyc +0 -0
  14. pyramid_fullauth/auth.py +67 -0
  15. pyramid_fullauth/config/default.yaml +26 -0
  16. pyramid_fullauth/events.py +281 -0
  17. pyramid_fullauth/exceptions.py +47 -0
  18. pyramid_fullauth/models/__init__.py +190 -0
  19. pyramid_fullauth/models/__pycache__/__init__.cpython-33.pyc +0 -0
  20. pyramid_fullauth/models/extensions/__init__.py +39 -0
  21. pyramid_fullauth/models/extensions/__pycache__/__init__.cpython-33.pyc +0 -0
  22. pyramid_fullauth/models/mixins/__init__.py +9 -0
  23. pyramid_fullauth/models/mixins/__pycache__/__init__.cpython-33.pyc +0 -0
  24. pyramid_fullauth/models/mixins/__pycache__/email.cpython-33.pyc +0 -0
  25. pyramid_fullauth/models/mixins/__pycache__/password.cpython-33.pyc +0 -0
  26. pyramid_fullauth/models/mixins/email.py +128 -0
  27. pyramid_fullauth/models/mixins/password.py +141 -0
  28. pyramid_fullauth/request.py +70 -0
  29. pyramid_fullauth/resources/helpers/social.mako +17 -0
  30. pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
  31. pyramid_fullauth/resources/templates/403.mako +11 -0
  32. pyramid_fullauth/resources/templates/_form.login.mako +44 -0
  33. pyramid_fullauth/resources/templates/_form.register.mako +47 -0
  34. pyramid_fullauth/resources/templates/_social.login.mako +17 -0
  35. pyramid_fullauth/resources/templates/activate.mako +14 -0
  36. pyramid_fullauth/resources/templates/email_change.mako +33 -0
  37. pyramid_fullauth/resources/templates/layout.mako +13 -0
  38. pyramid_fullauth/resources/templates/login.mako +17 -0
  39. pyramid_fullauth/resources/templates/register.mako +22 -0
  40. pyramid_fullauth/resources/templates/reset.mako +34 -0
  41. pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
  42. pyramid_fullauth/routing/__init__.py +5 -0
  43. pyramid_fullauth/routing/__pycache__/__init__.cpython-33.pyc +0 -0
  44. pyramid_fullauth/routing/__pycache__/predicates.cpython-33.pyc +0 -0
  45. pyramid_fullauth/routing/predicates.py +86 -0
  46. pyramid_fullauth/tools.py +69 -0
  47. pyramid_fullauth/views/__init__.py +15 -0
  48. pyramid_fullauth/views/__pycache__/__init__.cpython-33.pyc +0 -0
  49. pyramid_fullauth/views/__pycache__/social.cpython-33.pyc +0 -0
  50. pyramid_fullauth/views/basic/__init__.py +5 -0
  51. pyramid_fullauth/views/basic/__pycache__/__init__.cpython-33.pyc +0 -0
  52. pyramid_fullauth/views/basic/__pycache__/activate.cpython-33.pyc +0 -0
  53. pyramid_fullauth/views/basic/__pycache__/forbidden.cpython-33.pyc +0 -0
  54. pyramid_fullauth/views/basic/__pycache__/login.cpython-33.pyc +0 -0
  55. pyramid_fullauth/views/basic/__pycache__/logout.cpython-33.pyc +0 -0
  56. pyramid_fullauth/views/basic/__pycache__/register.cpython-33.pyc +0 -0
  57. pyramid_fullauth/views/basic/activate.py +44 -0
  58. pyramid_fullauth/views/basic/forbidden.py +46 -0
  59. pyramid_fullauth/views/basic/login.py +128 -0
  60. pyramid_fullauth/views/basic/logout.py +28 -0
  61. pyramid_fullauth/views/basic/profile/__init__.py +5 -0
  62. pyramid_fullauth/views/basic/profile/__pycache__/__init__.cpython-33.pyc +0 -0
  63. pyramid_fullauth/views/basic/profile/__pycache__/email.cpython-33.pyc +0 -0
  64. pyramid_fullauth/views/basic/profile/__pycache__/password.cpython-33.pyc +0 -0
  65. pyramid_fullauth/views/basic/profile/email.py +108 -0
  66. pyramid_fullauth/views/basic/profile/password.py +129 -0
  67. pyramid_fullauth/views/basic/register.py +111 -0
  68. pyramid_fullauth/views/social.py +221 -0
  69. tests/__init__.py +1 -0
  70. tests/__pycache__/__init__.cpython-33.pyc +0 -0
  71. tests/__pycache__/conftest.cpython-33.pyc +0 -0
  72. tests/__pycache__/tools.cpython-33.pyc +0 -0
  73. tests/conftest.py +201 -0
  74. tests/tools.py +54 -0
  75. tests/unit/__pycache__/test_default_settings.cpython-33.pyc +0 -0
  76. tests/unit/__pycache__/test_groupfinder.cpython-33.pyc +0 -0
  77. tests/unit/__pycache__/test_social_view.cpython-33.pyc +0 -0
  78. tests/unit/__pycache__/test_tools.cpython-33.pyc +0 -0
  79. tests/unit/__pycache__/test_user_active.cpython-33.pyc +0 -0
  80. tests/unit/__pycache__/test_user_admin.cpython-33.pyc +0 -0
  81. tests/unit/__pycache__/test_user_email.cpython-33.pyc +0 -0
  82. tests/unit/__pycache__/test_user_password.cpython-33.pyc +0 -0
  83. tests/unit/__pycache__/test_user_providers.cpython-33.pyc +0 -0
  84. tests/unit/__pycache__/test_user_repr.cpython-33.pyc +0 -0
  85. tests/unit/__pycache__/test_validators.cpython-33.pyc +0 -0
  86. tests/unit/test_default_settings.py +15 -0
  87. tests/unit/test_groupfinder.py +20 -0
  88. tests/unit/test_social_view.py +69 -0
  89. tests/unit/test_tools.py +24 -0
  90. tests/unit/test_user_active.py +31 -0
  91. tests/unit/test_user_admin.py +61 -0
  92. tests/unit/test_user_email.py +37 -0
  93. tests/unit/test_user_password.py +52 -0
  94. tests/unit/test_user_providers.py +24 -0
  95. tests/unit/test_user_repr.py +29 -0
  96. tests/unit/test_validators.py +44 -0
  97. tests/views/__init__.py +1 -0
  98. tests/views/__pycache__/__init__.cpython-33.pyc +0 -0
  99. tests/views/__pycache__/conftest.cpython-33.pyc +0 -0
  100. tests/views/__pycache__/test_activation.cpython-33.pyc +0 -0
  101. tests/views/__pycache__/test_email.cpython-33.pyc +0 -0
  102. tests/views/__pycache__/test_events.cpython-33.pyc +0 -0
  103. tests/views/__pycache__/test_login.cpython-33.pyc +0 -0
  104. tests/views/__pycache__/test_login_social.cpython-33.pyc +0 -0
  105. tests/views/__pycache__/test_logout.cpython-33.pyc +0 -0
  106. tests/views/__pycache__/test_register.cpython-33.pyc +0 -0
  107. tests/views/__pycache__/test_reset.cpython-33.pyc +0 -0
  108. tests/views/conftest.py +20 -0
  109. tests/views/test_activation.py +86 -0
  110. tests/views/test_email.py +175 -0
  111. tests/views/test_events.py +558 -0
  112. tests/views/test_login.py +172 -0
  113. tests/views/test_login_social.py +289 -0
  114. tests/views/test_logout.py +42 -0
  115. tests/views/test_register.py +138 -0
  116. tests/views/test_reset.py +105 -0
@@ -0,0 +1,44 @@
1
+ """Test various validators present on User class."""
2
+ import pytest
3
+ import transaction
4
+ from pyramid.compat import text_type
5
+
6
+ from pyramid_fullauth.models import User
7
+ from pyramid_fullauth.exceptions import EmptyError, EmailValidationError
8
+
9
+
10
+ @pytest.mark.parametrize('email', [
11
+ text_type('very.common@example.com'),
12
+ text_type('a.little.lengthy.but.fine@dept.example.com'),
13
+ text_type('disposable.style.email.with+symbol@example.com'),
14
+ text_type('"very.unusual.@.unusual.com"@example.com'),
15
+ text_type('!#$%&\'*+-/=?^_`{}|~@example.org'),
16
+ text_type('""@example.org'),
17
+ text_type('"much.more unusual"@example.com'),
18
+ text_type('"()<>[]:,;@\\\"!#$%&\'*+-/=?^_`{}| ~ ? ^_`{}|~.a"@example.org'),
19
+ ])
20
+ def test_email_valid_formats(db_session, user, email):
21
+ """Check all valid formats of Email (RFC 5321) can be set by user."""
22
+ user = db_session.merge(user)
23
+
24
+ user.email = email
25
+ transaction.commit()
26
+
27
+ user = db_session.query(User).filter(
28
+ User.username == text_type('u1')).one()
29
+ assert user.email == email
30
+
31
+
32
+ def test_email_empty(user):
33
+ """Test reaction of email validator for empty email."""
34
+ with pytest.raises(EmptyError):
35
+ user.email = text_type('')
36
+
37
+
38
+ def test_email_invalid_formats(db_session, user, invalid_email):
39
+ """Check all invalid formats of Email (RFC 5321) can not be set by user."""
40
+ user = db_session.merge(user)
41
+
42
+ with pytest.raises(EmailValidationError):
43
+ user.email = invalid_email
44
+ transaction.commit()
@@ -0,0 +1 @@
1
+ """Makes easier keeping some tests config with tests."""
@@ -0,0 +1,20 @@
1
+ """General view fixtures."""
2
+ import pytest
3
+ import transaction
4
+
5
+ from pyramid_fullauth.models import AuthenticationProvider
6
+
7
+
8
+ def mock_translate(msg, *args, **kwargs):
9
+ """Mock translate function (simply returns message)."""
10
+ return msg
11
+
12
+
13
+ @pytest.fixture
14
+ def facebook_user(active_user, db_session):
15
+ """Facebook user."""
16
+ active_user = db_session.merge(active_user)
17
+ active_user.providers.append(
18
+ AuthenticationProvider(provider='facebook', provider_id='1234'))
19
+ transaction.commit()
20
+ return db_session.merge(active_user)
@@ -0,0 +1,86 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Account activation related tests."""
3
+ try:
4
+ from urllib import quote
5
+ # python3
6
+ except ImportError:
7
+ from urllib.parse import quote
8
+
9
+ import transaction
10
+
11
+ from pyramid_fullauth.models import User
12
+ from tests.tools import authenticate, is_user_logged
13
+
14
+
15
+ def test_account_activation(user, db_session, default_app):
16
+ """Activate user."""
17
+ user = db_session.merge(user)
18
+
19
+ default_app.get('/register/activate/' + user.activate_key)
20
+ transaction.commit()
21
+ user = db_session.query(User).filter(User.email == user.email).one()
22
+
23
+ assert not user.activate_key
24
+ assert user.is_active
25
+ assert user.activated_at
26
+
27
+ authenticate(default_app)
28
+ assert is_user_logged(default_app) is True
29
+
30
+
31
+ def test_account_activation_wrong_key(user, db_session, default_app):
32
+ """Activate user with wrong key."""
33
+ user = db_session.merge(user)
34
+ activate_key = user.activate_key
35
+ res = default_app.get('/register/activate/' + activate_key[:-5], status=200)
36
+ transaction.commit()
37
+
38
+ assert 'Invalid activation code' in res.body.decode('unicode_escape')
39
+
40
+ user = db_session.query(User).filter(User.email == user.email).one()
41
+ assert user.activate_key == activate_key
42
+ assert user.activate_key is not None
43
+ assert not user.activated_at
44
+ # User should not have active account at this moment
45
+ assert not user.is_active
46
+
47
+
48
+ def test_account_activation_key_with_trash_chars(user, db_session, default_app):
49
+ """Strange characters in activation key."""
50
+ user = db_session.merge(user)
51
+
52
+ activate_key = user.activate_key
53
+ res = default_app.get(
54
+ '/register/activate/' + quote(
55
+ # ąśðłĸęł¶→łęóħó³→←śðđ[]}³½ĸżćŋðń→↓ŧ¶ħ→ĸł¼²³↓←ħ@ĸđśðĸ@ł¼ęłśħđó[³²½łðśđħ - already decoded
56
+ '\xc4\x85\xc5\x9b\xc3\xb0\xc5\x82\xc4\xb8\xc4\x99\xc5\x82\xc2\xb6\xe2\x86\x92\xc5\x82\xc4\x99\xc3\xb3\xc4\xa7\xc3\xb3\xc2\xb3\xe2\x86\x92\xe2\x86\x90\xc5\x9b\xc3\xb0\xc4\x91[]}\xc2\xb3\xc2\xbd\xc4\xb8\xc5\xbc\xc4\x87\xc5\x8b\xc3\xb0\xc5\x84\xe2\x86\x92\xe2\x86\x93\xc5\xa7\xc2\xb6\xc4\xa7\xe2\x86\x92\xc4\xb8\xc5\x82\xc2\xbc\xc2\xb2\xc2\xb3\xe2\x86\x93\xe2\x86\x90\xc4\xa7@\xc4\xb8\xc4\x91\xc5\x9b\xc3\xb0\xc4\xb8@\xc5\x82\xc2\xbc\xc4\x99\xc5\x82\xc5\x9b\xc4\xa7\xc4\x91\xc3\xb3[\xc2\xb3\xc2\xb2\xc2\xbd\xc5\x82\xc3\xb0\xc5\x9b\xc4\x91\xc4\xa7'
57
+ ),
58
+ status=200
59
+ )
60
+ transaction.commit()
61
+
62
+ assert 'Invalid activation code' in res.body.decode('unicode_escape')
63
+ user = db_session.query(User).filter(User.email == user.email).one()
64
+
65
+ assert user.activate_key == activate_key
66
+ assert user.activate_key is not None
67
+ assert not user.activated_at
68
+ # User should not have active account at this moment
69
+ assert not user.is_active
70
+
71
+
72
+ def test_account_activation_twice(user, db_session, default_app):
73
+ """Click activation link twice."""
74
+ user = db_session.merge(user)
75
+
76
+ activate_key = user.activate_key
77
+ res = default_app.get('/register/activate/' + activate_key)
78
+ transaction.commit()
79
+ user = db_session.query(User).filter(User.email == user.email).one()
80
+
81
+ assert not user.activate_key
82
+ assert user.is_active
83
+ assert user.activated_at
84
+
85
+ res = default_app.get('/register/activate/' + activate_key, status=200)
86
+ assert 'Invalid activation code' in res.body.decode('unicode_escape')
@@ -0,0 +1,175 @@
1
+ """Email change views."""
2
+ import pytest
3
+ import transaction
4
+
5
+ from sqlalchemy.orm.exc import NoResultFound
6
+ from pyramid.compat import text_type
7
+ from pyramid_fullauth.models import User
8
+
9
+ from tests.tools import authenticate, DEFAULT_USER
10
+
11
+
12
+ def test_email_view_not_logged(default_app):
13
+ """Try to access email change view anonymously."""
14
+ app = default_app
15
+ res = app.get('/email/change')
16
+ assert res.status_code == 302
17
+ assert res.location == 'http://localhost/login?after=%2Femail%2Fchange'
18
+
19
+
20
+ def test_email_view_logged(db_session, active_user, default_app):
21
+ """Simple get for change email view."""
22
+ app = default_app
23
+ db_session.close()
24
+ # Session are de-syncronised
25
+
26
+ # login user
27
+ authenticate(app)
28
+
29
+ res = app.get('/email/change')
30
+ assert res.status_code == 200
31
+ assert res.form
32
+ assert res.form['email']
33
+
34
+
35
+ def test_email_valid(db_session, active_user, default_app):
36
+ """Change email with valid data."""
37
+ app = default_app
38
+
39
+ authenticate(app)
40
+ email = DEFAULT_USER['email']
41
+ new_email = 'email@email.com'
42
+
43
+ user = db_session.query(User).filter(User.email == email).one()
44
+
45
+ res = app.get('/email/change')
46
+ form = res.form
47
+ form['email'] = new_email
48
+ res = form.submit()
49
+ assert res
50
+
51
+ transaction.commit()
52
+
53
+ user = db_session.query(User).filter(User.email == email).one()
54
+ assert user.new_email == new_email
55
+ assert user.email == email
56
+ assert user.email_change_key is not None
57
+
58
+
59
+ def test_email_valid_xhr(db_session, active_user, default_app):
60
+ """Change email with valid data."""
61
+ app = default_app
62
+
63
+ authenticate(app)
64
+ email = DEFAULT_USER['email']
65
+ new_email = 'email@email.com'
66
+
67
+ user = db_session.query(User).filter(User.email == email).one()
68
+
69
+ res = app.get('/email/change')
70
+ res = app.post(
71
+ '/email/change',
72
+ {
73
+ 'csrf_token': res.form['csrf_token'].value,
74
+ 'email': new_email},
75
+ xhr=True)
76
+ assert res.json['status'] is True
77
+
78
+ transaction.commit()
79
+
80
+ user = db_session.query(User).filter(User.email == email).one()
81
+ assert user.new_email == new_email
82
+ assert user.email == email
83
+ assert user.email_change_key is not None
84
+
85
+
86
+ def test_wrong_email(db_session, active_user, default_app, invalid_email):
87
+ """Change email with incorrect email."""
88
+ app = default_app
89
+ # login user
90
+ authenticate(app)
91
+
92
+ res = app.get('/email/change')
93
+ form = res.form
94
+ form['email'] = invalid_email
95
+ res = form.submit()
96
+ assert 'Error! Incorrect e-mail format' in res
97
+
98
+
99
+ def test_empty_email(db_session, active_user, default_app):
100
+ """Try to change email with empty value."""
101
+ app = default_app
102
+ # login user
103
+ authenticate(app)
104
+
105
+ res = app.get('/email/change')
106
+ form = res.form
107
+ form['email'] = ''
108
+ res = form.submit()
109
+ assert 'Error! E-mail is empty' in res
110
+
111
+
112
+ def test_existing_email(db_session, active_user, default_app):
113
+ """Try to change email to existing one email."""
114
+ # add other user
115
+ existing_email = text_type("existing@email.eg")
116
+ db_session.add(
117
+ User(
118
+ email=existing_email,
119
+ password=text_type("somepassword"),
120
+ address_ip=DEFAULT_USER['address_ip']
121
+ ))
122
+ transaction.commit()
123
+ # login user
124
+ authenticate(default_app)
125
+
126
+ # submit request!
127
+ res = default_app.get('/email/change')
128
+ form = res.form
129
+ form['email'] = existing_email
130
+ res = form.submit()
131
+ assert 'Error! User with this email exists' in res
132
+
133
+
134
+ def test_email_proceed(db_session, active_user, default_app):
135
+ """Confirm email change view."""
136
+ app = default_app
137
+ # login user
138
+ authenticate(app)
139
+
140
+ email = DEFAULT_USER['email']
141
+ user = db_session.query(User).filter(User.email == email).one()
142
+
143
+ new_email = text_type('email2@email.com')
144
+ user.set_new_email(new_email)
145
+ transaction.commit()
146
+
147
+ user = db_session.merge(user)
148
+ res = app.get('/email/change/' + user.email_change_key)
149
+ assert res.status_code == 303
150
+
151
+ with pytest.raises(NoResultFound):
152
+ # there is no user with old email
153
+ db_session.query(User).filter(User.email == email).one()
154
+
155
+ user = db_session.query(User).filter(User.email == new_email).one()
156
+ assert not user.email_change_key
157
+
158
+
159
+ def test_email_proceed_wrong_key(db_session, active_user, default_app):
160
+ """Try to confirm email change view with wrong key."""
161
+ app = default_app
162
+ # login user
163
+ authenticate(app)
164
+
165
+ email = DEFAULT_USER['email']
166
+ user = db_session.query(User).filter(User.email == email).one()
167
+
168
+ new_email = text_type('email2@email.com')
169
+ user.set_new_email(new_email)
170
+ transaction.commit()
171
+
172
+ user = db_session.merge(user)
173
+ res = app.get(
174
+ '/email/change/' + user.email_change_key + 'randomchars', status=404)
175
+ assert res.status_code == 404