CPI Ordering System (the old version)
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.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 

368 lines
11 KiB

''' account registration, login, logout and settings '''
import deform
from pyramid.httpexceptions import HTTPFound
from pyramid.security import remember, forget
from pyramid.view import view_config
from sqlalchemy import or_
from ordr2.events import ChangedEmail, CompleteRegistration, PasswordReset
from ordr2.models.account import User, Role, TokenSubject
from ordr2.schemas.account import (
RegistrationSchema,
ResetPasswordSchema,
AccountSettingsSchema
)
PROPOSED_PASSWORD_LENGTH = 12
# login and logout
@view_config(
context='ordr2:resources.account.AccountResource',
name='login',
request_method='GET',
permission='login',
renderer='ordr2:templates/account/login.jinja2'
)
def login_form(context, request):
return {}
@view_config(
context='ordr2:resources.account.AccountResource',
name='login',
request_method='POST',
permission='login',
renderer='ordr2:templates/account/login.jinja2'
)
def login(context, request):
''' loging in a user '''
username = request.POST.get('username')
password = request.POST.get('password')
# Form validation is not done for login forms,
# either the data represents a user or not.
user = request.dbsession.query(User).filter_by(username=username).first()
if user is not None:
if user.is_active and user.check_password(password):
headers = remember(request, user.id)
return HTTPFound(
request.resource_url(request.root, 'orders'),
headers=headers
)
request.session.flash(
'You entered the wrong username or password',
'error'
)
return {}
@view_config(
context='ordr2:resources.account.AccountResource',
name='logout',
permission='logout'
)
def logout(context, request):
''' log out an user '''
headers = forget(request)
return HTTPFound(request.resource_url(request.root), headers=headers)
# account registration
@view_config(
context='ordr2:resources.account.AccountResource',
name='register',
request_method='GET',
permission='register',
renderer='ordr2:templates/account/register.jinja2'
)
def registration_form(context, request):
''' the new user registraion page '''
form = RegistrationSchema.as_form(request)
return {'form': form}
@view_config(
context='ordr2:resources.account.AccountResource',
name='register',
request_method='POST',
permission='register',
renderer='ordr2:templates/account/register.jinja2'
)
def registration_form_processing(context, request):
''' registration form processing '''
if 'Cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
# validate the form data
form = RegistrationSchema.as_form(request)
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.USER_REGISTRATION)
notification = CompleteRegistration(request, account, {'token': token})
request.registry.notify(notification)
# issue a warning on a short password
if len(appstruct['password']) < PROPOSED_PASSWORD_LENGTH:
request.session.flash(
'You should really consider a longer password',
'warning'
)
return HTTPFound(request.resource_url(context, 'registered'))
@view_config(
context='ordr2:resources.account.AccountResource',
name='registered',
permission='register',
renderer='ordr2:templates/account/registration_confirmation.jinja2'
)
def registration_confirmation(context, request):
''' email to verify registration was sent '''
return {}
@view_config(
context='ordr2:resources.account.RegistrationToken',
permission='register',
renderer='ordr2:templates/account/registration_completed.jinja2'
)
def registration_completed(context, request):
''' registration was verified by mail link '''
context.model.owner.role = Role.NEW
request.dbsession.delete(context.model)
return {}
# password recovery
@view_config(
context='ordr2:resources.account.AccountResource',
name='forgot-password',
request_method='GET',
permission='reset password',
renderer='ordr2:templates/account/forgot_password_form.jinja2'
)
def forgot_password_form(context, request):
''' forgot password form '''
return {}
@view_config(
context='ordr2:resources.account.AccountResource',
name='forgot-password',
request_method='POST',
permission='reset password',
renderer='ordr2:templates/account/forgot_password_form.jinja2'
)
def forgot_password_form_processing(context, request):
''' forgot password form processing '''
if 'cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
identifier = request.POST.get('username_or_email')
account = (
request.dbsession
.query(User)
.filter(or_(User.username == identifier, User.email == identifier))
.first()
)
if not account:
request.session.flash(
'Username or email address unknown',
'error'
)
return {}
# create a forgot-my-password token and send email
token = account.issue_token(request, TokenSubject.RESET_PASSWORD)
notification = PasswordReset(request, account, {'token': token})
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'forgot-password-email'))
@view_config(
context='ordr2:resources.account.AccountResource',
name='forgot-password-email',
request_method='GET',
permission='reset password',
renderer='ordr2:templates/account/forgot_password_email.jinja2'
)
def forgot_password_email_sent(context, request):
''' password reset link was sent '''
return {}
@view_config(
context='ordr2:resources.account.ForgottenPasswordToken',
request_method='GET',
permission='reset password',
renderer='ordr2:templates/account/reset_password.jinja2'
)
def reset_password_form(context, request):
form = ResetPasswordSchema.as_form(request)
return {'form': form}
@view_config(
context='ordr2:resources.account.ForgottenPasswordToken',
request_method='POST',
permission='reset password',
renderer='ordr2:templates/account/reset_password.jinja2'
)
def reset_password_form_processing(context, request):
if 'Cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
# validate the form data
form = ResetPasswordSchema.as_form(request)
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
# set the new password
context.model.owner.set_password(appstruct['password'])
# delete the token
request.dbsession.delete(context.model)
# issue a warning on a short password
if len(appstruct['password']) < PROPOSED_PASSWORD_LENGTH:
request.session.flash(
'You should really consider a longer password',
'warning'
)
request.session.flash('Your password was changed', 'ok')
return HTTPFound(request.resource_url(context.__parent__, 'login'))
# account settings
@view_config(
context='ordr2:resources.account.AccountResource',
request_method='GET',
name='settings',
permission='settings',
renderer='ordr2:templates/account/settings.jinja2'
)
def settings_form(context, request):
prefill = {
'general': {
'username': context.model.username,
'first_name': context.model.first_name,
'last_name': context.model.last_name,
'email': context.model.email,
'role': str(context.model.role)
}
}
form = AccountSettingsSchema.as_form(request)
form.set_appstruct(prefill)
return {'form': form}
@view_config(
context='ordr2:resources.account.AccountResource',
request_method='POST',
name='settings',
permission='settings',
renderer='ordr2:templates/account/settings.jinja2'
)
def settings_form_processing(context, request):
if 'Cancel' in request.POST:
return HTTPFound(request.resource_url(request.root))
# validate the form data
form = AccountSettingsSchema.as_form(request)
data = request.POST.items()
try:
appstruct = form.validate(data)
except deform.ValidationFailure as e:
return {'form': form}
context.model.first_name = appstruct['general']['first_name']
context.model.last_name = appstruct['general']['last_name']
new_password = appstruct['change_password']['new_password']
if new_password:
context.model.set_password(new_password)
request.session.flash(
'Password updated sucessfully',
'success'
)
# issue a warning on a short password
if len(new_password) < PROPOSED_PASSWORD_LENGTH:
request.session.flash(
'You should really consider a longer password',
'warning'
)
# email address changed
# the email address is not updated directly,
# but a email sent to confirm the new address
new_email = appstruct['general']['email']
if new_email != context.model.email:
# create a verify-new-email token and send email
token = context.model.issue_token(
request,
TokenSubject.CHANGE_EMAIL,
{'new_email': new_email}
)
notification = ChangedEmail(
request,
context.model,
{'token': token},
send_to=new_email
)
request.registry.notify(notification)
return HTTPFound(request.resource_url(context, 'verify-new-email'))
return HTTPFound(request.resource_url(request.root))
@view_config(
context='ordr2:resources.account.AccountResource',
name='verify-new-email',
permission='settings',
renderer='ordr2:templates/account/email_confirmation.jinja2'
)
def email_confirmation(context, request):
''' email sent to new address '''
return {}
@view_config(
context='ordr2:resources.account.EmailVerificationToken',
permission='settings'
)
def email_change_confirmed(context, request):
''' changed email address is confirmed '''
context.model.owner.email = context.model.payload['new_email']
request.dbsession.delete(context.model)
request.session.flash('Email change sucessful', 'success')
return HTTPFound(request.resource_url(request.root, 'login'))