def redirect_to_twitter(twitter_handle): """Redirect GET requests for /@TwitterHandle/ to respective the OSF user account if it associated with an active account :param uid: uid for requested User :return: Redirect to User's Twitter account page """ try: user = User.find_one(Q('social.twitter', 'iexact', twitter_handle)) except NoResultsFound: raise HTTPError(http.NOT_FOUND, data={ 'message_short': 'User Not Found', 'message_long': 'There is no active user associated with the Twitter handle: {0}.'.format(twitter_handle) }) except MultipleResultsFound: users = User.find(Q('social.twitter', 'iexact', twitter_handle)) message_long = 'There are multiple OSF accounts associated with the ' \ 'Twitter handle: <strong>{0}</strong>. <br /> Please ' \ 'select from the accounts below. <br /><ul>'.format(twitter_handle) for user in users: message_long += '<li><a href="{0}">{1}</a></li>'.format(user.url, user.fullname) message_long += '</ul>' raise HTTPError(http.MULTIPLE_CHOICES, data={ 'message_short': 'Multiple Users Found', 'message_long': message_long }) return redirect(user.url)
def add_conference(endpoint, name, active, admins, info_url=None, logo_url=None, public_projects=None): try: admin_users = [ User.find_one(Q('username', 'iexact', admin)) for admin in admins ] except ModularOdmException: raise RuntimeError( "Admin must be a current registered user on the OSF.") conf = Conference(endpoint=endpoint, name=name, active=active, info_url=info_url, logo_url=logo_url, admins=admin_users) try: conf.save() except ModularOdmException: raise RuntimeError("Conference already exists.")
def redirect_to_twitter(twitter_handle): """Redirect GET requests for /@TwitterHandle/ to respective the OSF user account if it associated with an active account :param uid: uid for requested User :return: Redirect to User's Twitter account page """ try: user = User.find_one(Q('social.twitter', 'iexact', twitter_handle)) except NoResultsFound: raise HTTPError( http.NOT_FOUND, data={ 'message_short': 'User Not Found', 'message_long': 'There is no active user associated with the Twitter handle: {0}.' .format(twitter_handle) }) except MultipleResultsFound: users = User.find(Q('social.twitter', 'iexact', twitter_handle)) message_long = 'There are multiple OSF accounts associated with the ' \ 'Twitter handle: <strong>{0}</strong>. <br /> Please ' \ 'select from the accounts below. <br /><ul>'.format(twitter_handle) for user in users: message_long += '<li><a href="{0}">{1}</a></li>'.format( user.url, user.fullname) message_long += '</ul>' raise HTTPError(http.MULTIPLE_CHOICES, data={ 'message_short': 'Multiple Users Found', 'message_long': message_long }) return redirect(user.url)
def sync_data_from_mailchimp(**kwargs): """Endpoint that the mailchimp webhook sends its data to""" key = request.args.get('key') if key == settings.MAILCHIMP_WEBHOOK_SECRET_KEY: r = request action = r.values['type'] list_name = mailchimp_utils.get_list_name_from_id( list_id=r.values['data[list_id]']) username = r.values['data[email]'] try: user = User.find_one(Q('username', 'eq', username)) except NoResultsFound: sentry.log_exception() sentry.log_message("A user with this username does not exist.") raise HTTPError( 404, data=dict( message_short='User not found', message_long='A user with this username does not exist')) if action == 'unsubscribe': user.mailchimp_mailing_lists[list_name] = False user.save() elif action == 'subscribe': user.mailchimp_mailing_lists[list_name] = True user.save() else: # TODO: get tests to pass with sentry logging # sentry.log_exception() # sentry.log_message("Unauthorized request to the OSF.") raise HTTPError(http.UNAUTHORIZED)
def send_confirm_email(user, email): """Sends a confirmation email to `user` to a given email. :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None campaign = campaigns.campaign_for_user(user) # Choose the appropriate email template to use if merge_target: mail_template = mails.CONFIRM_MERGE elif campaign: mail_template = campaigns.email_template_for_campaign(campaign) else: mail_template = mails.CONFIRM_EMAIL mails.send_mail( email, mail_template, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, )
def sync_data_from_mailchimp(**kwargs): """Endpoint that the mailchimp webhook sends its data to""" key = request.args.get("key") if key == settings.MAILCHIMP_WEBHOOK_SECRET_KEY: r = request action = r.values["type"] list_name = mailchimp_utils.get_list_name_from_id(list_id=r.values["data[list_id]"]) username = r.values["data[email]"] try: user = User.find_one(Q("username", "eq", username)) except NoResultsFound: sentry.log_exception() sentry.log_message("A user with this username does not exist.") raise HTTPError( 404, data=dict(message_short="User not found", message_long="A user with this username does not exist") ) if action == "unsubscribe": user.mailchimp_mailing_lists[list_name] = False user.save() elif action == "subscribe": user.mailchimp_mailing_lists[list_name] = True user.save() else: # TODO: get tests to pass with sentry logging # sentry.log_exception() # sentry.log_message("Unauthorized request to the OSF.") raise HTTPError(http.UNAUTHORIZED)
def redirect_to_twitter(twitter_handle): """Redirect GET requests for /@TwitterHandle/ to respective the OSF user account if it associated with an active account :param uid: uid for requested User :return: Redirect to User's Twitter account page """ try: user = User.find_one(Q("social.twitter", "iexact", twitter_handle)) except NoResultsFound: raise HTTPError( http.NOT_FOUND, data={ "message_short": "User Not Found", "message_long": "There is no active user associated with the Twitter handle: {0}.".format( twitter_handle ), }, ) except MultipleResultsFound: users = User.find(Q("social.twitter", "iexact", twitter_handle)) message_long = ( "There are multiple OSF accounts associated with the " "Twitter handle: <strong>{0}</strong>. <br /> Please " "select from the accounts below. <br /><ul>".format(markupsafe.escape(twitter_handle)) ) for user in users: message_long += '<li><a href="{0}">{1}</a></li>'.format(user.url, markupsafe.escape(user.fullname)) message_long += "</ul>" raise HTTPError( http.MULTIPLE_CHOICES, data={"message_short": "Multiple Users Found", "message_long": message_long} ) return redirect(user.url)
def auth_email_logout(token, user): """ When a user is adding an email or merging an account, add the email to the user and log them out. """ redirect_url = cas.get_logout_url(service_url=cas.get_login_url(service_url=web_url_for('index', _absolute=True))) try: unconfirmed_email = user.get_unconfirmed_email_for_token(token) except InvalidTokenError: raise HTTPError(http.BAD_REQUEST, data={ 'message_short': 'Bad token', 'message_long': 'The provided token is invalid.' }) except ExpiredTokenError: status.push_status_message('The private link you used is expired.') raise HTTPError(http.BAD_REQUEST, data={ 'message_short': 'Expired link', 'message_long': 'The private link you used is expired.' }) try: user_merge = User.find_one(Q('emails', 'eq', unconfirmed_email)) except NoResultsFound: user_merge = False if user_merge: remove_sessions_for_user(user_merge) user.email_verifications[token]['confirmed'] = True user.save() remove_sessions_for_user(user) resp = redirect(redirect_url) resp.delete_cookie(settings.COOKIE_NAME, domain=settings.OSF_COOKIE_DOMAIN) return resp
def send_confirm_email(user, email): """Sends a confirmation email to `user` to a given email. :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None mails.send_mail( email, mails.CONFIRM_MERGE if merge_target else mails.CONFIRM_EMAIL, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, )
def send_confirm_email(user, email, renew=False, external_id_provider=None, external_id=None, destination=None): """ Sends `user` a confirmation to the given `email`. :param user: the user :param email: the email :param renew: refresh the token :param external_id_provider: user's external id provider :param external_id: user's external id :param destination: the destination page to redirect after confirmation :return: :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, renew=renew, external_id_provider=external_id_provider, destination=destination ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None campaign = campaigns.campaign_for_user(user) # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email. if external_id_provider and external_id: # first time login through external identity provider if user.external_identity[external_id_provider][external_id] == 'CREATE': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_CREATE elif user.external_identity[external_id_provider][external_id] == 'LINK': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_LINK elif merge_target: # merge account mail_template = mails.CONFIRM_MERGE confirmation_url = '{}?logout=1'.format(confirmation_url) elif user.is_active: # add email mail_template = mails.CONFIRM_EMAIL confirmation_url = '{}?logout=1'.format(confirmation_url) elif campaign: # campaign # TODO: In the future, we may want to make confirmation email configurable as well (send new user to # appropriate landing page or with redirect after) mail_template = campaigns.email_template_for_campaign(campaign) else: # account creation mail_template = mails.INITIAL_CONFIRM_EMAIL mails.send_mail( email, mail_template, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, external_id_provider=external_id_provider, )
def test_creates_user(self): username = '******' assert_equal(User.find(Q('username', 'eq', username)).count(), 0) with capture_signals() as mock_signals: res = self.app.post(self.url, self.build_payload(username)) assert_equal(res.status_code, 204) assert_equal(mock_signals.signals_sent(), set([signals.user_confirmed])) user = User.find_one(Q('username', 'eq', username)) assert_true(user) assert_in(self.institution, user.affiliated_institutions)
def merge_user_post(auth, **kwargs): '''View for merging an account. Takes either JSON or form data. Request data should include a "merged_username" and "merged_password" properties for the account to be merged in. ''' master = auth.user if request.json: merged_username = request.json.get('merged_username') merged_password = request.json.get('merged_password') else: form = MergeAccountForm(request.form) if not form.validate(): forms.push_errors_to_status(form.errors) return merge_user_get(**kwargs) master_password = form.user_password.data if not master.check_password(master_password): status.push_status_message( 'Could not authenticate. Please check your username and password.', trust=False) return merge_user_get(**kwargs) merged_username = form.merged_username.data merged_password = form.merged_password.data try: merged_user = User.find_one(Q('username', 'eq', merged_username)) except NoResultsFound: status.push_status_message( 'Could not find that user. Please check the username and password.', trust=False) return merge_user_get(**kwargs) if master and merged_user: if merged_user.check_password(merged_password): master.merge_user(merged_user) master.save() if request.form: status.push_status_message( 'Successfully merged {0} with this account'.format( merged_username), kind='success', trust=False) return redirect('/settings/') return {'status': 'success'} else: status.push_status_message( 'Could not find that user. Please check the username and password.', trust=False) return merge_user_get(**kwargs) else: raise HTTPError(http.BAD_REQUEST)
def send_confirm_email(user, email, external_id_provider=None, external_id=None): """ Sends a confirmation email to `user` to a given email. :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, external_id_provider=external_id_provider ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None campaign = campaigns.campaign_for_user(user) # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email. if external_id_provider and external_id: # first time login through external identity provider if user.external_identity[external_id_provider][external_id] == 'CREATE': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_CREATE elif user.external_identity[external_id_provider][external_id] == 'LINK': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_LINK elif merge_target: # merge account mail_template = mails.CONFIRM_MERGE confirmation_url = '{}?logout=1'.format(confirmation_url) elif user.is_active: # add email mail_template = mails.CONFIRM_EMAIL confirmation_url = '{}?logout=1'.format(confirmation_url) elif campaign: # campaign # TODO: In the future, we may want to make confirmation email configurable as well (send new user to # appropriate landing page or with redirect after) mail_template = campaigns.email_template_for_campaign(campaign) else: # account creation mail_template = mails.INITIAL_CONFIRM_EMAIL mails.send_mail( email, mail_template, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, external_id_provider=external_id_provider, )
def merge_user_post(**kwargs): '''View for merging an account. Takes either JSON or form data. Request data should include a "merged_username" and "merged_password" properties for the account to be merged in. ''' master = get_current_user() if request.json: merged_username = request.json.get("merged_username") merged_password = request.json.get("merged_password") else: form = MergeAccountForm(request.form) if not form.validate(): forms.push_errors_to_status(form.errors) return merge_user_get(**kwargs) master_password = form.user_password.data if not master.check_password(master_password): status.push_status_message( "Could not authenticate. Please check your username and password." ) return merge_user_get(**kwargs) merged_username = form.merged_username.data merged_password = form.merged_password.data try: merged_user = User.find_one(Q("username", "eq", merged_username)) except NoResultsFound: status.push_status_message( "Could not find that user. Please check the username and password." ) return merge_user_get(**kwargs) if master and merged_user: if merged_user.check_password(merged_password): master.merge_user(merged_user) master.save() if request.form: status.push_status_message( "Successfully merged {0} with this account".format( merged_username)) return redirect("/settings/") return {"status": "success"} else: status.push_status_message( "Could not find that user. Please check the username and password." ) return merge_user_get(**kwargs) else: raise HTTPError(http.BAD_REQUEST)
def get_or_create_user(fullname, address, is_spam): """Get or create user by email address. :param str fullname: User full name :param str address: User email address :param bool is_spam: User flagged as potential spam :return: Tuple of (user, created) """ try: user = User.find_one(Q('username', 'iexact', address)) return user, False except ModularOdmException: password = str(uuid.uuid4()) user = User.create_confirmed(address, password, fullname) user.verification_key = security.random_string(20) if is_spam: user.system_tags.append('is_spam') user.save() return user, True
def merge_user_post(auth, **kwargs): '''View for merging an account. Takes either JSON or form data. Request data should include a "merged_username" and "merged_password" properties for the account to be merged in. ''' master = auth.user if request.json: merged_username = request.json.get("merged_username") merged_password = request.json.get("merged_password") else: form = MergeAccountForm(request.form) if not form.validate(): forms.push_errors_to_status(form.errors) return merge_user_get(**kwargs) master_password = form.user_password.data if not master.check_password(master_password): status.push_status_message("Could not authenticate. Please check your username and password.", trust=False) return merge_user_get(**kwargs) merged_username = form.merged_username.data merged_password = form.merged_password.data try: merged_user = User.find_one(Q("username", "eq", merged_username)) except NoResultsFound: status.push_status_message("Could not find that user. Please check the username and password.", trust=False) return merge_user_get(**kwargs) if master and merged_user: if merged_user.check_password(merged_password): master.merge_user(merged_user) master.save() if request.form: status.push_status_message("Successfully merged {0} with this account".format(merged_username), kind='success', trust=False) return redirect("/settings/") return {"status": "success"} else: status.push_status_message("Could not find that user. Please check the username and password.", trust=False) return merge_user_get(**kwargs) else: raise HTTPError(http.BAD_REQUEST)
def send_confirm_email(user, email): """ Sends a confirmation email to `user` to a given email. :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None campaign = campaigns.campaign_for_user(user) # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email. if merge_target: # merge account mail_template = mails.CONFIRM_MERGE confirmation_url = '{}?logout=1'.format(confirmation_url) elif user.is_active: # add email mail_template = mails.CONFIRM_EMAIL confirmation_url = '{}?logout=1'.format(confirmation_url) elif campaign: # campaign mail_template = campaigns.email_template_for_campaign(campaign) else: # account creation mail_template = mails.INITIAL_CONFIRM_EMAIL mails.send_mail( email, mail_template, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, )
def add_conference(endpoint, name, active, admins, info_url=None, logo_url=None, public_projects=None): try: admin_users = [ User.find_one(Q('username', 'iexact', admin)) for admin in admins ] except ModularOdmException: raise RuntimeError("Admin must be a current registered user on the OSF.") conf = Conference( endpoint=endpoint, name=name, active=active, info_url=info_url, logo_url=logo_url, admins=admin_users ) try: conf.save() except ModularOdmException: raise RuntimeError("Conference already exists.")
def send_confirm_email(user, email, renew=False, external_id_provider=None, external_id=None, destination=None): """ Sends `user` a confirmation to the given `email`. :param user: the user :param email: the email :param renew: refresh the token :param external_id_provider: user's external id provider :param external_id: user's external id :param destination: the destination page to redirect after confirmation :return: :raises: KeyError if user does not have a confirmation token for the given email. """ confirmation_url = user.get_confirmation_url( email, external=True, force=True, renew=renew, external_id_provider=external_id_provider, destination=destination ) try: merge_target = User.find_one(Q('emails', 'eq', email)) except NoResultsFound: merge_target = None campaign = campaigns.campaign_for_user(user) branded_preprints_provider = None # Choose the appropriate email template to use and add existing_user flag if a merge or adding an email. if external_id_provider and external_id: # First time login through external identity provider, link or create an OSF account confirmation if user.external_identity[external_id_provider][external_id] == 'CREATE': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_CREATE elif user.external_identity[external_id_provider][external_id] == 'LINK': mail_template = mails.EXTERNAL_LOGIN_CONFIRM_EMAIL_LINK elif merge_target: # Merge account confirmation mail_template = mails.CONFIRM_MERGE confirmation_url = '{}?logout=1'.format(confirmation_url) elif user.is_active: # Add email confirmation mail_template = mails.CONFIRM_EMAIL confirmation_url = '{}?logout=1'.format(confirmation_url) elif campaign: # Account creation confirmation: from campaign mail_template = campaigns.email_template_for_campaign(campaign) if campaigns.is_proxy_login(campaign) and campaigns.get_service_provider(campaign) != 'OSF': branded_preprints_provider = campaigns.get_service_provider(campaign) else: # Account creation confirmation: from OSF mail_template = mails.INITIAL_CONFIRM_EMAIL mails.send_mail( email, mail_template, 'plain', user=user, confirmation_url=confirmation_url, email=email, merge_target=merge_target, external_id_provider=external_id_provider, branded_preprints_provider=branded_preprints_provider )
def find_by_email(email): try: return User.find_one(Q('username', 'iexact', email)) except ModularOdmException: return None