def preferences(request): schema = UserPreferencesSchema() button1 = Button('submit', _('Save changes')) button1.css_class = 'btn-primary' form = Form(schema, buttons=(button1, )) user = request.user if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} user.update_preferences(appstruct) Session.add(user) request.session.flash( _('The changes were saved successfully'), 'success', ) return HTTPFound(location=request.route_path('user_preferences')) return { 'form': form.render({ 'allow_google_analytics': user.allow_google_analytics, 'send_passwords_periodically': user.send_passwords_periodically, }) }
def verify_email(request): try: code = request.params['code'] except KeyError: return HTTPBadRequest('Missing code parameter') try: email = request.params['email'] except KeyError: return HTTPBadRequest('Missing email parameter') evc = EmailVerificationCode(code) user = evc.verify(email) if user is not None: request.session.flash( _('Congratulations, your email has been successfully verified'), 'success', ) user.verify_email() Session.add(user) return { 'verified': True, } else: request.session.flash( _('Sorry, your verification code is not correct or has expired'), 'error', ) return { 'verified': False, }
def verify_email(request): try: code = request.params['code'] except KeyError: return HTTPBadRequest('Missing code parameter') try: email = request.params['email'] except KeyError: return HTTPBadRequest('Missing email parameter') evc = EmailVerificationCode(code) if evc.verify(request.db, email): request.session.flash( _('Congratulations, your email has been successfully verified'), 'success', ) evc.remove(request.db, email, True) return { 'verified': True, } else: request.session.flash( _('Sorry, your verification code is not correct or has expired'), 'error', ) return { 'verified': False, }
class AccountDestroySchema(colander.MappingSchema): reason = colander.SchemaNode( colander.String(), missing='', widget=TextAreaWidget(rows=6), title=_('Do you mind telling us your reasons?'), description=_('We want to get better!'), )
def destroy(request): schema = AccountDestroySchema() button1 = Button('submit', _('Yes, I am sure. Destroy my account')) button1.css_class = 'btn-danger' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2)) user = request.user can_destroy = len(user.applications) == 0 context = { 'passwords': len(user.passwords), 'can_destroy': can_destroy, } if 'submit' in request.POST: if not can_destroy: request.session.flash( _('You must remove your applications before destroying your account' ), 'error', ) return HTTPFound( location=request.route_path('oauth2_developer_applications')) controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: context['form'] = e.render() return context reason = appstruct['reason'] notify_admins_of_account_removal(request, user, reason) Session.delete(user) request.session.flash( _('Your account has been removed. Have a nice day!'), 'success', ) return logout(request) elif 'cancel' in request.POST: request.session.flash( _('Thanks for reconsidering removing your account!'), 'info', ) return HTTPFound(location=request.route_path('user_information')) context['form'] = form.render() return context
def contributions_paypal_success(request): error_msg = _('There was a problem in the confirmation process. Please start the checkout again') if request.method == 'POST': if 'submit' in request.POST: token = request.POST.get('token', None) payerid = request.POST.get('payerid', None) amount = request.POST.get('amount', None) success = False if token and payerid and amount: try: amount = int(amount) except ValueError: return HTTPBadRequest('Amount must be an integer') paypal = PayPalExpressCheckout(request) success = paypal.do_express_checkout_payment(token, payerid, amount) if success: donation = create_donation(request, request.POST) send_thankyou_email(request, donation) send_notification_to_admins(request, donation) request.session.flash( _('Thank you very much for your great contribution'), 'success', ) else: request.session.flash(error_msg, 'error') return HTTPFound(location=request.route_path('contributions_index')) elif 'cancel' in request.POST: return HTTPFound(location=request.route_path('contributions_paypal_cancel_callback')) else: return HTTPBadRequest('Wrong action') else: token = request.GET.get('token', None) payerid = request.GET.get('PayerID', None) if token and payerid: paypal = PayPalExpressCheckout(request) details = paypal.get_express_checkout_details(token, payerid) details.update({ 'token': token, 'payerid': payerid, }) amount = details['amount'] details['include_sticker'] = include_sticker(amount) return details else: request.session.flash(error_msg, 'error') return HTTPFound(location=request.route_path('contributions_index'))
def contact(request): button1 = Button('submit', _('Send message')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default' form = Form(ContactSchema(), buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} context = {'link': request.route_url('contact')} context.update(appstruct) subject = ("%s sent a message from Yith's contact form" % appstruct['name']) result = send_email_to_admins( request, 'yithlibraryserver:templates/email_contact', context, subject, extra_headers={'Reply-To': appstruct['email']}, ) if result is None: log.error( '%s <%s> tried to send a message from the contact form but no ' 'admin emails were configured. Message: %s' % ( appstruct['name'], appstruct['email'], appstruct['message'], ) ) request.session.flash( _('Thank you very much for sharing your opinion'), 'info', ) return HTTPFound(location=request.route_path('home')) elif 'cancel' in request.POST: return HTTPFound(location=request.route_path('home')) initial = {} if request.user is not None: initial['name'] = request.user.get('first_name', '') if request.user.get('email_verified', False): initial['email'] = request.user.get('email', '') return {'form': form.render(initial)}
def contact(request): button1 = Button('submit', _('Send message')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default' form = Form(ContactSchema(), buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} context = {'link': request.route_url('contact')} context.update(appstruct) subject = ("%s sent a message from Yith's contact form" % appstruct['name']) result = send_email_to_admins( request, 'yithlibraryserver:templates/email_contact', context, subject, extra_headers={'Reply-To': appstruct['email']}, ) if result is None: log.error( '%s <%s> tried to send a message from the contact form but no ' 'admin emails were configured. Message: %s' % ( appstruct['name'], appstruct['email'], appstruct['message'], )) request.session.flash( _('Thank you very much for sharing your opinion'), 'info', ) return HTTPFound(location=request.route_path('home')) elif 'cancel' in request.POST: return HTTPFound(location=request.route_path('home')) initial = {} if request.user is not None: initial['name'] = request.user.first_name if request.user.email_verified: initial['email'] = request.user.email return {'form': form.render(initial)}
def destroy(request): schema = AccountDestroySchema() button1 = Button('submit', _('Yes, I am sure. Destroy my account')) button1.css_class = 'btn-danger' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2)) user = request.user can_destroy = len(user.applications) == 0 context = { 'passwords': len(user.passwords), 'can_destroy': can_destroy, } if 'submit' in request.POST: if not can_destroy: request.session.flash( _('You must remove your applications before destroying your account'), 'error', ) return HTTPFound(location=request.route_path('oauth2_developer_applications')) controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: context['form'] = e.render() return context reason = appstruct['reason'] notify_admins_of_account_removal(request, user, reason) Session.delete(user) request.session.flash( _('Your account has been removed. Have a nice day!'), 'success', ) return logout(request) elif 'cancel' in request.POST: request.session.flash( _('Thanks for reconsidering removing your account!'), 'info', ) return HTTPFound(location=request.route_path('user_information')) context['form'] = form.render() return context
class FullApplicationSchema(ApplicationSchema): client_id = colander.SchemaNode( colander.String(), title=_('Client Id'), widget=ReadOnlyTextInputWidget(), ) client_secret = colander.SchemaNode( colander.String(), title=_('Client secret'), widget=ReadOnlyTextInputWidget(), )
def user_information(request): schema = UserSchema() button1 = Button('submit', _('Save changes')) button1.css_class = 'btn-primary' form = Form(schema, buttons=(button1, )) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} changes = { 'first_name': appstruct['first_name'], 'last_name': appstruct['last_name'], 'screen_name': appstruct['screen_name'], 'email': appstruct['email']['email'], } if request.user['email'] != appstruct['email']['email']: changes['email_verified'] = False result = request.db.users.update({'_id': request.user['_id']}, {'$set': changes}, safe=True) if result['n'] == 1: request.session.flash( _('The changes were saved successfully'), 'success', ) return HTTPFound(location=request.route_path('user_information')) else: request.session.flash( _('There were an error while saving your changes'), 'error', ) return {'form': appstruct} return { 'form': form.render({ 'first_name': request.user['first_name'], 'last_name': request.user['last_name'], 'screen_name': request.user['screen_name'], 'email': { 'email': request.user['email'], 'email_verified': request.user['email_verified'], }, }), }
def contributions_paypal_success(request): error_msg = _("There was a problem in the confirmation process. Please start the checkout again") if request.method == "POST": if "submit" in request.POST: token = request.POST.get("token", None) payerid = request.POST.get("payerid", None) amount = request.POST.get("amount", None) success = False if token and payerid and amount: try: amount = int(amount) except ValueError: return HTTPBadRequest("Amount must be an integer") paypal = PayPalExpressCheckout(request) success = paypal.do_express_checkout_payment(token, payerid, amount) if success: donation = create_donation(request, request.POST) send_thankyou_email(request, donation) send_notification_to_admins(request, donation) request.session.flash(_("Thank you very much for your great contribution"), "success") else: request.session.flash(error_msg, "error") return HTTPFound(location=request.route_path("contributions_index")) elif "cancel" in request.POST: return HTTPFound(location=request.route_path("contributions_paypal_cancel_callback")) else: return HTTPBadRequest("Wrong action") else: token = request.GET.get("token", None) payerid = request.GET.get("PayerID", None) if token and payerid: paypal = PayPalExpressCheckout(request) details = paypal.get_express_checkout_details(token, payerid) details.update({"token": token, "payerid": payerid}) amount = details["amount"] details["include_sticker"] = include_sticker(amount) return details else: request.session.flash(error_msg, "error") return HTTPFound(location=request.route_path("contributions_index"))
class ContactSchema(colander.MappingSchema): name = colander.SchemaNode( colander.String(), title=_('Name'), ) email = colander.SchemaNode( colander.String(), title=_('Email'), ) message = colander.SchemaNode( colander.String(), widget=TextAreaWidget(rows=10), title=_('Message'), )
def identity_providers(request): current_provider = request.session.get('current_provider', None) accounts = get_accounts(request.db, request.user, current_provider) context = { 'accounts': accounts } verified = [ac for ac in accounts if ac['is_verified']] context['can_merge'] = len(verified) > 1 if 'submit' in request.POST: if not context['can_merge']: return HTTPBadRequest('You do not have enough accounts to merge') def is_verified(ac): for a in accounts: if a['id'] == ac: return a['is_verified'] return False accounts_to_merge = [account.replace('account-', '') for account in request.POST.keys() if account != 'submit'] accounts_to_merge = [account for account in accounts_to_merge if is_verified(account)] if len(accounts_to_merge) > 1: merged = merge_accounts(request.db, request.user, accounts_to_merge) localizer = get_localizer(request) msg = localizer.pluralize( _('Congratulations, ${n_merged} of your accounts has been merged into the current one'), _('Congratulations, ${n_merged} of your accounts have been merged into the current one'), merged, domain=translation_domain, mapping={'n_merged': merged}, ) request.session.flash(msg, 'success') else: request.session.flash( _('Not enough accounts for merging'), 'error', ) return HTTPFound( location=request.route_path('user_identity_providers')) return context
def destroy(request): schema = AccountDestroySchema() button1 = Button('submit', _('Yes, I am sure. Destroy my account')) button1.css_class = 'btn-danger' button2 = Button('cancel', _('Cancel')) button2.css_class = '' form = Form(schema, buttons=(button1, button2)) passwords_manager = PasswordsManager(request.db) context = { 'passwords': passwords_manager.retrieve(request.user).count(), } if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: context['form'] = e.render() return context reason = appstruct['reason'] admin_emails = request.registry.settings['admin_emails'] if admin_emails: notify_admins_of_account_removal(request, request.user, reason, admin_emails) passwords_manager.delete(request.user) # TODO: remove user's applications delete_user(request.db, request.user) request.session.flash( _('Your account has been removed. Have a nice day!'), 'success', ) return logout(request) elif 'cancel' in request.POST: request.session.flash( _('Thanks for reconsidering removing your account!'), 'info', ) return HTTPFound(location=request.route_path('user_information')) context['form'] = form.render() return context
def backups_import(request): response = HTTPFound(location=request.route_path('backups_index')) if 'passwords-file' in request.POST: passwords_field = request.POST['passwords-file'] if passwords_field != '': try: compressed_data = passwords_field.file.read() json_data = uncompress(compressed_data) except (IOError, ValueError): request.session.flash( _('There was a problem reading your passwords file'), 'error') return response Session.query(Password).filter( Password.user == request.user).delete( synchronize_session=False) for password_data in json_data: if 'secret' in password_data: password = Password(user=request.user, **password_data) Session.add(password) n_passwords = len(json_data) localizer = get_localizer(request) msg = localizer.pluralize( _('Congratulations, ${n_passwords} password has been imported' ), _('Congratulations, ${n_passwords} passwords have been imported' ), n_passwords, domain=translation_domain, mapping={'n_passwords': n_passwords}, ) request.session.flash(msg, 'success') else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response return response
def identity_providers(request): current_provider = request.session.get('current_provider', None) accounts = request.user.get_accounts(current_provider) context = {'accounts': accounts} verified = [ac for ac in accounts if ac['is_verified']] context['can_merge'] = len(verified) > 1 if 'submit' in request.POST: if not context['can_merge']: return HTTPBadRequest('You do not have enough accounts to merge') def is_verified(ac): for a in accounts: if a['id'] == ac: return a['is_verified'] return False accounts_to_merge = [ account.replace('account-', '') for account in request.POST.keys() if account != 'submit' ] accounts_to_merge = [ account for account in accounts_to_merge if is_verified(account) ] if len(accounts_to_merge) > 1: merged = merge_accounts(request.user, accounts_to_merge) localizer = get_localizer(request) msg = localizer.pluralize( _('Congratulations, ${n_merged} of your accounts has been merged into the current one' ), _('Congratulations, ${n_merged} of your accounts have been merged into the current one' ), merged, domain=translation_domain, mapping={'n_merged': merged}, ) request.session.flash(msg, 'success') else: request.session.flash( _('Not enough accounts for merging'), 'error', ) return HTTPFound( location=request.route_path('user_identity_providers')) return context
def revoke_application(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if 'submit' in request.POST: authorized_apps = Session.query(AuthorizedApplication).filter( AuthorizedApplication.application == app, AuthorizedApplication.user == request.user).all() for authorized_app in authorized_apps: Session.delete(authorized_app) request.session.flash( _('The access to application ${app} has been revoked', mapping={'app': app.name}), 'success', ) return HTTPFound( location=request.route_path('oauth2_authorized_applications')) return {'app': app}
def developer_application_delete(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if app.user != request.user: return HTTPUnauthorized() if 'submit' in request.POST: Session.delete(app) request.session.flash( _('The application ${app} was deleted successfully', mapping={'app': app.name}), 'success', ) return HTTPFound( location=request.route_path('oauth2_developer_applications')) return {'app': app}
class UserPreferencesSchema(colander.MappingSchema): allow_google_analytics = colander.SchemaNode( colander.Boolean(), title=_('Allow statistics cookie'), missing=False, ) send_passwords_periodically = colander.SchemaNode( colander.Boolean(), title=_('Send my passwords to my email monthly'), missing=False, description= _('You will receive your passwords backup on the first day of the month' ), )
class NewUserSchema(BaseUserSchema): email = colander.SchemaNode( colander.String(), title=_('Email'), missing='', )
def revoke_application(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if 'submit' in request.POST: authorized_apps = Session.query(AuthorizedApplication).filter( AuthorizedApplication.application == app, AuthorizedApplication.user == request.user ).all() for authorized_app in authorized_apps: Session.delete(authorized_app) request.session.flash( _('The access to application ${app} has been revoked', mapping={'app': app.name}), 'success', ) return HTTPFound( location=request.route_path('oauth2_authorized_applications')) return {'app': app}
def revoke_application(request): assert_authenticated_user_is_registered(request) try: app_id = bson.ObjectId(request.matchdict['app']) except bson.errors.InvalidId: return HTTPBadRequest(body='Invalid application id') app = request.db.applications.find_one(app_id) if app is None: return HTTPNotFound() authorizator = Authorizator(request.db, app) if not authorizator.is_app_authorized(request.user): return HTTPUnauthorized() if 'submit' in request.POST: authorizator.remove_user_authorization(request.user) request.session.flash( _('The access to application ${app} has been revoked', mapping={'app': app['name']}), 'success', ) return HTTPFound( location=request.route_path('oauth2_authorized_applications')) return {'app': app}
def developer_application_delete(request): try: app_id = bson.ObjectId(request.matchdict['app']) except bson.errors.InvalidId: return HTTPBadRequest(body='Invalid application id') app = request.db.applications.find_one(app_id) if app is None: return HTTPNotFound() assert_authenticated_user_is_registered(request) if app['owner'] != request.user['_id']: return HTTPUnauthorized() if 'submit' in request.POST: request.db.applications.remove(app_id, safe=True) request.session.flash( _('The application ${app} was deleted successfully', mapping={'app': app['name']}), 'success', ) return HTTPFound( location=request.route_path('oauth2_developer_applications')) return {'app': app}
class BaseUserSchema(colander.MappingSchema): first_name = colander.SchemaNode( colander.String(), title=_('First name'), missing='', ) last_name = colander.SchemaNode( colander.String(), title=_('Last name'), missing='', ) screen_name = colander.SchemaNode( colander.String(), title=_('Screen name'), missing='', )
def backups_import(request): response = HTTPFound(location=request.route_path('backups_index')) if 'passwords-file' in request.POST: passwords_field = request.POST['passwords-file'] if passwords_field != '': try: compressed_data = passwords_field.file.read() json_data = uncompress(compressed_data) except (IOError, ValueError): request.session.flash( _('There was a problem reading your passwords file'), 'error') return response Session.query(Password).filter( Password.user == request.user ).delete(synchronize_session=False) for password_data in json_data: if 'secret' in password_data: password = Password(user=request.user, **password_data) Session.add(password) n_passwords = len(json_data) localizer = get_localizer(request) msg = localizer.pluralize( _('Congratulations, ${n_passwords} password has been imported'), _('Congratulations, ${n_passwords} passwords have been imported'), n_passwords, domain=translation_domain, mapping={'n_passwords': n_passwords}, ) request.session.flash(msg, 'success') else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response return response
def user_information(request): schema = UserSchema() button1 = Button('submit', _('Save changes')) button1.css_class = 'btn-primary' form = Form(schema, buttons=(button1, )) user = request.user if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} changes = { 'first_name': appstruct['first_name'], 'last_name': appstruct['last_name'], 'screen_name': appstruct['screen_name'], 'email': appstruct['email']['email'], } user.update_user_info(changes) Session.add(user) request.session.flash( _('The changes were saved successfully'), 'success', ) return HTTPFound(location=request.route_path('user_information')) return { 'form': form.render({ 'first_name': user.first_name, 'last_name': user.last_name, 'screen_name': user.screen_name, 'email': { 'email': user.email, 'email_verified': user.email_verified, }, }), }
def developer_application_new(request): assert_authenticated_user_is_registered(request) schema = ApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = '' form = Form(schema, buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} # the data is fine, save into the db application = { 'owner': request.user['_id'], 'name': appstruct['name'], 'main_url': appstruct['main_url'], 'callback_url': appstruct['callback_url'], 'authorized_origins': appstruct['authorized_origins'], 'production_ready': appstruct['production_ready'], 'image_url': appstruct['image_url'], 'description': appstruct['description'], } create_client_id_and_secret(application) request.session.flash( _('The application ${app} was created successfully', mapping={'app': appstruct['name']}), 'success') request.db.applications.insert(application, safe=True) return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return {'form': form.render()}
class UserSchema(BaseUserSchema): email = EmailSchema( title=_('Email'), widget=EmailWidget(), missing={ 'email': '', 'email_verified': False }, )
def developer_application_new(request): assert_authenticated_user_is_registered(request) schema = ApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} # the data is fine, save into the db application = Application( name=appstruct['name'], main_url=appstruct['main_url'], callback_url=appstruct['callback_url'], authorized_origins=appstruct['authorized_origins'], production_ready=appstruct['production_ready'], image_url=appstruct['image_url'], description=appstruct['description'], ) request.user.applications.append(application) request.session.flash( _('The application ${app} was created successfully', mapping={'app': appstruct['name']}), 'success') Session.add(request.user) return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return {'form': form.render()}
def backups_import(request): response = HTTPFound(location=request.route_path('backups_index')) if 'passwords-file' in request.POST: passwords_field = request.POST['passwords-file'] if passwords_field != '': try: json_data = uncompress(passwords_field.file.read()) passwords_manager = PasswordsManager(request.db) passwords_manager.delete(request.user) passwords_manager.create(request.user, json_data) except (IOError, ValueError): request.session.flash( _('There was a problem reading your passwords file'), 'error') return response n_passwords = len(json_data) localizer = get_localizer(request) msg = localizer.pluralize( _('Congratulations, ${n_passwords} password has been imported'), _('Congratulations, ${n_passwords} passwords have been imported'), n_passwords, domain=translation_domain, mapping={'n_passwords': n_passwords}, ) request.session.flash(msg, 'success') else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response else: request.session.flash( _('The passwords file is required to upload the passwords'), 'error') return response return response
def preferences(request): schema = UserPreferencesSchema() button1 = Button('submit', _('Save changes')) button1.css_class = 'btn-primary' form = Form(schema, buttons=(button1, )) today = request.date_service.today() # use 28 to get a consistent day_to_send no matter what the # current month is. The disadvantage is that there are # several days in a regular month that are not used. day_to_send = get_day_to_send(request.user, 28) if day_to_send > today.day: day_to_send_msg = _( 'You will receive your passwords backup on the day ${day} of this month', mapping={'day': day_to_send}) elif day_to_send < today.day: day_to_send_msg = _( 'You will receive your passwords backup on the day ${day} of next month', mapping={'day': day_to_send}) else: day_to_send_msg = _( 'You will receive your passwords backup today!', mapping={'day': day_to_send}) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render(), 'day_to_send': day_to_send_msg} changes = dict([(pref, appstruct[pref]) for pref in ( analytics.USER_ATTR, 'send_passwords_periodically', )]) result = request.db.users.update({'_id': request.user['_id']}, {'$set': changes}, safe=True) if result['n'] == 1: request.session.flash( _('The changes were saved successfully'), 'success', ) return HTTPFound(location=request.route_path('user_preferences')) else: request.session.flash( _('There were an error while saving your changes'), 'error', ) return {'form': appstruct, 'day_to_send': day_to_send_msg} return {'form': form.render(request.user), 'day_to_send': day_to_send_msg}
def preferences(request): schema = UserPreferencesSchema() button1 = Button('submit', _('Save changes')) button1.css_class = 'btn-primary' form = Form(schema, buttons=(button1, )) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} changes = dict([(pref, appstruct[pref]) for pref in ( analytics.USER_ATTR, 'send_passwords_periodically', )]) result = request.db.users.update({'_id': request.user['_id']}, {'$set': changes}) if result['n'] == 1: request.session.flash( _('The changes were saved successfully'), 'success', ) return HTTPFound(location=request.route_path('user_preferences')) else: request.session.flash( _('There were an error while saving your changes'), 'error', ) return {'form': appstruct} return {'form': form.render(request.user)}
class ApplicationSchema(colander.MappingSchema): name = colander.SchemaNode( colander.String(), title=_('Name'), ) main_url = colander.SchemaNode( colander.String(), title=_('Main URL'), ) callback_url = colander.SchemaNode( colander.String(), title=_('Callback URL'), ) authorized_origins = AuthorizedOriginsNode( colander.String(), title=_('Authorized Origins'), description=_('One per line. For example https://example.com'), widget=TextAreaWidget(rows=5), missing=[], ) production_ready = colander.SchemaNode( colander.Boolean(), title=_('Production ready'), missing=False, ) image_url = colander.SchemaNode( colander.String(), title=_('Image URL'), missing='', ) description = colander.SchemaNode( colander.String(), title=_('Description'), missing='', )
from pyramid.httpexceptions import HTTPNotImplemented, HTTPUnauthorized from pyramid.view import view_config from yithlibraryserver.i18n import TranslationString as _ from yithlibraryserver.oauth2.application import create_client_id_and_secret from yithlibraryserver.oauth2.authentication import authenticate_client from yithlibraryserver.oauth2.authorization import Authorizator from yithlibraryserver.oauth2.schemas import ApplicationSchema from yithlibraryserver.oauth2.schemas import FullApplicationSchema from yithlibraryserver.user.security import assert_authenticated_user_is_registered DEFAULT_SCOPE = 'passwords' SCOPE_NAMES = { 'passwords': _('Access your passwords'), } @view_config(route_name='oauth2_developer_applications', renderer='templates/developer_applications.pt', permission='view-applications') def developer_applications(request): assert_authenticated_user_is_registered(request) owned_apps_filter = {'owner': request.user['_id']} return { 'applications': request.db.applications.find(owned_apps_filter) } @view_config(route_name='oauth2_developer_application_new',
def developer_application_edit(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if app.user != request.user: return HTTPUnauthorized() schema = FullApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('delete', _('Delete application')) button2.css_class = 'btn-danger' button3 = Button('cancel', _('Cancel')) button3.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2, button3)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render(), 'app': app} # the data is fine, save into the db app.name = appstruct['name'] app.main_url = appstruct['main_url'] app.callback_url = appstruct['callback_url'] app.authorized_origins = appstruct['authorized_origins'] app.production_ready = appstruct['production_ready'] app.image_url = appstruct['image_url'] app.description = appstruct['description'] Session.add(app) request.session.flash(_('The changes were saved successfully'), 'success') return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'delete' in request.POST: return HTTPFound(location=request.route_path( 'oauth2_developer_application_delete', app=app.id)) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return { 'form': form.render({ 'name': app.name, 'main_url': app.main_url, 'callback_url': app.callback_url, 'authorized_origins': app.authorized_origins, 'production_ready': app.production_ready, 'image_url': app.image_url, 'description': app.description, 'client_id': app.id, 'client_secret': app.secret, }), 'app': app, }
def authorization_endpoint(request): response_type = request.params.get('response_type') if response_type is None: return HTTPBadRequest('Missing required response_type') if response_type != 'code': return HTTPNotImplemented('Only code is supported') client_id = request.params.get('client_id') if client_id is None: return HTTPBadRequest('Missing required client_type') app = request.db.applications.find_one({'client_id': client_id}) if app is None: return HTTPNotFound() redirect_uri = request.params.get('redirect_uri') if redirect_uri is None: redirect_uri = app['callback_url'] else: if redirect_uri != app['callback_url']: return HTTPBadRequest( 'Redirect URI does not match registered callback URL') scope = request.params.get('scope', DEFAULT_SCOPE) state = request.params.get('state') user = assert_authenticated_user_is_registered(request) authorizator = Authorizator(request.db, app) if 'submit' in request.POST: if not authorizator.is_app_authorized(request.user): authorizator.store_user_authorization(request.user) code = authorizator.auth_codes.create( request.user['_id'], app['client_id'], scope) url = authorizator.auth_codes.get_redirect_url( code, redirect_uri, state) return HTTPFound(location=url) elif 'cancel' in request.POST: return HTTPFound(app['main_url']) else: if authorizator.is_app_authorized(user): code = authorizator.auth_codes.create( user['_id'], app['client_id'], scope) url = authorizator.auth_codes.get_redirect_url( code, redirect_uri, state) return HTTPFound(location=url) else: authorship_information = '' owner_id = app.get('owner', None) if owner_id is not None: owner = request.db.users.find_one({'_id': owner_id}) if owner: email = owner.get('email', None) if email: authorship_information = _('By ${owner}', mapping={'owner': email}) scopes = [SCOPE_NAMES.get(scope, scope) for scope in scope.split(' ')] return { 'response_type': response_type, 'client_id': client_id, 'redirect_uri': redirect_uri, 'scope': scope, 'state': state, 'app': app, 'scopes': scopes, 'authorship_information': authorship_information, }
def contributions_paypal_cancel(request): request.session.flash( _('Thanks for considering donating to Yith Library. We will be ready if you change your mind'), 'info', ) return HTTPFound(location=request.route_path('contributions_index'))
def message(self): return _('Log in with ${idp}', mapping={'idp': self.name})
def register_new_user(request): try: user_info = request.session['user_info'] except KeyError: return HTTPBadRequest('Missing user info in the session') try: next_url = request.session['next_url'] except KeyError: next_url = request.route_url('oauth2_clients') schema = NewUserSchema() button1 = Button('submit', _('Register into Yith Library')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default logout' form = Form(schema, buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return { 'form': e.render(), 'provider': user_info.get('provider', ''), 'email': user_info.get('email', ''), 'next_url': next_url, } email = appstruct['email'] if email != '' and email == user_info['email']: email_verified = True else: email_verified = False user_attrs = { 'screen_name': appstruct['screen_name'], 'first_name': appstruct['first_name'], 'last_name': appstruct['last_name'], 'email': email, 'email_verified': email_verified, } if request.google_analytics.is_in_session(): allow_analytics = request.google_analytics.show_in_session() user_attrs[analytics.USER_ATTR] = allow_analytics request.google_analytics.clean_session() user = User(**user_attrs) provider = user_info['provider'] external_id = user_info['external_id'] user.add_identity(provider, external_id) Session.add(user) if not email_verified and email != '': evc = EmailVerificationCode() user.email_verification_code = evc.code link = request.route_url('user_verify_email') evc.send(request, user, link) del request.session['user_info'] if 'next_url' in request.session: del request.session['next_url'] Session.flush() request.session['current_provider'] = provider return HTTPFound(location=next_url, headers=remember(request, str(user.id))) elif 'cancel' in request.POST: del request.session['user_info'] if 'next_url' in request.session: del request.session['next_url'] return HTTPFound(location=next_url) return { 'form': form.render({ 'first_name': user_info.get('first_name', ''), 'last_name': user_info.get('last_name', ''), 'screen_name': user_info.get('screen_name', ''), 'email': user_info.get('email', ''), }), 'provider': user_info.get('provider', ''), 'email': user_info.get('email', ''), 'next_url': next_url, }
class RequestValidator(oauthlib.oauth2.RequestValidator): scopes = { 'read-passwords': _('Access your passwords'), 'write-passwords': _('Modify your passwords'), 'read-userinfo': _('Access your user information'), } def __init__(self, default_scopes=None): if default_scopes is None: self.default_scopes = ['read-passwords'] else: self.default_scopes = default_scopes def get_client(self, client_id): try: uuid.UUID(client_id) except ValueError: client = None else: try: client = Session.query(Application).filter( Application.id == client_id).one() except NoResultFound: client = None return client def get_pretty_scopes(self, scopes): return [self.scopes.get(scope) for scope in scopes] # Pre- and post-authorization def validate_client_id(self, client_id, request, *args, **kwargs): """Simple validity check, does client exist? Not banned?""" request.client = self.get_client(client_id) result = request.client is not None logger.debug('Validating client id: %s Result: %s', client_id, result) return result def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs): """Is the client allowed to use the supplied redirect_uri? i.e. has the client previously registered this EXACT redirect uri. """ client = request.client or self.get_client(client_id) return client.callback_url == redirect_uri def get_default_redirect_uri(self, client_id, request, *args, **kwargs): """The redirect used if none has been supplied. Prefer your clients to pre register a redirect uri rather than supplying one on each authorization request. """ client = request.client or self.get_client(client_id) return client.callback_url def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): """Is the client allowed to access the requested scopes?""" valid_scopes = self.scopes.keys() return set(valid_scopes).issuperset(set(scopes)) def get_default_scopes(self, client_id, request, *args, **kwargs): """Scopes a client will authorize for if none are supplied in the authorization request. """ return self.default_scopes def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs): """Clients should only be allowed to use one type of response type, the one associated with their one allowed grant type. In this case it must be "code" or "token". """ # TODO: store the allowed types in the client return response_type in ('code', 'token') # Post-authorization def save_authorization_code(self, client_id, code, request, *args, **kwargs): """Remember to associate it with request.scopes, request.redirect_uri request.client, request.state and request.user (the last is passed in post_authorization credentials, i.e. { 'user': request.user}. """ now = datetime.datetime.utcnow() expiration = now + datetime.timedelta(minutes=10) authorization_code = AuthorizationCode( code=code['code'], creation=now, expiration=expiration, scope=request.scopes, redirect_uri=request.redirect_uri, application=request.client, user=request.user, ) Session.add(authorization_code) # Token request def authenticate_client(self, request, *args, **kwargs): """Whichever authentication method suits you, HTTP Basic might work.""" auth = request.headers.get('Authorization', None) if auth: auth_type, s = auth.split(' ') if auth_type != 'Basic': return False client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') else: client_id = getattr(request, 'client_id', None) client_secret = getattr(request, 'client_secret', None) if client_id is None or client_secret is None: return False client = self.get_client(client_id) if not client: return False request.client = client request.client_id = client_id # oauthlib expect the client to has a client_id attribute request.client.client_id = client_id if client.secret != client_secret: return False # if client.client_type != 'confidential': # return False return True def authenticate_client_id(self, client_id, request, *args, **kwargs): """Don't allow public (non-authenticated) clients.""" raise NotImplementedError() def validate_code(self, client_id, code, client, request, *args, **kwargs): """Validate the code belongs to the client. Add associated scopes, state and user to request.scopes, request.state and request.user. """ try: record = Session.query(AuthorizationCode).filter( AuthorizationCode.code == code, AuthorizationCode.application == request.client, ).one() except NoResultFound: record = None if record is None: return False if datetime.datetime.utcnow() > record.expiration: return False request.user = record.user request.scopes = record.scope return True def confirm_redirect_uri(self, client_id, code, redirect_uri, client, *args, **kwargs): """You did save the redirect uri with the authorization code right?""" if redirect_uri is None: return True try: authorization_code = Session.query(AuthorizationCode).filter( AuthorizationCode.code == code, AuthorizationCode.application == client, ).one() except NoResultFound: authorization_code = None if authorization_code is None: return False return authorization_code.redirect_uri == redirect_uri def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs): """Clients should only be allowed to use one type of grant. In this case, it must be "authorization_code" or "refresh_token". """ return grant_type == 'authorization_code' def save_bearer_token(self, token, request, *args, **kwargs): """Remember to associate it with request.scopes, request.user and request.client. The two former will be set when you validate# the authorization code. Don't forget to save both the access_token and the refresh_token and set expiration for the access_token to now + expires_in seconds. """ now = datetime.datetime.utcnow() expiration = now + datetime.timedelta(seconds=token['expires_in']) access_code = AccessCode( code=token['access_token'], code_type=token['token_type'], expiration=expiration, refresh_code=token.get('refresh_token', ''), user=request.user, scope=request.scopes, application=request.client, ) Session.add(access_code) def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs): """Authorization codes are use once, invalidate it when a Bearer token has been acquired. """ authorization_code = Session.query(AuthorizationCode).filter( AuthorizationCode.code == code, AuthorizationCode.application == request.client, ).one() Session.delete(authorization_code) # Protected resource request def validate_bearer_token(self, token, scopes, request): """Remember to check expiration and scope membership""" if token is None: return False try: access_code = Session.query(AccessCode).filter( AccessCode.code == token, ).one() except NoResultFound: access_code = None if access_code is None: return False if datetime.datetime.utcnow() > access_code.expiration: return False if not set(access_code.scope).issuperset(set(scopes)): return False request.access_token = access_code request.user = access_code.user request.scopes = scopes request.client_id = access_code.application_id request.client = access_code.application return True # Token refresh request def get_original_scopes(self, refresh_token, request, *args, **kwargs): """Obtain the token associated with the given refresh_token and return its scopes, these will be passed on to the refreshed access token if the client did not specify a scope during the request. """ raise NotImplementedError()
def message(self): return _("Log in with ${idp}", mapping={"idp": self.name.capitalize()})
def contact(request): button1 = Button('submit', _('Send message')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = '' form = Form(ContactSchema(), buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render()} context = {'link': request.route_url('contact')} context.update(appstruct) text_body = render('yithlibraryserver:templates/email_contact.txt', context, request=request) # chamaleon txt templates are rendered as utf-8 bytestrings text_body = text_body.decode('utf-8') html_body = render('yithlibraryserver:templates/email_contact.pt', context, request=request) admin_emails = request.registry.settings['admin_emails'] if admin_emails: message = Message( subject=("%s sent a message from Yith's contact form" % appstruct['name']), recipients=request.registry.settings['admin_emails'], body=text_body, html=html_body, extra_headers={'Reply-To': appstruct['email']}, ) get_mailer(request).send(message) else: log.error( '%s <%s> tried to send a message from the contact form but no ' 'admin emails were configured. Message: %s' % ( appstruct['name'], appstruct['email'], appstruct['message'], ) ) request.session.flash( _('Thank you very much for sharing your opinion'), 'info', ) return HTTPFound(location=request.route_path('home')) elif 'cancel' in request.POST: return HTTPFound(location=request.route_path('home')) initial = {} if request.user is not None: initial['name'] = request.user.get('first_name', '') if request.user.get('email_verified', False): initial['email'] = request.user.get('email', '') return {'form': form.render(initial)}
def developer_application_edit(request): try: app_id = bson.ObjectId(request.matchdict['app']) except bson.errors.InvalidId: return HTTPBadRequest(body='Invalid application id') assert_authenticated_user_is_registered(request) app = request.db.applications.find_one(app_id) if app is None: return HTTPNotFound() if app['owner'] != request.user['_id']: return HTTPUnauthorized() schema = FullApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('delete', _('Delete application')) button2.css_class = 'btn-danger' button3 = Button('cancel', _('Cancel')) button3.css_class = '' form = Form(schema, buttons=(button1, button2, button3)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render(), 'app': app} # the data is fine, save into the db application = { 'owner': request.user['_id'], 'name': appstruct['name'], 'main_url': appstruct['main_url'], 'callback_url': appstruct['callback_url'], 'authorized_origins': appstruct['authorized_origins'], 'production_ready': appstruct['production_ready'], 'image_url': appstruct['image_url'], 'description': appstruct['description'], 'client_id': app['client_id'], 'client_secret': app['client_secret'], } request.db.applications.update({'_id': app['_id']}, application, safe=True) request.session.flash(_('The changes were saved successfully'), 'success') return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'delete' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_application_delete', app=app['_id'])) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return {'form': form.render(app), 'app': app}
def developer_application_edit(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if app.user != request.user: return HTTPUnauthorized() schema = FullApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('delete', _('Delete application')) button2.css_class = 'btn-danger' button3 = Button('cancel', _('Cancel')) button3.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2, button3)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render(), 'app': app} # the data is fine, save into the db app.name = appstruct['name'] app.main_url = appstruct['main_url'] app.callback_url = appstruct['callback_url'] app.authorized_origins = appstruct['authorized_origins'] app.production_ready = appstruct['production_ready'] app.image_url = appstruct['image_url'] app.description = appstruct['description'] Session.add(app) request.session.flash(_('The changes were saved successfully'), 'success') return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'delete' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_application_delete', app=app.id)) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return { 'form': form.render({ 'name': app.name, 'main_url': app.main_url, 'callback_url': app.callback_url, 'authorized_origins': app.authorized_origins, 'production_ready': app.production_ready, 'image_url': app.image_url, 'description': app.description, 'client_id': app.id, 'client_secret': app.secret, }), 'app': app, }
def contributions_paypal_success(request): error_msg = _('There was a problem in the confirmation process. Please start the checkout again') if request.method == 'POST': if 'submit' in request.POST: token = request.POST.get('token', None) payerid = request.POST.get('payerid', None) amount = request.POST.get('amount', None) success = False if token and payerid and amount: try: amount = int(amount) except ValueError: return HTTPBadRequest('Amount must be an integer') paypal = PayPalExpressCheckout(request) success = paypal.do_express_checkout_payment(token, payerid, amount) if success: donation = Donation( amount=amount, first_name=request.POST['firstname'], last_name=request.POST['lastname'], city=request.POST['city'], country=request.POST['country'], state=request.POST['state'], street=request.POST['street'], zipcode=request.POST['zip'], email=request.POST['email'], ) if donation.should_include_sticker(): if 'no-sticker' in request.POST: donation.send_sticker = False else: donation.send_sticker = True else: donation.send_sticker = False donation.user = request.user Session.add(donation) Session.flush() send_thankyou_email(request, donation) send_notification_to_admins(request, donation) request.session.flash( _('Thank you very much for your great contribution'), 'success', ) else: request.session.flash(error_msg, 'error') return HTTPFound(location=request.route_path('contributions_index')) elif 'cancel' in request.POST: return HTTPFound(location=request.route_path('contributions_paypal_cancel_callback')) else: return HTTPBadRequest('Wrong action') else: token = request.GET.get('token', None) payerid = request.GET.get('PayerID', None) if token and payerid: paypal = PayPalExpressCheckout(request) details = paypal.get_express_checkout_details(token, payerid) details.update({ 'token': token, 'payerid': payerid, }) amount = details['amount'] details['include_sticker'] = include_sticker(amount) return details else: request.session.flash(error_msg, 'error') return HTTPFound(location=request.route_path('contributions_index'))
def register_new_user(request): try: user_info = request.session['user_info'] except KeyError: return HTTPBadRequest('Missing user info in the session') try: next_url = request.session['next_url'] except KeyError: next_url = request.route_url('oauth2_clients') schema = NewUserSchema() button1 = Button('submit', _('Register into Yith Library')) button1.css_class = 'btn-primary' button2 = Button('cancel', _('Cancel')) button2.css_class = 'btn-default logout' form = Form(schema, buttons=(button1, button2)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return { 'form': e.render(), 'provider': user_info.get('provider', ''), 'email': user_info.get('email', ''), 'next_url': next_url, } provider = user_info['provider'] provider_key = provider + '_id' email = appstruct['email'] if email != '' and email == user_info['email']: email_verified = True else: email_verified = False now = datetime.datetime.now(tz=utc) user_attrs = { provider_key: user_info[provider_key], 'screen_name': appstruct['screen_name'], 'first_name': appstruct['first_name'], 'last_name': appstruct['last_name'], 'email': email, 'email_verified': email_verified, 'date_joined': now, 'last_login': now, 'send_passwords_periodically': False, } if request.google_analytics.is_in_session(): allow_analytics = request.google_analytics.show_in_session() user_attrs[analytics.USER_ATTR] = allow_analytics request.google_analytics.clean_session() _id = request.db.users.insert(user_attrs) if not email_verified and email != '': evc = EmailVerificationCode() user = request.db.users.find_one({'_id': _id}) if evc.store(request.db, user): link = request.route_url('user_verify_email') evc.send(request, user, link) del request.session['user_info'] if 'next_url' in request.session: del request.session['next_url'] request.session['current_provider'] = provider return HTTPFound(location=next_url, headers=remember(request, str(_id))) elif 'cancel' in request.POST: del request.session['user_info'] if 'next_url' in request.session: del request.session['next_url'] return HTTPFound(location=next_url) return { 'form': form.render({ 'first_name': user_info.get('first_name', ''), 'last_name': user_info.get('last_name', ''), 'screen_name': user_info.get('screen_name', ''), 'email': user_info.get('email', ''), }), 'provider': user_info.get('provider', ''), 'email': user_info.get('email', ''), 'next_url': next_url, }