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 edit_playlist(playlist_mbid): """ Edit the private/public status, name, description or list of collaborators for an exising playlist. The Authorization header must be set and correspond to the owner of the playlist otherwise a 403 error will be returned. All fields will be overwritten with new values. :reqheader Authorization: Token <user token> :statuscode 200: playlist accepted. :statuscode 400: invalid JSON sent, see error message for details. :statuscode 401: invalid authorization. See error message for details. :statuscode 403: forbidden. The subitting user is not allowed to edit playlists for other users. :resheader Content-Type: *application/json* """ user = validate_auth_header() data = request.json validate_playlist(data) if not is_valid_uuid(playlist_mbid): log_raise_400("Provided playlist ID is invalid.") playlist = db_playlist.get_by_mbid(playlist_mbid, False) if playlist is None or not playlist.is_visible_by(user["id"]): raise APINotFound("Cannot find playlist: %s" % playlist_mbid) if playlist.creator_id != user["id"]: raise APIForbidden("You are not allowed to edit this playlist.") try: playlist.public = data["playlist"]["extension"][PLAYLIST_EXTENSION_URI]["public"] except KeyError: pass if "annotation" in data["playlist"]: # If the annotation key exists but the value is empty ("" or None), # unset the description description = data["playlist"]["annotation"] if description: description = _filter_description_html(description) else: description = None playlist.description = description if data["playlist"].get("title"): playlist.name = data["playlist"]["title"] collaborators = data.get("playlist", {}).\ get("extension", {}).get(PLAYLIST_EXTENSION_URI, {}).\ get("collaborators", []) users = {} # Uniquify collaborators list collaborators = list(set(collaborators)) # Don't allow creator to also be a collaborator if user["musicbrainz_id"] in collaborators: collaborators.remove(user["musicbrainz_id"]) if collaborators: users = db_user.get_many_users_by_mb_id(collaborators) collaborator_ids = [] for collaborator in collaborators: if collaborator.lower() not in users: log_raise_400("Collaborator {} doesn't exist".format(collaborator)) collaborator_ids.append(users[collaborator.lower()]["id"]) playlist.collaborators = collaborators playlist.collaborator_ids = collaborator_ids db_playlist.update_playlist(playlist) return jsonify({'status': 'ok'})
def create_playlist(): """ Create a playlist. The playlist must be in JSPF format with MusicBrainz extensions, which is defined here: https://musicbrainz.org/doc/jspf . To create an empty playlist, you can send an empty playlist with only the title field filled out. If you would like to create a playlist populated with recordings, each of the track items in the playlist must have an identifier element that contains the MusicBrainz recording that includes the recording MBID. When creating a playlist, only the playlist title and the track identifier elements will be used -- all other elements in the posted JSPF wil be ignored. If a created_for field is found and the user is not an approved playlist bot, then a 403 forbidden will be raised. :reqheader Authorization: Token <user token> :statuscode 200: playlist accepted. :statuscode 400: invalid JSON sent, see error message for details. :statuscode 401: invalid authorization. See error message for details. :statuscode 403: forbidden. The submitting user is not allowed to create playlists for other users. :resheader Content-Type: *application/json* """ user = validate_auth_header() data = request.json validate_create_playlist_required_items(data) validate_playlist(data) public = data["playlist"]["extension"][PLAYLIST_EXTENSION_URI]["public"] collaborators = data.get("playlist", {}).\ get("extension", {}).get(PLAYLIST_EXTENSION_URI, {}).\ get("collaborators", []) # Uniquify collaborators list collaborators = list(set(collaborators)) # Don't allow creator to also be a collaborator if user["musicbrainz_id"] in collaborators: collaborators.remove(user["musicbrainz_id"]) username_lookup = collaborators created_for = data["playlist"].get("created_for", None) if created_for: username_lookup.append(created_for) users = {} if username_lookup: users = db_user.get_many_users_by_mb_id(username_lookup) collaborator_ids = [] for collaborator in collaborators: if collaborator.lower() not in users: log_raise_400("Collaborator {} doesn't exist".format(collaborator)) collaborator_ids.append(users[collaborator.lower()]["id"]) # filter description description = data["playlist"].get("annotation", None) if description is not None: description = _filter_description_html(description) playlist = WritablePlaylist(name=data['playlist']['title'], creator_id=user["id"], description=description, collaborator_ids=collaborator_ids, collaborators=collaborators, public=public) if data["playlist"].get("created_for", None): if user["musicbrainz_id"] not in current_app.config["APPROVED_PLAYLIST_BOTS"]: raise APIForbidden("Playlist contains a created_for field, but submitting user is not an approved playlist bot.") created_for_user = users.get(data["playlist"]["created_for"].lower()) if not created_for_user: log_raise_400("created_for user does not exist.") playlist.created_for_id = created_for_user["id"] if "track" in data["playlist"]: for track in data["playlist"]["track"]: try: playlist.recordings.append(WritablePlaylistRecording(mbid=UUID(track['identifier'][len(PLAYLIST_TRACK_URI_PREFIX):]), added_by_id=user["id"])) except ValueError: log_raise_400("Invalid recording MBID found in submitted recordings") try: playlist = db_playlist.create(playlist) except Exception as e: current_app.logger.error("Error while creating new playlist: {}".format(e)) raise APIInternalServerError("Failed to create the playlist. Please try again.") return jsonify({'status': 'ok', 'playlist_mbid': playlist.mbid})