You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
11 KiB
402 lines
11 KiB
''' 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 |
|
|
|
|
|
# account resource root |
|
|
|
@view_config( |
|
context='ordr.resources.account.AccountResource', |
|
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', |
|
name='settings', |
|
request_method='GET', |
|
renderer='ordr:templates/account/settings_form.jinja2' |
|
) |
|
def settings_form(context, request): |
|
''' show the settings form ''' |
|
prefill = { |
|
'username': request.user.username, |
|
'first_name': request.user.first_name, |
|
'last_name': request.user.last_name, |
|
'email': request.user.email, |
|
} |
|
form = context.get_settings_form(prefill=prefill) |
|
return {'form': form} |
|
|
|
|
|
@view_config( |
|
context='ordr.resources.account.AccountResource', |
|
permission='edit', |
|
name='settings', |
|
request_method='POST', |
|
renderer='ordr:templates/account/settings_form.jinja2' |
|
) |
|
def settings_form_processing(context, request): |
|
''' process the settings form ''' |
|
if 'change' not in request.POST: |
|
return HTTPFound(request.resource_url(request.root)) |
|
|
|
form = context.get_settings_form() |
|
data = request.POST.items() |
|
try: |
|
appstruct = form.validate(data) |
|
except deform.ValidationFailure as e: |
|
return {'form': form} |
|
|
|
# form validation successfull, change user |
|
request.user.first_name = appstruct['first_name'] |
|
request.user.last_name = appstruct['last_name'] |
|
|
|
if appstruct['email'] == request.user.email: |
|
# email was not changed |
|
return HTTPFound(request.resource_url(request.root)) |
|
|
|
# create a verify-new-email token and send email |
|
token = request.user.issue_token( |
|
request, |
|
TokenSubject.CHANGE_EMAIL, |
|
payload={'email': appstruct['email']} |
|
) |
|
notification = ChangeEmailNotification( |
|
request, |
|
account, |
|
{'token': token}, |
|
send_to=appstruct['email'] |
|
) |
|
request.registry.notify(notification) |
|
|
|
return HTTPFound(request.resource_url(context, 'verify')) |
|
|
|
|
|
@view_config( |
|
context='ordr.resources.account.ChangeEmailTokenResource', |
|
permission='edit', |
|
request_method='GET', |
|
renderer='ordr:templates/account/settings_mail_changed.jinja2' |
|
) |
|
def verify_email_change(context, request): |
|
''' show email verification text ''' |
|
payload = context.model.payload |
|
request.user.email = payload['email'] |
|
request.dbsession.delete(context.model) |
|
return {} |
|
|
|
|
|
# change password |
|
|
|
@view_config( |
|
context='ordr.resources.account.AccountResource', |
|
permission='edit', |
|
name='password', |
|
request_method='GET', |
|
renderer='ordr:templates/account/password_form.jinja2' |
|
) |
|
def password_form(context, request): |
|
''' show the change password form ''' |
|
form = context.get_password_form() |
|
return {'form': form} |
|
|
|
|
|
@view_config( |
|
context='ordr.resources.account.AccountResource', |
|
permission='edit', |
|
name='password', |
|
request_method='POST', |
|
renderer='ordr:templates/account/password_form.jinja2' |
|
) |
|
def password_form_processing(context, request): |
|
''' process the change password form ''' |
|
if 'change' not in request.POST: |
|
return HTTPFound(request.resource_url(request.root)) |
|
|
|
form = context.get_password_form() |
|
data = request.POST.items() |
|
try: |
|
appstruct = form.validate(data) |
|
except deform.ValidationFailure as e: |
|
return {'form': form} |
|
|
|
# form validation successfull, change the password |
|
request.user.set_password(appstruct['password']) |
|
return HTTPFound(request.resource_url(context, 'changed')) |
|
|
|
|
|
@view_config( |
|
context='ordr.resources.account.AccountResource', |
|
permission='edit', |
|
name='changed', |
|
request_method='GET', |
|
renderer='ordr:templates/account/password_changed.jinja2' |
|
) |
|
def password_changed(context, request): |
|
''' the password changed message ''' |
|
return {}
|
|
|