def handle_similar_users(message): """ Save the similar users data to the DB """ if current_app.config['TESTING']: return user_count, avg_similar_users, error = import_user_similarities( message['data']) if error: send_mail( subject='Similar User data failed to be calculated', text=render_template( 'emails/similar_users_failed_notification.txt', error=error), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@' + current_app.config['MAIL_FROM_DOMAIN'], ) else: send_mail( subject='Similar User data has been calculated', text=render_template( 'emails/similar_users_updated_notification.txt', user_count=str(user_count), avg_similar_users="%.1f" % avg_similar_users), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@' + current_app.config['MAIL_FROM_DOMAIN'], )
def test_send_email(self, mock_smtp): app = flask.CustomFlask(__name__) app.config['SMTP_SERVER'] = 'localhost' app.config['SMTP_PORT'] = 25 with app.app_context(): from_address = '*****@*****.**' recipients = [ '*****@*****.**', '*****@*****.**' ] text = 'It is a test mail' from_name = 'ListenBrainz' subject = 'ListenBrainz Spotify Importer Error' boundary = '===============2220963697271485568==' message = MIMEMultipart(boundary=boundary) message[ 'To'] = "[email protected], [email protected]" message['Subject'] = subject message['From'] = '%s <%s>' % (from_name, from_address) message.attach(MIMEText(text, _charset='utf-8')) mail.send_mail(subject='ListenBrainz Spotify Importer Error', text='It is a test mail', recipients=recipients, attachments=None, from_name='ListenBrainz', from_addr='*****@*****.**', boundary=boundary) mock_smtp.return_value.sendmail.assert_called_once_with( from_address, recipients, message.as_string())
def notify_user_stats_update(stat_type): if not current_app.config['TESTING']: send_mail( subject="New user stats are being written into the DB - ListenBrainz", text=render_template('emails/user_stats_notification.txt', now=str(datetime.utcnow()), stat_type=stat_type), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'] )
def send_dump_creation_notification(dump_name, dump_type): if not current_app.config['TESTING']: dump_link = 'http://ftp.musicbrainz.org/pub/musicbrainz/listenbrainz/{}/{}'.format(dump_type, dump_name) send_mail( subject="ListenBrainz dump created - {}".format(dump_name), text=render_template('emails/data_dump_created_notification.txt', dump_name=dump_name, dump_link=dump_link), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'] )
def test_send_email_string_recipients(self): app = flask.CustomFlask(__name__) with app.app_context(): with self.assertRaises(ValueError) as err: mail.send_mail(subject='ListenBrainz Spotify Importer Error', text='It is a test mail', recipients='*****@*****.**', attachments=None, from_name='ListenBrainz', from_addr='*****@*****.**', boundary='b') assert str(err.exception ) == "recipients must be a list of email addresses"
def test_send_email_missing_config(self): app = flask.CustomFlask(__name__) with app.app_context(): with self.assertRaises(ValueError) as err: mail.send_mail(subject='ListenBrainz Spotify Importer Error', text='It is a test mail', recipients=[], attachments=None, from_name='ListenBrainz', from_addr='*****@*****.**', boundary='b') assert "Flask current_app requires config items" in str( err.exception)
def notify_cf_recording_recommendations_update(): """ Send an email to notify recommendations are being written into db. """ if current_app.config['TESTING']: return send_mail( subject="Recommendations being written into the DB - ListenBrainz", text=render_template( 'emails/cf_recording_recommendation_notification.txt', now=str(datetime.utcnow())), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@' + current_app.config['MAIL_FROM_DOMAIN'])
def notify_mapping_import(data): """ Send an email after msid mbid mapping has been successfully imported into the cluster. """ if current_app.config['TESTING']: return mapping_name = data['imported_mapping'] import_completion_time = data['time'] send_mail( subject='MSID MBID mapping has been imported into the Spark cluster', text=render_template('emails/mapping_import_notification.txt', mapping_name=mapping_name, time=import_completion_time), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def handle_model(data): """ Send an email after trained data (model) has been successfully uploaded to HDFS. """ if current_app.config['TESTING']: return model_upload_time = data['model_upload_time'] model_creation_time = data['total_time'] send_mail( subject='Model created and successfully uploaded to HDFS', text=render_template('emails/cf_recording_model_upload_notification.txt', time_to_upload=model_upload_time, total_time=model_creation_time), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def handle_dump_imported(data): """ Process the response that the cluster sends after importing a new dump We don't really need to _do_ anything, just send an email over for observability. """ if current_app.config['TESTING']: return dump_name = data['imported_dump'] import_completion_time = data['time'] send_mail( subject='A {} has been imported into the Spark cluster'.format(' '.join(data['type'].split('_')[1:])), text=render_template('emails/dump_import_notification.txt', dump_name=", ".join(dump_name), time=import_completion_time), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def notify_error(musicbrainz_row_id, error): """ Notifies specified user via email about error during Spotify import. Args: musicbrainz_row_id (int): the MusicBrainz row ID of the user error (str): a description of the error encountered. """ user_email = mb_editor.get_editor_by_id(musicbrainz_row_id)['email'] spotify_url = current_app.config['SERVER_ROOT_URL'] + '/profile/connect-spotify' text = render_template('emails/spotify_import_error.txt', error=error, link=spotify_url) send_mail( subject='ListenBrainz Spotify Importer Error', text=text, recipients=[user_email], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def handle_candidate_sets(data): """ Send an email after candidate sets have been successfully uploaded to HDFS. """ if current_app.config['TESTING']: return candidate_sets_upload_time = data['candidate_sets_upload_time'] candidate_set_creation_time = data['total_time'] from_date = data['from_date'] to_date = data['to_date'] send_mail( subject='Candidate sets created and successfully uploaded to HDFS', text=render_template('emails/cf_candidate_sets_upload_notification.txt', time_to_upload=candidate_sets_upload_time, from_date=from_date, to_date=to_date, total_time=candidate_set_creation_time), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def check_ftp_dump_ages(): """ Fetch the FTP dir listing of the full and incremental dumps and check their ages. Send mail to the observability list in case the dumps are too old. """ msg = "" try: id, dt = _fetch_latest_file_info_from_ftp_dir( MAIN_FTP_SERVER_URL, '/pub/musicbrainz/listenbrainz/fullexport') age = datetime.now() - dt if age > timedelta(days=FULLEXPORT_MAX_AGE): msg = "Full dump %d is more than %d days old: %s\n" % ( id, FULLEXPORT_MAX_AGE, str(age)) print(msg, end="") else: print("Full dump %s is %s old, good!" % (id, str(age))) except Exception as err: msg = "Cannot fetch full dump age: %s" % str(err) try: id, dt = _fetch_latest_file_info_from_ftp_dir( MAIN_FTP_SERVER_URL, '/pub/musicbrainz/listenbrainz/incremental') age = datetime.now() - dt if age > timedelta(hours=INCREMENTAL_MAX_AGE): msg = "Incremental dump %s is more than %s hours old: %s\n" % ( id, INCREMENTAL_MAX_AGE, str(age)) print(msg, end="") else: print("Incremental dump %s is %s old, good!" % (id, str(age))) except Exception as err: msg = "Cannot fetch full dump age: %s" % str(err) app = create_app() with app.app_context(): if not current_app.config['TESTING'] and msg: send_mail(subject="ListenBrainz outdated dumps!", text=render_template('emails/data_dump_outdated.txt', msg=msg), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@' + current_app.config['MAIL_FROM_DOMAIN'])
def notify_artist_relation_import(data): """ Send an email after artist relation has been sucessfully imported into the cluster. """ if current_app.config['TESTING']: return artist_relation_name = data['import_artist_relation'] import_time = data['import_time'] time_taken_to_import = data['time_taken_to_import'] send_mail( subject='Artist relation has been imported into the Spark cluster', text=render_template('emails/artist_relation_import_notification.txt', artist_relation_name=artist_relation_name, import_time=import_time, time_taken_to_import=time_taken_to_import), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def handle_dump_imported(data): """ Process the response that the cluster sends after importing a new dump We don't really need to _do_ anything, just send an email over if there was an error. """ if current_app.config['TESTING']: return errors = data['errors'] import_completion_time = data['time'] if errors: send_mail( subject='Spark Cluster Dump import failures!', text=render_template('emails/dump_import_failure.txt', errors=errors, time=import_completion_time), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def notify_cf_recording_recommendations_generation(data): """ Send an email to notify recommendations have been generated and are being written into db. """ if current_app.config['TESTING']: return active_user_count = data['active_user_count'] total_time = data['total_time'] top_artist_user_count = data['top_artist_user_count'] similar_artist_user_count = data['similar_artist_user_count'] send_mail( subject='Recommendations have been generated and pushed to the queue.', text=render_template('emails/cf_recording_recommendation_notification.txt', active_user_count=active_user_count, total_time=total_time, top_artist_user_count=top_artist_user_count, similar_artist_user_count=similar_artist_user_count), recipients=['*****@*****.**'], from_name='ListenBrainz', from_addr='noreply@'+current_app.config['MAIL_FROM_DOMAIN'], )
def notify_error(musicbrainz_id: str, error: str): """ Notifies specified user via email about error during Spotify import. Args: musicbrainz_id: the MusicBrainz ID of the user error: a description of the error encountered. """ user_email = db_user.get_by_mb_id(musicbrainz_id, fetch_email=True)["email"] if not user_email: return spotify_url = current_app.config[ 'SERVER_ROOT_URL'] + '/profile/music-services/details/' text = render_template('emails/spotify_import_error.txt', error=error, link=spotify_url) send_mail( subject='ListenBrainz Spotify Importer Error', text=text, recipients=[user_email], from_name='ListenBrainz', from_addr='noreply@' + current_app.config['MAIL_FROM_DOMAIN'], )