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. 8
      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. 4
      tests/_functional/__init__.py
  10. 10
      tests/_functional/account/__init__.py
  11. 7
      tests/_functional/account/forgotten_password.py
  12. 35
      tests/_functional/account/login_logout.py
  13. 16
      tests/_functional/account/registration.py
  14. 9
      tests/_functional/account/settings.py
  15. 22
      tests/_functional/layout.py
  16. 4
      tests/_functional/pages.py
  17. 49
      tests/resources/account.py
  18. 8
      tests/resources/root.py
  19. 22
      tests/views/account/__init__.py
  20. 30
      tests/views/account/forgotten_password.py
  21. 95
      tests/views/account/login_logout.py
  22. 20
      tests/views/account/registration.py
  23. 19
      tests/views/account/settings.py
  24. 76
      tests/views/pages.py

8
ordr/resources/__init__.py

@ -2,11 +2,7 @@ @@ -2,11 +2,7 @@
from pyramid.security import Allow, Everyone, DENY_ALL
from .account import (
RegistrationResource,
PasswordResetResource,
AccountResource
)
from .account import AccountResource
class RootResource:
@ -38,8 +34,6 @@ class RootResource: @@ -38,8 +34,6 @@ class RootResource:
:raises: KeyError if child resource is not found
'''
map = {
'register': RegistrationResource,
'forgot': PasswordResetResource,
'account': AccountResource,
}
child_class = map[key]

30
ordr/resources/account.py

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

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

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

20
ordr/templates/layout.jinja2

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

268
ordr/views/account.py

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

120
ordr/views/forgotten_password.py

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

57
ordr/views/pages.py

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

86
ordr/views/registration.py

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

4
tests/_functional/__init__.py

@ -23,7 +23,7 @@ class CustomTestApp(webtest.TestApp): @@ -23,7 +23,7 @@ class CustomTestApp(webtest.TestApp):
def login(self, username, password):
''' login '''
self.logout()
result = self.get('/login')
result = self.get('/account/login')
login_form = result.forms[0]
login_form['username'] = username
login_form['password'] = password
@ -33,7 +33,7 @@ class CustomTestApp(webtest.TestApp): @@ -33,7 +33,7 @@ class CustomTestApp(webtest.TestApp):
def logout(self):
''' logout '''
self.get('/logout')
self.get('/account/logout')
def reset(self):
''' reset the webapp '''

10
tests/_functional/account/__init__.py

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

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

@ -7,7 +7,7 @@ from . import testappsetup, testapp, get_token_url # noqa: F401 @@ -7,7 +7,7 @@ from . import testappsetup, testapp, get_token_url # noqa: F401
def test_forgot_password_process(testapp): # noqa: F811
''' test the forgot password form '''
response = testapp.get('/forgot')
response = testapp.get('/account/forgot')
active_nav = response.html.find('li', class_='active')
active_step = response.html.find('p', class_='text-primary')
assert active_nav is None
@ -27,10 +27,11 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -27,10 +27,11 @@ def test_forgot_password_process(testapp): # noqa: F811
assert 'Username or email address unknown' in response
# fill out this form with valid data
response = testapp.get('/account/forgot')
form = response.form
form['identifier'] = 'TerryGilliam'
response = form.submit(name='send_mail')
assert response.location == 'http://localhost/forgot/verify'
assert response.location == 'http://localhost/account/forgot/verify'
response = response.follow()
active_nav = response.html.find('li', class_='active')
@ -70,7 +71,7 @@ def test_forgot_password_process(testapp): # noqa: F811 @@ -70,7 +71,7 @@ def test_forgot_password_process(testapp): # noqa: F811
form['password'] = 'Lost in La Mancha'
form['password-confirm'] = 'Lost in La Mancha'
response = form.submit(name='change')
assert response.location == 'http://localhost/forgot/completed'
assert response.location == 'http://localhost/account/forgot/completed'
response = response.follow()
active_nav = response.html.find('li', class_='active')

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

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

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

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

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

@ -2,14 +2,7 @@ @@ -2,14 +2,7 @@
from pyramid_mailer import get_mailer
from . import testappsetup, testapp, get_token_url # noqa: F401
def test_account_root(testapp): # noqa: F811
''' check the redirect if '/account' is requested '''
testapp.login('TerryGilliam', 'Terry')
response = testapp.get('/account')
assert response.location == 'http://localhost/'
from .. import testappsetup, testapp, get_token_url # noqa: F401
def test_account_change_settings(testapp): # noqa: F811

22
tests/_functional/layout.py

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

4
tests/_functional/pages.py

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

49
tests/resources/account.py

@ -15,7 +15,7 @@ def test_registration_token_acl(): @@ -15,7 +15,7 @@ def test_registration_token_acl():
parent = DummyResource(request='request')
resource = RegistrationTokenResource('name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'register'), DENY_ALL]
def test_registration_acl():
@ -26,7 +26,7 @@ def test_registration_acl(): @@ -26,7 +26,7 @@ def test_registration_acl():
parent = DummyResource(request='request')
resource = RegistrationResource('a name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'register'), DENY_ALL]
def test_registration_get_registration_form():
@ -97,7 +97,7 @@ def test_password_reset_token_acl(): @@ -97,7 +97,7 @@ def test_password_reset_token_acl():
parent = DummyResource(request='request')
resource = PasswordResetTokenResource('name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'reset'), DENY_ALL]
def test_password_reset_token_get_reset_form():
@ -124,7 +124,7 @@ def test_password_reset_acl(): @@ -124,7 +124,7 @@ def test_password_reset_acl():
parent = DummyResource(request='request')
resource = PasswordResetResource('a name', parent)
assert resource.__acl__() == [(Allow, Everyone, 'view'), DENY_ALL]
assert resource.__acl__() == [(Allow, Everyone, 'reset'), DENY_ALL]
def test_password_reset_getitem_found(dbsession): # noqa: F811
@ -171,7 +171,7 @@ def test_password_reset_getitem_not_found(dbsession): # noqa: F811 @@ -171,7 +171,7 @@ def test_password_reset_getitem_not_found(dbsession): # noqa: F811
resource['unknown hash']
def test_change_email_reset_token_acl(dbsession): # noqa: F811
def test_change_email_token_acl(dbsession): # noqa: F811
''' test access controll list for PasswordResetTokenResource '''
from pyramid.security import Allow, DENY_ALL
from ordr.models.account import Role, Token, TokenSubject
@ -204,17 +204,50 @@ def test_account_resource_set_model_from_request(): @@ -204,17 +204,50 @@ def test_account_resource_set_model_from_request():
def test_account_resource_acl():
''' test access controll list for PasswordResetResource '''
from pyramid.security import Allow, Authenticated, DENY_ALL
from pyramid.security import (
Allow,
Everyone,
Authenticated,
DENY_ALL
)
from ordr.resources.account import AccountResource
request = DummyRequest()
parent = DummyResource(request=request)
resource = AccountResource('a name', parent)
assert resource.__acl__() == [(Allow, Authenticated, 'edit'), DENY_ALL]
assert resource.__acl__() == [
(Allow, Everyone, 'view'),
(Allow, Everyone, 'login'),
(Allow, Everyone, 'logout'),
(Allow, Everyone, 'register'),
(Allow, Everyone, 'reset'),
(Allow, Authenticated, 'edit'),
DENY_ALL
]
@pytest.mark.parametrize('key', ['register', 'forgot']) # noqa: F811
def test_account_resource_getitem_static(dbsession, key):
''' test '__getitem__()' method returns static resources '''
from ordr.resources.account import (
AccountResource,
PasswordResetResource,
RegistrationResource
)
request = DummyRequest(dbsession=dbsession)
parent = DummyResource(request=request)
resource = AccountResource('some name', parent)
result = resource[key]
if key == 'register':
assert isinstance(result, RegistrationResource)
elif key == 'forgot':
assert isinstance(result, PasswordResetResource)
def test_account_resource_getitem_found(dbsession): # noqa: F811
def test_account_resource_getitem_token(dbsession): # noqa: F811
''' test '__getitem__()' method returns child resource '''
from ordr.models.account import Role, TokenSubject
from ordr.resources.account import (

8
tests/resources/root.py

@ -2,11 +2,7 @@ @@ -2,11 +2,7 @@
import pytest
from ordr.resources.account import (
RegistrationResource,
PasswordResetResource,
AccountResource
)
from ordr.resources.account import AccountResource
def test_root_init():
@ -28,8 +24,6 @@ def test_root_acl(): @@ -28,8 +24,6 @@ def test_root_acl():
@pytest.mark.parametrize(
'key,resource_class', [
('register', RegistrationResource),
('forgot', PasswordResetResource),
('account', AccountResource)
]
)

22
tests/views/account/__init__.py

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

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

@ -4,7 +4,7 @@ import pytest @@ -4,7 +4,7 @@ import pytest
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from .. import ( # noqa: F401
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
@ -15,7 +15,7 @@ from .. import ( # noqa: F401 @@ -15,7 +15,7 @@ from .. import ( # noqa: F401
def test_forgotten_password_form():
''' test the view for the forgotten password form '''
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import forgotten_password_form
from ordr.views.account import forgotten_password_form
request = DummyRequest()
parent = DummyResource(request=request)
@ -33,7 +33,7 @@ def test_forgotten_password_processing_ok(dbsession, identifier): @@ -33,7 +33,7 @@ def test_forgotten_password_processing_ok(dbsession, identifier):
''' test the processing of the forgotten password form '''
from ordr.models.account import Role, TokenSubject
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
@ -70,7 +70,7 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier): @@ -70,7 +70,7 @@ def test_forgotten_password_processing_not_ok(dbsession, identifier):
''' test error processing of the forgotten password form '''
from ordr.models.account import Role, Token
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
@ -95,7 +95,7 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811 @@ -95,7 +95,7 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811
''' test the canceling of the forgotten password form '''
from ordr.models.account import Token
from ordr.resources.account import PasswordResetResource
from ordr.views.forgotten_password import (
from ordr.views.account import (
forgotten_password_form_processing
)
@ -113,17 +113,17 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811 @@ -113,17 +113,17 @@ def test_forgotten_password_processing_cancel(dbsession): # noqa: F811
assert dbsession.query(Token).count() == 0
def test_verify():
def test_forgotten_password_verify_email():
''' test the message view for check your email '''
from ordr.views.forgotten_password import verify
result = verify(None, None)
from ordr.views.account import forgotten_password_verify_email
result = forgotten_password_verify_email(None, None)
assert result == {}
def test_completed():
def test_forgotten_password_completed():
''' test the view for a completed reset process '''
from ordr.views.forgotten_password import completed
result = completed(None, None)
from ordr.views.account import forgotten_password_completed
result = forgotten_password_completed(None, None)
assert result == {}
@ -131,7 +131,7 @@ def test_reset_password_form(): @@ -131,7 +131,7 @@ def test_reset_password_form():
''' test reset password form view '''
from ordr.resources.account import PasswordResetTokenResource
from ordr.schemas.account import ResetPasswordSchema
from ordr.views.forgotten_password import reset_password_form
from ordr.views.account import reset_password_form
request = DummyRequest()
parent = DummyResource(request=request)
@ -147,7 +147,7 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811 @@ -147,7 +147,7 @@ def test_reset_password_form_processing_valid(dbsession): # noqa: F811
''' test reset password form processing '''
from ordr.models.account import User, Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',
@ -185,7 +185,7 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811 @@ -185,7 +185,7 @@ def test_reset_password_form_processing_invalid_data(dbsession): # noqa: F811
from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.schemas.account import ResetPasswordSchema
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',
@ -216,7 +216,7 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811 @@ -216,7 +216,7 @@ def test_reset_password_form_processing_cancel(dbsession): # noqa: F811
''' test reset password form processing '''
from ordr.models.account import Role, Token, TokenSubject
from ordr.resources.account import PasswordResetTokenResource
from ordr.views.forgotten_password import reset_password_form_processing
from ordr.views.account import reset_password_form_processing
data = {
'__start__': 'password:mapping',

95
tests/views/account/login_logout.py

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

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

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

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

@ -3,7 +3,7 @@ import deform @@ -3,7 +3,7 @@ import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.testing import DummyRequest, DummyResource
from .. import ( # noqa: F401
from ... import ( # noqa: F401
app_config,
dbsession,
get_example_user,
@ -11,17 +11,6 @@ from .. import ( # noqa: F401 @@ -11,17 +11,6 @@ from .. import ( # noqa: F401
)
def test_account_redirect():
''' redirect on root of account resource '''
from ordr.views.account import account
request = DummyRequest()
result = account(None, request)
assert isinstance(result, HTTPFound)
assert result.location == 'http://example.com//'
def test_settings_form():
''' tests for displaying the settings form '''
from ordr.models.account import Role
@ -181,10 +170,10 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811 @@ -181,10 +170,10 @@ def test_settings_form_processing_cancel(dbsession): # noqa: F811
assert account.first_name == 'Terry'
def test_verify_email(dbsession): # noqa: F811
def test_verify_email_change(dbsession): # noqa: F811
''' tests for processing the change password form '''
from ordr.models.account import Role, Token, TokenSubject
from ordr.views.account import verify_email
from ordr.views.account import verify_email_change
user = get_example_user(Role.USER)
request = DummyRequest(dbsession=dbsession, user=user)
@ -199,7 +188,7 @@ def test_verify_email(dbsession): # noqa: F811 @@ -199,7 +188,7 @@ def test_verify_email(dbsession): # noqa: F811
token = dbsession.query(Token).first()
context = DummyResource(model=token)
result = verify_email(context, request)
result = verify_email_change(context, request)
assert result == {}
assert user.email == 'amy@example.com'
assert dbsession.query(Token).count() == 0

76
tests/views/pages.py

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