Browse Source

refactored account resource and view

login/logout, registration of a new account and resetting a forgotten
password are now child resources of the account resource. The views for
these resources are also grouped together. This should make a reusage of
the code easier
rework
Holger Frey 7 years ago
parent
commit
f8d6d475d1
  1. 16
      ordr/resources/__init__.py
  2. 30
      ordr/resources/account.py
  3. 2
      ordr/templates/account/login.jinja2
  4. 20
      ordr/templates/layout.jinja2
  5. 268
      ordr/views/account.py
  6. 120
      ordr/views/forgotten_password.py
  7. 57
      ordr/views/pages.py
  8. 86
      ordr/views/registration.py
  9. 12
      tests/_functional/__init__.py
  10. 10
      tests/_functional/account/__init__.py
  11. 19
      tests/_functional/account/forgotten_password.py
  12. 45
      tests/_functional/account/login_logout.py
  13. 28
      tests/_functional/account/registration.py
  14. 31
      tests/_functional/account/settings.py
  15. 24
      tests/_functional/layout.py
  16. 8
      tests/_functional/pages.py
  17. 137
      tests/resources/account.py
  18. 14
      tests/resources/root.py
  19. 22
      tests/views/account/__init__.py
  20. 76
      tests/views/account/forgotten_password.py
  21. 95
      tests/views/account/login_logout.py
  22. 28
      tests/views/account/registration.py
  23. 93
      tests/views/account/settings.py
  24. 80
      tests/views/pages.py

16
ordr/resources/__init__.py

