def notify_yim_users(): lb_logo_cid = make_msgid() with open("/static/img/listenbrainz-logo.png", "rb") as img: lb_logo = img.read() with db.engine.connect() as connection: result = connection.execute(""" SELECT user_id , musicbrainz_id , email FROM statistics.year_in_music yim JOIN "user" ON "user".id = yim.user_id """) rows = result.fetchall() for row in rows: user_name = row["musicbrainz_id"] # cannot use url_for because we do not set SERVER_NAME and # a request_context will not be available in this script. base_url = "https://listenbrainz.org" year_in_music = f"{base_url}/user/{user_name}/year-in-music/" params = { "user_name": user_name, "year_in_music": year_in_music, "statistics": f"{base_url}/user/{user_name}/reports/", "feed": f"{base_url}/feed/", "feedback": f"{base_url}/user/{user_name}/feedback/", "pins": f"{base_url}/user/{user_name}/pins/", "playlists": f"{base_url}/user/{user_name}/playlists/", "collaborations": f"{base_url}/user/{user_name}/collaborations/", "lb_logo_cid": lb_logo_cid[1:-1] } try: send_mail(subject="Year In Music 2021", text=render_template("emails/year_in_music.txt", **params), to_email=row["email"], to_name=user_name, html=render_template("emails/year_in_music.html", **params), lb_logo_cid=lb_logo_cid, lb_logo=lb_logo) except Exception: current_app.logger.error("Could not send YIM email to %s", user_name, exc_info=True) # create timeline event too timeline_message = 'ListenBrainz\' very own retrospective on 2021 has just dropped: Check out ' \ f'your own <a href="{year_in_music}">Year in Music</a> now!' metadata = NotificationMetadata(creator="troi-bot", message=timeline_message) create_user_notification_event(row["user_id"], metadata)
def create_user_notification_event(user_name): """ Post a message with a link on a user's timeline. Only approved users are allowed to perform this action. The request should contain the following data: .. code-block:: json { "metadata": { "message": <the message to post, required>, } } :param user_name: The MusicBrainz ID of the user on whose timeline the message is to be posted. :type user_name: ``str`` :statuscode 200: Successful query, message has been posted! :statuscode 400: Bad request, check ``response['error']`` for more details. :statuscode 403: Forbidden, you are not an approved user. :statuscode 404: User not found :resheader Content-Type: *application/json* """ creator = validate_auth_header() if creator["musicbrainz_id"] not in current_app.config[ 'APPROVED_PLAYLIST_BOTS']: raise APIForbidden( "Only approved users are allowed to post a message on a user's timeline." ) user = db_user.get_by_mb_id(user_name) if user is None: raise APINotFound(f"Cannot find user: {user_name}") try: data = ujson.loads(request.get_data())['metadata'] except (ValueError, KeyError) as e: raise APIBadRequest(f"Invalid JSON: {str(e)}") if "message" not in data: raise APIBadRequest("Invalid metadata: message is missing") message = _filter_description_html(data["message"]) metadata = NotificationMetadata(creator=creator['musicbrainz_id'], message=message) try: db_user_timeline_event.create_user_notification_event( user['id'], metadata) except DatabaseException: raise APIInternalServerError("Something went wrong, please try again.") return jsonify({'status': 'ok'})
def test_create_user_notification_event(self): message = 'You have a <a href="https://listenbrainz.org/non-existent-playlist">playlist</a>' event = db_user_timeline_event.create_user_notification_event( user_id=self.user['id'], metadata=NotificationMetadata( creator=self.user['musicbrainz_id'], message=message, )) self.assertEqual(self.user['id'], event.user_id) self.assertEqual(message, event.metadata.message) self.assertEqual(self.user['musicbrainz_id'], event.metadata.creator) self.assertEqual(UserTimelineEventType.NOTIFICATION, event.event_type)
def test_delete_feed_events(self): # creating recording recommendation and checking event_rec = db_user_timeline_event.create_user_track_recommendation_event( user_id=self.user['id'], metadata=RecordingRecommendationMetadata( track_name="All Caps", artist_name="MF DOOM", recording_msid=str(uuid.uuid4()), artist_msid=str(uuid.uuid4()), )) self.assertEqual(UserTimelineEventType.RECORDING_RECOMMENDATION, event_rec.event_type) self.assertEqual(self.user['id'], event_rec.user_id) # creating a new user for notification new_user = db_user.get_or_create(2, 'riksucks') message = 'You have a <a href="https://listenbrainz.org/non-existent-playlist">playlist</a>' event_not = db_user_timeline_event.create_user_notification_event( user_id=new_user['id'], metadata=NotificationMetadata( creator=new_user['musicbrainz_id'], message=message, )) self.assertEqual(new_user['id'], event_not.user_id) self.assertEqual(message, event_not.metadata.message) self.assertEqual(new_user['musicbrainz_id'], event_not.metadata.creator) self.assertEqual(UserTimelineEventType.NOTIFICATION, event_not.event_type) # deleting recording recommendation db_user_timeline_event.delete_user_timeline_event( id=event_rec.id, user_id=self.user["id"], ) event_rec = db_user_timeline_event.get_user_notification_events( user_id=self.user["id"], count=1, ) self.assertEqual(0, len(event_rec)) # deleting notification db_user_timeline_event.delete_user_timeline_event( id=event_not.id, user_id=new_user["id"], ) event_not = db_user_timeline_event.get_user_notification_events( user_id=new_user["id"], count=1, ) self.assertEqual(0, len(event_not))