def do(self): token = self.request.get('token') new_password = self.request.get('new_password') # Check the token user = self.api.check_reset_password_token(token) if user is None: return {'success': True, 'data': 'invalid_token'} # Change the user's password. user.hashed_password = util.hash_password(new_password) user.put() # Clear existing tokens. self.api.clear_reset_password_tokens(user.id) # Alert the user that their password has been changed. mandrill.send( to_address=user.login_email, subject=config.change_password_subject, body=config.change_password_body, ) logging.info('api_handlers.ResetPasswordHandler') logging.info('sending an email to: {}'.format(user.login_email)) return {'success': True, 'data': 'changed'}
def post(self): body = json.loads(self.request.body) if 'organization' in body: organization = body['organization'] else: organization = 'N/A' message = u""" Message from {} <{}>: Organization: {} Message: {} ____ -- Sent via Contact Form -- """.format(body['name'], body['email'], organization, body['message']) # Send a message to the PERTS staff via @contact. mandrill.send( to_address='', subject='Inquiry from PERTS.net', body=mandrill.render_markdown(message), ) logging.info('api_handlers.SendContactEmailHandler') logging.info('sending an email to: ') return {'success': True, 'data': ''}
def get(self): md_id = self.request.get('md_id') md_email = self.request.get('md_email') mandrill.send( to_address=config.from_server_email_address, subject="Please Re-subscribe!", body=("🐇 Heyo,<br><br>Someone requested they be " "re-subscribed to the MSK mailing list. We have to do this " "manually. Here's their info.<br><br><b>Email:</b> {}<br>" "<b>ID:</b> {}<br><br>Thanks!!".format(md_email, md_id)), ) self.write('resubscribe.html', )
def send(self, emails): to_addresses = [] for email in emails: if self.we_are_spamming(email): # Do not send # This user has already recieved very recent emails # Debugging info logging.error("We are spamming {}:\n{}".format( email.to_address, email.to_dict())) elif email.to_address in to_addresses: # Do not send # We don't send multiple emails to an address per 'send' # Debugging info logging.error("We are spamming {}:\n{}".format( email.to_address, email.to_dict())) else: # Not spam! Let's send it to_addresses.append(email.to_address) # Debugging info logging.info(u"sending email: {}".format(email.to_dict())) logging.info(u"to: {}".format(email.to_address)) logging.info(u"subject: {}".format(email.subject)) if email.body: logging.info(u"body:\n{}".format(email.body)) mandrill.send( to_address=email.to_address, subject=email.subject, body=email.body, template_data=email.template_data, ) elif email.template: logging.info(u"template: {}".format(email.template)) mandrill.send( to_address=email.to_address, subject=email.subject, template=email.template, template_data=email.template_data, ) email.was_sent = True logging.info("""Sent successfully!""") # Note that we are attempting to send so that we don't keep attempting. email.was_attempted = True email.put()
def check_status_update(self, **kwargs): """Checks the status of an updated page to determine if the creator should be notified of approval or rejection. """ new_status = kwargs.get('status', None) now_reviewed = new_status in ('approved', 'rejected') changing = self.status != new_status if not now_reviewed or not changing: return authors = User.get_by_id(self.authors) or [] for author in authors: short_name = author.first_name or '' full_name = author.full_name if new_status == 'approved': # Send acceptance message # @todo: add name to subject line mandrill.send( to_address=author.email, subject="Your page upload is approved!", template="accepted_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'entity_name': self.title, 'entity_url': '/pages/' + self.short_uid, 'domain': 'https://{}'.format(os.environ['HOSTING_DOMAIN']), 'year': datetime.date.today().year, }, ) else: # Send rejection message mandrill.send( to_address=author.email, subject="We couldn't approve your page...", template="rejected_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'entity_name': self.title, 'entity_url': '/pages/' + self.short_uid, 'edit_url': '/pages/edit/' + self.short_uid, 'domain': 'https://{}'.format(os.environ['HOSTING_DOMAIN']), 'year': datetime.date.today().year, }, )
def mail_log(self): body = self.body + self.get_recent_log() subject = self.subject + self.get_error_summary() # Ignore the normal email queueing / spam-prevention system because the # addressees are devs, and they can customize the deluge themselves. for to in self.to_addresses: # We want to send this immediately, not in batches. mandrill.send( to_address=to, subject=subject, body=body, ) self.last_email = self.now return (subject, body)
def set_password(self, new_password): """May raise util.BadPassword.""" logging.info("Setting new password {} for user {}.".format( new_password, self)) self.hashed_password = util.hash_password(new_password) # Alert the user that their password has been changed. mandrill.send( to_address=self.email, subject="Your Mindset Kit password has been changed.", template="change_password.html", ) logging.info('User.set_password queueing an email to: {}'.format( self.email))
def post(self): address = self.request.get('address') private_key = self.request.get('private_key') metric = self.request.get('metric') if address and private_key and metric: private_key.encode('ascii') # handle unicode properly public_key = util.Keys().get_public(private_key) root = "http://survey.perts.net" take_link = root + '/take/' + metric + '?public_key=' + public_key results_link = root + '/results/' + private_key message = self.render_str('email.html', address=address, take_link=take_link, results_link=results_link, metric=metric) result = mandrill.send( to_address=address, subject="Mindset Meter Study Links", body=message, ) if result: logging.info('Email sent to ' + address + ' with the message ' + message) self.write_json({'ok': True}) else: message = "address, private_key, and metric are necessary to email a user" logging.error(message) self.write_json({'error': message})
def create(klass, **kwargs): feedback = super(klass, klass).create(**kwargs) # Email interested parties about new feedback :) mandrill.send(to_address=config.feedback_recipients, subject="Mindset Kit Feedback!", template="feedback_notification.html", template_data={'feedback': feedback, 'domain': os.environ['HOSTING_DOMAIN']}, ) logging.info('model.Feedback queueing an email to: {}' .format(config.feedback_recipients)) return feedback
def set_password(self, new_password): """May raise BadPassword.""" logging.info("Setting new password {} for user {}.".format( new_password, self)) self.hashed_password = self.hash_password(new_password) # Alert the user that their password has been changed. mandrill.send( to_address=self.email, subject="Your BELE Library password has been changed.", template="change_password.html", template_data={ 'domain': 'https://{}'.format(os.environ['HOSTING_DOMAIN']), 'year': datetime.date.today().year, }, )
def post(self): params = self.get_params() logging.info( "Sending reflection email to user with params: {}".format(params)) current_date = datetime.date.today().strftime("%B %d, %Y") # Send rejection message mandrill.send( to_address=params['to_address'], subject= "Belonging for Educators - What does belonging look like in my classroom?", template="reflection_email.html", template_data={ 'questions': params['questions'], 'reflection': params['reflection'], 'response_date': current_date, 'domain': os.environ['HOSTING_DOMAIN'] }, )
def check_status_update(self, **kwargs): """Checks the status of an updated practice to determine if the creator should be notified of approval or rejection Only triggered if pending set from True to False (prevents duplicates) """ if (self.pending is True and kwargs.get('pending') is False): creator = self.get_parent_user() short_name = creator.first_name if creator.first_name else '' full_name = creator.full_name if (self.listed is False and kwargs.get('listed') is True): # Send acceptance message # @todo: add name to subject line mandrill.send( to_address=creator.email, subject="Your practice upload is approved!", template="accepted_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'practice_name': self.name, 'practice_url': '/practices/' + self.short_uid, 'domain': os.environ['HOSTING_DOMAIN'] }, ) else: # Send rejection message mandrill.send( to_address=creator.email, subject="We couldn't approve your practice...", template="rejected_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'practice_name': self.name, 'practice_url': '/practices/' + self.short_uid, 'edit_url': '/practices/edit/' + self.short_uid, 'domain': os.environ['HOSTING_DOMAIN'] }, )
def send_reminders(self): """Check for teachers that need reminders and add them to the email queue. See id_model@Reminder for details. """ # already sent? # check if today's reminders have already been sent # if so, return. today = Reminder.get_pst_date() already_queued = self.api.get('Reminder', {'pst_date': today.isoformat()}) if already_queued: return {'message': 'Reminders already queued to email'} # get reminders reminders = self.get_reminders_by_date(today.isoformat()) # send a summary to perts admins self._send_reminder_summary(reminders) # queue emails for r in reminders: to = r['to_address'] or config.to_dev_team_email_address mandrill.send( to_address=to, subject=r['subject'], body=r['body'], ) # save as already sent todays_reminder = Reminder.create(pst_date=today.isoformat()) todays_reminder.put() return { 'message': 'Reminders sent', 'reminders': reminders, 'date': today.isoformat() }
def create(klass, **kwargs): """Sends email to interested parties. """ practice = super(klass, klass).create(**kwargs) # Email interested parties that a practice has been uploaded. mandrill.send( to_address=config.practice_upload_recipients, subject="Practice Uploaded to Mindset Kit!", template="practice_upload_notification.html", template_data={ 'user': practice.get_parent_user(), 'practice': practice, 'domain': os.environ['HOSTING_DOMAIN'] }, ) logging.info('model.Practice queueing an email to: {}'.format( config.practice_upload_recipients)) return practice
def _send_reminder_summary(self, reminders): # send summary to perts team body = """ To whom it may concern, Lots of reminders today (or not)! The full list of emails is below. Recreationally Yours,<br /> Yellowstone ---- {} """.format(''.join([self._reminder_summary(r) for r in reminders])) mandrill.send( to_address=config.reminder_summary_recipients, subject="{} Reminder Emails sent today".format(len(reminders)), body=mandrill.render_markdown(body), )
def post(self): # Reply to is optional reply_to = self.request.get('reply_to') logging.error('reply to is : {}'.format(reply_to)) message = self.request.get('message') to_address = config.from_server_email_address message = self.render_str( 'email_feedback.html', reply_to=reply_to, message=message, ) mandrill.send( to_address=to_address, subject="Feedback on the mindset meter", body=message, ) logging.info('Feedback Email sent to ' + to_address + ' with the message ' + message) self.write_json({'ok': True})
def do(self): new_password = self.request.get('new_password') or None auth_response = self.authenticate( auth_type='direct', username=self.request.get('username'), password=self.request.get('current_password')) if auth_response is False or auth_response is None: return {'success': True, 'data': 'invalid_credentials'} user = auth_response user.hashed_password = util.hash_password(new_password) user.put() # Alert the user that their password has been changed. mandrill.send(to_address=user.login_email, subject=config.change_password_subject, body=mandrill.render_markdown( config.change_password_body)) logging.info('api_handlers.ChangePasswordHandler') logging.info('sending an email to: {}'.format(user.login_email)) return {'success': True, 'data': 'changed'}
def get(self): # ensure this email address belongs to a known user email = self.request.get('email').lower() # Look up users by auth_id because that's how they log in; # there are other kinds of auth type ('google', 'facebook') that we # wouldn't want returned. user = User.query(User.auth_id == 'own:' + email).get() if user: # then this email address is valid; proceed with send # deactivate any existing reset tokens ResetPasswordToken.clear_all_tokens_for_user(user) # create a new token for them new_token = ResetPasswordToken.create(user_id=user.uid) new_token.put() mandrill.send( to_address=email, subject="Password reset requested.", template="forgot_password.html", template_data={ 'token': new_token.token(), 'domain': os.environ['HOSTING_DOMAIN'] }, ) logging.info( 'ForgotPassword queueing an email to: {}'.format(email)) self.write('sent') else: logging.info( 'ForgotPassword invalid email address: {}'.format(email)) self.write('not_sent')
def do(self): # ensure this email address belongs to a known user email = self.request.get('email').lower() # Look up users by auth_id because that's how they log in; # there are other kinds of auth type ('google', 'public') that we # wouldn't want returned. result = self.internal_api.get('user', {'auth_id': 'direct_' + email}) if len(result) is 1 and result[0].is_test is False: # then this email address is valid; proceed with send user = result[0] # deactivate any existing reset tokens self.api.clear_reset_password_tokens(user.id) # create a new token for them new_token = ResetPasswordToken.create(user=user.id) new_token.put() # and email them about it link = '/reset_password/' + new_token.token() mandrill.send( to_address=email, subject=config.forgot_password_subject, body=mandrill.render_markdown( config.forgot_password_body.format(link)), ) logging.info( 'ForgotPasswordHandler sending an email to: {}'.format(email)) return {'success': True, 'data': 'sent'} else: logging.info( 'ForgotPasswordHandler invalid email: {}'.format(email)) return {'success': True, 'data': 'not_sent'}
def register(self, auth_type, first_name=None, last_name=None, email=None, password=None, facebook_access_token=None, should_subscribe=True): """Logs in users and registers them if they're new. Returns: User entity registration successful 'credentials_missing' looked for credentials but didn't find any of the appropriate kind. 'email_exists:[auth_type]' a user with that email already exists, with the specified auth type. In rare cases, we may know the email exists already, but not be able to query for it (gotta love eventual consistency), in which case the auth type will be 'unknown'. """ if auth_type not in config.auth_types: raise Exception("Bad auth_type: {}.".format(auth_type)) if auth_type == 'own': if None in [email, password]: return 'credentials_missing' creation_kwargs = { 'first_name': first_name, 'last_name': last_name, 'email': email, 'auth_id': User.get_auth_id(auth_type, email), 'hashed_password': util.hash_password(password), } # These are the third party identity providers we currently know # how to handle. See util_handlers.BaseHandler.get_third_party_auth(). elif auth_type in ['google', 'facebook']: creation_kwargs, error = self.get_third_party_auth( auth_type, facebook_access_token) if error: return error elif not creation_kwargs: return 'credentials_missing' # Make it easy for devs to become admins. if auth_type == 'google' and app_engine_users.is_current_user_admin(): creation_kwargs['is_admin'] = True # Pass through subscription parameter # Currently defaults true (planning to change later) creation_kwargs['should_subscribe'] = should_subscribe email = creation_kwargs['email'] # Try to register the user. If a user with the same email already # exists, we'll get a DuplicateUser exception. try: user = User.create(**creation_kwargs) except DuplicateUser: # Attempt to retrieve the user entity which already exists. user = User.query(User.email == email).get() logging.info('Exception case with UserRegister') return 'email_exists:' + (user.auth_type if user else 'unknown') logging.info("BaseHandler created user: {}".format(user)) # Registration succeeded; set them up. user.put() self.log_in(user) short_name = user.first_name if user.first_name else '' if user.first_name and user.last_name: full_name = user.first_name + ' ' + user.last_name else: full_name = user.username # Send them an email to confirm that they have registered. mandrill.send( to_address=email, subject="Welcome to Mindset Kit", template="signup_confirmation.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'user': user, 'domain': os.environ['HOSTING_DOMAIN'] }, ) logging.info(u'BaseHandler.register()') logging.info(u"Sending an email to: {}.".format(email)) return user
def do(self): params = util.get_request_dictionary(self.request) # Check that the requested program allows public registration. program = self.internal_api.get_from_path('program', params['program']) program_config = Program.get_app_configuration(program.abbreviation) if not getattr(program_config, 'public_registration', False): user = self.get_current_user() logging.error("User {} attempted public registration on program " "{}, but it isn't allowed.".format( user, program.abbreviation)) # Create a school admin based on the user's information. # They get the special auth_type 'public', preventing them from # appearing in sign-in queries or reset-password queries. # However, the user entity will still hold data and be associated with # the created schools. params['user']['user_type'] = 'school_admin' params['user']['auth_id'] = 'public_' + params['user']['login_email'] school_admin = self.internal_api.create('user', params['user']) # If the school already exists, use the id to find the right cohort. if 'existing_school_id' in params: s_id = params['existing_school_id'] cohort_list = self.internal_api.get('cohort', {'assc_school_list': s_id}) if len(cohort_list) is not 1: raise Exception("Problem with public registration: found {} " "cohorts for school {}".format( len(cohort_list), s_id)) cohort = cohort_list[0] school = None classroom = None activities = None # Otherwise, create a school, cohort, and classroom based on the # provided data. else: school = self.internal_api.create('school', params['new_school']) cohort = self.internal_api.create( 'cohort', { 'name': params['new_school']['name'], 'school': school.id, 'program': program.id, 'promised_students': params['promised_students'], }) classroom = self.internal_api.create( 'classroom', { 'name': 'All Students', 'program': program.id, 'cohort': cohort.id, 'user': school_admin.id, }) activities = self.internal_api.init_activities( 'student', school_admin.id, program.id, cohort_id=cohort.id, classroom_id=classroom.id) # Whether the cohort is new or exisiting, make the new user owner of it self.internal_api.associate('set_owner', school_admin, cohort) # Send an email to the user with all the information they need to # participate. mandrill.send(to_address=school_admin.login_email, subject=program_config.registration_email_subject, body=mandrill.render_markdown( program_config.registration_email_body), template_data={ 'email': school_admin.login_email, 'cohort_id': cohort.id }) logging.info('api_handlers.CreatePublicSchoolHandler') logging.info('sending an email to: {}'.format( school_admin.login_email)) return { 'success': True, 'data': { 'user': school_admin.to_dict(), 'program': program.to_dict(), 'school': school.to_dict() if school else None, 'cohort': cohort.to_dict(), 'classroom': classroom.to_dict() if classroom else None, 'activities': ([a.to_dict() for a in activities] if activities else None), } }
def create(klass, **kwargs): if ('practice_id' not in kwargs) and ('lesson_id' not in kwargs) and ( 'page_id' not in kwargs): raise Exception( 'Must specify a practice, lesson, or page when ' 'creating a comment. Received kwargs: {}'.format(kwargs)) comment = super(klass, klass).create(**kwargs) # For email notifications content_url = '/' content = None if comment.page_id: page = Page.get_by_id(comment.page_id) if page is not None: page.num_comments += 1 page.put() # For email content = page content_url = '/pages/{}'.format(page.short_uid) # Send email to creator author_ids = page.authors commenter = comment.get_parent_user() authors = User.get_by_id(author_ids) or [] for author in authors: # logic to not email yourself... if author != commenter.email: short_name = author.first_name or '' full_name = author.full_name commenter_image_url = commenter.profile_image # Uses Email model to queue email and prevent spam email = Email.create( to_address=author.email, subject= "Someone commented on your BELE Library upload", template="comment_creator_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'commenter_name': commenter.full_name, 'commenter_image_url': commenter_image_url, 'content_name': content.title, 'comment_body': comment.body, 'content_url': content_url, 'domain': 'https://{}'.format( os.environ['HOSTING_DOMAIN']), 'year': datetime.date.today().year, }, ) email.put() # Send email to any users @replied to usernames = re.search('\@(\w+)', comment.body) if usernames is not None: username = usernames.group(0).split('@')[1] # Fetch user from username and send email message replied_to = User.query( User.username == username).fetch(1) if replied_to: replied_to = replied_to[0] short_name = replied_to.first_name or '' full_name = replied_to.full_name commenter_image_url = commenter.profile_image # Uses Email model to queue email and prevent spam email = Email.create( to_address=replied_to.email, subject= "Someone replied to you on BELE Library", template="comment_reply_notification.html", template_data={ 'short_name': short_name, 'full_name': full_name, 'commenter_name': commenter.full_name, 'commenter_image_url': commenter_image_url, 'content_name': content.title, 'comment_body': comment.body, 'content_url': content_url, 'domain': 'https://{}'.format( os.environ['HOSTING_DOMAIN']), 'year': datetime.date.today().year, }, ) email.put() # Email interested team members that a comment has been created mandrill.send( to_address=config.comment_recipients, subject="New Comment on BELE Library!", template="comment_notification.html", template_data={ 'comment': comment, 'user': comment.get_parent_user(), 'content_name': content.title, 'content_url': content_url, 'domain': 'https://{}'.format(os.environ['HOSTING_DOMAIN']) }, ) logging.info('model.Comment queueing an email to: {}'.format( config.comment_recipients)) return comment
def register(self, program_id, auth_type, username=None, password=None, cohort_id=None): """Logs in users and registers them if they're new. Raises exceptions when the system appears to be broken (e.g. redundant users). Returns tuple( user - mixed, False when given non-sensical data by users (e.g. registering an existing email under a new auth type) or matching user entity, user_is_new - bool, True if user was newly registered ) """ user_is_new = False if auth_type not in config.allowed_auth_types: raise Exception("Bad auth_type: {}.".format(auth_type)) if auth_type == 'direct': if None in [username, password]: raise Exception("Credentials incomplete.") creation_kwargs = { 'login_email': username, 'auth_id': 'direct_' + username, 'plaintext_password': password, # it WILL be hashed later } # These are the third party identity providers we currently know # how to handle. See util_handlers.BaseHandler.get_third_party_auth(). elif auth_type in ['google']: # may raise CredentialsMissing creation_kwargs = self.get_third_party_auth(auth_type) # Check that the user hasn't already registered in two ways. # 1) If the email matches but the auth type is different, we reject # the request to register so the UI can warn the user. email_match_params = {'login_email': creation_kwargs['login_email']} email_matches = self.internal_api.get('user', email_match_params) for user in email_matches: if user.auth_type() != auth_type: user = False return (user, user_is_new) # 2) If the auth_id matches, they tried to register when they should # have logged in. Just log them in. auth_match_params = {'auth_id': creation_kwargs['auth_id']} auth_matches = self.internal_api.get('user', auth_match_params) if len(auth_matches) == 1: # they already have an account user = auth_matches[0] # This user hasn't already registered. Register them. elif len(auth_matches) == 0: user_is_new = True # Having collected the user's information, build a user object. creation_kwargs['user_type'] = 'teacher' # Include the program id as an initial relationship (see # config.optional_associations). creation_kwargs['program'] = program_id user = self.api.create('user', creation_kwargs) # Refresh the api with the user's new privileges. self.api = Api(user) # Send them an email to confirm that they have registered. # The email text is hard coded in the program app. program = self.api.get_from_path('program', program_id) program_conf = Program.get_app_configuration(program.abbreviation) mandrill.send( to_address=creation_kwargs['login_email'], subject=program_conf.registration_email_subject, body=mandrill.render_markdown( program_conf.registration_email_body), template_data={'email': creation_kwargs['login_email'], 'cohort_id': cohort_id} ) logging.info('url_handlers.BaseHandler.register()') logging.info('sending an email to: {}' .format(creation_kwargs['login_email'])) # There's a big problem. else: logging.error("Two matching users! {}".format(auth_match_params)) # Sort the users by modified time, so we take the most recently # modified one. auth_matches = sorted( auth_matches, key=lambda u: u.modified, reverse=True) user = auth_matches[0] # Sign in the user. self.session['user'] = user.id return (user, user_is_new)