@ -2,11 +2,7 @@ @@ -2,11 +2,7 @@
from pyramid.security import Allow, Everyone, DENY_ALL
from .account import (
RegistrationResource,
PasswordResetResource,
AccountResource
)
from .account import AccountResource
class RootResource:
@ -14,12 +10,12 @@ class RootResource: @@ -14,12 +10,12 @@ class RootResource:
:param pyramid.request.Request request: the current request object
'''
nav_active = 'welcome'
def __init__(self, request):
''' Create the root resource
:param pyramid.request.Request request: the current request object
'''
self.__name__ = None
@ -29,17 +25,15 @@ class RootResource: @@ -29,17 +25,15 @@ class RootResource:
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL]
def __getitem__(self, key):
''' retruns a child resource
:param str key: name of the child resource
:returns: child resource
:raises: KeyError if child resource is not found
'''
map = {
'register': RegistrationResource,
'forgot': PasswordResetResource,
'account': AccountResource,
}
child_class = map[key]

30
ordr/resources/account.py

@ -28,7 +28,7 @@ class RegistrationTokenResource(BaseChildResource): @@ -28,7 +28,7 @@ class RegistrationTokenResource(BaseChildResource):
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL]
return [(Allow, Everyone, 'register'), DENY_ALL]
class RegistrationResource(BaseChildResource):
@ -43,7 +43,7 @@ class RegistrationResource(BaseChildResource): @@ -43,7 +43,7 @@ class RegistrationResource(BaseChildResource):
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL]
return [(Allow, Everyone, 'register'), DENY_ALL]
def __getitem__(self, key):
''' returns a resource for a valid registration token '''
@ -81,7 +81,7 @@ class PasswordResetTokenResource(BaseChildResource): @@ -81,7 +81,7 @@ class PasswordResetTokenResource(BaseChildResource):
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL]
return [(Allow, Everyone, 'reset'), DENY_ALL]
def get_reset_form(self, **kwargs):
''' returns password reset form '''
@ -107,7 +107,7 @@ class PasswordResetResource(BaseChildResource): @@ -107,7 +107,7 @@ class PasswordResetResource(BaseChildResource):
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL]
return [(Allow, Everyone, 'reset'), DENY_ALL]
def __getitem__(self, key):
''' returns a resource for a valid reset password token '''
@ -156,10 +156,28 @@ class AccountResource(BaseChildResource): @@ -156,10 +156,28 @@ class AccountResource(BaseChildResource):
def __acl__(self):
''' access controll list for the resource '''
return [(Allow, Authenticated, 'edit'), DENY_ALL]
return [
(Allow, Everyone, 'view'),
(Allow, Everyone, 'login'),
(Allow, Everyone, 'logout'),
(Allow, Everyone, 'register'),
(Allow, Everyone, 'reset'),
(Allow, Authenticated, 'edit'),
DENY_ALL
]
def __getitem__(self, key):
''' returns a resource for a valid change email token '''
''' returns a resource for child resource '''
# static child resources
map = {
'register': RegistrationResource,
'forgot': PasswordResetResource,
}
if key in map:
child_class = map[key]
return child_class(name=key, parent=self)
# change email verification
token = Token.retrieve(self.request, key, TokenSubject.CHANGE_EMAIL)
if token is None:
raise KeyError(f'Token {key} not found')

2
ordr/templates/pages/login.jinja2 → ordr/templates/account/login.jinja2

@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
<div class="row">
<div class="col-4 offset-2">
<h4 class="mb-4">Login</h4>
<form action="/login" method="POST">
<form action="{{ request.resource_url(context, 'login') }}" method="POST">
<div class="form-group">
<input type="hidden" name="csrf_token" value="{{get_csrf_token()}}">
<input type="text" class="form-control {% if loginerror %}is-invalid{% endif %}" id="input-username" placeholder="Username" name="username" autofocus="autofocus">

20
ordr/templates/layout.jinja2

@ -22,30 +22,30 @@ @@ -22,30 +22,30 @@
<body>
<nav class="navbar navbar-dark bg-dark navbar-expand-sm">
<a class="navbar-brand text-primary" href="/"><strong>ordr</strong></a>
<a class="navbar-brand text-primary" href="{{ request.resource_url(request.root) }}"><strong>ordr</strong></a>
{% if not request.user %}
<ul class="navbar-nav mr-auto">
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='login' %}active{% endif %}">
<a href="/" class="nav-link">Welcome</a>
<a href="{{ request.resource_url(request.root) }}" class="nav-link">Welcome</a>
</li>
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='faq' %}active{% endif %}">
<a href="/faq" class="nav-link">FAQs</a>
<a href="{{ request.resource_url(request.root, 'faq') }}" class="nav-link">FAQs</a>
</li>
<li class="nav-item {% if context.nav_active=='registration' %}active{% endif %}">
<a href="/register" class="nav-link">Register</a>
<a href="{{ request.resource_url(request.root, 'account', 'register') }}" class="nav-link">Register</a>
</li>
</ul>
{% else %}
<ul class="navbar-nav mr-auto">
<li class="nav-item {% if context.nav_active=='orders' %}active{% endif %}">
<a href="/orders" class="nav-link">Orders</a>
<a href="{{ request.resource_url(request.root, 'orders') }}" class="nav-link">Orders</a>
</li>
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='faq' %}active{% endif %}">
<a href="/faq" class="nav-link">FAQs</a>
<a href="{{ request.resource_url(request.root, 'faq') }}" class="nav-link">FAQs</a>
</li>
{% if 'role:admin' in request.user.principals %}
<li class="nav-item {% if context.nav_active=='admin' %}active{% endif %}">
<a href="/admin" class="nav-link">Admin</a>
<a href="{{ request.resource_url(request.root, 'admin') }}" class="nav-link">Admin</a>
</li>
{% endif %}
</ul>
@ -55,10 +55,10 @@ @@ -55,10 +55,10 @@
{{ request.user }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown">
<a class="dropdown-item" href="/logout">Logout</a>
<a class="dropdown-item" href="{{ request.resource_url(request.root, 'account', 'logout') }}">Logout</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item small" href="/account/settings">Settings</a>
<a class="dropdown-item small" href="/account/password">Change Password</a>
<a class="dropdown-item small" href="{{ request.resource_url(request.root, 'account', 'settings') }}">Settings</a>
<a class="dropdown-item small" href="{{ request.resource_url(request.root, 'account', 'password') }}">Change Password</a>
</div>
</li>
</ul>

268
ordr/views/account.py

@ -1,21 +1,279 @@ @@ -1,21 +1,279 @@
''' views for user accounts
This includes login, logout, registration, forgotten passwords, changing
settings and passwords
'''
import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config
from sqlalchemy import func, or_
from ordr.events import (
ChangeEmailNotification,
PasswordResetNotification,
RegistrationNotification
)
from ordr.models.account import Role, TokenSubject, User
from ordr.events import ChangeEmailNotification
from ordr.models.account import TokenSubject
# account resource root
@view_config(
context='ordr.resources.account.AccountResource',
permission='edit'
permission='view'
)
def account(context, request):
''' redirect if '/account' was requested directly '''
return HTTPFound(request.resource_url(request.root))
# login and logout
@view_config(
context='ordr.resources.account.AccountResource',
name='login',
request_method='GET',
permission='login',
renderer='ordr:templates/account/login.jinja2',
)
def login(context, request):
''' shows the login page '''
context.nav_active = 'welcome'
return {'loginerror': False}
@view_config(
context='ordr.resources.account.AccountResource',
name='login',
request_method='POST',
permission='login',
renderer='ordr:templates/account/login.jinja2',
)
def check_login(context, request):
''' check user credentials '''
username = request.POST.get('username')
password = request.POST.get('password')
user = (
request.dbsession
.query(User)
.filter_by(username=username)
.first()
)
if user and user.is_active and user.check_password(password):
headers = remember(request, user.id)
return HTTPFound(request.resource_url(request.root), headers=headers)
context.nav_active = 'welcome'
return {'loginerror': True}
@view_config(
context='ordr.resources.account.AccountResource',
name='logout',
permission='logout'
)
def logout(context, request):
''' log out of an user '''
headers = forget(request)
return HTTPFound(request.resource_url(request.root), headers=headers)
# registration process
@view_config(
context='ordr.resources.account.RegistrationResource',
permission='register',
request_method='GET',
renderer='ordr:templates/account/registration_form.jinja2'
)
def registration_form(context, request):
''' show registration form '''
form = context.get_registration_form()
return {'form': form}
@view_config(
context='ordr.resources.account.RegistrationResource',
permission='register',
request_method='POST',
renderer='ordr:templates/account/registration_form.jinja2'
)
def registration_form_processing(context, request):
''' process registration form '''
if 'create' not in request.POST:
return HTTPFound(request.resource_url(request.root))
form = context.get_registration_form()
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# form validation successfull, create user
account = User(
username=appstruct['username'],
first_name=appstruct['first_name'],
last_name=appstruct['last_name'],
email=appstruct['email'],
role=Role.UNVALIDATED
)
account.set_password(appstruct['password'])
request.dbsession.add(account)
# create a verify-new-account token and send email
token = account.issue_token(request, TokenSubject.REGISTRATION)
notification = RegistrationNotification(request, account, {'token': token})
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'verify'))
@view_config(
context='ordr.resources.account.RegistrationResource',
name='verify',
permission='register',
request_method='GET',
renderer='ordr:templates/account/registration_verify.jinja2'
)
def registration_verify_email(context, request):
''' show email verification text '''
return {}
@view_config(
context='ordr.resources.account.RegistrationTokenResource',
permission='register',
request_method='GET',
renderer='ordr:templates/account/registration_completed.jinja2'
)
def registration_completed(context, request):
''' registration is completed, awaiting activation by admin '''
token = context.model
account = token.owner
account.role = Role.NEW
request.dbsession.delete(token)
return {}
# forgotten password process
@view_config(
context='ordr.resources.account.PasswordResetResource',
permission='reset',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_form.jinja2'
)
def forgotten_password_form(context, request):
''' show forgotten password form '''
return {'formerror': False}
@view_config(
context='ordr.resources.account.PasswordResetResource',
permission='reset',
request_method='POST',
renderer='ordr:templates/account/forgotten_password_form.jinja2'
)
def forgotten_password_form_processing(context, request):
''' process forgotten password form '''
if 'cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
identifier = request.POST.get('identifier', '')
account = (
request.dbsession
.query(User)
.filter(or_(
func.lower(User.username) == identifier.lower(),
func.lower(User.email) == identifier.lower()
))
.first()
)
if account is None or not account.is_active:
return {'formerror': True}
# create a verify-new-account token and send email
token = account.issue_token(request, TokenSubject.RESET_PASSWORD)
notification = PasswordResetNotification(
request,
account,
{'token': token}
)
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'verify'))
@view_config(
context='ordr.resources.account.PasswordResetResource',
name='verify',
permission='reset',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_verify.jinja2'
)
def forgotten_password_verify_email(context, request):
''' show email verification text '''
return {}
@view_config(
context='ordr.resources.account.PasswordResetResource',
name='completed',
permission='reset',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_completed.jinja2'
)
def forgotten_password_completed(context, request):
''' user is verified, process reset password form '''
return {}
@view_config(
context='ordr.resources.account.PasswordResetTokenResource',
permission='reset',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_reset.jinja2'
)
def reset_password_form(context, request):
''' user is verified, show reset password form '''
form = context.get_reset_form()
return {'form': form}
@view_config(
context='ordr.resources.account.PasswordResetTokenResource',
permission='reset',
request_method='POST',
renderer='ordr:templates/account/forgotten_password_reset.jinja2'
)
def reset_password_form_processing(context, request):
''' process the password reset form '''
if 'change' not in request.POST:
return HTTPFound(request.resource_url(request.root))
form = context.get_reset_form()
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# set new password
token = context.model
account = token.owner
account.set_password(appstruct['password'])
request.dbsession.delete(token)
return HTTPFound(request.resource_url(context.__parent__, 'completed'))
# account settings
@view_config(
context='ordr.resources.account.AccountResource',
permission='edit',
@ -85,7 +343,7 @@ def settings_form_processing(context, request): @@ -85,7 +343,7 @@ def settings_form_processing(context, request):
request_method='GET',
renderer='ordr:templates/account/settings_mail_changed.jinja2'
)
def verify_email(context, request):
def verify_email_change(context, request):
''' show email verification text '''
payload = context.model.payload
request.user.email = payload['email']
@ -93,6 +351,8 @@ def verify_email(context, request): @@ -93,6 +351,8 @@ def verify_email(context, request):
return {}
# change password
@view_config(
context='ordr.resources.account.AccountResource',
permission='edit',

120
ordr/views/forgotten_password.py

@ -1,120 +0,0 @@ @@ -1,120 +0,0 @@
import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
from sqlalchemy import func, or_
from ordr.models.account import User, TokenSubject
from ordr.events import PasswordResetNotification
# below this password length a warning is displayed
MIN_PW_LENGTH = 12
@view_config(
context='ordr.resources.account.PasswordResetResource',
permission='view',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_form.jinja2'
)
def forgotten_password_form(context, request):
''' show forgotten password form '''
return {'formerror': False}
@view_config(
context='ordr.resources.account.PasswordResetResource',
permission='view',
request_method='POST',
renderer='ordr:templates/account/forgotten_password_form.jinja2'
)
def forgotten_password_form_processing(context, request):
''' process forgotten password form '''
if 'cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
identifier = request.POST.get('identifier', '')
account = (
request.dbsession
.query(User)
.filter(or_(
func.lower(User.username) == identifier.lower(),
func.lower(User.email) == identifier.lower()
))
.first()
)
if account is None or not account.is_active:
return {'formerror': True}
# create a verify-new-account token and send email
token = account.issue_token(request, TokenSubject.RESET_PASSWORD)
notification = PasswordResetNotification(
request,
account,
{'token': token}
)
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'verify'))
@view_config(
context='ordr.resources.account.PasswordResetResource',
name='verify',
permission='view',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_verify.jinja2'
)
def verify(context, request):
''' show email verification text '''
return {}
@view_config(
context='ordr.resources.account.PasswordResetResource',
name='completed',
permission='view',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_completed.jinja2'
)
def completed(context, request):
''' user is verified, process reset password form '''
return {}
@view_config(
context='ordr.resources.account.PasswordResetTokenResource',
permission='view',
request_method='GET',
renderer='ordr:templates/account/forgotten_password_reset.jinja2'
)
def reset_password_form(context, request):
''' user is verified, show reset password form '''
form = context.get_reset_form()
return {'form': form}
@view_config(
context='ordr.resources.account.PasswordResetTokenResource',
permission='view',
request_method='POST',
renderer='ordr:templates/account/forgotten_password_reset.jinja2'
)
def reset_password_form_processing(context, request):
''' process the password reset form '''
if 'change' not in request.POST:
return HTTPFound(request.resource_url(request.root))
form = context.get_reset_form()
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# set new password
token = context.model
account = token.owner
account.set_password(appstruct['password'])
request.dbsession.delete(token)
return HTTPFound(request.resource_url(context.__parent__, 'completed'))

57
ordr/views/pages.py

@ -1,9 +1,6 @@ @@ -1,9 +1,6 @@
from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config
from ordr.models import User
@view_config(
context='ordr.resources.RootResource',
@ -11,8 +8,10 @@ from ordr.models import User @@ -11,8 +8,10 @@ from ordr.models import User
)
def welcome(context, request):
''' web root redirects '''
next = 'orders' if request.user else 'login'
redirect_to = request.resource_url(context, next)
if request.user:
redirect_to = request.resource_url(context, 'orders')
else:
redirect_to = request.resource_url(context, 'account', 'login')
return HTTPFound(redirect_to)
@ -25,51 +24,3 @@ def welcome(context, request): @@ -25,51 +24,3 @@ def welcome(context, request):
def faq(context, request):
''' displays the FAQ page '''
return {}
@view_config(
context='ordr.resources.RootResource',
name='login',
request_method='GET',
permission='view',
renderer='ordr:templates/pages/login.jinja2',
)
def login(context, request):
''' shows the login page '''
return {'loginerror': False}
@view_config(
context='ordr.resources.RootResource',
name='login',
request_method='POST',
permission='view',
renderer='ordr:templates/pages/login.jinja2',
)
def check_login(context, request):
''' check user credentials '''
username = request.POST.get('username')
password = request.POST.get('password')
user = (
request.dbsession
.query(User)
.filter_by(username=username)
.first()
)
if user and user.is_active and user.check_password(password):
headers = remember(request, user.id)
return HTTPFound(request.resource_url(request.root), headers=headers)
return {'loginerror': True}
@view_config(
context='ordr.resources.RootResource',
name='logout',
permission='view'
)
def logout(context, request):
''' log out of an user '''
headers = forget(request)
return HTTPFound(request.resource_url(request.root), headers=headers)

86
ordr/views/registration.py

@ -1,86 +0,0 @@ @@ -1,86 +0,0 @@
import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
from ordr.models.account import User, Role, TokenSubject
from ordr.events import RegistrationNotification
# below this password length a warning is displayed
MIN_PW_LENGTH = 12
@view_config(
context='ordr.resources.account.RegistrationResource',
permission='view',
request_method='GET',
renderer='ordr:templates/account/registration_form.jinja2'
)
def registration_form(context, request):
''' show registration form '''
form = context.get_registration_form()
return {'form': form}
@view_config(
context='ordr.resources.account.RegistrationResource',
permission='view',
request_method='POST',
renderer='ordr:templates/account/registration_form.jinja2'
)
def registration_form_processing(context, request):
''' process registration form '''
if 'create' not in request.POST:
return HTTPFound(request.resource_url(request.root))
form = context.get_registration_form()
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# form validation successfull, create user
account = User(
username=appstruct['username'],
first_name=appstruct['first_name'],
last_name=appstruct['last_name'],
email=appstruct['email'],
role=Role.UNVALIDATED
)
account.set_password(appstruct['password'])
request.dbsession.add(account)
# create a verify-new-account token and send email
token = account.issue_token(request, TokenSubject.REGISTRATION)
notification = RegistrationNotification(request, account, {'token': token})
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'verify'))
@view_config(
context='ordr.resources.account.RegistrationResource',
name='verify',
permission='view',
request_method='GET',
renderer='ordr:templates/account/registration_verify.jinja2'
)
def verify(context, request):
''' show email verification text '''
return {}
@view_config(
context='ordr.resources.account.RegistrationTokenResource',
permission='view',
request_method='GET',
renderer='ordr:templates/account/registration_completed.jinja2'
)
def completed(context, request):
''' registration is completed, awaiting activation by admin '''
token = context.model
account = token.owner
account.role = Role.NEW
request.dbsession.delete(token)
return {}

12
tests/_functional/__init__.py

@ -19,22 +19,22 @@ WEBTEST_SETTINGS['pyramid.includes'] = [ @@ -19,22 +19,22 @@ WEBTEST_SETTINGS['pyramid.includes'] = [
class CustomTestApp(webtest.TestApp):
''' might add custom functionality to webtest.TestApp '''
pass
def login(self, username, password):
''' login '''
self.logout()
result = self.get('/login')
result = self.get('/account/login')
login_form = result.forms[0]
login_form['username'] = username
login_form['password'] = password
login_form.submit()
response = self.get('/faq')
return username in response
def logout(self):
''' logout '''
self.get('/logout')
self.get('/account/logout')
def reset(self):
''' reset the webapp '''
self.logout()
@ -60,7 +60,7 @@ def get_token_url(email, prefix='/'): @@ -60,7 +60,7 @@ def get_token_url(email, prefix='/'):
@pytest.fixture(scope='module')
def testappsetup():
''' setup of fixture for using webtest
this fixture just sets up the testapp. please use the testapp() fixture
below for real tests.
'''

10
tests/_functional/account/__init__.py

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
''' functional tests for ordr accounts '''
from .. import testappsetup, testapp, get_token_url # noqa: F401
def test_account_root(testapp): # noqa: F811
''' check the redirect if '/account' is requested '''
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account')
assert response.location == 'http://localhost/'

19
tests/_functional/forgotten_password.py → tests/_functional/account/forgotten_password.py

@ -7,14 +7,14 @@ from . import testappsetup, testapp, get_token_url # noqa: F401 @@ -7,14 +7,14 @@ from . import testappsetup, testapp, get_token_url # noqa: F401
def test_forgot_password_process(testapp): # noqa: F811
''' test the forgot password form '''
response = testapp.get('/forgot')
response = testapp.get('/account/forgot')
active_nav = response.html.find('li', class_='active')
active_step = response.html.find('p', class_='text-primary')
assert active_nav is None
assert 'Step 1: Validate Account' in active_step.text
assert 'Forgot Your Password?' in response
assert 'unknown username or email' not in response
# fill out this form with invalid data
form = response.form
form['identifier'] = 'unknown identifier'
@ -25,12 +25,13 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -25,12 +25,13 @@ def test_forgot_password_process(testapp): # noqa: F811
assert 'Step 1: Validate Account' in active_step.text
assert 'Forgot Your Password?' in response
assert 'Username or email address unknown' in response
# fill out this form with valid data
response = testapp.get('/account/forgot')
form = response.form
form['identifier'] = 'TerryGilliam'
response = form.submit(name='send_mail')
assert response.location == 'http://localhost/forgot/verify'
assert response.location == 'http://localhost/account/forgot/verify'
response = response.follow()
active_nav = response.html.find('li', class_='active')
@ -38,12 +39,12 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -38,12 +39,12 @@ def test_forgot_password_process(testapp): # noqa: F811
assert active_nav is None
assert 'Step 1: Validate Account' in active_step.text
assert 'Verify Your Email Address' in response
# click the email verification token
mailer = get_mailer(testapp.app.registry)
email = mailer.outbox[-1]
assert email.subject == '[ordr] Password Reset'
token_link = get_token_url(email, prefix='/forgot/')
response = testapp.get(token_link)
active_nav = response.html.find('li', class_='active')
@ -52,7 +53,7 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -52,7 +53,7 @@ def test_forgot_password_process(testapp): # noqa: F811
assert 'Step 2: Change Password' in active_step.text
assert 'Forgot Your Password?' in response
assert 'do not match' not in response
# fill out the change password form with invalid data
form = response.form
form['password'] = 'some passwords'
@ -70,8 +71,8 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -70,8 +71,8 @@ def test_forgot_password_process(testapp): # noqa: F811
form['password'] = 'Lost in La Mancha'
form['password-confirm'] = 'Lost in La Mancha'
response = form.submit(name='change')
assert response.location == 'http://localhost/forgot/completed'
assert response.location == 'http://localhost/account/forgot/completed'
response = response.follow()
active_nav = response.html.find('li', class_='active')
active_step = response.html.find('p', class_='text-primary')

45
tests/_functional/login_logout.py → tests/_functional/account/login_logout.py

@ -7,26 +7,28 @@ from . import testappsetup, testapp # noqa: F401 @@ -7,26 +7,28 @@ from . import testappsetup, testapp # noqa: F401
def test_login_get(testapp): # noqa: F811
''' test the login form '''
response = testapp.get('/login')
response = testapp.get('/account/login')
active = response.html.find('li', class_='active')
assert active.a['href'] == '/'
expected = {'/', '/faq', '/register', '/forgot', '/register'}
hrefs = {a['href'] for a in response.html.find_all('a')}
assert expected == hrefs
form = response.form
assert active.a['href'] == 'http://localhost/'
assert form.action == 'http://localhost/account/login'
def test_login_ok(testapp): # noqa: F811
''' test login form with valid credentials '''
response = testapp.get('/login')
response = testapp.get('/account/login')
login_form = response.forms[0]
login_form['username'] = 'TerryGilliam'
login_form['password'] = 'Terry'
response = login_form.submit()
assert response.location == 'http://localhost/'
response = testapp.get('/faq')
assert 'TerryGilliam' in response
@pytest.mark.parametrize( # noqa: F811
'username,password',
@ -34,11 +36,30 @@ def test_login_ok(testapp): # noqa: F811 @@ -34,11 +36,30 @@ def test_login_ok(testapp): # noqa: F811
)
def test_login_denied(testapp, username, password):
''' test login form with invalid credentials '''
response = testapp.get('/login')
response = testapp.get('/account/login')
login_form = response.forms[0]
login_form['username'] = 'John'
login_form['password'] = 'Cleese'
response = login_form.submit()
assert 'account is not activated' in response
def test_logout(testapp): # noqa: F811
''' test login form with valid credentials '''
response = testapp.get('/account/login')
login_form = response.forms[0]
login_form['username'] = 'TerryGilliam'
login_form['password'] = 'Terry'
login_form.submit()
response = testapp.get('/faq')
assert 'TerryGilliam' in response
response = testapp.get('/account/logout')
assert response.location == 'http://localhost/'
response = testapp.get('/faq')
assert 'TerryGilliam' not in response

28
tests/_functional/registration.py → tests/_functional/account/registration.py

@ -7,28 +7,28 @@ from . import testappsetup, testapp, get_token_url # noqa: F401 @@ -7,28 +7,28 @@ from . import testappsetup, testapp, get_token_url # noqa: F401
def test_registration_form(testapp): # noqa: F811
''' test the registration form '''
response = testapp.get('/register')
response = testapp.get('/account/register')
active = response.html.find('li', class_='active')
assert active.a['href'] == '/register'
assert active.a['href'] == 'http://localhost/account/register'
assert 'Registration' in response.html.title.text
def test_registration_form_invalid(testapp): # noqa: F811
''' test the registration form with invalid data '''
response = testapp.get('/register')
response = testapp.get('/account/register')
form = response.form
form['email'] = 'not an email address'
response = form.submit(name='create')
assert 'Invalid email address' in response
assert 'Registration' in response.html.title.text
def test_registration_process(testapp): # noqa: F811
''' test the registration process with valid data '''
response = testapp.get('/register')
response = testapp.get('/account/register')
form = response.form
form['username'] = 'AmyMcDonald',
form['first_name'] = 'Amy',
@ -37,22 +37,22 @@ def test_registration_process(testapp): # noqa: F811 @@ -37,22 +37,22 @@ def test_registration_process(testapp): # noqa: F811
form['password'] = 'Make Amy McDonald A Rich Girl Fund',
form['password-confirm'] = 'Make Amy McDonald A Rich Girl Fund',
response = form.submit(name='create')
assert response.location == 'http://localhost/register/verify'
assert response.location == 'http://localhost/account/register/verify'
response = response.follow()
active = response.html.find('li', class_='active')
assert active.a['href'] == '/register'
assert active.a['href'] == 'http://localhost/account/register'
assert 'Please follow the link in the email' in response
assert 'Registration' in response.html.title.text
# click the email verification token
mailer = get_mailer(testapp.app.registry)
email = mailer.outbox[-1]
assert email.subject == '[ordr] Please verify your email address'
token_link = get_token_url(email, prefix='/register/')
token_link = get_token_url(email, prefix='/account/register/')
response = testapp.get(token_link)
active = response.html.find('li', class_='active')
assert active.a['href'] == '/register'
assert active.a['href'] == 'http://localhost/account/register'
assert 'Registration Completed' in response
assert 'Registration' in response.html.title.text

31
tests/_functional/account.py → tests/_functional/account/settings.py

@ -2,26 +2,19 @@ @@ -2,26 +2,19 @@
from pyramid_mailer import get_mailer
from . import testappsetup, testapp, get_token_url # noqa: F401
def test_account_root(testapp): # noqa: F811
''' check the redirect if '/account' is requested '''
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account')
assert response.location == 'http://localhost/'
from .. import testappsetup, testapp, get_token_url # noqa: F401
def test_account_change_settings(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/settings')
active_nav = response.html.find('li', class_='active')
assert active_nav is None
assert 'Change Settings' in response
assert 'value="gilliam@example.com"' in response
assert 'Wrong Password' not in response
# fill out the form without confirmation password
form = response.form
form['first_name'] = 'Amy'
@ -44,7 +37,7 @@ def test_account_change_settings(testapp): # noqa: F811 @@ -44,7 +37,7 @@ def test_account_change_settings(testapp): # noqa: F811
assert active_nav is None
assert 'Change Settings' in response
assert 'Invalid email address' in response
# fill out the form with valid data and correct password
response = testapp.get('/account/settings')
form = response.form
@ -53,7 +46,7 @@ def test_account_change_settings(testapp): # noqa: F811 @@ -53,7 +46,7 @@ def test_account_change_settings(testapp): # noqa: F811
form['confirmation'] = 'Terry'
response = form.submit(name='change')
assert response.location == 'http://localhost/'
response = testapp.get('/account/settings')
assert 'value="Amy"' in response
@ -61,7 +54,7 @@ def test_account_change_settings(testapp): # noqa: F811 @@ -61,7 +54,7 @@ def test_account_change_settings(testapp): # noqa: F811
def test_account_change_email(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/settings')
# fill out the form with valid data and correct password
form = response.form
form['email'] = 'amy@example.com'
@ -74,7 +67,7 @@ def test_account_change_email(testapp): # noqa: F811 @@ -74,7 +67,7 @@ def test_account_change_email(testapp): # noqa: F811
email = mailer.outbox[-1]
assert email.subject == '[ordr] Verify New Email Address'
assert email.recipients == ['amy@example.com']
token_link = get_token_url(email, prefix='/account/')
response = testapp.get(token_link)
active_nav = response.html.find('li', class_='active')
@ -85,13 +78,13 @@ def test_account_change_email(testapp): # noqa: F811 @@ -85,13 +78,13 @@ def test_account_change_email(testapp): # noqa: F811
def test_account_change_password(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/password')
active_nav = response.html.find('li', class_='active')
assert active_nav is None
assert 'Change Password' in response
assert 'Wrong Password' not in response
# fill out the form with incorrect confirmation password
form = response.form
form['password'] = 'Lost in La Mancha'
@ -114,7 +107,7 @@ def test_account_change_password(testapp): # noqa: F811 @@ -114,7 +107,7 @@ def test_account_change_password(testapp): # noqa: F811
assert active_nav is None
assert 'Change Password' in response
assert 'Password did not match confirm' in response
# fill out the form with valid data and correct password
response = testapp.get('/account/password')
form = response.form
@ -123,10 +116,10 @@ def test_account_change_password(testapp): # noqa: F811 @@ -123,10 +116,10 @@ def test_account_change_password(testapp): # noqa: F811
form['confirmation'] = 'Terry'
response = form.submit(name='change')
assert response.location == 'http://localhost/account/changed'
response = response.follow()
active_nav = response.html.find('li', class_='active')
assert active_nav is None
assert 'Your password was changed successfully' in response
assert testapp.login('TerryGilliam', 'Lost in La Mancha')

24
tests/_functional/layout.py

@ -13,9 +13,14 @@ def test_navbar_no_user(testapp): # noqa: F811 @@ -13,9 +13,14 @@ def test_navbar_no_user(testapp): # noqa: F811
''' test the navigation on top of the page for an unauthenticated user '''
response = testapp.get('/faq')
navbar = response.html.find('nav', class_='navbar-dark')
expected = ['/', '/', '/faq', '/register']
expected = [
'http://localhost/',
'http://localhost/',
'http://localhost/faq',
'http://localhost/account/register'
]
hrefs = [a['href'] for a in navbar.find_all('a')]
assert expected == hrefs
assert '/orders' not in response
assert 'nav-item dropdown' not in response
@ -25,7 +30,7 @@ def test_navbar_no_user(testapp): # noqa: F811 @@ -25,7 +30,7 @@ def test_navbar_no_user(testapp): # noqa: F811
'username,password,extras', [
('TerryGilliam', 'Terry', []),
('EricIdle', 'Eric', []),
('TerryJones', 'Terry', ['/admin']),
('TerryJones', 'Terry', ['http://localhost/admin']),
]
)
def test_navbar_with_user(testapp, username, password, extras):
@ -34,9 +39,18 @@ def test_navbar_with_user(testapp, username, password, extras): @@ -34,9 +39,18 @@ def test_navbar_with_user(testapp, username, password, extras):
response = testapp.get('/faq')
navbar = response.html.find('nav', class_='navbar-dark')
hrefs = [a['href'] for a in navbar.find_all('a')]
expected = ['/', '/orders', '/faq']
expected = [
'http://localhost/',
'http://localhost/orders',
'http://localhost/faq'
]
expected.extend(extras)
expected.extend(['#', '/logout', '/account/settings', '/account/password'])
expected.extend([
'#',
'http://localhost/account/logout',
'http://localhost/account/settings',
'http://localhost/account/password'
])
assert expected == hrefs
assert 'nav-item dropdown' in response

8
tests/_functional/pages.py

@ -6,10 +6,10 @@ from . import testappsetup, testapp # noqa: F401 @@ -6,10 +6,10 @@ from . import testappsetup, testapp # noqa: F401
def test_welcome(testapp): # noqa: F811
''' test the redirects on web root '''
response = testapp.get('/')
assert response.location == 'http://localhost/login'
assert response.location == 'http://localhost/account/login'
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/')
assert response.location == 'http://localhost/orders'
@ -18,4 +18,4 @@ def test_faq(testapp): # noqa: F811 @@ -18,4 +18,4 @@ def test_faq(testapp): # noqa: F811
''' test the faq page '''
response = testapp.get('/faq')
active = response.html.find('li', class_='active')
assert active.a['href'] == '/faq'
assert active.a['href'] == 'http://localhost/faq'

137
tests/resources/account.py

@ -11,34 +11,34 @@ def test_registration_token_acl(): @@ -11,34 +11,34 @@ def test_registration_token_acl():
''' test access controll list for RegistrationTokenResource '''
from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import RegistrationTokenResource
parent = DummyResource(request='request')
resource = RegistrationTokenResource('name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'register'), DENY_ALL]
def test_registration_acl():
''' test access controll list for RegistrationResource '''
from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import RegistrationResource
parent = DummyResource(request='request')
resource = RegistrationResource('a name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'register'), DENY_ALL]
def test_registration_get_registration_form():
''' test 'get_registration_form()' method of RegistrationResource '''
from ordr.resources.account import RegistrationResource
import deform
request = DummyRequest()
parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent)
form = resource.get_registration_form()
assert isinstance(form, deform.Form)
assert len(form.buttons) == 2
assert form.buttons[0].title == 'Create Account'
@ -54,16 +54,16 @@ def test_registration_getitem_found(dbsession): # noqa: F811 @@ -54,16 +54,16 @@ def test_registration_getitem_found(dbsession): # noqa: F811
)
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.REGISTRATION)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent)
result = resource[token.hash]
assert isinstance(result, RegistrationTokenResource)
assert result.__name__ == token.hash
assert result.__parent__ == resource
@ -76,15 +76,15 @@ def test_registration_getitem_not_found(dbsession): # noqa: F811 @@ -76,15 +76,15 @@ def test_registration_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import RegistrationResource
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.REGISTRATION)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent)
with pytest.raises(KeyError):
resource['unknown hash']
@ -93,23 +93,23 @@ def test_password_reset_token_acl(): @@ -93,23 +93,23 @@ def test_password_reset_token_acl():
''' test access controll list for PasswordResetTokenResource '''
from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import PasswordResetTokenResource
parent = DummyResource(request='request')
resource = PasswordResetTokenResource('name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'reset'), DENY_ALL]
def test_password_reset_token_get_reset_form():
''' test the setup of the password reset form'''
from ordr.resources.account import PasswordResetTokenResource
import deform
request = DummyRequest()
parent = DummyResource(request=request)
resource = PasswordResetTokenResource('some name', parent)
form = resource.get_reset_form()
assert isinstance(form, deform.Form)
assert len(form.buttons) == 2
assert form.buttons[0].title == 'Set New Password'
@ -120,11 +120,11 @@ def test_password_reset_acl(): @@ -120,11 +120,11 @@ def test_password_reset_acl():
''' test access controll list for PasswordResetResource '''
from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import PasswordResetResource
parent = DummyResource(request='request')
resource = PasswordResetResource('a name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'reset'), DENY_ALL]
def test_password_reset_getitem_found(dbsession): # noqa: F811
@ -136,16 +136,16 @@ def test_password_reset_getitem_found(dbsession): # noqa: F811 @@ -136,16 +136,16 @@ def test_password_reset_getitem_found(dbsession): # noqa: F811
)
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = PasswordResetResource('a name', parent)
result = resource[token.hash]
assert isinstance(result, PasswordResetTokenResource)
assert result.__name__ == token.hash
assert result.__parent__ == resource
@ -158,63 +158,96 @@ def test_password_reset_getitem_not_found(dbsession): # noqa: F811 @@ -158,63 +158,96 @@ def test_password_reset_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import PasswordResetResource
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = PasswordResetResource('a name', parent)
with pytest.raises(KeyError):
resource['unknown hash']
def test_change_email_reset_token_acl(dbsession): # noqa: F811
def test_change_email_token_acl(dbsession): # noqa: F811
''' test access controll list for PasswordResetTokenResource '''
from pyramid.security import Allow, DENY_ALL
from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import ChangeEmailTokenResource
request = DummyRequest()
user = get_example_user(Role.USER)
dbsession.add(user)
user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.flush()
token = dbsession.query(Token).first()
parent = DummyResource(request='request')
resource = ChangeEmailTokenResource('name', parent, model=token)
assert resource.__acl__() == [(Allow, 'user:3', 'edit'), DENY_ALL]
def test_account_resource_set_model_from_request():
''' test access controll list for PasswordResetResource '''
from ordr.resources.account import AccountResource
request = DummyRequest(user='Amy McDonald')
parent = DummyResource(request=request)
resource = AccountResource('a name', parent)
assert resource.model == 'Amy McDonald'
def test_account_resource_acl():
''' test access controll list for PasswordResetResource '''
from pyramid.security import Allow, Authenticated, DENY_ALL
from pyramid.security import (
Allow,
Everyone,
Authenticated,
DENY_ALL
)
from ordr.resources.account import AccountResource
request = DummyRequest()
parent = DummyResource(request=request)
resource = AccountResource('a name', parent)
assert resource.__acl__() == [(Allow, Authenticated, 'edit'), DENY_ALL]
assert resource.__acl__() == [
(Allow, Everyone, 'view'),
(Allow, Everyone, 'login'),
(Allow, Everyone, 'logout'),
(Allow, Everyone, 'register'),
(Allow, Everyone, 'reset'),
(Allow, Authenticated, 'edit'),
DENY_ALL
]
@pytest.mark.parametrize('key', ['register', 'forgot']) # noqa: F811
def test_account_resource_getitem_static(dbsession, key):
''' test '__getitem__()' method returns static resources '''
from ordr.resources.account import (
AccountResource,
PasswordResetResource,
RegistrationResource
)
request = DummyRequest(dbsession=dbsession)
parent = DummyResource(request=request)
resource = AccountResource('some name', parent)
result = resource[key]
if key == 'register':
assert isinstance(result, RegistrationResource)
elif key == 'forgot':
assert isinstance(result, PasswordResetResource)
def test_account_resource_getitem_found(dbsession): # noqa: F811
def test_account_resource_getitem_token(dbsession): # noqa: F811
''' test '__getitem__()' method returns child resource '''
from ordr.models.account import Role, TokenSubject
from ordr.resources.account import (
@ -223,16 +256,16 @@ def test_account_resource_getitem_found(dbsession): # noqa: F811 @@ -223,16 +256,16 @@ def test_account_resource_getitem_found(dbsession): # noqa: F811
)
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = AccountResource('a name', parent)
result = resource[token.hash]
assert isinstance(result, ChangeEmailTokenResource)
assert result.__name__ == token.hash
assert result.__parent__ == resource
@ -245,15 +278,15 @@ def test_account_resource_getitem_not_found(dbsession): # noqa: F811 @@ -245,15 +278,15 @@ def test_account_resource_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import AccountResource
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.add(user)
dbsession.flush()
parent = DummyResource(request=request)
resource = AccountResource('a name', parent)
with pytest.raises(KeyError):
resource['unknown hash']
@ -262,12 +295,12 @@ def test_account_resource_get_settings_form(): @@ -262,12 +295,12 @@ def test_account_resource_get_settings_form():
''' test the setup of the settings form'''
from ordr.resources.account import AccountResource
import deform
request = DummyRequest()
parent = DummyResource(request=request)
resource = AccountResource('some name', parent)
form = resource.get_settings_form()
assert isinstance(form, deform.Form)
assert len(form.buttons) == 2
assert form.buttons[0].title == 'Change Settings'
@ -278,12 +311,12 @@ def test_account_resource_get_password_form(): @@ -278,12 +311,12 @@ def test_account_resource_get_password_form():
''' test the setup of the change password form'''
from ordr.resources.account import AccountResource
import deform
request = DummyRequest()
parent = DummyResource(request=request)
resource = AccountResource('some name', parent)
form = resource.get_password_form()
assert isinstance(form, deform.Form)
assert len(form.buttons) == 2
assert form.buttons[0].title == 'Change Password'

14
tests/resources/root.py

@ -2,11 +2,7 @@ @@ -2,11 +2,7 @@
import pytest
from ordr.resources.account import (
RegistrationResource,
PasswordResetResource,
AccountResource
)
from ordr.resources.account import AccountResource
def test_root_init():
@ -17,7 +13,7 @@ def test_root_init(): @@ -17,7 +13,7 @@ def test_root_init():
assert root.__parent__ is None
assert root.request == 'request'
def test_root_acl():
''' test access controll list for RootResource '''
from pyramid.security import Allow, Everyone, DENY_ALL
@ -28,18 +24,16 @@ def test_root_acl(): @@ -28,18 +24,16 @@ def test_root_acl():
@pytest.mark.parametrize(
'key,resource_class', [
('register', RegistrationResource),
('forgot', PasswordResetResource),
('account', AccountResource)
]
)
def test_root_getitem(key, resource_class):
''' test '__getitem__()' method of RootResource '''
from ordr.resources import RootResource
root = RootResource(None)
child = root[key]
assert isinstance(child, resource_class)
assert child.__name__ == key
assert child.__parent__ == root

22
tests/views/account/__init__.py

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
get_post_request
)
# test for account resource root
def test_account_redirect(dbsession): # noqa: F811
''' redirect on root of account resource '''
from ordr.views.account import account
request = DummyRequest(dbsession=dbsession)
result = account(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'

76
tests/views/forgotten_password.py → tests/views/account/forgotten_password.py

@ -4,7 +4,7 @@ import pytest @@ -4,7 +4,7 @@ import pytest
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from .. import ( # noqa: F401
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
@ -15,7 +15,7 @@ from .. import ( # noqa: F401 @@ -15,7 +15,7 @@ from .. import ( # noqa: F401
def test_forgotten_password_form():
''' test the view for the forgotten password form '''
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import forgotten_password_form
from ordr.views.account import forgotten_password_form
request = DummyRequest()
parent = DummyResource(request=request)
@ -33,14 +33,14 @@ def test_forgotten_password_processing_ok(dbsession, identifier): @@ -33,14 +33,14 @@ def test_forgotten_password_processing_ok(dbsession, identifier):
''' test the processing of the forgotten password form '''
from ordr.models.account import Role, TokenSubject
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
user = get_example_user(Role.USER)
dbsession.add(user)
dbsession.flush()
post_data = {
'identifier': identifier,
'send_mail': 'send_mail',
@ -49,10 +49,10 @@ def test_forgotten_password_processing_ok(dbsession, identifier): @@ -49,10 +49,10 @@ def test_forgotten_password_processing_ok(dbsession, identifier):
parent = DummyResource(request=request)
context = PasswordResetResource(name=None, parent=parent)
result = forgotten_password_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//verify'
# a token should be created
token = user.tokens[0]
assert token.subject == TokenSubject.RESET_PASSWORD
@ -70,14 +70,14 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier): @@ -70,14 +70,14 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier):
''' test error processing of the forgotten password form '''
from ordr.models.account import Role, Token
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
user = get_example_user(Role.UNVALIDATED)
dbsession.add(user)
dbsession.flush()
post_data = {
'identifier': identifier,
'send_mail': 'send_mail',
@ -86,7 +86,7 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier): @@ -86,7 +86,7 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier):
parent = DummyResource(request=request)
context = PasswordResetResource(name=None, parent=parent)
result = forgotten_password_form_processing(context, request)
assert result == {'formerror': True}
assert dbsession.query(Token).count() == 0
@ -95,10 +95,10 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811 @@ -95,10 +95,10 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811
''' test the canceling of the forgotten password form '''
from ordr.models.account import Token
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
post_data = {
'identifier': 'TerryGilliam',
'cancel': 'cancel',
@ -107,32 +107,32 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811 @@ -107,32 +107,32 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811
parent = DummyResource(request=request)
context = PasswordResetResource(name=None, parent=parent)
result = forgotten_password_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
assert dbsession.query(Token).count() == 0
def test_verify():
def test_forgotten_password_verify_email():
''' test the message view for check your email '''
from ordr.views.forgotten_password import verify
result = verify(None, None)
from ordr.views.account import forgotten_password_verify_email
result = forgotten_password_verify_email(None, None)
assert result == {}
def test_completed():
def test_forgotten_password_completed():
''' test the view for a completed reset process '''
from ordr.views.forgotten_password import completed
result = completed(None, None)
from ordr.views.account import forgotten_password_completed
result = forgotten_password_completed(None, None)
assert result == {}
def test_reset_password_form():
''' test reset password form view '''
from ordr.resources.account import PasswordResetTokenResource
from ordr.schemas.account import ResetPasswordSchema
from ordr.views.forgotten_password import reset_password_form
from ordr.views.account import reset_password_form
request = DummyRequest()
parent = DummyResource(request=request)
context = PasswordResetTokenResource(name=None, parent=parent)
@ -147,8 +147,8 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811 @@ -147,8 +147,8 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811
''' test reset password form processing '''
from ordr.models.account import User, Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'Lost in La Mancha',
@ -157,13 +157,13 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811 @@ -157,13 +157,13 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811
'change': 'Set New Password'
}
request = get_post_request(data, dbsession=dbsession)
user = get_example_user(Role.USER)
dbsession.add(user)
user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.flush()
token = dbsession.query(Token).first()
parent = DummyResource(request=request)
context = PasswordResetTokenResource(name=None, parent=parent, model=token)
result = reset_password_form_processing(context, request)
@ -175,7 +175,7 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811 @@ -175,7 +175,7 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811
# password of the user should be updated
user = dbsession.query(User).filter_by(username='TerryGilliam').first()
assert user.check_password('Lost in La Mancha')
token_count = dbsession.query(Token).count()
assert token_count == 0
@ -185,8 +185,8 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811 @@ -185,8 +185,8 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811
from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.schemas.account import ResetPasswordSchema
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'does not match',
@ -195,17 +195,17 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811 @@ -195,17 +195,17 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811
'change': 'Set New Password'
}
request = get_post_request(data, dbsession=dbsession)
user = get_example_user(Role.USER)
dbsession.add(user)
user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.flush()
token = dbsession.query(Token).first()
parent = DummyResource(request=request)
context = PasswordResetTokenResource(name=None, parent=parent, model=token)
result = reset_password_form_processing(context, request)
form = result['form']
assert isinstance(form, deform.Form)
@ -216,8 +216,8 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811 @@ -216,8 +216,8 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811
''' test reset password form processing '''
from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'Lost in La Mancha',
@ -226,16 +226,16 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811 @@ -226,16 +226,16 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811
'cancel': 'Cancel'
}
request = get_post_request(data, dbsession=dbsession)
user = get_example_user(Role.USER)
dbsession.add(user)
user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.flush()
token = dbsession.query(Token).first()
parent = DummyResource(request=request)
context = PasswordResetTokenResource(name=None, parent=parent, model=token)
result = reset_password_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'

95
tests/views/account/login_logout.py

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
import pytest
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from ordr.models.account import Role
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
get_post_request
)
def test_login():
''' test the view for the login form '''
from ordr.views.account import login
context = DummyResource(nav_active=None)
result = login(context, None)
assert result == {'loginerror': False}
assert context.nav_active == 'welcome'
@pytest.mark.parametrize( # noqa: F811
'role', [Role.USER, Role.PURCHASER, Role.ADMIN]
)
def test_check_login_ok(dbsession, role):
''' test the processing of the login form with valid credentials '''
from ordr.views.account import check_login
user = get_example_user(role)
dbsession.add(user)
post_data = {'username': user.username, 'password': user.first_name}
request = DummyRequest(dbsession=dbsession, POST=post_data)
context = DummyResource(nav_active=None)
result = check_login(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
@pytest.mark.parametrize( # noqa: F811
'role', [Role.UNVALIDATED, Role.NEW, Role.INACTIVE]
)
def test_check_login_not_activated(dbsession, role):
''' test the processing of the login form with an inactive user '''
from ordr.views.account import check_login
user = get_example_user(role)
dbsession.add(user)
post_data = {'username': user.username, 'password': user.first_name}
request = DummyRequest(dbsession=dbsession, POST=post_data)
context = DummyResource(nav_active=None)
result = check_login(context, request)
assert result == {'loginerror': True}
assert context.nav_active == 'welcome'
@pytest.mark.parametrize( # noqa: F811
'username,password', [
('', ''),
('TerryGilliam', ''),
('', 'Terry'),
('TerryGilliam', 'wrong password'),
('wrong username', 'Terry'),
]
)
def test_check_login_invalid_credentials(dbsession, username, password):
''' test the processing of the login form with invalid credentials '''
from ordr.views.account import check_login
user = get_example_user(Role.USER)
dbsession.add(user)
post_data = {'username': username, 'password': password}
request = DummyRequest(dbsession=dbsession, POST=post_data)
context = DummyResource(nav_active=None)
result = check_login(context, request)
assert result == {'loginerror': True}
assert context.nav_active == 'welcome'
def test_logout():
''' test the logout view '''
from ordr.views.account import logout
request = DummyRequest()
result = logout(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'

28
tests/views/registration.py → tests/views/account/registration.py

@ -3,7 +3,7 @@ import deform @@ -3,7 +3,7 @@ import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from .. import ( # noqa: F401
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
@ -28,7 +28,7 @@ def test_registration_form(): @@ -28,7 +28,7 @@ def test_registration_form():
''' test the view for the registration form '''
from ordr.resources.account import RegistrationResource
from ordr.schemas.account import RegistrationSchema
from ordr.views.registration import registration_form
from ordr.views.account import registration_form
request = DummyRequest()
parent = DummyResource(request=request)
@ -44,7 +44,7 @@ def test_registration_form_valid(dbsession): # noqa: F811 @@ -44,7 +44,7 @@ def test_registration_form_valid(dbsession): # noqa: F811
''' test processing the registration form with valid data '''
from ordr.models.account import User, Role, TokenSubject
from ordr.resources.account import RegistrationResource
from ordr.views.registration import registration_form_processing
from ordr.views.account import registration_form_processing
data = REGISTRATION_FORM_DATA.copy()
request = get_post_request(data, dbsession=dbsession)
@ -76,45 +76,45 @@ def test_registration_form_valid(dbsession): # noqa: F811 @@ -76,45 +76,45 @@ def test_registration_form_valid(dbsession): # noqa: F811
def test_registration_form_invalid(dbsession): # noqa: F811
''' test processing registration form with invalid data '''
from ordr.views.registration import registration_form_processing
from ordr.views.account import registration_form_processing
from ordr.resources.account import RegistrationResource
data = REGISTRATION_FORM_DATA.copy()
data['email'] = 'not an email address'
request = get_post_request(data, dbsession=dbsession)
parent = DummyResource(request=request)
context = RegistrationResource(name=None, parent=parent)
result = registration_form_processing(context, request)
assert result['form'].error is not None
def test_registration_form_no_create_button(dbsession): # noqa: F811
''' test processing registration form, create button not clicked '''
from ordr.views.registration import registration_form_processing
from ordr.views.account import registration_form_processing
from ordr.resources.account import RegistrationResource
data = REGISTRATION_FORM_DATA.copy()
data.pop('create')
request = get_post_request(data, dbsession=dbsession)
parent = DummyResource(request=request)
context = RegistrationResource(name=None, parent=parent)
result = registration_form_processing(context, request)
assert result.location == 'http://example.com//'
def test_registration_verify():
def test_registration_verify_email():
''' test the view displaying that a verifcation email has been sent '''
from ordr.views.registration import verify
result = verify(None, None)
from ordr.views.account import registration_verify_email
result = registration_verify_email(None, None)
assert result == {}
def test_registration_completed(dbsession): # noqa: F811
''' test the view for the completed registration process '''
from ordr.models.account import User, Role, Token, TokenSubject
from ordr.views.registration import completed
from ordr.views.account import registration_completed
request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.UNVALIDATED)
@ -123,7 +123,7 @@ def test_registration_completed(dbsession): # noqa: F811 @@ -123,7 +123,7 @@ def test_registration_completed(dbsession): # noqa: F811
dbsession.flush()
token = user.tokens[0]
context = DummyResource(model=token)
result = completed(context, request)
result = registration_completed(context, request)
assert result == {}
assert user.role == Role.NEW

93
tests/views/account.py → tests/views/account/settings.py

@ -3,7 +3,7 @@ import deform @@ -3,7 +3,7 @@ import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from .. import ( # noqa: F401
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
@ -11,44 +11,33 @@ from .. import ( # noqa: F401 @@ -11,44 +11,33 @@ from .. import ( # noqa: F401
)
def test_account_redirect():
''' redirect on root of account resource '''
from ordr.views.account import account
request = DummyRequest()
result = account(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
def test_settings_form():
''' tests for displaying the settings form '''
from ordr.models.account import Role
from ordr.resources.account import AccountResource
from ordr.schemas.account import SettingsSchema
from ordr.views.account import settings_form
user = get_example_user(Role.USER)
request = DummyRequest(user=user)
parent = DummyResource(request=request)
context = AccountResource(None, parent)
result = settings_form(context, request)
form = result['form']
assert isinstance(form, deform.Form)
assert isinstance(form.schema, SettingsSchema)
def test_settings_form_processing_valid_data(dbsession): # noqa: F811
''' tests for processing the settings form
The data is valid, but no email change requested
'''
from ordr.models.account import Role, Token, User
from ordr.resources.account import AccountResource
from ordr.views.account import settings_form_processing
data = {
'username': 'TerryG',
'first_name': 'Amy',
@ -57,7 +46,7 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811 @@ -57,7 +46,7 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811
'confirmation': 'Terry',
'change': 'Change Settings'
}
user = get_example_user(Role.USER)
dbsession.add(user)
dbsession.flush()
@ -66,10 +55,10 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811 @@ -66,10 +55,10 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811
context = AccountResource(None, parent)
request.context = context
result = settings_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
account = dbsession.query(User).first()
assert account.username == 'TerryGilliam'
assert account.first_name == 'Amy'
@ -80,13 +69,13 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811 @@ -80,13 +69,13 @@ def test_settings_form_processing_valid_data(dbsession): # noqa: F811
def test_settings_form_processing_mail_change(dbsession): # noqa: F811
''' tests for processing the settings form
The data is valid and an email change is requested
'''
from ordr.models.account import Role, Token, TokenSubject, User
from ordr.resources.account import AccountResource
from ordr.views.account import settings_form_processing
data = {
'username': 'TerryG',
'first_name': 'Amy',
@ -95,7 +84,7 @@ def test_settings_form_processing_mail_change(dbsession): # noqa: F811 @@ -95,7 +84,7 @@ def test_settings_form_processing_mail_change(dbsession): # noqa: F811
'confirmation': 'Terry',
'change': 'Change Settings'
}
user = get_example_user(Role.USER)
dbsession.add(user)
request = get_post_request(data=data, dbsession=dbsession, user=user)
@ -103,16 +92,16 @@ def test_settings_form_processing_mail_change(dbsession): # noqa: F811 @@ -103,16 +92,16 @@ def test_settings_form_processing_mail_change(dbsession): # noqa: F811
context = AccountResource(None, parent)
request.context = context
result = settings_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//verify'
account = dbsession.query(User).first()
assert account.username == 'TerryGilliam'
assert account.first_name == 'Amy'
assert account.last_name == 'McDonald'
assert account.email == 'gilliam@example.com'
token = dbsession.query(Token).first()
assert token.subject == TokenSubject.CHANGE_EMAIL
assert token.payload == {'email': 'amy@example.com'}
@ -128,7 +117,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811 @@ -128,7 +117,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811
from ordr.resources.account import AccountResource
from ordr.schemas.account import SettingsSchema
from ordr.views.account import settings_form_processing
data = {
'username': 'TerryG',
'first_name': 'Amy',
@ -137,7 +126,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811 @@ -137,7 +126,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811
'confirmation': 'Terry',
'change': 'Change Settings'
}
user = get_example_user(Role.USER)
dbsession.add(user)
request = get_post_request(data=data, dbsession=dbsession, user=user)
@ -146,7 +135,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811 @@ -146,7 +135,7 @@ def test_settings_form_processing_invalid_data(dbsession): # noqa: F811
request.context = context
result = settings_form_processing(context, request)
form = result['form']
assert isinstance(form, deform.Form)
assert isinstance(form.schema, SettingsSchema)
@ -156,7 +145,7 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811 @@ -156,7 +145,7 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811
from ordr.models.account import Role, User
from ordr.resources.account import AccountResource
from ordr.views.account import settings_form_processing
data = {
'username': 'TerryG',
'first_name': 'Amy',
@ -165,7 +154,7 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811 @@ -165,7 +154,7 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811
'confirmation': 'Terry',
'cancel': 'cancel'
}
user = get_example_user(Role.USER)
dbsession.add(user)
request = get_post_request(data=data, dbsession=dbsession, user=user)
@ -173,22 +162,22 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811 @@ -173,22 +162,22 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811
context = AccountResource(None, parent)
request.context = context
result = settings_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
account = dbsession.query(User).first()
assert account.first_name == 'Terry'
def test_verify_email(dbsession): # noqa: F811
def test_verify_email_change(dbsession): # noqa: F811
''' tests for processing the change password form '''
from ordr.models.account import Role, Token, TokenSubject
from ordr.views.account import verify_email
from ordr.views.account import verify_email_change
user = get_example_user(Role.USER)
request = DummyRequest(dbsession=dbsession, user=user)
user.issue_token(
request,
TokenSubject.CHANGE_EMAIL,
@ -198,12 +187,12 @@ def test_verify_email(dbsession): # noqa: F811 @@ -198,12 +187,12 @@ def test_verify_email(dbsession): # noqa: F811
dbsession.flush()
token = dbsession.query(Token).first()
context = DummyResource(model=token)
result = verify_email(context, request)
result = verify_email_change(context, request)
assert result == {}
assert user.email == 'amy@example.com'
assert dbsession.query(Token).count() == 0
def test_password_form():
''' tests for displaying the change password form '''
@ -211,24 +200,24 @@ def test_password_form(): @@ -211,24 +200,24 @@ def test_password_form():
from ordr.resources.account import AccountResource
from ordr.schemas.account import ChangePasswordSchema
from ordr.views.account import password_form
user = get_example_user(Role.USER)
request = DummyRequest(user=user)
parent = DummyResource(request=request)
context = AccountResource(None, parent)
result = password_form(context, request)
form = result['form']
assert isinstance(form, deform.Form)
assert isinstance(form.schema, ChangePasswordSchema)
def test_password_form_processing_valid(dbsession): # noqa: F811
''' tests for processing the change password form '''
from ordr.models.account import Role
from ordr.resources.account import AccountResource
from ordr.views.account import password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'Make Amy McDonald A Rich Girl Fund',
@ -237,13 +226,13 @@ def test_password_form_processing_valid(dbsession): # noqa: F811 @@ -237,13 +226,13 @@ def test_password_form_processing_valid(dbsession): # noqa: F811
'confirmation': 'Terry',
'change': 'Change Password'
}
user = get_example_user(Role.USER)
request = get_post_request(data=data, user=user)
parent = DummyResource(request=request)
context = AccountResource(None, parent)
result = password_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//changed'
assert not user.check_password('Terry')
@ -256,7 +245,7 @@ def test_password_form_processing_invalid(dbsession): # noqa: F811 @@ -256,7 +245,7 @@ def test_password_form_processing_invalid(dbsession): # noqa: F811
from ordr.resources.account import AccountResource
from ordr.schemas.account import ChangePasswordSchema
from ordr.views.account import password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'Make Amy McDonald A Rich Girl Fund',
@ -265,14 +254,14 @@ def test_password_form_processing_invalid(dbsession): # noqa: F811 @@ -265,14 +254,14 @@ def test_password_form_processing_invalid(dbsession): # noqa: F811
'confirmation': 'not the right password for confirmation',
'change': 'Change Password'
}
user = get_example_user(Role.USER)
request = get_post_request(data=data, user=user)
parent = DummyResource(request=request)
context = AccountResource(None, parent)
result = password_form_processing(context, request)
form = result['form']
assert isinstance(form, deform.Form)
assert isinstance(form.schema, ChangePasswordSchema)
assert user.check_password('Terry')
@ -283,7 +272,7 @@ def test_password_form_processing_cancel(dbsession): # noqa: F811 @@ -283,7 +272,7 @@ def test_password_form_processing_cancel(dbsession): # noqa: F811
from ordr.models.account import Role
from ordr.resources.account import AccountResource
from ordr.views.account import password_form_processing
data = {
'__start__': 'password:mapping',
'password': 'Make Amy McDonald A Rich Girl Fund',
@ -292,17 +281,17 @@ def test_password_form_processing_cancel(dbsession): # noqa: F811 @@ -292,17 +281,17 @@ def test_password_form_processing_cancel(dbsession): # noqa: F811
'confirmation': 'Terry',
'cancel': 'cancel'
}
user = get_example_user(Role.USER)
request = get_post_request(data=data, user=user)
parent = DummyResource(request=request)
context = AccountResource(None, parent)
result = password_form_processing(context, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
assert user.check_password('Terry')
def test_password_changed():
''' show password has changed message '''

80
tests/views/pages.py

@ -3,22 +3,21 @@ import pytest @@ -3,22 +3,21 @@ import pytest
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest
from ordr.models.account import Role
from .. import app_config, dbsession, get_example_user # noqa: F401
@pytest.mark.parametrize(
'user,location',
[(None, '/login'), ('someone', '/orders')]
[(None, '/account/login'), ('someone', '/orders')]
)
def test_welcome(user, location):
''' test redirects on web root '''
from ordr.views.pages import welcome
request = DummyRequest(user=user)
result = welcome(None, request)
assert isinstance(result, HTTPFound)
assert result.location == f'http://example.com/{location}'
@ -28,76 +27,3 @@ def test_faq(): @@ -28,76 +27,3 @@ def test_faq():
from ordr.views.pages import faq
result = faq(None, None)
assert result == {}
def test_login():
''' test the view for the login form '''
from ordr.views.pages import login
result = login(None, None)
assert result == {'loginerror': False}
@pytest.mark.parametrize( # noqa: F811
'role', [Role.USER, Role.PURCHASER, Role.ADMIN]
)
def test_check_login_ok(dbsession, role):
''' test the processing of the login form with valid credentials '''
from ordr.views.pages import check_login
user = get_example_user(role)
dbsession.add(user)
post_data = {'username': user.username, 'password': user.first_name}
request = DummyRequest(dbsession=dbsession, POST=post_data)
result = check_login(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
@pytest.mark.parametrize( # noqa: F811
'role', [Role.UNVALIDATED, Role.NEW, Role.INACTIVE]
)
def test_check_login_not_activated(dbsession, role):
''' test the processing of the login form with an inactive user '''
from ordr.views.pages import check_login
user = get_example_user(role)
dbsession.add(user)
post_data = {'username': user.username, 'password': user.first_name}
request = DummyRequest(dbsession=dbsession, POST=post_data)
result = check_login(None, request)
assert result == {'loginerror': True}
@pytest.mark.parametrize( # noqa: F811
'username,password', [
('', ''),
('TerryGilliam', ''),
('', 'Terry'),
('TerryGilliam', 'wrong password'),
('wrong username', 'Terry'),
]
)
def test_check_login_invalid_credentials(dbsession, username, password):
''' test the processing of the login form with invalid credentials '''
from ordr.views.pages import check_login
user = get_example_user(Role.USER)
dbsession.add(user)
post_data = {'username': username, 'password': password}
request = DummyRequest(dbsession=dbsession, POST=post_data)
result = check_login(None, request)
assert result == {'loginerror': True}
def test_logout():
''' test the logout view '''
from ordr.views.pages import logout
request = DummyRequest()
result = logout(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'