pyramid-fullauth 0.4.0__py3.4.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.
- EGG-INFO/PKG-INFO +184 -0
- EGG-INFO/SOURCES.txt +93 -0
- EGG-INFO/dependency_links.txt +1 -0
- EGG-INFO/not-zip-safe +1 -0
- EGG-INFO/requires.txt +13 -0
- EGG-INFO/top_level.txt +2 -0
- pyramid_fullauth/__init__.py +106 -0
- pyramid_fullauth/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/auth.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/events.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/exceptions.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/request.cpython-34.pyc +0 -0
- pyramid_fullauth/__pycache__/tools.cpython-34.pyc +0 -0
- pyramid_fullauth/auth.py +67 -0
- pyramid_fullauth/config/default.yaml +26 -0
- pyramid_fullauth/events.py +281 -0
- pyramid_fullauth/exceptions.py +47 -0
- pyramid_fullauth/models/__init__.py +190 -0
- pyramid_fullauth/models/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/extensions/__init__.py +39 -0
- pyramid_fullauth/models/extensions/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__init__.py +9 -0
- pyramid_fullauth/models/mixins/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/models/mixins/email.py +128 -0
- pyramid_fullauth/models/mixins/password.py +141 -0
- pyramid_fullauth/request.py +70 -0
- pyramid_fullauth/resources/helpers/social.mako +17 -0
- pyramid_fullauth/resources/locale/pyramid_fullauth.pot +216 -0
- pyramid_fullauth/resources/templates/403.mako +11 -0
- pyramid_fullauth/resources/templates/_form.login.mako +44 -0
- pyramid_fullauth/resources/templates/_form.register.mako +47 -0
- pyramid_fullauth/resources/templates/_social.login.mako +17 -0
- pyramid_fullauth/resources/templates/activate.mako +14 -0
- pyramid_fullauth/resources/templates/email_change.mako +33 -0
- pyramid_fullauth/resources/templates/layout.mako +13 -0
- pyramid_fullauth/resources/templates/login.mako +17 -0
- pyramid_fullauth/resources/templates/register.mako +22 -0
- pyramid_fullauth/resources/templates/reset.mako +34 -0
- pyramid_fullauth/resources/templates/reset.proceed.mako +41 -0
- pyramid_fullauth/routing/__init__.py +5 -0
- pyramid_fullauth/routing/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/__pycache__/predicates.cpython-34.pyc +0 -0
- pyramid_fullauth/routing/predicates.py +86 -0
- pyramid_fullauth/tools.py +69 -0
- pyramid_fullauth/views/__init__.py +15 -0
- pyramid_fullauth/views/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/__pycache__/social.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__init__.py +5 -0
- pyramid_fullauth/views/basic/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/activate.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/forbidden.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/login.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/logout.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/__pycache__/register.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/activate.py +44 -0
- pyramid_fullauth/views/basic/forbidden.py +46 -0
- pyramid_fullauth/views/basic/login.py +128 -0
- pyramid_fullauth/views/basic/logout.py +28 -0
- pyramid_fullauth/views/basic/profile/__init__.py +5 -0
- pyramid_fullauth/views/basic/profile/__pycache__/__init__.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/email.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/__pycache__/password.cpython-34.pyc +0 -0
- pyramid_fullauth/views/basic/profile/email.py +108 -0
- pyramid_fullauth/views/basic/profile/password.py +129 -0
- pyramid_fullauth/views/basic/register.py +111 -0
- pyramid_fullauth/views/social.py +221 -0
- tests/__init__.py +1 -0
- tests/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/__pycache__/tools.cpython-34.pyc +0 -0
- tests/conftest.py +201 -0
- tests/tools.py +54 -0
- tests/unit/__pycache__/test_default_settings.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_groupfinder.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_social_view.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_tools.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_active.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_admin.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_email.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_password.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_providers.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_user_repr.cpython-34.pyc +0 -0
- tests/unit/__pycache__/test_validators.cpython-34.pyc +0 -0
- tests/unit/test_default_settings.py +15 -0
- tests/unit/test_groupfinder.py +20 -0
- tests/unit/test_social_view.py +69 -0
- tests/unit/test_tools.py +24 -0
- tests/unit/test_user_active.py +31 -0
- tests/unit/test_user_admin.py +61 -0
- tests/unit/test_user_email.py +37 -0
- tests/unit/test_user_password.py +52 -0
- tests/unit/test_user_providers.py +24 -0
- tests/unit/test_user_repr.py +29 -0
- tests/unit/test_validators.py +44 -0
- tests/views/__init__.py +1 -0
- tests/views/__pycache__/__init__.cpython-34.pyc +0 -0
- tests/views/__pycache__/conftest.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_activation.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_email.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_events.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_login_social.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_logout.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_register.cpython-34.pyc +0 -0
- tests/views/__pycache__/test_reset.cpython-34.pyc +0 -0
- tests/views/conftest.py +20 -0
- tests/views/test_activation.py +86 -0
- tests/views/test_email.py +175 -0
- tests/views/test_events.py +558 -0
- tests/views/test_login.py +172 -0
- tests/views/test_login_social.py +289 -0
- tests/views/test_logout.py +42 -0
- tests/views/test_register.py +138 -0
- tests/views/test_reset.py +105 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Email mixin related module."""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
import uuid
|
|
9
|
+
|
|
10
|
+
from sqlalchemy import Column, Unicode, String
|
|
11
|
+
from sqlalchemy.orm import validates
|
|
12
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from pyramid_fullauth.exceptions import EmptyError, EmailValidationError
|
|
16
|
+
from pyramid_fullauth.models.extensions import CaseInsensitive
|
|
17
|
+
|
|
18
|
+
pattern_mail = re.compile(
|
|
19
|
+
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]{0,256}(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+){0,256}" # dot-atom
|
|
20
|
+
# quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
|
|
21
|
+
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177 ]|\\[\001-\011\013\014\016-\177 ]){0,256}"'
|
|
22
|
+
r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2}\.?)$)' # domain
|
|
23
|
+
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class UserEmailMixin(object):
|
|
27
|
+
|
|
28
|
+
"""User email fields and functionality."""
|
|
29
|
+
|
|
30
|
+
__pattern_mail = pattern_mail
|
|
31
|
+
|
|
32
|
+
_email = Column('email', Unicode(254), unique=True, nullable=False) # RFC5321 and RFC3696(errata)
|
|
33
|
+
_new_email = Column('new_email', Unicode(254), unique=True, nullable=True) # RFC5321 and RFC3696(errata)
|
|
34
|
+
email_change_key = Column(String(255), default=None, unique=True)
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args, **kwargs):
|
|
37
|
+
"""Switch possible email and new_email kwarg into new column attribute names."""
|
|
38
|
+
if 'email' in kwargs:
|
|
39
|
+
kwargs['_email'] = kwargs.pop('email')
|
|
40
|
+
if 'new_email' in kwargs:
|
|
41
|
+
kwargs['_new_email'] - kwargs.pop('new_email')
|
|
42
|
+
|
|
43
|
+
super(UserEmailMixin, self).__init__(*args, **kwargs)
|
|
44
|
+
|
|
45
|
+
@hybrid_property
|
|
46
|
+
def email(self):
|
|
47
|
+
"""Email field getter."""
|
|
48
|
+
if self._email:
|
|
49
|
+
return self._email.lower()
|
|
50
|
+
return self._email
|
|
51
|
+
|
|
52
|
+
@email.setter
|
|
53
|
+
def email(self, value):
|
|
54
|
+
"""Email field setter."""
|
|
55
|
+
if value:
|
|
56
|
+
value = value.lower()
|
|
57
|
+
self._email = value
|
|
58
|
+
|
|
59
|
+
@email.comparator
|
|
60
|
+
def email(cls):
|
|
61
|
+
"""Email field comparator."""
|
|
62
|
+
return CaseInsensitive(cls._email)
|
|
63
|
+
|
|
64
|
+
@hybrid_property
|
|
65
|
+
def new_email(self):
|
|
66
|
+
"""New email field getter."""
|
|
67
|
+
if self._new_email:
|
|
68
|
+
return self._new_email.lower()
|
|
69
|
+
return self._new_email
|
|
70
|
+
|
|
71
|
+
@new_email.setter
|
|
72
|
+
def new_email(self, value):
|
|
73
|
+
"""New email field setter."""
|
|
74
|
+
if value:
|
|
75
|
+
value = value.lower()
|
|
76
|
+
self._new_email = value
|
|
77
|
+
|
|
78
|
+
@new_email.comparator
|
|
79
|
+
def new_email(cls):
|
|
80
|
+
"""New email field comparator."""
|
|
81
|
+
return CaseInsensitive(cls._new_email)
|
|
82
|
+
|
|
83
|
+
@validates('_email', '_new_email')
|
|
84
|
+
def validate_email(self, key, address):
|
|
85
|
+
"""
|
|
86
|
+
Validate email addresses.
|
|
87
|
+
|
|
88
|
+
.. note::
|
|
89
|
+
|
|
90
|
+
See pyramid docs about `simple validators <http://docs.sqlalchemy.org/en/latest/orm/mapper_config.html#simple-validators>`_
|
|
91
|
+
|
|
92
|
+
:param str key: field key
|
|
93
|
+
:param str address: email address
|
|
94
|
+
|
|
95
|
+
:raises EmailValidationError:
|
|
96
|
+
:raises EmptyError:
|
|
97
|
+
"""
|
|
98
|
+
if address:
|
|
99
|
+
if pattern_mail.match(address):
|
|
100
|
+
return address
|
|
101
|
+
else:
|
|
102
|
+
raise EmailValidationError('Incorrect e-mail format')
|
|
103
|
+
|
|
104
|
+
raise EmptyError('E-mail is empty')
|
|
105
|
+
|
|
106
|
+
def set_new_email(self, email_new):
|
|
107
|
+
"""
|
|
108
|
+
Set new email and generate new email change hash.
|
|
109
|
+
|
|
110
|
+
:param str email_new: email address
|
|
111
|
+
|
|
112
|
+
:returns: generated email_change_key
|
|
113
|
+
:trype: str
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
self.new_email = email_new
|
|
117
|
+
self.email_change_key = str(uuid.uuid4())
|
|
118
|
+
return self.email_change_key
|
|
119
|
+
|
|
120
|
+
def change_email(self):
|
|
121
|
+
"""
|
|
122
|
+
Change email after activation.
|
|
123
|
+
|
|
124
|
+
We don't clear new email field because of validator of email which won't allow to None value.
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
self.email = self.new_email
|
|
128
|
+
self.email_change_key = None
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""Password mixin related module."""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import hashlib
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
from sqlalchemy import Column
|
|
12
|
+
from sqlalchemy import Unicode
|
|
13
|
+
from sqlalchemy import Enum
|
|
14
|
+
from sqlalchemy import String
|
|
15
|
+
from sqlalchemy.orm import validates
|
|
16
|
+
from pyramid.compat import text_type
|
|
17
|
+
from pyramid_fullauth.exceptions import EmptyError
|
|
18
|
+
|
|
19
|
+
try: # pragma: no cover
|
|
20
|
+
algorithms = hashlib.algorithms
|
|
21
|
+
except AttributeError: # pragma: no cover
|
|
22
|
+
# Simple tuple for Python 2.6
|
|
23
|
+
algorithms = ('md5', 'sha1')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class UserPasswordMixin(object):
|
|
27
|
+
|
|
28
|
+
"""Authentication field definition along with appropriate methods."""
|
|
29
|
+
|
|
30
|
+
#: password field
|
|
31
|
+
password = Column(Unicode(40), nullable=False)
|
|
32
|
+
|
|
33
|
+
#: hash_algorithm field
|
|
34
|
+
_hash_algorithm = Column('hash_algorithm',
|
|
35
|
+
Enum(*algorithms, name="hash_algorithms_enum"),
|
|
36
|
+
default=text_type('sha1'), nullable=False)
|
|
37
|
+
|
|
38
|
+
#: salt field
|
|
39
|
+
_salt = Column('salt', Unicode(50), nullable=False)
|
|
40
|
+
|
|
41
|
+
#: reset key field
|
|
42
|
+
reset_key = Column(String(255), unique=True)
|
|
43
|
+
|
|
44
|
+
def check_password(self, password):
|
|
45
|
+
"""
|
|
46
|
+
Check if password correspond to the saved one.
|
|
47
|
+
|
|
48
|
+
:param str password: password to compare
|
|
49
|
+
|
|
50
|
+
:returns: True, if password is same, False if not
|
|
51
|
+
:rtype: bool
|
|
52
|
+
"""
|
|
53
|
+
if password and self.hash_password(password, self._salt, self._hash_algorithm) == self.password:
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
def set_reset(self):
|
|
59
|
+
"""Generate password reset key."""
|
|
60
|
+
self.reset_key = str(uuid.uuid4())
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def hash_password(cls, password, salt, hash_method):
|
|
64
|
+
"""
|
|
65
|
+
Produce hash out of a password.
|
|
66
|
+
|
|
67
|
+
:param str password: password string, not hashed
|
|
68
|
+
:param str salt: salt
|
|
69
|
+
:param callable hash_method: a hash method which will be used to generate hash
|
|
70
|
+
|
|
71
|
+
:returns: hashed password
|
|
72
|
+
:rtype: str
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
# let's allow passing just method name
|
|
76
|
+
if not callable(hash_method):
|
|
77
|
+
hash_method = getattr(hashlib, hash_method)
|
|
78
|
+
|
|
79
|
+
# let's convert password to string from unicode
|
|
80
|
+
if isinstance(password, text_type):
|
|
81
|
+
password = password.encode('utf-8')
|
|
82
|
+
|
|
83
|
+
# it's actually for Python 3, where str is unicode not bytestring,
|
|
84
|
+
# and haslib methods accepts only bytestr
|
|
85
|
+
if isinstance(salt, text_type):
|
|
86
|
+
salt = salt.encode('utf-8')
|
|
87
|
+
|
|
88
|
+
# generating salted hash
|
|
89
|
+
return hash_method(password + salt).hexdigest()
|
|
90
|
+
|
|
91
|
+
@validates('password')
|
|
92
|
+
def password_validator(self, key, password):
|
|
93
|
+
"""
|
|
94
|
+
Validate password.
|
|
95
|
+
|
|
96
|
+
Password validator keeps new password hashed.
|
|
97
|
+
Rises Value error on empty password
|
|
98
|
+
|
|
99
|
+
:param str key: field key
|
|
100
|
+
:param str password: new password
|
|
101
|
+
|
|
102
|
+
:returns: hashed and salted password
|
|
103
|
+
:rtype: str
|
|
104
|
+
:raises: pyramid_fullauth.exceptions.EmptyError
|
|
105
|
+
|
|
106
|
+
.. note::
|
|
107
|
+
|
|
108
|
+
If you're using this Mixin on your own User object,
|
|
109
|
+
don't forget to add a listener as well, like that:
|
|
110
|
+
|
|
111
|
+
.. code-block:: python
|
|
112
|
+
|
|
113
|
+
from sqlalchemy.event import listen
|
|
114
|
+
|
|
115
|
+
listen(User.password, 'set', User.password_listener, retval=True)
|
|
116
|
+
|
|
117
|
+
.. note::
|
|
118
|
+
|
|
119
|
+
For more information on Attribute Events in sqlalchemy see:
|
|
120
|
+
|
|
121
|
+
:meth:`sqlalchemy.orm.events.AttributeEvents.set`
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
if not password:
|
|
125
|
+
raise EmptyError('password-empty')
|
|
126
|
+
|
|
127
|
+
# reading default hash_algorithm
|
|
128
|
+
hash_algorithm = self.__class__._hash_algorithm.property.columns[0].default.arg
|
|
129
|
+
|
|
130
|
+
# getting currently used hash method
|
|
131
|
+
hash_method = getattr(hashlib, hash_algorithm)
|
|
132
|
+
|
|
133
|
+
# generating salt
|
|
134
|
+
salt = hash_method()
|
|
135
|
+
salt.update(os.urandom(60))
|
|
136
|
+
salt_value = salt.hexdigest()
|
|
137
|
+
|
|
138
|
+
# storing used hash algorithm
|
|
139
|
+
self._hash_algorithm = hash_algorithm
|
|
140
|
+
self._salt = text_type(salt_value)
|
|
141
|
+
return text_type(self.__class__.hash_password(password, salt_value, hash_method))
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
2
|
+
#
|
|
3
|
+
# This module is part of pyramid_fullauth and is released under
|
|
4
|
+
# the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
5
|
+
"""These method gets added to each ``pyramid.request.Request`` object."""
|
|
6
|
+
|
|
7
|
+
from pyramid.httpexceptions import HTTPSeeOther
|
|
8
|
+
from pyramid.security import remember, forget
|
|
9
|
+
from sqlalchemy.sql.expression import func
|
|
10
|
+
from sqlalchemy.orm.exc import NoResultFound
|
|
11
|
+
import pyramid_basemodel
|
|
12
|
+
|
|
13
|
+
from pyramid_fullauth.models import User
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def login_perform(request, user, location=None, remember_me=False):
|
|
17
|
+
"""
|
|
18
|
+
Perform login action.
|
|
19
|
+
|
|
20
|
+
:param pyramid.request.Request request: a request object
|
|
21
|
+
:param pyramid_fullauth.models.User user: a user object
|
|
22
|
+
:param str location: where user should be redirected after login
|
|
23
|
+
:param bool remember_me: if True set cookie max_age to one month (60 * 60 * 24 * 30 seconds)
|
|
24
|
+
|
|
25
|
+
:returns: redirect exception
|
|
26
|
+
:rtype: pyramid.httpexceptions.HTTPSeeOther
|
|
27
|
+
"""
|
|
28
|
+
user.logged_at = func.now()
|
|
29
|
+
if remember_me: # if remember in POST set cookie timeout to one from configure
|
|
30
|
+
headers = remember(request, user.id,
|
|
31
|
+
max_age=request.registry['config'].fullauth.login.cookie_max_age)
|
|
32
|
+
else:
|
|
33
|
+
headers = remember(request, user.id)
|
|
34
|
+
if not location:
|
|
35
|
+
location = '/'
|
|
36
|
+
|
|
37
|
+
# this remembers user immediately, without the need to redirect (see below)
|
|
38
|
+
request.response.headers.extend(headers)
|
|
39
|
+
return HTTPSeeOther(location=location, headers=request.response.headers)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def user(request):
|
|
43
|
+
"""
|
|
44
|
+
Return user object.
|
|
45
|
+
|
|
46
|
+
When called for the first time, it queries for user, which is later available as a pure property
|
|
47
|
+
overriding this method. See :meth:`pyramid_fullauth.includeme` for logic behind property.
|
|
48
|
+
|
|
49
|
+
:returns: logged in user object, or None
|
|
50
|
+
:rtype: pyramid_fullauth.models.User
|
|
51
|
+
"""
|
|
52
|
+
if request.unauthenticated_userid:
|
|
53
|
+
try:
|
|
54
|
+
user = pyramid_basemodel.Session.query(User).filter(
|
|
55
|
+
User.id == request.unauthenticated_userid
|
|
56
|
+
).one()
|
|
57
|
+
return user
|
|
58
|
+
except NoResultFound: # pragma: no cover
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def logout(request):
|
|
63
|
+
"""
|
|
64
|
+
Log user out.
|
|
65
|
+
|
|
66
|
+
:param pyramid.request.Request request: a request object
|
|
67
|
+
"""
|
|
68
|
+
if request.user:
|
|
69
|
+
request.response.headerlist.extend(forget(request))
|
|
70
|
+
request.user = None
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
|
|
9
|
+
<%def name="social_auth_uri(name, **kw)">
|
|
10
|
+
<%
|
|
11
|
+
from velruse import login_url
|
|
12
|
+
import urllib
|
|
13
|
+
%>
|
|
14
|
+
% if name in request.registry['config'].fullauth.social:
|
|
15
|
+
${login_url(request, name) + ('?{0}'.format(urllib.urlencode(kw)) if kw else '')}
|
|
16
|
+
% endif
|
|
17
|
+
</%def>
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Translations template for pyramid_fullauth.
|
|
2
|
+
# Copyright (C) 2014 ORGANIZATION
|
|
3
|
+
# This file is distributed under the same license as the pyramid_fullauth
|
|
4
|
+
# project.
|
|
5
|
+
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
|
|
6
|
+
#
|
|
7
|
+
#, fuzzy
|
|
8
|
+
msgid ""
|
|
9
|
+
msgstr ""
|
|
10
|
+
"Project-Id-Version: pyramid_fullauth 0.2.3\n"
|
|
11
|
+
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
|
12
|
+
"POT-Creation-Date: 2014-04-11 23:41+0200\n"
|
|
13
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
|
14
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
15
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
16
|
+
"MIME-Version: 1.0\n"
|
|
17
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
18
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
19
|
+
"Generated-By: Babel 1.3\n"
|
|
20
|
+
|
|
21
|
+
#: pyramid_fullauth/tools.py:47
|
|
22
|
+
msgid "Please enter your password"
|
|
23
|
+
msgstr ""
|
|
24
|
+
|
|
25
|
+
#: pyramid_fullauth/tools.py:53
|
|
26
|
+
msgid "Password is too short"
|
|
27
|
+
msgstr ""
|
|
28
|
+
|
|
29
|
+
#: pyramid_fullauth/tools.py:61
|
|
30
|
+
#: pyramid_fullauth/views/basic/profile/password.py:124
|
|
31
|
+
msgid "password-mismatch"
|
|
32
|
+
msgstr ""
|
|
33
|
+
|
|
34
|
+
#: pyramid_fullauth/resources/templates/403.mako:11
|
|
35
|
+
msgid "Sorry, we couldn't serve you this, your clearance code is too low!"
|
|
36
|
+
msgstr ""
|
|
37
|
+
|
|
38
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:11
|
|
39
|
+
#: pyramid_fullauth/resources/templates/_form.register.mako:12
|
|
40
|
+
msgid "E-mail"
|
|
41
|
+
msgstr ""
|
|
42
|
+
|
|
43
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:21
|
|
44
|
+
#: pyramid_fullauth/resources/templates/_form.register.mako:21
|
|
45
|
+
#: pyramid_fullauth/resources/templates/reset.proceed.mako:20
|
|
46
|
+
msgid "Password"
|
|
47
|
+
msgstr ""
|
|
48
|
+
|
|
49
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:27
|
|
50
|
+
msgid "Remember me"
|
|
51
|
+
msgstr ""
|
|
52
|
+
|
|
53
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:34
|
|
54
|
+
msgid "Forgot your password, right?"
|
|
55
|
+
msgstr ""
|
|
56
|
+
|
|
57
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:35
|
|
58
|
+
msgid "Want to join? Sign Up!"
|
|
59
|
+
msgstr ""
|
|
60
|
+
|
|
61
|
+
#: pyramid_fullauth/resources/templates/_form.login.mako:40
|
|
62
|
+
msgid "Log in"
|
|
63
|
+
msgstr ""
|
|
64
|
+
|
|
65
|
+
#: pyramid_fullauth/resources/templates/_form.register.mako:34
|
|
66
|
+
#: pyramid_fullauth/resources/templates/reset.proceed.mako:27
|
|
67
|
+
msgid "Confirm password"
|
|
68
|
+
msgstr ""
|
|
69
|
+
|
|
70
|
+
#: pyramid_fullauth/resources/templates/_form.register.mako:44
|
|
71
|
+
msgid "Sign up"
|
|
72
|
+
msgstr ""
|
|
73
|
+
|
|
74
|
+
#: pyramid_fullauth/resources/templates/_social.login.mako:9
|
|
75
|
+
msgid "Social login"
|
|
76
|
+
msgstr ""
|
|
77
|
+
|
|
78
|
+
#: pyramid_fullauth/resources/templates/_social.login.mako:12
|
|
79
|
+
msgid "Connect with facebook"
|
|
80
|
+
msgstr ""
|
|
81
|
+
|
|
82
|
+
#: pyramid_fullauth/resources/templates/_social.login.mako:15
|
|
83
|
+
msgid "Connect with twitter"
|
|
84
|
+
msgstr ""
|
|
85
|
+
|
|
86
|
+
#: pyramid_fullauth/resources/templates/activate.mako:10
|
|
87
|
+
msgid "Invalid activation code"
|
|
88
|
+
msgstr ""
|
|
89
|
+
|
|
90
|
+
#: pyramid_fullauth/resources/templates/activate.mako:12
|
|
91
|
+
msgid "Thank you for activating your account!"
|
|
92
|
+
msgstr ""
|
|
93
|
+
|
|
94
|
+
#: pyramid_fullauth/resources/templates/activate.mako:13
|
|
95
|
+
msgid "And welcome to our site!"
|
|
96
|
+
msgstr ""
|
|
97
|
+
|
|
98
|
+
#: pyramid_fullauth/resources/templates/email_change.mako:10
|
|
99
|
+
msgid "Change your email"
|
|
100
|
+
msgstr ""
|
|
101
|
+
|
|
102
|
+
#: pyramid_fullauth/resources/templates/email_change.mako:15
|
|
103
|
+
#: pyramid_fullauth/resources/templates/login.mako:11
|
|
104
|
+
#: pyramid_fullauth/resources/templates/register.mako:13
|
|
105
|
+
#: pyramid_fullauth/resources/templates/reset.mako:15
|
|
106
|
+
#: pyramid_fullauth/resources/templates/reset.proceed.mako:14
|
|
107
|
+
msgid "Error!"
|
|
108
|
+
msgstr ""
|
|
109
|
+
|
|
110
|
+
#: pyramid_fullauth/resources/templates/email_change.mako:20
|
|
111
|
+
#: pyramid_fullauth/resources/templates/reset.mako:20
|
|
112
|
+
msgid "Your e-mail address"
|
|
113
|
+
msgstr ""
|
|
114
|
+
|
|
115
|
+
#: pyramid_fullauth/resources/templates/email_change.mako:27
|
|
116
|
+
msgid "Change email"
|
|
117
|
+
msgstr ""
|
|
118
|
+
|
|
119
|
+
#: pyramid_fullauth/resources/templates/layout.mako:10
|
|
120
|
+
msgid "Welcome, to pyramid_fullauth!"
|
|
121
|
+
msgstr ""
|
|
122
|
+
|
|
123
|
+
#: pyramid_fullauth/resources/templates/login.mako:9
|
|
124
|
+
msgid "Please, log in"
|
|
125
|
+
msgstr ""
|
|
126
|
+
|
|
127
|
+
#: pyramid_fullauth/resources/templates/register.mako:9
|
|
128
|
+
msgid "Please, register"
|
|
129
|
+
msgstr ""
|
|
130
|
+
|
|
131
|
+
#: pyramid_fullauth/resources/templates/register.mako:18
|
|
132
|
+
msgid "Success!"
|
|
133
|
+
msgstr ""
|
|
134
|
+
|
|
135
|
+
#: pyramid_fullauth/resources/templates/register.mako:18
|
|
136
|
+
msgid "You have sucessfully registered"
|
|
137
|
+
msgstr ""
|
|
138
|
+
|
|
139
|
+
#: pyramid_fullauth/resources/templates/reset.mako:10
|
|
140
|
+
msgid "Recover your password"
|
|
141
|
+
msgstr ""
|
|
142
|
+
|
|
143
|
+
#: pyramid_fullauth/resources/templates/reset.mako:27
|
|
144
|
+
#: pyramid_fullauth/resources/templates/reset.proceed.mako:34
|
|
145
|
+
msgid "Reset Password"
|
|
146
|
+
msgstr ""
|
|
147
|
+
|
|
148
|
+
#: pyramid_fullauth/resources/templates/reset.proceed.mako:10
|
|
149
|
+
msgid "Recover your password - choose new password"
|
|
150
|
+
msgstr ""
|
|
151
|
+
|
|
152
|
+
#: pyramid_fullauth/views/social.py:134
|
|
153
|
+
msgid "Your account is already connected to other ${provider} account."
|
|
154
|
+
msgstr ""
|
|
155
|
+
|
|
156
|
+
#: pyramid_fullauth/views/social.py:141
|
|
157
|
+
msgid "Your account has been connected to ${provider} account."
|
|
158
|
+
msgstr ""
|
|
159
|
+
|
|
160
|
+
#: pyramid_fullauth/views/social.py:147
|
|
161
|
+
msgid "This ${provider} account is already connected with other account."
|
|
162
|
+
msgstr ""
|
|
163
|
+
|
|
164
|
+
#: pyramid_fullauth/views/basic/forbidden.py:39
|
|
165
|
+
msgid "forbidden-notallowed"
|
|
166
|
+
msgstr ""
|
|
167
|
+
|
|
168
|
+
#: pyramid_fullauth/views/basic/forbidden.py:44
|
|
169
|
+
msgid "forbidden-login"
|
|
170
|
+
msgstr ""
|
|
171
|
+
|
|
172
|
+
#: pyramid_fullauth/views/basic/login.py:35
|
|
173
|
+
msgid "Login error"
|
|
174
|
+
msgstr ""
|
|
175
|
+
|
|
176
|
+
#: pyramid_fullauth/views/basic/login.py:51
|
|
177
|
+
msgid "Already logged in!"
|
|
178
|
+
msgstr ""
|
|
179
|
+
|
|
180
|
+
#: pyramid_fullauth/views/basic/login.py:95
|
|
181
|
+
#: pyramid_fullauth/views/basic/login.py:133
|
|
182
|
+
msgid "Wrong e-mail or password."
|
|
183
|
+
msgstr ""
|
|
184
|
+
|
|
185
|
+
#: pyramid_fullauth/views/basic/register.py:38
|
|
186
|
+
msgid "You have an error in your registration form"
|
|
187
|
+
msgstr ""
|
|
188
|
+
|
|
189
|
+
#: pyramid_fullauth/views/basic/register.py:51
|
|
190
|
+
msgid "You have successfully registered"
|
|
191
|
+
msgstr ""
|
|
192
|
+
|
|
193
|
+
#: pyramid_fullauth/views/basic/register.py:75
|
|
194
|
+
msgid "User with given e-mail already exists!"
|
|
195
|
+
msgstr ""
|
|
196
|
+
|
|
197
|
+
#: pyramid_fullauth/views/basic/profile/email.py:44
|
|
198
|
+
msgid "User with this email exists"
|
|
199
|
+
msgstr ""
|
|
200
|
+
|
|
201
|
+
#: pyramid_fullauth/views/basic/profile/email.py:60
|
|
202
|
+
msgid "E-mail is empty"
|
|
203
|
+
msgstr ""
|
|
204
|
+
|
|
205
|
+
#: pyramid_fullauth/views/basic/profile/email.py:66
|
|
206
|
+
msgid "Incorrect e-mail format"
|
|
207
|
+
msgstr ""
|
|
208
|
+
|
|
209
|
+
#: pyramid_fullauth/views/basic/profile/email.py:73
|
|
210
|
+
msgid "We sent you email to activate your new email address"
|
|
211
|
+
msgstr ""
|
|
212
|
+
|
|
213
|
+
#: pyramid_fullauth/views/basic/profile/password.py:48
|
|
214
|
+
msgid "user-not-exists"
|
|
215
|
+
msgstr ""
|
|
216
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<%inherit file="pyramid_fullauth:resources/templates/layout.mako" />
|
|
9
|
+
|
|
10
|
+
<h1>HTTP://403</h1>
|
|
11
|
+
<p>${_('Sorry, we couldn\'t serve you this, your clearance code is too low!', domain='pyramid_fullauth')}</p>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<form id="login_form" name="login_form" method="POST" action="${request.route_path('login')}">
|
|
9
|
+
<fieldset>
|
|
10
|
+
<div class="control-group">
|
|
11
|
+
<label class="control-label">${_('E-mail', domain='pyramid_fullauth')}:</label>
|
|
12
|
+
<div class="controls">
|
|
13
|
+
<input type="email" placeholder="username@hostname.com" name="email" class="input-xlarge"/>
|
|
14
|
+
% if after:
|
|
15
|
+
<input type="hidden" name="after" value="${after}" />
|
|
16
|
+
% endif
|
|
17
|
+
<input type="hidden" name="csrf_token" value="${csrf_token}" />
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="control-group">
|
|
21
|
+
<label class="control-label">${_('Password', domain='pyramid_fullauth')}:</label>
|
|
22
|
+
<div class="controls">
|
|
23
|
+
<input type="password" name="password" class="input-xlarge"/>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="control-group">
|
|
27
|
+
<label class="control-label">${_('Remember me', domain='pyramid_fullauth')}:</label>
|
|
28
|
+
<div class="controls">
|
|
29
|
+
<input type="checkbox" name="remember" value="1" />
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="control-group">
|
|
33
|
+
<div class="controls options">
|
|
34
|
+
<a href="${request.route_path('password:reset')}">${_('Forgot your password, right?', domain='pyramid_fullauth')}</a><br/>
|
|
35
|
+
<a id="sign_up_login" href="${request.route_path('register')}">${_('Want to join? Sign Up!', domain='pyramid_fullauth')}</a><br/>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="modal-footer center">
|
|
39
|
+
<div>
|
|
40
|
+
<button type="submit" class="btn btn-primary btn-large f18 w180"><strong>${_('Log in', domain='pyramid_fullauth')}</strong></button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</fieldset>
|
|
44
|
+
</form>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
## -*- coding: utf-8 -*-
|
|
2
|
+
<%doc>
|
|
3
|
+
Copyright (c) 2013 - 2014 by pyramid_fullauth authors and contributors <see AUTHORS file>
|
|
4
|
+
|
|
5
|
+
This module is part of pyramid_fullauth and is released under
|
|
6
|
+
the MIT License (MIT): http://opensource.org/licenses/MIT
|
|
7
|
+
</%doc>
|
|
8
|
+
<form class="registerForm" id="register_form" name="register_form" method="POST" action="${request.route_path('register')}">
|
|
9
|
+
<input type="hidden" name="csrf_token" value="${csrf_token}" />
|
|
10
|
+
<fieldset>
|
|
11
|
+
<div class="control-group ${'error' if 'email' in errors else ''}">
|
|
12
|
+
<label class="control-label">${_('E-mail', domain='pyramid_fullauth')}:</label>
|
|
13
|
+
<div class="controls">
|
|
14
|
+
<input id="email" placeholder="username@hostname.com" type="email" name="email" required="required" value="${request.params.get('email','')}" />
|
|
15
|
+
% if 'email' in errors:
|
|
16
|
+
<span class="help-inline">${errors['email']}</span>
|
|
17
|
+
% endif
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="control-group ${'error' if 'password' in errors else ''}">
|
|
21
|
+
<label class="control-label">${_('Password', domain='pyramid_fullauth')}:</label>
|
|
22
|
+
<div class="controls">
|
|
23
|
+
<input type="password" id="password" name="password" required="required"/>
|
|
24
|
+
% if 'password' in errors:
|
|
25
|
+
<span class="help-inline">${errors['password']}</span>
|
|
26
|
+
% endif
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<%
|
|
30
|
+
password_options = request.registry['config'].fullauth.register.password
|
|
31
|
+
%>
|
|
32
|
+
% if password_options['confirm']:
|
|
33
|
+
<div class="control-group ${'error' if 'confirm_password' in errors else ''}">
|
|
34
|
+
<label class="control-label">${_('Confirm password', domain='pyramid_fullauth')}:</label>
|
|
35
|
+
<div class="controls">
|
|
36
|
+
<input type="password" name="confirm_password" id="confirm_password" required="required"/>
|
|
37
|
+
% if 'confirm_password' in errors:
|
|
38
|
+
<span class="help-inline">${errors['confirm_password']}</span>
|
|
39
|
+
% endif
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
% endif
|
|
43
|
+
<div>
|
|
44
|
+
<button id="submit_register" type="submit" class="btn btn-primary btn-large"><strong>${_('Sign up', domain='pyramid_fullauth')}</strong></button>
|
|
45
|
+
</div>
|
|
46
|
+
</fieldset>
|
|
47
|
+
</form>
|