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

30
ordr/resources/account.py

@ -28,7 +28,7 @@ class RegistrationTokenResource(BaseChildResource):
def __acl__(self): def __acl__(self):
''' access controll list for the resource ''' ''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL] return [(Allow, Everyone, 'register'), DENY_ALL]
class RegistrationResource(BaseChildResource): class RegistrationResource(BaseChildResource):
@ -43,7 +43,7 @@ class RegistrationResource(BaseChildResource):
def __acl__(self): def __acl__(self):
''' access controll list for the resource ''' ''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL] return [(Allow, Everyone, 'register'), DENY_ALL]
def __getitem__(self, key): def __getitem__(self, key):
''' returns a resource for a valid registration token ''' ''' returns a resource for a valid registration token '''
@ -81,7 +81,7 @@ class PasswordResetTokenResource(BaseChildResource):
def __acl__(self): def __acl__(self):
''' access controll list for the resource ''' ''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL] return [(Allow, Everyone, 'reset'), DENY_ALL]
def get_reset_form(self, **kwargs): def get_reset_form(self, **kwargs):
''' returns password reset form ''' ''' returns password reset form '''
@ -107,7 +107,7 @@ class PasswordResetResource(BaseChildResource):
def __acl__(self): def __acl__(self):
''' access controll list for the resource ''' ''' access controll list for the resource '''
return [(Allow, Everyone, 'view'), DENY_ALL] return [(Allow, Everyone, 'reset'), DENY_ALL]
def __getitem__(self, key): def __getitem__(self, key):
''' returns a resource for a valid reset password token ''' ''' returns a resource for a valid reset password token '''
@ -156,10 +156,28 @@ class AccountResource(BaseChildResource):
def __acl__(self): def __acl__(self):
''' access controll list for the resource ''' ''' 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): 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) token = Token.retrieve(self.request, key, TokenSubject.CHANGE_EMAIL)
if token is None: if token is None:
raise KeyError(f'Token {key} not found') raise KeyError(f'Token {key} not found')

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

@ -12,7 +12,7 @@
<div class="row"> <div class="row">
<div class="col-4 offset-2"> <div class="col-4 offset-2">
<h4 class="mb-4">Login</h4> <h4 class="mb-4">Login</h4>
<form action="/login" method="POST"> <form action="{{ request.resource_url(context, 'login') }}" method="POST">
<div class="form-group"> <div class="form-group">
<input type="hidden" name="csrf_token" value="{{get_csrf_token()}}"> <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"> <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 @@
<body> <body>
<nav class="navbar navbar-dark bg-dark navbar-expand-sm"> <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 %} {% if not request.user %}
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='login' %}active{% endif %}"> <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>
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='faq' %}active{% endif %}"> <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>
<li class="nav-item {% if context.nav_active=='registration' %}active{% endif %}"> <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> </li>
</ul> </ul>
{% else %} {% else %}
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
<li class="nav-item {% if context.nav_active=='orders' %}active{% endif %}"> <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>
<li class="nav-item {% if context.nav_active=='welcome' and request.view_name=='faq' %}active{% endif %}"> <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>
{% if 'role:admin' in request.user.principals %} {% if 'role:admin' in request.user.principals %}
<li class="nav-item {% if context.nav_active=='admin' %}active{% endif %}"> <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> </li>
{% endif %} {% endif %}
</ul> </ul>
@ -55,10 +55,10 @@
{{ request.user }} {{ request.user }}
</a> </a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="userDropdown"> <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> <div class="dropdown-divider"></div>
<a class="dropdown-item small" href="/account/settings">Settings</a> <a class="dropdown-item small" href="{{ request.resource_url(request.root, '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', 'password') }}">Change Password</a>
</div> </div>
</li> </li>
</ul> </ul>

268
ordr/views/account.py

@ -1,21 +1,279 @@
''' views for user accounts
This includes login, logout, registration, forgotten passwords, changing
settings and passwords
'''
import deform import deform
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config 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( @view_config(
context='ordr.resources.account.AccountResource', context='ordr.resources.account.AccountResource',
permission='edit' permission='view'
) )
def account(context, request): def account(context, request):
''' redirect if '/account' was requested directly ''' ''' redirect if '/account' was requested directly '''
return HTTPFound(request.resource_url(request.root)) 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( @view_config(
context='ordr.resources.account.AccountResource', context='ordr.resources.account.AccountResource',
permission='edit', permission='edit',
@ -85,7 +343,7 @@ def settings_form_processing(context, request):
request_method='GET', request_method='GET',
renderer='ordr:templates/account/settings_mail_changed.jinja2' renderer='ordr:templates/account/settings_mail_changed.jinja2'
) )
def verify_email(context, request): def verify_email_change(context, request):
''' show email verification text ''' ''' show email verification text '''
payload = context.model.payload payload = context.model.payload
request.user.email = payload['email'] request.user.email = payload['email']
@ -93,6 +351,8 @@ def verify_email(context, request):
return {} return {}
# change password
@view_config( @view_config(
context='ordr.resources.account.AccountResource', context='ordr.resources.account.AccountResource',
permission='edit', permission='edit',

120
ordr/views/forgotten_password.py

@ -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 @@
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config from pyramid.view import view_config
from ordr.models import User
@view_config( @view_config(
context='ordr.resources.RootResource', context='ordr.resources.RootResource',
@ -11,8 +8,10 @@ from ordr.models import User
) )
def welcome(context, request): def welcome(context, request):
''' web root redirects ''' ''' web root redirects '''
next = 'orders' if request.user else 'login' if request.user:
redirect_to = request.resource_url(context, next) redirect_to = request.resource_url(context, 'orders')
else:
redirect_to = request.resource_url(context, 'account', 'login')
return HTTPFound(redirect_to) return HTTPFound(redirect_to)
@ -25,51 +24,3 @@ def welcome(context, request):
def faq(context, request): def faq(context, request):
''' displays the FAQ page ''' ''' displays the FAQ page '''
return {} 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 @@
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'] = [
class CustomTestApp(webtest.TestApp): class CustomTestApp(webtest.TestApp):
''' might add custom functionality to webtest.TestApp ''' ''' might add custom functionality to webtest.TestApp '''
pass pass
def login(self, username, password): def login(self, username, password):
''' login ''' ''' login '''
self.logout() self.logout()
result = self.get('/login') result = self.get('/account/login')
login_form = result.forms[0] login_form = result.forms[0]
login_form['username'] = username login_form['username'] = username
login_form['password'] = password login_form['password'] = password
login_form.submit() login_form.submit()
response = self.get('/faq') response = self.get('/faq')
return username in response return username in response
def logout(self): def logout(self):
''' logout ''' ''' logout '''
self.get('/logout') self.get('/account/logout')
def reset(self): def reset(self):
''' reset the webapp ''' ''' reset the webapp '''
self.logout() self.logout()
@ -60,7 +60,7 @@ def get_token_url(email, prefix='/'):
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def testappsetup(): def testappsetup():
''' setup of fixture for using webtest ''' setup of fixture for using webtest
this fixture just sets up the testapp. please use the testapp() fixture this fixture just sets up the testapp. please use the testapp() fixture
below for real tests. below for real tests.
''' '''

10
tests/_functional/account/__init__.py

@ -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
def test_forgot_password_process(testapp): # noqa: F811 def test_forgot_password_process(testapp): # noqa: F811
''' test the forgot password form ''' ''' test the forgot password form '''
response = testapp.get('/forgot') response = testapp.get('/account/forgot')
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
active_step = response.html.find('p', class_='text-primary') active_step = response.html.find('p', class_='text-primary')
assert active_nav is None assert active_nav is None
assert 'Step 1: Validate Account' in active_step.text assert 'Step 1: Validate Account' in active_step.text
assert 'Forgot Your Password?' in response assert 'Forgot Your Password?' in response
assert 'unknown username or email' not in response assert 'unknown username or email' not in response
# fill out this form with invalid data # fill out this form with invalid data
form = response.form form = response.form
form['identifier'] = 'unknown identifier' form['identifier'] = 'unknown identifier'
@ -25,12 +25,13 @@ def test_forgot_password_process(testapp): # noqa: F811
assert 'Step 1: Validate Account' in active_step.text assert 'Step 1: Validate Account' in active_step.text
assert 'Forgot Your Password?' in response assert 'Forgot Your Password?' in response
assert 'Username or email address unknown' in response assert 'Username or email address unknown' in response
# fill out this form with valid data # fill out this form with valid data
response = testapp.get('/account/forgot')
form = response.form form = response.form
form['identifier'] = 'TerryGilliam' form['identifier'] = 'TerryGilliam'
response = form.submit(name='send_mail') response = form.submit(name='send_mail')
assert response.location == 'http://localhost/forgot/verify' assert response.location == 'http://localhost/account/forgot/verify'
response = response.follow() response = response.follow()
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
@ -38,12 +39,12 @@ def test_forgot_password_process(testapp): # noqa: F811
assert active_nav is None assert active_nav is None
assert 'Step 1: Validate Account' in active_step.text assert 'Step 1: Validate Account' in active_step.text
assert 'Verify Your Email Address' in response assert 'Verify Your Email Address' in response
# click the email verification token # click the email verification token
mailer = get_mailer(testapp.app.registry) mailer = get_mailer(testapp.app.registry)
email = mailer.outbox[-1] email = mailer.outbox[-1]
assert email.subject == '[ordr] Password Reset' assert email.subject == '[ordr] Password Reset'
token_link = get_token_url(email, prefix='/forgot/') token_link = get_token_url(email, prefix='/forgot/')
response = testapp.get(token_link) response = testapp.get(token_link)
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
@ -52,7 +53,7 @@ def test_forgot_password_process(testapp): # noqa: F811
assert 'Step 2: Change Password' in active_step.text assert 'Step 2: Change Password' in active_step.text
assert 'Forgot Your Password?' in response assert 'Forgot Your Password?' in response
assert 'do not match' not in response assert 'do not match' not in response
# fill out the change password form with invalid data # fill out the change password form with invalid data
form = response.form form = response.form
form['password'] = 'some passwords' form['password'] = 'some passwords'
@ -70,8 +71,8 @@ def test_forgot_password_process(testapp): # noqa: F811
form['password'] = 'Lost in La Mancha' form['password'] = 'Lost in La Mancha'
form['password-confirm'] = 'Lost in La Mancha' form['password-confirm'] = 'Lost in La Mancha'
response = form.submit(name='change') response = form.submit(name='change')
assert response.location == 'http://localhost/forgot/completed' assert response.location == 'http://localhost/account/forgot/completed'
response = response.follow() response = response.follow()
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
active_step = response.html.find('p', class_='text-primary') 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
def test_login_get(testapp): # noqa: F811 def test_login_get(testapp): # noqa: F811
''' test the login form ''' ''' test the login form '''
response = testapp.get('/login') response = testapp.get('/account/login')
active = response.html.find('li', class_='active') active = response.html.find('li', class_='active')
assert active.a['href'] == '/' form = response.form
expected = {'/', '/faq', '/register', '/forgot', '/register'} assert active.a['href'] == 'http://localhost/'
hrefs = {a['href'] for a in response.html.find_all('a')} assert form.action == 'http://localhost/account/login'
assert expected == hrefs
def test_login_ok(testapp): # noqa: F811 def test_login_ok(testapp): # noqa: F811
''' test login form with valid credentials ''' ''' test login form with valid credentials '''
response = testapp.get('/login') response = testapp.get('/account/login')
login_form = response.forms[0] login_form = response.forms[0]
login_form['username'] = 'TerryGilliam' login_form['username'] = 'TerryGilliam'
login_form['password'] = 'Terry' login_form['password'] = 'Terry'
response = login_form.submit() response = login_form.submit()
assert response.location == 'http://localhost/' assert response.location == 'http://localhost/'
response = testapp.get('/faq')
assert 'TerryGilliam' in response
@pytest.mark.parametrize( # noqa: F811 @pytest.mark.parametrize( # noqa: F811
'username,password', 'username,password',
@ -34,11 +36,30 @@ def test_login_ok(testapp): # noqa: F811
) )
def test_login_denied(testapp, username, password): def test_login_denied(testapp, username, password):
''' test login form with invalid credentials ''' ''' test login form with invalid credentials '''
response = testapp.get('/login') response = testapp.get('/account/login')
login_form = response.forms[0] login_form = response.forms[0]
login_form['username'] = 'John' login_form['username'] = 'John'
login_form['password'] = 'Cleese' login_form['password'] = 'Cleese'
response = login_form.submit() response = login_form.submit()
assert 'account is not activated' in response 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
def test_registration_form(testapp): # noqa: F811 def test_registration_form(testapp): # noqa: F811
''' test the registration form ''' ''' test the registration form '''
response = testapp.get('/register') response = testapp.get('/account/register')
active = response.html.find('li', class_='active') 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 assert 'Registration' in response.html.title.text
def test_registration_form_invalid(testapp): # noqa: F811 def test_registration_form_invalid(testapp): # noqa: F811
''' test the registration form with invalid data ''' ''' test the registration form with invalid data '''
response = testapp.get('/register') response = testapp.get('/account/register')
form = response.form form = response.form
form['email'] = 'not an email address' form['email'] = 'not an email address'
response = form.submit(name='create') response = form.submit(name='create')
assert 'Invalid email address' in response assert 'Invalid email address' in response
assert 'Registration' in response.html.title.text assert 'Registration' in response.html.title.text
def test_registration_process(testapp): # noqa: F811 def test_registration_process(testapp): # noqa: F811
''' test the registration process with valid data ''' ''' test the registration process with valid data '''
response = testapp.get('/register') response = testapp.get('/account/register')
form = response.form form = response.form
form['username'] = 'AmyMcDonald', form['username'] = 'AmyMcDonald',
form['first_name'] = 'Amy', form['first_name'] = 'Amy',
@ -37,22 +37,22 @@ def test_registration_process(testapp): # noqa: F811
form['password'] = 'Make Amy McDonald A Rich Girl Fund', form['password'] = 'Make Amy McDonald A Rich Girl Fund',
form['password-confirm'] = 'Make Amy McDonald A Rich Girl Fund', form['password-confirm'] = 'Make Amy McDonald A Rich Girl Fund',
response = form.submit(name='create') response = form.submit(name='create')
assert response.location == 'http://localhost/register/verify' assert response.location == 'http://localhost/account/register/verify'
response = response.follow() response = response.follow()
active = response.html.find('li', class_='active') 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 'Please follow the link in the email' in response
assert 'Registration' in response.html.title.text assert 'Registration' in response.html.title.text
# click the email verification token # click the email verification token
mailer = get_mailer(testapp.app.registry) mailer = get_mailer(testapp.app.registry)
email = mailer.outbox[-1] email = mailer.outbox[-1]
assert email.subject == '[ordr] Please verify your email address' 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) response = testapp.get(token_link)
active = response.html.find('li', class_='active') 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 Completed' in response
assert 'Registration' in response.html.title.text assert 'Registration' in response.html.title.text

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

@ -2,26 +2,19 @@
from pyramid_mailer import get_mailer from pyramid_mailer import get_mailer
from . import testappsetup, testapp, get_token_url # noqa: F401 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/'
def test_account_change_settings(testapp): # noqa: F811 def test_account_change_settings(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry') testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/settings') response = testapp.get('/account/settings')
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
assert active_nav is None assert active_nav is None
assert 'Change Settings' in response assert 'Change Settings' in response
assert 'value="gilliam@example.com"' in response assert 'value="gilliam@example.com"' in response
assert 'Wrong Password' not in response assert 'Wrong Password' not in response
# fill out the form without confirmation password # fill out the form without confirmation password
form = response.form form = response.form
form['first_name'] = 'Amy' form['first_name'] = 'Amy'
@ -44,7 +37,7 @@ def test_account_change_settings(testapp): # noqa: F811
assert active_nav is None assert active_nav is None
assert 'Change Settings' in response assert 'Change Settings' in response
assert 'Invalid email address' in response assert 'Invalid email address' in response
# fill out the form with valid data and correct password # fill out the form with valid data and correct password
response = testapp.get('/account/settings') response = testapp.get('/account/settings')
form = response.form form = response.form
@ -53,7 +46,7 @@ def test_account_change_settings(testapp): # noqa: F811
form['confirmation'] = 'Terry' form['confirmation'] = 'Terry'
response = form.submit(name='change') response = form.submit(name='change')
assert response.location == 'http://localhost/' assert response.location == 'http://localhost/'
response = testapp.get('/account/settings') response = testapp.get('/account/settings')
assert 'value="Amy"' in response assert 'value="Amy"' in response
@ -61,7 +54,7 @@ def test_account_change_settings(testapp): # noqa: F811
def test_account_change_email(testapp): # noqa: F811 def test_account_change_email(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry') testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/settings') response = testapp.get('/account/settings')
# fill out the form with valid data and correct password # fill out the form with valid data and correct password
form = response.form form = response.form
form['email'] = 'amy@example.com' form['email'] = 'amy@example.com'
@ -74,7 +67,7 @@ def test_account_change_email(testapp): # noqa: F811
email = mailer.outbox[-1] email = mailer.outbox[-1]
assert email.subject == '[ordr] Verify New Email Address' assert email.subject == '[ordr] Verify New Email Address'
assert email.recipients == ['amy@example.com'] assert email.recipients == ['amy@example.com']
token_link = get_token_url(email, prefix='/account/') token_link = get_token_url(email, prefix='/account/')
response = testapp.get(token_link) response = testapp.get(token_link)
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
@ -85,13 +78,13 @@ def test_account_change_email(testapp): # noqa: F811
def test_account_change_password(testapp): # noqa: F811 def test_account_change_password(testapp): # noqa: F811
testapp.login('TerryGilliam', 'Terry') testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account/password') response = testapp.get('/account/password')
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
assert active_nav is None assert active_nav is None
assert 'Change Password' in response assert 'Change Password' in response
assert 'Wrong Password' not in response assert 'Wrong Password' not in response
# fill out the form with incorrect confirmation password # fill out the form with incorrect confirmation password
form = response.form form = response.form
form['password'] = 'Lost in La Mancha' form['password'] = 'Lost in La Mancha'
@ -114,7 +107,7 @@ def test_account_change_password(testapp): # noqa: F811
assert active_nav is None assert active_nav is None
assert 'Change Password' in response assert 'Change Password' in response
assert 'Password did not match confirm' in response assert 'Password did not match confirm' in response
# fill out the form with valid data and correct password # fill out the form with valid data and correct password
response = testapp.get('/account/password') response = testapp.get('/account/password')
form = response.form form = response.form
@ -123,10 +116,10 @@ def test_account_change_password(testapp): # noqa: F811
form['confirmation'] = 'Terry' form['confirmation'] = 'Terry'
response = form.submit(name='change') response = form.submit(name='change')
assert response.location == 'http://localhost/account/changed' assert response.location == 'http://localhost/account/changed'
response = response.follow() response = response.follow()
active_nav = response.html.find('li', class_='active') active_nav = response.html.find('li', class_='active')
assert active_nav is None assert active_nav is None
assert 'Your password was changed successfully' in response assert 'Your password was changed successfully' in response
assert testapp.login('TerryGilliam', 'Lost in La Mancha') 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
''' test the navigation on top of the page for an unauthenticated user ''' ''' test the navigation on top of the page for an unauthenticated user '''
response = testapp.get('/faq') response = testapp.get('/faq')
navbar = response.html.find('nav', class_='navbar-dark') 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')] hrefs = [a['href'] for a in navbar.find_all('a')]
assert expected == hrefs assert expected == hrefs
assert '/orders' not in response assert '/orders' not in response
assert 'nav-item dropdown' not in response assert 'nav-item dropdown' not in response
@ -25,7 +30,7 @@ def test_navbar_no_user(testapp): # noqa: F811
'username,password,extras', [ 'username,password,extras', [
('TerryGilliam', 'Terry', []), ('TerryGilliam', 'Terry', []),
('EricIdle', 'Eric', []), ('EricIdle', 'Eric', []),
('TerryJones', 'Terry', ['/admin']), ('TerryJones', 'Terry', ['http://localhost/admin']),
] ]
) )
def test_navbar_with_user(testapp, username, password, extras): 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') response = testapp.get('/faq')
navbar = response.html.find('nav', class_='navbar-dark') navbar = response.html.find('nav', class_='navbar-dark')
hrefs = [a['href'] for a in navbar.find_all('a')] 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(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 expected == hrefs
assert 'nav-item dropdown' in response assert 'nav-item dropdown' in response

8
tests/_functional/pages.py

@ -6,10 +6,10 @@ from . import testappsetup, testapp # noqa: F401
def test_welcome(testapp): # noqa: F811 def test_welcome(testapp): # noqa: F811
''' test the redirects on web root ''' ''' test the redirects on web root '''
response = testapp.get('/') response = testapp.get('/')
assert response.location == 'http://localhost/login' assert response.location == 'http://localhost/account/login'
testapp.login('TerryGilliam', 'Terry') testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/') response = testapp.get('/')
assert response.location == 'http://localhost/orders' assert response.location == 'http://localhost/orders'
@ -18,4 +18,4 @@ def test_faq(testapp): # noqa: F811
''' test the faq page ''' ''' test the faq page '''
response = testapp.get('/faq') response = testapp.get('/faq')
active = response.html.find('li', class_='active') 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():
''' test access controll list for RegistrationTokenResource ''' ''' test access controll list for RegistrationTokenResource '''
from pyramid.security import Allow, Everyone, DENY_ALL from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import RegistrationTokenResource from ordr.resources.account import RegistrationTokenResource
parent = DummyResource(request='request') parent = DummyResource(request='request')
resource = RegistrationTokenResource('name', parent) resource = RegistrationTokenResource('name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL] assert resource.__acl__() == [(Allow, Everyone, 'register'), DENY_ALL]
def test_registration_acl(): def test_registration_acl():
''' test access controll list for RegistrationResource ''' ''' test access controll list for RegistrationResource '''
from pyramid.security import Allow, Everyone, DENY_ALL from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import RegistrationResource from ordr.resources.account import RegistrationResource
parent = DummyResource(request='request') parent = DummyResource(request='request')
resource = RegistrationResource('a name', parent) 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(): def test_registration_get_registration_form():
''' test 'get_registration_form()' method of RegistrationResource ''' ''' test 'get_registration_form()' method of RegistrationResource '''
from ordr.resources.account import RegistrationResource from ordr.resources.account import RegistrationResource
import deform import deform
request = DummyRequest() request = DummyRequest()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent) resource = RegistrationResource('a name', parent)
form = resource.get_registration_form() form = resource.get_registration_form()
assert isinstance(form, deform.Form) assert isinstance(form, deform.Form)
assert len(form.buttons) == 2 assert len(form.buttons) == 2
assert form.buttons[0].title == 'Create Account' assert form.buttons[0].title == 'Create Account'
@ -54,16 +54,16 @@ def test_registration_getitem_found(dbsession): # noqa: F811
) )
request = DummyRequest(dbsession=dbsession) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.REGISTRATION) token = user.issue_token(request, TokenSubject.REGISTRATION)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent) resource = RegistrationResource('a name', parent)
result = resource[token.hash] result = resource[token.hash]
assert isinstance(result, RegistrationTokenResource) assert isinstance(result, RegistrationTokenResource)
assert result.__name__ == token.hash assert result.__name__ == token.hash
assert result.__parent__ == resource assert result.__parent__ == resource
@ -76,15 +76,15 @@ def test_registration_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import RegistrationResource from ordr.resources.account import RegistrationResource
request = DummyRequest(dbsession=dbsession) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.REGISTRATION) user.issue_token(request, TokenSubject.REGISTRATION)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = RegistrationResource('a name', parent) resource = RegistrationResource('a name', parent)
with pytest.raises(KeyError): with pytest.raises(KeyError):
resource['unknown hash'] resource['unknown hash']
@ -93,23 +93,23 @@ def test_password_reset_token_acl():
''' test access controll list for PasswordResetTokenResource ''' ''' test access controll list for PasswordResetTokenResource '''
from pyramid.security import Allow, Everyone, DENY_ALL from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import PasswordResetTokenResource from ordr.resources.account import PasswordResetTokenResource
parent = DummyResource(request='request') parent = DummyResource(request='request')
resource = PasswordResetTokenResource('name', parent) 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(): def test_password_reset_token_get_reset_form():
''' test the setup of the password reset form''' ''' test the setup of the password reset form'''
from ordr.resources.account import PasswordResetTokenResource from ordr.resources.account import PasswordResetTokenResource
import deform import deform
request = DummyRequest() request = DummyRequest()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = PasswordResetTokenResource('some name', parent) resource = PasswordResetTokenResource('some name', parent)
form = resource.get_reset_form() form = resource.get_reset_form()
assert isinstance(form, deform.Form) assert isinstance(form, deform.Form)
assert len(form.buttons) == 2 assert len(form.buttons) == 2
assert form.buttons[0].title == 'Set New Password' assert form.buttons[0].title == 'Set New Password'
@ -120,11 +120,11 @@ def test_password_reset_acl():
''' test access controll list for PasswordResetResource ''' ''' test access controll list for PasswordResetResource '''
from pyramid.security import Allow, Everyone, DENY_ALL from pyramid.security import Allow, Everyone, DENY_ALL
from ordr.resources.account import PasswordResetResource from ordr.resources.account import PasswordResetResource
parent = DummyResource(request='request') parent = DummyResource(request='request')
resource = PasswordResetResource('a name', parent) 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 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) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.RESET_PASSWORD) token = user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = PasswordResetResource('a name', parent) resource = PasswordResetResource('a name', parent)
result = resource[token.hash] result = resource[token.hash]
assert isinstance(result, PasswordResetTokenResource) assert isinstance(result, PasswordResetTokenResource)
assert result.__name__ == token.hash assert result.__name__ == token.hash
assert result.__parent__ == resource assert result.__parent__ == resource
@ -158,63 +158,96 @@ def test_password_reset_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import PasswordResetResource from ordr.resources.account import PasswordResetResource
request = DummyRequest(dbsession=dbsession) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.RESET_PASSWORD) user.issue_token(request, TokenSubject.RESET_PASSWORD)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = PasswordResetResource('a name', parent) resource = PasswordResetResource('a name', parent)
with pytest.raises(KeyError): with pytest.raises(KeyError):
resource['unknown hash'] 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 ''' ''' test access controll list for PasswordResetTokenResource '''
from pyramid.security import Allow, DENY_ALL from pyramid.security import Allow, DENY_ALL
from ordr.models.account import Role, Token, TokenSubject from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import ChangeEmailTokenResource from ordr.resources.account import ChangeEmailTokenResource
request = DummyRequest() request = DummyRequest()
user = get_example_user(Role.USER) user = get_example_user(Role.USER)
dbsession.add(user) dbsession.add(user)
user.issue_token(request, TokenSubject.CHANGE_EMAIL) user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.flush() dbsession.flush()
token = dbsession.query(Token).first() token = dbsession.query(Token).first()
parent = DummyResource(request='request') parent = DummyResource(request='request')
resource = ChangeEmailTokenResource('name', parent, model=token) resource = ChangeEmailTokenResource('name', parent, model=token)
assert resource.__acl__() == [(Allow, 'user:3', 'edit'), DENY_ALL] assert resource.__acl__() == [(Allow, 'user:3', 'edit'), DENY_ALL]
def test_account_resource_set_model_from_request(): def test_account_resource_set_model_from_request():
''' test access controll list for PasswordResetResource ''' ''' test access controll list for PasswordResetResource '''
from ordr.resources.account import AccountResource from ordr.resources.account import AccountResource
request = DummyRequest(user='Amy McDonald') request = DummyRequest(user='Amy McDonald')
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('a name', parent) resource = AccountResource('a name', parent)
assert resource.model == 'Amy McDonald' assert resource.model == 'Amy McDonald'
def test_account_resource_acl(): def test_account_resource_acl():
''' test access controll list for PasswordResetResource ''' ''' 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 from ordr.resources.account import AccountResource
request = DummyRequest() request = DummyRequest()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('a name', parent) 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 ''' ''' test '__getitem__()' method returns child resource '''
from ordr.models.account import Role, TokenSubject from ordr.models.account import Role, TokenSubject
from ordr.resources.account import ( from ordr.resources.account import (
@ -223,16 +256,16 @@ def test_account_resource_getitem_found(dbsession): # noqa: F811
) )
request = DummyRequest(dbsession=dbsession) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
token = user.issue_token(request, TokenSubject.CHANGE_EMAIL) token = user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('a name', parent) resource = AccountResource('a name', parent)
result = resource[token.hash] result = resource[token.hash]
assert isinstance(result, ChangeEmailTokenResource) assert isinstance(result, ChangeEmailTokenResource)
assert result.__name__ == token.hash assert result.__name__ == token.hash
assert result.__parent__ == resource assert result.__parent__ == resource
@ -245,15 +278,15 @@ def test_account_resource_getitem_not_found(dbsession): # noqa: F811
from ordr.resources.account import AccountResource from ordr.resources.account import AccountResource
request = DummyRequest(dbsession=dbsession) request = DummyRequest(dbsession=dbsession)
user = get_example_user(Role.NEW) user = get_example_user(Role.NEW)
user.issue_token(request, TokenSubject.CHANGE_EMAIL) user.issue_token(request, TokenSubject.CHANGE_EMAIL)
dbsession.add(user) dbsession.add(user)
dbsession.flush() dbsession.flush()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('a name', parent) resource = AccountResource('a name', parent)
with pytest.raises(KeyError): with pytest.raises(KeyError):
resource['unknown hash'] resource['unknown hash']
@ -262,12 +295,12 @@ def test_account_resource_get_settings_form():
''' test the setup of the settings form''' ''' test the setup of the settings form'''
from ordr.resources.account import AccountResource from ordr.resources.account import AccountResource
import deform import deform
request = DummyRequest() request = DummyRequest()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('some name', parent) resource = AccountResource('some name', parent)
form = resource.get_settings_form() form = resource.get_settings_form()
assert isinstance(form, deform.Form) assert isinstance(form, deform.Form)
assert len(form.buttons) == 2 assert len(form.buttons) == 2
assert form.buttons[0].title == 'Change Settings' assert form.buttons[0].title == 'Change Settings'
@ -278,12 +311,12 @@ def test_account_resource_get_password_form():
''' test the setup of the change password form''' ''' test the setup of the change password form'''
from ordr.resources.account import AccountResource from ordr.resources.account import AccountResource
import deform import deform
request = DummyRequest() request = DummyRequest()
parent = DummyResource(request=request) parent = DummyResource(request=request)
resource = AccountResource('some name', parent) resource = AccountResource('some name', parent)
form = resource.get_password_form() form = resource.get_password_form()
assert isinstance(form, deform.Form) assert isinstance(form, deform.Form)
assert len(form.buttons) == 2 assert len(form.buttons) == 2
assert form.buttons[0].title == 'Change Password' assert form.buttons[0].title == 'Change Password'

