# For copyright and license terms, see COPYRIGHT.rst (top level of repository)
# Repository: https://github.com/C3S/collecting_society_web
import datetime
import logging
import colander
import deform
from portal_web.resources import FrontendResource
from portal_web.views.forms import LoginWebuser
from portal_web.models import (
Tdb,
WebUser,
WebUserRole
)
from portal_web.services import send_mail
from pyramid.httpexceptions import HTTPFound
from ...services import _
log = logging.getLogger(__name__)
AGE_ADULT = 16 # don't allow kids to register
# --- Controller --------------------------------------------------------------
[docs]
class RegisterWebuser(LoginWebuser):
"""
form controller for registration of web_user
"""
__stage__ = 'claims_membership' # initial stage
[docs]
def controller(self):
if self.stage == 'claims_membership':
self.claims_membership()
if self.stage == 'wants_membership':
self.wants_membership()
if self.stage == 'register_webuser':
self.register_webuser()
return self.response
# --- Stages --------------------------------------------------------------
[docs]
def claims_membership(self):
self.stage = 'claims_membership'
self.form = claims_membership_form()
self.render(self.data)
# has membership
if self.submitted('claims_membership'):
self.data.update({'member_c3s': True})
self.register_webuser()
# has no membership
if self.submitted('claims_no_membership'):
self.data.update({'member_c3s': False})
self.wants_membership()
[docs]
def wants_membership(self):
self.stage = 'wants_membership'
self.form = wants_membership_form()
self.render(self.data)
# wants membership
if self.submitted('wants_membership'):
self.response = HTTPFound("https://yes.c3s.cc?from=repertoire")
# wants no membership
if self.submitted('wants_no_membership'):
self.register_webuser()
# back
if self.submitted('back'):
self.claims_membership()
[docs]
def register_webuser(self):
self.stage = 'register_webuser'
if self.data['member_c3s']:
# TODO: Change back, when membership is integrated
# self.form = register_member_form()
self.form = register_nonmember_form()
else:
self.form = register_nonmember_form()
self.render(self.data)
# register webuser
if self.submitted('register_webuser') and self.validate():
self.data.update(self.appstruct.copy())
self.register()
# back
if self.submitted('back'):
if self.data['member_c3s']:
self.claims_membership()
else:
self.wants_membership()
# --- Conditions ----------------------------------------------------------
[docs]
def is_registered(self, web_user):
if WebUser.search_by_email(web_user['email']):
return True
return False
[docs]
def passes_authentication(self, web_user):
if WebUser.authenticate(web_user['email'], web_user['password']):
return True
return False
[docs]
def is_claiming_membership(self, data):
if data['member_c3s']:
return True
return False
# --- Actions -------------------------------------------------------------
[docs]
@Tdb.transaction(readonly=False)
def register(self):
_create = False
# always save email lowercase, so tryton uniqueness is ensured
_web_user = {
'email': self.data['email'].lower(),
'password': self.data['password'],
'roles': [('add', [WebUserRole.search_by_code('licenser').id,
WebUserRole.search_by_code('licensee').id])]
}
template_variables = {}
# user is already registered
if self.is_registered(_web_user):
# user passes authentication (accidently registered to login)
if self.passes_authentication(_web_user):
opt_in_state = WebUser.get_opt_in_state_by_email(
_web_user['email']
)
if opt_in_state == 'opted-in':
self.request.session.flash(
_("You are already registered with your "
"credentials."),
'main-alert-info')
self.login()
return
else:
self.request.session.flash(
_("Your email address is not verified yet. Please "
"follow the instructions in our email."),
'main-alert-info')
return
# user fails authentication (email already registered)
else:
template_name = "registration-fail_registered"
# user is not registered yet
else:
# user claims to be a c3s member
if self.is_claiming_membership(self.data):
_create = True
template_name = "registration-member_success"
# user claims not to be a c3s member
else:
_create = True
template_name = "registration-nonmember_success"
# create
if _create:
web_users = WebUser.create([_web_user])
# creation failed
if not web_users or len(web_users) != 1:
log.info("web_user creation not successful: %s" % _web_user)
self.request.session.flash(
_(
"There was an error during the registration process. "
"Please try again later and contact us, if this "
"error occurs again. Sorry for the inconveniece."
),
'main-alert-danger'
)
return False
# creation successful
web_user = web_users[0]
if self.is_claiming_membership(self.data):
# c3s membership
web_user.party.member_c3s = True
# save values of non-c3s-member form fields
web_user.party.repertoire_terms_accepted = self.data[
'terms_accepted']
web_user.party.name = self.data['firstname'] + ' ' + self.data[
'lastname']
# also save separately for clarity
web_user.party.firstname = self.data['firstname']
web_user.party.lastname = self.data['lastname']
web_user.party.birthdate = self.data['birthdate']
web_user.party.save()
template_variables = {
'link': self.request.resource_url(
self.request.root, 'verify_email',
WebUser.get_opt_in_uuid_by_id(web_user.id)
)
}
log.info("web_user creation successful: %s" % web_user.email)
# flash message
self.request.session.flash(
_(
"Thank you for your registration. We are now processing your "
"request and will send you an email with further "
"instructions."
),
'main-alert-success'
)
# send mail
send_mail(
self.request,
template=template_name,
variables=template_variables,
recipients=[_web_user['email']]
)
if _create:
web_user.opt_in_state = "mail-sent"
web_user.save()
# reset form
self.redirect(FrontendResource)
# --- Validators --------------------------------------------------------------
[docs]
def not_empty(value):
if not value or len(value) < 2:
return _("Please enter your name.")
return True
[docs]
def terms_accepted(value):
if not value:
return _("You need to accept the terms of service.")
return True
[docs]
def right_age(value):
if not value:
return _("You need to provide your birthdate.")
if value < datetime.date(1900, 1, 1):
return _('Sorry, I don\'t believe you are that old.')
if value > datetime.date.today() - datetime.timedelta(days=AGE_ADULT*364):
return _("Sorry, you are too young to register here.")
# return _(
# u"Sorry, you have to be ${age} years or older to register here.",
#
# # TODO: mapping doesn't work here
# # also see line 580 in repertoire_upload.py
# mapping={'age': AGE_ADULT}
# )
# colander.Range(
# min=datetime.date(1900, 1, 1),
# min_err=TOO_OLD_MESSAGE,
# max=datetime.date.today() - datetime.timedelta(days=AGE_ADULT*364),
# max_err=TOO_YOUNG_MESSAGE
# )
return True
# --- Options -----------------------------------------------------------------
# --- Widgets -----------------------------------------------------------------
# --- Fields ------------------------------------------------------------------
[docs]
class FirstnameField(colander.SchemaNode):
oid = "firstname"
schema_type = colander.String
validator = colander.Function(not_empty)
[docs]
class LastnameField(colander.SchemaNode):
oid = "lastname"
schema_type = colander.String
validator = colander.Function(not_empty)
[docs]
class BirthdateField(colander.SchemaNode):
oid = "birthdate"
schema_type = colander.Date
widget = deform.widget.DateInputWidget(
options={'selectMonths': True,
'formatSubmit': "yyyy-mm-dd",
'selectYears': 200,
'format': 'yyyy-mm-dd'}
)
validator = colander.Function(right_age)
[docs]
class EmailField(colander.SchemaNode):
oid = "register_email"
schema_type = colander.String
validator = colander.Email()
[docs]
class CheckedPasswordField(colander.SchemaNode):
oid = "register_password"
schema_type = colander.String
validator = colander.Length(min=8)
widget = deform.widget.CheckedPasswordWidget()
[docs]
class CheckboxWithLabel(colander.SchemaNode):
oid = "terms_accepted"
schema_type = colander.Boolean
validator = colander.Function(terms_accepted)
# --- Schemas -----------------------------------------------------------------
[docs]
class RegisterMemberSchema(colander.MappingSchema):
email = EmailField(
title=_("Email"),
description=_(
"Please use the email address as in your membership application."
)
)
password = CheckedPasswordField(title=_("Password"))
terms_accepted = CheckboxWithLabel(
title=_("Terms of Service"),
label=_("I accept the terms of service.")
)
[docs]
class RegisterNonmemberSchema(colander.MappingSchema):
firstname = FirstnameField(title=_("Firstname"))
lastname = LastnameField(title=_("Lastname"))
birthdate = BirthdateField(title=_("Birthdate"))
email = EmailField(title=_("Email"))
password = CheckedPasswordField(title=_("Password"))
terms_accepted = CheckboxWithLabel(
title=_("Terms of Service"),
label=_("I accept the terms of service.")
)
# --- Forms -------------------------------------------------------------------