|
|
@ -1,22 +1,67 @@ |
|
|
|
''' Resources for account registraion and settings ''' |
|
|
|
''' Resources for account registraion and settings ''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from datetime import datetime |
|
|
|
from pyramid.security import Allow, Authenticated, Everyone, Deny, DENY_ALL |
|
|
|
from pyramid.security import Allow, Authenticated, Everyone, Deny, DENY_ALL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from ordr2.models.account import Token, TokenSubject |
|
|
|
from ordr2.resources.base import BaseResource |
|
|
|
from ordr2.resources.base import BaseResource |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RegistrationToken(BaseResource): |
|
|
|
|
|
|
|
''' representing :class:`ordr2.models.account.Token` for registration ''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __acl__(self): |
|
|
|
|
|
|
|
''' access controll list for the resource ''' |
|
|
|
|
|
|
|
return [ |
|
|
|
|
|
|
|
(Deny, Authenticated, 'register'), |
|
|
|
|
|
|
|
(Allow, Everyone, 'register'), |
|
|
|
|
|
|
|
DENY_ALL |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EmailVerificationToken(BaseResource): |
|
|
|
|
|
|
|
''' representing :class:`ordr2.models.account.Token` for email change ''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __acl__(self): |
|
|
|
|
|
|
|
''' access controll list for the resource |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a logged in user might only access his own tokens |
|
|
|
|
|
|
|
''' |
|
|
|
|
|
|
|
# self.model is a :class:`ordr2.models.account.Token` instance |
|
|
|
|
|
|
|
return [ |
|
|
|
|
|
|
|
(Allow, self.model.user.principal, 'settings'), |
|
|
|
|
|
|
|
DENY_ALL |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ForgottenPasswordToken(BaseResource): |
|
|
|
|
|
|
|
''' representing :class:`ordr2.models.account.Token` for password reset ''' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __acl__(self): |
|
|
|
|
|
|
|
''' access controll list for the resource ''' |
|
|
|
|
|
|
|
return [ |
|
|
|
|
|
|
|
(Allow, Everyone, 'reset password'), |
|
|
|
|
|
|
|
DENY_ALL |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AccountResource(BaseResource): |
|
|
|
class AccountResource(BaseResource): |
|
|
|
''' Resouce class for account registration and settings ''' |
|
|
|
''' Resouce class for account registration and settings ''' |
|
|
|
|
|
|
|
|
|
|
|
#: name of the main navigation section for template highlighting |
|
|
|
#: name of the main navigation section for template highlighting |
|
|
|
nav_section = 'account' |
|
|
|
nav_section = 'account' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#: mapping token subjects to token resouce classes |
|
|
|
|
|
|
|
token_resources = { |
|
|
|
|
|
|
|
TokenSubject.USER_REGISTRATION: RegistrationToken, |
|
|
|
|
|
|
|
TokenSubject.CHANGE_EMAIL: EmailVerificationToken, |
|
|
|
|
|
|
|
TokenSubject.RESET_PASSWORD: ForgottenPasswordToken |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, name, parent, model=None): |
|
|
|
def __init__(self, name, parent, model=None): |
|
|
|
''' Create a base resource ''' |
|
|
|
''' Create a base resource ''' |
|
|
|
super().__init__(name, parent) |
|
|
|
# the current model is the current logged in user or None |
|
|
|
# the current model depends is the current logged in user or None |
|
|
|
super().__init__(name, parent, self.request.user) |
|
|
|
self.model = self.request.user |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __acl__(self): |
|
|
|
def __acl__(self): |
|
|
|
''' access controll list for the resource |
|
|
|
''' access controll list for the resource |
|
|
@ -31,6 +76,28 @@ class AccountResource(BaseResource): |
|
|
|
(Allow, Everyone, 'logout'), |
|
|
|
(Allow, Everyone, 'logout'), |
|
|
|
(Deny, Authenticated, 'register'), |
|
|
|
(Deny, Authenticated, 'register'), |
|
|
|
(Allow, Everyone, 'register'), |
|
|
|
(Allow, Everyone, 'register'), |
|
|
|
|
|
|
|
(Allow, Everyone, 'reset password'), |
|
|
|
(Allow, Authenticated, 'settings'), |
|
|
|
(Allow, Authenticated, 'settings'), |
|
|
|
DENY_ALL |
|
|
|
DENY_ALL |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, key): |
|
|
|
|
|
|
|
''' provides the dict like interface to access child resources |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:param str key: |
|
|
|
|
|
|
|
token hash or path segment for a child resource |
|
|
|
|
|
|
|
:rtype: |
|
|
|
|
|
|
|
subclass of ordr2.resources.base.BaseResource |
|
|
|
|
|
|
|
:raises: |
|
|
|
|
|
|
|
KeyError if token hash or path segment is not found |
|
|
|
|
|
|
|
''' |
|
|
|
|
|
|
|
token = self.request.dbsession.query(Token).filter_by(hash=key).first() |
|
|
|
|
|
|
|
if token is None: |
|
|
|
|
|
|
|
# no token found, search for child node |
|
|
|
|
|
|
|
return super().__getitem__(key) |
|
|
|
|
|
|
|
elif token.expires < datetime.utcnow(): |
|
|
|
|
|
|
|
# token has expired, delete it |
|
|
|
|
|
|
|
self.request.dbsession.delete(token) |
|
|
|
|
|
|
|
raise KeyError(f'Token {key} has expired on {token.expires}') |
|
|
|
|
|
|
|
resource_class = self.token_resources[token.subject] |
|
|
|
|
|
|
|
return resource_class(key, self, model=token) |
|
|
|