def get_profile(request): id_type = request.matchdict.get('type').strip() identifier = request.matchdict.get('identifier').strip() session = AgentProfile.default_db if id_type == 'u': username = session.query(Username).filter_by( username=identifier).first() if not username: raise HTTPNotFound() profile = username.user elif id_type == 'id': try: id = int(identifier) except: raise HTTPNotFound() profile = session.query(AgentProfile).get(id) if not profile: raise HTTPNotFound() elif id_type == 'email': identifier = EmailString.normalize_email_case(identifier) account = session.query(AbstractAgentAccount).filter_by( email_ci=identifier).order_by(desc( AbstractAgentAccount.verified)).first() if not account: raise HTTPNotFound() profile = account.profile else: account = session.query(IdentityProviderAccount).join( IdentityProvider).filter( IdentityProviderAccount.username == identifier and IdentityProvider.type == id_type).first() if not account: raise HTTPNotFound() profile = account.profile return profile
def upgrade(pyramid_env): # Do stuff with the app's models here. from assembl import models as m db = m.get_session_maker()() with transaction.manager: for acc in db.query(m.AbstractAgentAccount): if not acc.email: continue if not is_email(acc.email): acc.verified = False else: acc.email = EmailString.normalize_email_case(acc.email) for user in db.query(m.User).filter(m.User.preferred_email != None): if not is_email(user.preferred_email): user.preferred_email = None else: user.preferred_email = EmailString.normalize_email_case( user.preferred_email)
def confirm_email_sent(request): localizer = request.localizer # TODO: How to make this not become a spambot? email = request.matchdict.get('email') if not email: raise HTTPNotFound() if '@' not in email: raise HTTPBadRequest("Not an email") email = EmailString.normalize_email_case(email) email_objects = AbstractAgentAccount.default_db.query( AbstractAgentAccount).filter_by(email_ci=email) verified_emails = [e for e in email_objects if e.verified] unverified_emails = [e for e in email_objects if not e.verified] if len(verified_emails) > 1: # TODO!: Merge accounts. raise HTTPServerError("Multiple verified emails") elif len(verified_emails): if len(unverified_emails): # TODO!: Send an email, mention duplicates, and... # offer to merge accounts? # Send an email to other emails of the duplicate? Sigh! pass return HTTPFound(location=maybe_contextual_route( request, 'login', _query=dict(identifer=email, error=localizer.translate( _("This email is already confirmed."))))) else: if len(unverified_emails): # Normal case: Send an email. May be spamming for email_account in unverified_emails: send_confirmation_email(request, email_account) slug = request.matchdict.get('discussion_slug', None) slug_prefix = "/" + slug if slug else "" return dict( get_default_context(request), action="%s/confirm_email_sent/%s" % (slug_prefix, email), email=email, title=localizer.translate(_('Confirmation requested')), description=localizer.translate( _('A confirmation e-mail has been sent to your account and should be in your inbox in a few minutes. ' 'It contains a confirmation link, please click on it in order to confirm your e-mail address. ' 'If you did not receive any confirmation e-mail (check your spams), click here.' ))) else: # We do not have an email to this name. return HTTPFound(location=maybe_contextual_route( request, 'register', email=email, _query=dict(error=localizer.translate( _("We do not know about this email.")))))
def from_identifier(identifier): session = AgentProfile.default_db if '@' in identifier: identifier = EmailString.normalize_email_case(identifier) account = session.query(AbstractAgentAccount).filter_by( email_ci=identifier).order_by(AbstractAgentAccount.verified.desc()).first() if account: user = account.profile return (user, account) else: username = session.query(Username).filter_by( username=identifier).first() if username: return (username.user, None) return None, None
def confirm_email_sent(request): localizer = request.localizer # TODO: How to make this not become a spambot? email = request.matchdict.get('email') if not email: raise HTTPNotFound() if '@' not in email: raise HTTPBadRequest("Not an email") email = EmailString.normalize_email_case(email) email_objects = AbstractAgentAccount.default_db.query( AbstractAgentAccount).filter_by(email_ci=email) verified_emails = [e for e in email_objects if e.verified] unverified_emails = [e for e in email_objects if not e.verified] if len(verified_emails) > 1: # TODO!: Merge accounts. raise HTTPServerError("Multiple verified emails") elif len(verified_emails): if len(unverified_emails): # TODO!: Send an email, mention duplicates, and... # offer to merge accounts? # Send an email to other emails of the duplicate? Sigh! pass return HTTPFound(location=maybe_contextual_route( request, 'login', _query=dict( identifer=email, error=localizer.translate(_( "This email is already confirmed."))))) else: if len(unverified_emails): # Normal case: Send an email. May be spamming for email_account in unverified_emails: send_confirmation_email(request, email_account) slug = request.matchdict.get('discussion_slug', None) slug_prefix = "/" + slug if slug else "" return dict( get_default_context(request), action = "%s/confirm_email_sent/%s" % (slug_prefix, email), email=email, title=localizer.translate(_('Confirmation requested')), description=localizer.translate(_( 'A confirmation e-mail has been sent to your account and should be in your inbox in a few minutes. ' 'Please follow the confirmation link in order to confirm your email'))) else: # We do not have an email to this name. return HTTPFound(location=maybe_contextual_route( request, 'register', email=email, _query=dict( error=localizer.translate(_( "We do not know about this email.")))))
def assembl_register_view(request): slug = request.matchdict.get('discussion_slug', "") next_view = handle_next_view(request) if not request.params.get('email'): if request.scheme == "http"\ and asbool(config.get("accept_secure_connection")): return HTTPFound(get_global_base_url(True) + request.path_qs) response = get_login_context(request) return response forget(request) session = AgentProfile.default_db localizer = request.localizer name = request.params.get('name', '').strip() if not name or len(name) < 3: return dict(get_default_context(request), error=localizer.translate(_( "Please use a name of at least 3 characters"))) password = request.params.get('password', '').strip() password2 = request.params.get('password2', '').strip() email = request.params.get('email', '').strip() if not is_email(email): return dict(get_default_context(request), error=localizer.translate(_( "This is not a valid email"))) email = EmailString.normalize_email_case(email) # Find agent account to avoid duplicates! if session.query(AbstractAgentAccount).filter_by( email_ci=email, verified=True).count(): return dict(get_default_context(request), error=localizer.translate(_( "We already have a user with this email."))) if password != password2: return dict(get_default_context(request), error=localizer.translate(_( "The passwords should be identical"))) # TODO: Validate password quality # otherwise create. validate_registration = asbool(config.get( 'assembl.validate_registration_emails')) user = User( name=name, password=password, verified=not validate_registration, creation_date=datetime.utcnow() ) email_account = EmailAccount( email=email, verified=not validate_registration, profile=user ) session.add(user) session.add(email_account) discussion = discussion_from_request(request) if discussion: permissions = get_permissions(Everyone, discussion.id) if not (P_SELF_REGISTER in permissions or P_SELF_REGISTER_REQUEST in permissions): discussion = None if discussion: _now = datetime.utcnow() agent_status = AgentStatusInDiscussion( agent_profile=user, discussion=discussion, first_visit=_now, last_visit=_now, user_created_on_this_discussion=True) session.add(agent_status) session.flush() if not validate_registration: if asbool(config.get('pyramid.debug_authorization')): # for debugging purposes from assembl.auth.password import email_token print "email token:", request.route_url( 'user_confirm_email', token=email_token(email_account)) headers = remember(request, user.id) user.last_login = datetime.utcnow() request.response.headerlist.extend(headers) if discussion: maybe_auto_subscribe(user, discussion) # TODO: Tell them to expect an email. return HTTPFound(location=next_view) return HTTPFound(location=maybe_contextual_route( request, 'confirm_emailid_sent', email_account_id=email_account.id))
def assembl_register_user(request): forget(request) localizer = request.localizer session = AgentProfile.default_db json = request.json logger = logging.getLogger() discussion = discussion_from_request(request) permissions = get_permissions(Everyone, discussion.id if discussion else None) name = json.get('real_name', '').strip() errors = JSONError() if not name or len(name) < 3: errors.add_error( localizer.translate( _("Please use a name of at least 3 characters")), ErrorTypes.SHORT_NAME) password = json.get('password', '').strip() # TODO: Check password strength. maybe pwdmeter? email = None for account in json.get('accounts', ()): email = account.get('email', None) if not is_email(email): errors.add_error( localizer.translate(_("This is not a valid email")), ErrorTypes.INVALID_EMAIL) continue email = EmailString.normalize_email_case(email) # Find agent account to avoid duplicates! if session.query(AbstractAgentAccount).filter_by( email_ci=email).count(): if not discussion.preferences['generic_errors']: errors.add_error( localizer.translate( _("We already have a user with this email.")), ErrorTypes.EXISTING_EMAIL, HTTPConflict.code) else: errors.add_error(localizer.translate(generic_error_message), ErrorTypes.GENERIC, HTTPConflict.code) logger.error( "[User creation]: We already have a user with this email %s" % email) if not email: errors.add_error(localizer.translate(_("No email.")), ErrorTypes.INVALID_EMAIL) username = json.get('username', None) if username: if session.query(Username).filter( func.lower(Username.username) == username.lower()).count(): if not discussion.preferences['generic_errors']: errors.add_error( localizer.translate( _("We already have a user with this username.")), ErrorTypes.EXISTING_USERNAME, HTTPConflict.code) else: errors.add_error(localizer.translate(generic_error_message), ErrorTypes.GENERIC, HTTPConflict.code) logger.error("We already have a user with username %s" % username) if len(username) > 20: errors.add_error( localizer.translate( _("The username must be less than 20 characters.")), ErrorTypes.USERNAME_TOO_LONG, HTTPBadRequest.code) if discussion: check_subscription = discussion.preferences['whitelist_on_register'] whitelist = discussion.preferences['require_email_domain'] if check_subscription and whitelist: status = discussion.check_email(email) if not status: admin_emails = discussion.get_admin_emails() num = len(admin_emails) errors.add_error( localizer.pluralize( _("Your email domain has not been approved for registration. Please contact ${emails} for support." ), _("Your email domain has not been approved for registration. Please contact one of ${emails} for support." ), num, mapping={'emails': ", ".join(admin_emails)})) if errors: raise errors # This logic needs to be above the JSONError checks to ensure that whitelisting is applied # even if the discussion does not have a P_SELF_REGISTER on system.Everyone if discussion and not (P_SELF_REGISTER in permissions or P_SELF_REGISTER_REQUEST in permissions): # Consider it without context discussion = None validate_registration = asbool( config.get('assembl.validate_registration_emails')) old_autoflush = session.autoflush session.autoflush = False try: now = datetime.utcnow() user = User(name=name, password=password, verified=not validate_registration, creation_date=now) session.add(user) session.flush() user.update_from_json(json, user_id=user.id) account = user.accounts[0] email = account.email account.verified = not validate_registration if discussion: agent_status = AgentStatusInDiscussion( agent_profile=user, discussion=discussion, first_visit=now, last_visit=now, user_created_on_this_discussion=True) session.add(agent_status) session.flush() # create the profile fields for custom fields for global_id, value in json.get('profileFields', {}).iteritems(): configurable_field_id = from_global_id(global_id)[1] configurable_field = AbstractConfigurableField.get( configurable_field_id) profile_field = ProfileField( agent_profile=user, configurable_field=configurable_field, discussion=configurable_field.discussion, value_data={u'value': value}) session.add(profile_field) session.flush() if validate_registration: send_confirmation_email(request, account) else: user.verified = True for account in user.accounts: account.verified = True user.successful_login() if asbool(config.get('pyramid.debug_authorization')): # for debugging purposes from assembl.auth.password import email_token print "email token:", request.route_url( 'user_confirm_email', token=email_token(account)) if discussion: check_subscription = discussion.preferences[ 'whitelist_on_register'] maybe_auto_subscribe(user, discussion, check_authorization=check_subscription) session.flush() return CreationResponse(user, Everyone, permissions) finally: session.autoflush = old_autoflush
def assembl_register_view(request): slug = request.matchdict.get('discussion_slug', "") p_slug = "/" + slug if slug else "" next_view = handle_next_view(request) if not request.params.get('email'): if request.scheme == "http"\ and asbool(config.get("accept_secure_connection")): raise HTTPFound("https://" + request.host + request.path_qs) response = dict(get_login_context(request), slug_prefix=p_slug) if request.GET.get('error', None): response['error'] = request.GET['error'] return response forget(request) session = AgentProfile.default_db localizer = request.localizer name = request.params.get('name', '').strip() if not name or len(name) < 3: return dict(get_default_context(request), slug_prefix=p_slug, error=localizer.translate(_( "Please use a name of at least 3 characters"))) password = request.params.get('password', '').strip() password2 = request.params.get('password2', '').strip() email = request.params.get('email', '').strip() if not is_email(email): return dict(get_default_context(request), slug_prefix=p_slug, error=localizer.translate(_( "This is not a valid email"))) email = EmailString.normalize_email_case(email) # Find agent account to avoid duplicates! if session.query(AbstractAgentAccount).filter_by( email_ci=email, verified=True).count(): return dict(get_default_context(request), slug_prefix=p_slug, error=localizer.translate(_( "We already have a user with this email."))) if password != password2: return dict(get_default_context(request), slug_prefix=p_slug, error=localizer.translate(_( "The passwords should be identical"))) # TODO: Validate password quality # otherwise create. validate_registration = asbool(config.get( 'assembl.validate_registration_emails')) user = User( name=name, password=password, verified=not validate_registration, creation_date=datetime.utcnow() ) email_account = EmailAccount( email=email, verified=not validate_registration, profile=user ) session.add(user) session.add(email_account) discussion = discussion_from_request(request) if discussion: _now = datetime.utcnow() agent_status = AgentStatusInDiscussion( agent_profile=user, discussion=discussion, first_visit=_now, last_visit=_now, user_created_on_this_discussion=True) session.add(agent_status) session.flush() if not validate_registration: if asbool(config.get('pyramid.debug_authorization')): # for debugging purposes from assembl.auth.password import email_token print "email token:", request.route_url( 'user_confirm_email', ticket=email_token(email_account)) headers = remember(request, user.id) user.last_login = datetime.utcnow() request.response.headerlist.extend(headers) if discussion: maybe_auto_subscribe(user, discussion) # TODO: Tell them to expect an email. return HTTPFound(location=next_view) return HTTPFound(location=maybe_contextual_route( request, 'confirm_emailid_sent', email_account_id=email_account.id))
def assembl_register_user(request): forget(request) localizer = request.localizer session = AgentProfile.default_db json = request.json discussion = discussion_from_request(request) permissions = ctx.get_permissions() name = json.get('real_name', '').strip() errors = JSONError() if not name or len(name) < 3: errors.add_error(localizer.translate(_( "Please use a name of at least 3 characters")), ErrorTypes.SHORT_NAME) password = json.get('password', '').strip() # TODO: Check password strength. maybe pwdmeter? email = None for account in json.get('accounts', ()): email = account.get('email', None) if not is_email(email): errors.add_error(localizer.translate(_( "This is not a valid email")), ErrorTypes.INVALID_EMAIL) continue email = EmailString.normalize_email_case(email) # Find agent account to avoid duplicates! if session.query(AbstractAgentAccount).filter_by( email_ci=email, verified=True).count(): errors.add_error(localizer.translate(_( "We already have a user with this email.")), ErrorTypes.EXISTING_EMAIL, HTTPConflict.code) if not email: errors.add_error(localizer.translate(_("No email.")), ErrorTypes.INVALID_EMAIL) username = json.get('username', None) if username: if session.query(User).filter_by( username=username).count(): errors.add_error(localizer.translate(_( "We already have a user with this username.")), ErrorTypes.EXISTING_USERNAME, HTTPConflict.code) if errors: raise errors validate_registration = asbool(settings.get( 'assembl.validate_registration_emails')) old_autoflush = session.autoflush session.autoflush = False try: now = datetime.utcnow() user = User( name=name, password=password, verified=not validate_registration, creation_date=now ) session.add(user) session.flush() user.update_from_json(json, user_id=user.id) if discussion and not ( P_SELF_REGISTER in permissions or P_SELF_REGISTER_REQUEST in permissions): # Consider it without context discussion = None if discussion: agent_status = AgentStatusInDiscussion( agent_profile=user, discussion=discussion, first_visit=now, last_visit=now, user_created_on_this_discussion=True) session.add(agent_status) session.flush() account = user.accounts[0] email = account.email account.verified = not validate_registration if validate_registration: send_confirmation_email(request, account) else: user.verified = True for account in user.accounts: account.verified = True if asbool(settings.get('pyramid.debug_authorization')): # for debugging purposes from assembl.auth.password import email_token log.info("email token: " + request.route_url( 'user_confirm_email', token=email_token(account))) if discussion: maybe_auto_subscribe(user, discussion) session.flush() return CreationResponse(user, Everyone, permissions) finally: session.autoflush = old_autoflush
def assembl_register_user(request): forget(request) localizer = request.localizer session = AgentProfile.default_db json = request.json logger = logging.getLogger() discussion = discussion_from_request(request) permissions = get_permissions( Everyone, discussion.id if discussion else None) name = json.get('real_name', '').strip() errors = JSONError() if not name or len(name) < 3: errors.add_error(localizer.translate(_( "Please use a name of at least 3 characters")), ErrorTypes.SHORT_NAME) password = json.get('password', '').strip() # TODO: Check password strength. maybe pwdmeter? email = None for account in json.get('accounts', ()): email = account.get('email', None) if not is_email(email): errors.add_error(localizer.translate(_( "This is not a valid email")), ErrorTypes.INVALID_EMAIL) continue email = EmailString.normalize_email_case(email) # Find agent account to avoid duplicates! if session.query(AbstractAgentAccount).filter_by( email_ci=email).count(): if not discussion.preferences['generic_errors']: errors.add_error(localizer.translate(_( "We already have a user with this email.")), ErrorTypes.EXISTING_EMAIL, HTTPConflict.code) else: errors.add_error(localizer.translate( generic_error_message), ErrorTypes.GENERIC, HTTPConflict.code) logger.error("[User creation]: We already have a user with this email %s" % email) if not email: errors.add_error(localizer.translate(_("No email.")), ErrorTypes.INVALID_EMAIL) username = json.get('username', None) if username: if session.query(Username).filter( func.lower(Username.username) == username.lower()).count(): if not discussion.preferences['generic_errors']: errors.add_error(localizer.translate(_( "We already have a user with this username.")), ErrorTypes.EXISTING_USERNAME, HTTPConflict.code) else: errors.add_error(localizer.translate( generic_error_message), ErrorTypes.GENERIC, HTTPConflict.code) logger.error("We already have a user with username %s" % username) if len(username) > 20: errors.add_error(localizer.translate(_( "The username must be less than 20 characters.")), ErrorTypes.USERNAME_TOO_LONG, HTTPBadRequest.code) if discussion: check_subscription = discussion.preferences['whitelist_on_register'] whitelist = discussion.preferences['require_email_domain'] if check_subscription and whitelist: status = discussion.check_email(email) if not status: admin_emails = discussion.get_admin_emails() num = len(admin_emails) errors.add_error( localizer.pluralize( _("Your email domain has not been approved for registration. Please contact ${emails} for support."), _("Your email domain has not been approved for registration. Please contact one of ${emails} for support."), num, mapping={'emails': ", ".join(admin_emails)} ) ) if errors: raise errors # This logic needs to be above the JSONError checks to ensure that whitelisting is applied # even if the discussion does not have a P_SELF_REGISTER on system.Everyone if discussion and not ( P_SELF_REGISTER in permissions or P_SELF_REGISTER_REQUEST in permissions): # Consider it without context discussion = None validate_registration = asbool(config.get( 'assembl.validate_registration_emails')) old_autoflush = session.autoflush session.autoflush = False try: now = datetime.utcnow() user = User( name=name, password=password, verified=not validate_registration, creation_date=now ) session.add(user) session.flush() user.update_from_json(json, user_id=user.id) account = user.accounts[0] email = account.email account.verified = not validate_registration if discussion: agent_status = AgentStatusInDiscussion( agent_profile=user, discussion=discussion, first_visit=now, last_visit=now, user_created_on_this_discussion=True) session.add(agent_status) session.flush() # create the profile fields for custom fields for global_id, value in json.get('profileFields', {}).iteritems(): configurable_field_id = from_global_id(global_id)[1] configurable_field = AbstractConfigurableField.get(configurable_field_id) profile_field = ProfileField( agent_profile=user, configurable_field=configurable_field, discussion=configurable_field.discussion, value_data={ u'value': value } ) session.add(profile_field) session.flush() if validate_registration: send_confirmation_email(request, account) else: user.verified = True for account in user.accounts: account.verified = True user.successful_login() if asbool(config.get('pyramid.debug_authorization')): # for debugging purposes from assembl.auth.password import email_token print "email token:", request.route_url( 'user_confirm_email', token=email_token(account)) if discussion: check_subscription = discussion.preferences['whitelist_on_register'] maybe_auto_subscribe(user, discussion, check_authorization=check_subscription) session.flush() return CreationResponse(user, Everyone, permissions) finally: session.autoflush = old_autoflush