14
tests/resources/root.py

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

22
tests/views/account/__init__.py

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

95
tests/views/account/login_logout.py

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

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

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

80
tests/views/pages.py

@ -3,22 +3,21 @@ import pytest
from pyramid.httpexceptions import HTTPFound from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest from pyramid.testing import DummyRequest
from ordr.models.account import Role
from .. import app_config, dbsession, get_example_user # noqa: F401 from .. import app_config, dbsession, get_example_user # noqa: F401
@pytest.mark.parametrize( @pytest.mark.parametrize(
'user,location', 'user,location',
[(None, '/login'), ('someone', '/orders')] [(None, '/account/login'), ('someone', '/orders')]
) )
def test_welcome(user, location): def test_welcome(user, location):
''' test redirects on web root ''' ''' test redirects on web root '''
from ordr.views.pages import welcome from ordr.views.pages import welcome
request = DummyRequest(user=user) request = DummyRequest(user=user)
result = welcome(None, request) result = welcome(None, request)
assert isinstance(result, HTTPFound) assert isinstance(result, HTTPFound)
assert result.location == f'http://example.com/{location}' assert result.location == f'http://example.com/{location}'
@ -28,76 +27,3 @@ def test_faq():
from ordr.views.pages import faq from ordr.views.pages import faq
result = faq(None, None) result = faq(None, None)
assert result == {} 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//'