From 635b5d18e59907efdb5dead2675e54ec7577c7c2 Mon Sep 17 00:00:00 2001 From: Kartik Ohri Date: Sun, 5 Jan 2025 23:36:51 +0530 Subject: [PATCH] Refactor .route to .get/.post --- listenbrainz/webserver/decorators.py | 6 +++- listenbrainz/webserver/views/api.py | 36 +++++++++---------- listenbrainz/webserver/views/api_compat.py | 4 +-- listenbrainz/webserver/views/art.py | 2 +- listenbrainz/webserver/views/art_api.py | 10 +++--- listenbrainz/webserver/views/atom.py | 23 ++++++------ listenbrainz/webserver/views/color_api.py | 2 +- .../webserver/views/do_not_recommend_api.py | 2 +- listenbrainz/webserver/views/donor_api.py | 6 ++-- listenbrainz/webserver/views/donors.py | 6 ++-- listenbrainz/webserver/views/entity_pages.py | 22 ++++++------ listenbrainz/webserver/views/explore.py | 12 +++---- listenbrainz/webserver/views/explore_api.py | 6 ++-- listenbrainz/webserver/views/export.py | 10 +++--- listenbrainz/webserver/views/feedback_api.py | 14 ++++---- .../webserver/views/fresh_releases.py | 5 ++- listenbrainz/webserver/views/index.py | 16 ++++----- listenbrainz/webserver/views/login.py | 8 ++--- listenbrainz/webserver/views/metadata_api.py | 16 ++++----- .../webserver/views/metadata_viewer.py | 6 ++-- .../views/missing_musicbrainz_data_api.py | 2 +- .../webserver/views/pinned_recording_api.py | 14 ++++---- listenbrainz/webserver/views/player.py | 8 ++--- listenbrainz/webserver/views/playlist.py | 6 ++-- listenbrainz/webserver/views/playlist_api.py | 32 ++++++++--------- .../webserver/views/popularity_api.py | 12 +++---- .../views/recommendations_cf_recording.py | 8 ++--- .../views/recommendations_cf_recording_api.py | 2 +- ...commendations_cf_recording_feedback_api.py | 8 ++--- listenbrainz/webserver/views/settings.py | 30 ++++++++-------- listenbrainz/webserver/views/social_api.py | 8 ++--- listenbrainz/webserver/views/stats_api.py | 34 +++++++++--------- listenbrainz/webserver/views/status_api.py | 6 ++-- listenbrainz/webserver/views/user.py | 26 +++++++------- .../webserver/views/user_settings_api.py | 8 ++--- .../views/user_timeline_event_api.py | 20 +++++------ 36 files changed, 222 insertions(+), 214 deletions(-) diff --git a/listenbrainz/webserver/decorators.py b/listenbrainz/webserver/decorators.py index c6fdaefe59..e97a1a715d 100644 --- a/listenbrainz/webserver/decorators.py +++ b/listenbrainz/webserver/decorators.py @@ -6,7 +6,11 @@ def crossdomain(f): - """ Decorator to add CORS headers to flask endpoints """ + """ Decorator to add CORS headers to flask endpoints. + + This decorator should be applied just after the route to ensure the provide_automatic_options + is set correctly. + """ @wraps(f) def decorator(*args, **kwargs): options_resp = current_app.make_default_options_response() diff --git a/listenbrainz/webserver/views/api.py b/listenbrainz/webserver/views/api.py index 928603977c..768960e9a3 100644 --- a/listenbrainz/webserver/views/api.py +++ b/listenbrainz/webserver/views/api.py @@ -34,7 +34,7 @@ SEARCH_USER_LIMIT = 10 -@api_bp.route('/search/users/', methods=['GET', 'OPTIONS']) +@api_bp.get("/search/users/") @crossdomain @ratelimit() def search_user(): @@ -50,7 +50,7 @@ def search_user(): return jsonify({'users': users}) -@api_bp.route("/submit-listens", methods=["POST"]) +@api_bp.post("/submit-listens") @crossdomain @ratelimit() def submit_listen(): @@ -134,7 +134,7 @@ def submit_listen(): return jsonify({'status': 'ok'}) -@api_bp.route("/user//listens", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//listens") @crossdomain @ratelimit() @api_listenstore_needed @@ -180,7 +180,7 @@ def get_listens(user_name): }}) -@api_bp.route("/user//listen-count", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//listen-count") @crossdomain @ratelimit() @api_listenstore_needed @@ -210,7 +210,7 @@ def get_listen_count(user_name): }}) -@api_bp.route("/user//playing-now", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playing-now") @crossdomain @ratelimit() def get_playing_now(user_name): @@ -248,7 +248,7 @@ def get_playing_now(user_name): }) -@api_bp.route("/user//similar-users", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//similar-users") @crossdomain @ratelimit() def get_similar_users(user_name): @@ -284,7 +284,7 @@ def get_similar_users(user_name): }) -@api_bp.route("/user//similar-to/", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//similar-to/") @crossdomain @ratelimit() def get_similar_to_user(user_name, other_user_name): @@ -320,7 +320,7 @@ def get_similar_to_user(user_name, other_user_name): raise APINotFound("Similar-to user not found") -@api_bp.route('/latest-import', methods=['GET', 'POST', 'OPTIONS']) +@api_bp.route("/latest-import", methods=["GET", "POST"]) @crossdomain @ratelimit() def latest_import(): @@ -392,7 +392,7 @@ def latest_import(): return jsonify({'status': 'ok'}) -@api_bp.route('/validate-token', methods=['GET', 'OPTIONS']) +@api_bp.get("/validate-token") @crossdomain @ratelimit() def validate_token(): @@ -459,7 +459,7 @@ def validate_token(): }) -@api_bp.route('/delete-listen', methods=['POST', 'OPTIONS']) +@api_bp.post("/delete-listen") @crossdomain @ratelimit() @api_listenstore_needed @@ -537,7 +537,7 @@ def serialize_playlists(playlists, playlist_count, count, offset): "count": count} -@api_bp.route("/user//playlists", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playlists") @crossdomain @ratelimit() def get_playlists_for_user(playlist_user_name): @@ -572,7 +572,7 @@ def get_playlists_for_user(playlist_user_name): return jsonify(serialize_playlists(playlists, playlist_count, count, offset)) -@api_bp.route("/user//playlists/createdfor", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playlists/createdfor") @crossdomain @ratelimit() def get_playlists_created_for_user(playlist_user_name): @@ -604,7 +604,7 @@ def get_playlists_created_for_user(playlist_user_name): return jsonify(serialize_playlists(playlists, playlist_count, count, offset)) -@api_bp.route("/user//playlists/collaborator", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playlists/collaborator") @crossdomain @ratelimit() def get_playlists_collaborated_on_for_user(playlist_user_name): @@ -643,7 +643,7 @@ def get_playlists_collaborated_on_for_user(playlist_user_name): return jsonify(serialize_playlists(playlists, playlist_count, count, offset)) -@api_bp.route("/user//playlists/recommendations", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playlists/recommendations") @crossdomain @ratelimit() @api_listenstore_needed @@ -666,7 +666,7 @@ def user_recommendations(playlist_user_name): return jsonify(serialize_playlists(playlists, len(playlists), 0, 0)) -@api_bp.route("/user//playlists/search", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//playlists/search") @crossdomain @ratelimit() @api_listenstore_needed @@ -696,7 +696,7 @@ def search_user_playlist(playlist_user_name): return jsonify(serialize_playlists(playlists, playlist_count, count, offset)) -@api_bp.route("/user//services", methods=['GET', 'OPTIONS']) +@api_bp.get("/user//services") @crossdomain @ratelimit() def get_service_details(user_name): @@ -725,7 +725,7 @@ def get_service_details(user_name): return jsonify({'user_name': user_name, 'services': services}) -@api_bp.route("/lb-radio/tags", methods=['GET', 'OPTIONS']) +@api_bp.get("/lb-radio/tags") @crossdomain @ratelimit() def get_tags_dataset(): @@ -805,7 +805,7 @@ def _get_listen_type(listen_type): }.get(listen_type) -@api_bp.route("/lb-radio/artist/", methods=['GET', 'OPTIONS']) +@api_bp.get("/lb-radio/artist/") @crossdomain @ratelimit() def get_artist_radio_recordings(seed_artist_mbid): diff --git a/listenbrainz/webserver/views/api_compat.py b/listenbrainz/webserver/views/api_compat.py index 352d124244..9acbc8bd6d 100644 --- a/listenbrainz/webserver/views/api_compat.py +++ b/listenbrainz/webserver/views/api_compat.py @@ -24,7 +24,7 @@ api_bp = Blueprint('api_compat', __name__) -@api_bp.route('/api/auth/', methods=['GET']) +@api_bp.get('/api/auth/') @ratelimit() @login_required def api_auth(): @@ -35,7 +35,7 @@ def api_auth(): ) -@api_bp.route('/api/auth/', methods=['POST']) +@api_bp.post('/api/auth/') @ratelimit() @login_required def api_auth_approve(): diff --git a/listenbrainz/webserver/views/art.py b/listenbrainz/webserver/views/art.py index 51013be06f..65f1002f22 100755 --- a/listenbrainz/webserver/views/art.py +++ b/listenbrainz/webserver/views/art.py @@ -3,7 +3,7 @@ art_bp = Blueprint('art', __name__) -@art_bp.route("/") +@art_bp.get("/") def index(): """ This page shows of a bit of what can be done with the cover art, as a sort of showcase. """ return render_template("art/index.html", api_url=current_app.config["API_URL"]) diff --git a/listenbrainz/webserver/views/art_api.py b/listenbrainz/webserver/views/art_api.py index 6b0f9ffeaf..67b33a9bd5 100755 --- a/listenbrainz/webserver/views/art_api.py +++ b/listenbrainz/webserver/views/art_api.py @@ -28,7 +28,7 @@ def _repeat_images(images, size=9): return images -@art_api_bp.route("/grid/", methods=["POST"]) +@art_api_bp.post("/grid/") @crossdomain @ratelimit() def cover_art_grid_post(): @@ -171,8 +171,7 @@ def get_release_group_mbids() -> tuple[list, str]: } -@art_api_bp.route("/grid-stats/////", - methods=["GET"]) +@art_api_bp.get("/grid-stats/////") @crossdomain @ratelimit() def cover_art_grid_stats(user_name, time_range, dimension, layout, image_size): @@ -233,7 +232,7 @@ def cover_art_grid_stats(user_name, time_range, dimension, layout, image_size): } -@art_api_bp.route("////", methods=["GET"]) +@art_api_bp.get("////") @crossdomain @ratelimit() def cover_art_custom_stats(custom_name, user_name, time_range, image_size): @@ -420,6 +419,7 @@ def _cover_art_yim_albums_2023(user_name, stats): images=images, ) + def _cover_art_yim_albums_2024(user_name, stats, yim24): """ Create the SVG using YIM top albums for 2024. """ cac = CoverArtGenerator(current_app.config["MB_DATABASE_URI"], 3, 250) @@ -724,7 +724,7 @@ def _cover_art_yim_overview(user_name, stats, year, yim24): return render_template("art/svg-templates/year-in-music-2024/yim-2024-overview.svg", **props, **yim24) -@art_api_bp.route("/year-in-music//", methods=["GET"]) +@art_api_bp.get("/year-in-music//") @crossdomain @ratelimit() def cover_art_yim(user_name, year: int = 2024): diff --git a/listenbrainz/webserver/views/atom.py b/listenbrainz/webserver/views/atom.py index ed1ee6a5a4..125f55895b 100644 --- a/listenbrainz/webserver/views/atom.py +++ b/listenbrainz/webserver/views/atom.py @@ -164,7 +164,7 @@ def _init_feed(id, title, alternate_url, self_url): return fg -@atom_bp.route("/user//listens", methods=["GET"]) +@atom_bp.get("/user//listens") @crossdomain @ratelimit() @api_listenstore_needed @@ -252,7 +252,7 @@ def get_listens(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/fresh-releases", methods=["GET"]) +@atom_bp.get("/fresh-releases") @crossdomain @ratelimit() def get_fresh_releases(): @@ -333,8 +333,9 @@ def get_fresh_releases(): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//fresh-releases", methods=["GET"]) +@atom_bp.get("/user//fresh-releases") @crossdomain +@ratelimit() def get_user_fresh_releases(user_name): """ Get fresh releases for a user, sorted by release date. @@ -426,7 +427,7 @@ def _get_entity_stats(user_id: str, entity: str, range: str, count: int): return entity_list, stats.to_ts, stats.last_updated -@atom_bp.route("/user//stats/top-artists") +@atom_bp.get("/user//stats/top-artists") @crossdomain @ratelimit() def get_artist_stats(user_name): @@ -507,7 +508,7 @@ def get_artist_stats(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//stats/top-albums") +@atom_bp.get("/user//stats/top-albums") @crossdomain @ratelimit() def get_release_group_stats(user_name): @@ -589,7 +590,7 @@ def get_release_group_stats(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//stats/top-tracks") +@atom_bp.get("/user//stats/top-tracks") @crossdomain @ratelimit() def get_recording_stats(user_name): @@ -670,7 +671,7 @@ def get_recording_stats(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/playlist/") +@atom_bp.get("/playlist/") @crossdomain @api_listenstore_needed @ratelimit() @@ -743,7 +744,7 @@ def get_playlist_recordings(playlist_mbid): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//recommendations") +@atom_bp.get("/user//recommendations") @crossdomain @api_listenstore_needed @ratelimit() @@ -833,7 +834,7 @@ def get_recommendation(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//stats/art/grid") +@atom_bp.get("/user//stats/art/grid") @crossdomain @ratelimit() def get_cover_art_grid_stats(user_name): @@ -941,7 +942,7 @@ def get_cover_art_grid_stats(user_name): return Response(atomfeed, mimetype="application/atom+xml") -@atom_bp.route("/user//stats/art/custom") +@atom_bp.get("/user//stats/art/custom") @crossdomain @ratelimit() def get_cover_art_custom_stats(user_name): @@ -1088,7 +1089,7 @@ def _generate_event_title(event): # Commented out as new OAuth is not merged yet. Once merged, update this function to use the new OAuth API to # authenticate the user and then fetch the user's events feed. -# @atom_bp.route("/user//events", methods=["GET"]) +# @atom_bp.get("/user//events") # @crossdomain # @ratelimit() # @api_listenstore_needed diff --git a/listenbrainz/webserver/views/color_api.py b/listenbrainz/webserver/views/color_api.py index e351cfc119..0ec68f80d8 100644 --- a/listenbrainz/webserver/views/color_api.py +++ b/listenbrainz/webserver/views/color_api.py @@ -16,7 +16,7 @@ color_api_bp = Blueprint('color_api_v1', __name__) -@color_api_bp.route("/", methods=["GET"]) +@color_api_bp.get("/") @crossdomain @ratelimit() def huesound(color): diff --git a/listenbrainz/webserver/views/do_not_recommend_api.py b/listenbrainz/webserver/views/do_not_recommend_api.py index ad8eb136b4..e751beee20 100644 --- a/listenbrainz/webserver/views/do_not_recommend_api.py +++ b/listenbrainz/webserver/views/do_not_recommend_api.py @@ -15,7 +15,7 @@ do_not_recommend_api_bp = Blueprint('do_not_recommend_api_v1', __name__) -@do_not_recommend_api_bp.route("/user//do-not-recommend", methods=["GET"]) +@do_not_recommend_api_bp.get("/user//do-not-recommend") @crossdomain @ratelimit() def get_do_not_recommends(user_name): diff --git a/listenbrainz/webserver/views/donor_api.py b/listenbrainz/webserver/views/donor_api.py index 679415a938..3581fba9de 100644 --- a/listenbrainz/webserver/views/donor_api.py +++ b/listenbrainz/webserver/views/donor_api.py @@ -13,7 +13,7 @@ DEFAULT_DONOR_COUNT = 25 -@donor_api_bp.route("/recent", methods=["GET"]) +@donor_api_bp.get("/recent") @crossdomain @ratelimit() def recent_donors(): @@ -30,7 +30,7 @@ def recent_donors(): return jsonify(donors) -@donor_api_bp.route("/biggest", methods=["GET"]) +@donor_api_bp.get("/biggest") @crossdomain @ratelimit() def biggest_donors(): @@ -47,7 +47,7 @@ def biggest_donors(): return jsonify(donors) -@donor_api_bp.route("/all-flairs", methods=["GET"]) +@donor_api_bp.get("/all-flairs") @crossdomain @ratelimit() def all_flairs(): diff --git a/listenbrainz/webserver/views/donors.py b/listenbrainz/webserver/views/donors.py index 6818c7b7b6..db0d112e72 100644 --- a/listenbrainz/webserver/views/donors.py +++ b/listenbrainz/webserver/views/donors.py @@ -12,13 +12,13 @@ donors_bp = Blueprint("donors", __name__) -@donors_bp.route("/", defaults={'path': ''}) -@donors_bp.route('//') +@donors_bp.get("/", defaults={'path': ''}) +@donors_bp.get('//') def donors(path): return render_template("index.html") -@donors_bp.route("/", methods=["POST"]) +@donors_bp.post("/") def donors_post(): page = _parse_int_arg("page", 1) sort = request.args.get("sort", "date") diff --git a/listenbrainz/webserver/views/entity_pages.py b/listenbrainz/webserver/views/entity_pages.py index c32280ca93..d6b47da7af 100644 --- a/listenbrainz/webserver/views/entity_pages.py +++ b/listenbrainz/webserver/views/entity_pages.py @@ -82,13 +82,13 @@ def get_cover_art_for_artist(release_groups): ) -@release_bp.route("/", defaults={'path': ''}) -@release_bp.route('//') +@release_bp.get("/", defaults={'path': ''}) +@release_bp.get('//') def release_page(path): return render_template("index.html") -@release_bp.route("//", methods=["POST"]) +@release_bp.post("//") @web_listenstore_needed def release_redirect(release_mbid): if not is_valid_uuid(release_mbid): @@ -110,13 +110,13 @@ def release_redirect(release_mbid): return jsonify({"releaseGroupMBID": result["release_group_mbid"]}) -@artist_bp.route("/", defaults={'path': ''}) -@artist_bp.route('//') +@artist_bp.get("/", defaults={'path': ''}) +@artist_bp.get('//') def artist_page(path): return render_template("index.html") -@artist_bp.route("//", methods=["POST"]) +@artist_bp.post("//") @web_listenstore_needed def artist_entity(artist_mbid): """ Show a artist page with all their relevant information """ @@ -208,13 +208,13 @@ def artist_entity(artist_mbid): return jsonify(data) -@album_bp.route("/", defaults={'path': ''}) -@album_bp.route('//') +@album_bp.get("/", defaults={'path': ''}) +@album_bp.get('//') def album_page(path): return render_template("index.html") -@album_bp.route("//", methods=["POST"]) +@album_bp.post("//") @web_listenstore_needed def album_entity(release_group_mbid): """ Show an album page with all their relevant information """ @@ -267,7 +267,7 @@ def album_entity(release_group_mbid): return jsonify(data) -@release_group_bp.route("/", defaults={'path': ''}) -@release_group_bp.route('//') +@release_group_bp.get("/", defaults={'path': ''}) +@release_group_bp.get('//') def release_group_redirect(path): return render_template("index.html") diff --git a/listenbrainz/webserver/views/explore.py b/listenbrainz/webserver/views/explore.py index a1ff6cd682..13f98cd1dc 100644 --- a/listenbrainz/webserver/views/explore.py +++ b/listenbrainz/webserver/views/explore.py @@ -8,7 +8,7 @@ explore_bp = Blueprint('explore', __name__) -@explore_bp.route("/similar-users/", methods=['POST']) +@explore_bp.post("/similar-users/") def similar_users(): """ Show all of the users with the highest similarity in order to make them visible to all of our users. This view can show bugs in the algorithm @@ -22,7 +22,7 @@ def similar_users(): }) -@explore_bp.route("/music-neighborhood/", methods=['POST']) +@explore_bp.post("/music-neighborhood/") def artist_similarity(): """ Explore artist similarity """ @@ -42,14 +42,14 @@ def artist_similarity(): return jsonify(data) -@explore_bp.route("/ai-brainz/") +@explore_bp.get("/ai-brainz/") def ai_brainz(): """ Explore your love of Rick """ return render_template("index.html") -@explore_bp.route("/lb-radio/", methods=["POST"]) +@explore_bp.post("/lb-radio/") def lb_radio(): """ LB Radio view @@ -82,8 +82,8 @@ def lb_radio(): return jsonify(data) -@explore_bp.route('/', defaults={'path': ''}) -@explore_bp.route('//') +@explore_bp.get('/', defaults={'path': ''}) +@explore_bp.get('//') def index(path): """ Main explore page for users to browse the various explore features """ diff --git a/listenbrainz/webserver/views/explore_api.py b/listenbrainz/webserver/views/explore_api.py index 1466c7b6e1..b38cd5397c 100644 --- a/listenbrainz/webserver/views/explore_api.py +++ b/listenbrainz/webserver/views/explore_api.py @@ -21,7 +21,7 @@ explore_api_bp = Blueprint('explore_api_v1', __name__) -@explore_api_bp.route("/fresh-releases/", methods=["GET"]) +@explore_api_bp.get("/fresh-releases/") @crossdomain @ratelimit() def get_fresh_releases(): @@ -94,7 +94,7 @@ def get_fresh_releases(): }) -@explore_api_bp.route("/color/", methods=["GET"]) +@explore_api_bp.get("/color/") @crossdomain @ratelimit() def huesound(color): @@ -145,7 +145,7 @@ def huesound(color): return jsonify({"payload": {"releases": results}}) -@explore_api_bp.route("/lb-radio", methods=["GET"]) +@explore_api_bp.get("/lb-radio") @crossdomain @ratelimit() def lb_radio(): diff --git a/listenbrainz/webserver/views/export.py b/listenbrainz/webserver/views/export.py index ec90d45c88..551d199b01 100644 --- a/listenbrainz/webserver/views/export.py +++ b/listenbrainz/webserver/views/export.py @@ -14,7 +14,7 @@ export_bp = Blueprint("export", __name__) -@export_bp.route("/", methods=["POST"]) +@export_bp.post("/") @api_login_required @web_listenstore_needed def create_export_task(): @@ -64,7 +64,7 @@ def create_export_task(): raise APIInternalServerError(f'Error while exporting user data {current_user.musicbrainz_id}, please try again later.') -@export_bp.route("//", methods=["GET"]) +@export_bp.get("//") @api_login_required @web_listenstore_needed def get_export_task(export_id): @@ -87,7 +87,7 @@ def get_export_task(export_id): }) -@export_bp.route("/list/", methods=["GET"]) +@export_bp.get("/list/") @api_login_required @web_listenstore_needed def list_export_tasks(): @@ -108,7 +108,7 @@ def list_export_tasks(): } for row in rows]) -@export_bp.route("/download//", methods=["POST"]) +@export_bp.post("/download//") @api_login_required @web_listenstore_needed def download_export_archive(export_id): @@ -126,7 +126,7 @@ def download_export_archive(export_id): -@export_bp.route("/delete//", methods=["POST"]) +@export_bp.post("/delete//") @api_login_required @web_listenstore_needed def delete_export_archive(export_id): diff --git a/listenbrainz/webserver/views/feedback_api.py b/listenbrainz/webserver/views/feedback_api.py index 5a4157179e..b9ce2a1af3 100644 --- a/listenbrainz/webserver/views/feedback_api.py +++ b/listenbrainz/webserver/views/feedback_api.py @@ -21,7 +21,7 @@ FEEDBACK_DEFAULT_SCORE = 0 -@feedback_api_bp.route("/recording-feedback", methods=["POST"]) +@feedback_api_bp.post("/recording-feedback") @crossdomain @ratelimit() def recording_feedback(): @@ -71,7 +71,7 @@ def recording_feedback(): return jsonify({'status': 'ok'}) -@feedback_api_bp.route("/user//get-feedback", methods=["GET"]) +@feedback_api_bp.get("/user//get-feedback") @crossdomain @ratelimit() def get_feedback_for_user(user_name): @@ -125,7 +125,7 @@ def get_feedback_for_user(user_name): }) -@feedback_api_bp.route("/recording//get-feedback-mbid", methods=["GET"]) +@feedback_api_bp.get("/recording//get-feedback-mbid") @crossdomain @ratelimit() def get_feedback_for_recording_mbid(recording_mbid): @@ -149,7 +149,7 @@ def get_feedback_for_recording_mbid(recording_mbid): return _get_feedback_for_recording("recording_mbid", recording_mbid) -@feedback_api_bp.route("/recording//get-feedback", methods=["GET"]) +@feedback_api_bp.get("/recording//get-feedback") @crossdomain @ratelimit() def get_feedback_for_recording_msid(recording_msid): @@ -229,7 +229,7 @@ def _get_feedback_for_recordings_for_user_helper(user_name, recording_msids, rec }) -@feedback_api_bp.route("/user//get-feedback-for-recordings", methods=["POST"]) +@feedback_api_bp.post("/user//get-feedback-for-recordings") @crossdomain @ratelimit() def get_feedback_for_recordings_for_user_post(user_name): @@ -256,7 +256,7 @@ def get_feedback_for_recordings_for_user_post(user_name): return _get_feedback_for_recordings_for_user_helper(user_name, recording_msids, recording_mbids) -@feedback_api_bp.route("/user//get-feedback-for-recordings", methods=["GET"]) +@feedback_api_bp.get("/user//get-feedback-for-recordings") @crossdomain @ratelimit() def get_feedback_for_recordings_for_user_get(user_name): @@ -298,7 +298,7 @@ def get_feedback_for_recordings_for_user_get(user_name): -@feedback_api_bp.route("/import", methods=["POST"]) +@feedback_api_bp.post("/import") @crossdomain @ratelimit() def import_feedback(): diff --git a/listenbrainz/webserver/views/fresh_releases.py b/listenbrainz/webserver/views/fresh_releases.py index ed00a3476b..beb63e4995 100644 --- a/listenbrainz/webserver/views/fresh_releases.py +++ b/listenbrainz/webserver/views/fresh_releases.py @@ -1,5 +1,7 @@ import sentry_sdk import datetime + +from brainzutils.ratelimit import ratelimit from flask import Blueprint, jsonify, request import listenbrainz.db.user as db_user @@ -13,8 +15,9 @@ fresh_releases_bp = Blueprint('fresh_releases_v1', __name__) -@fresh_releases_bp.route("/user//fresh_releases") +@fresh_releases_bp.get("/user//fresh_releases") @crossdomain +@ratelimit() def get_releases(user_name): """ Get fresh releases data for the given user. diff --git a/listenbrainz/webserver/views/index.py b/listenbrainz/webserver/views/index.py index b00edbc592..c0e59776d2 100644 --- a/listenbrainz/webserver/views/index.py +++ b/listenbrainz/webserver/views/index.py @@ -38,7 +38,7 @@ SEARCH_USER_LIMIT = 100 # max number of users to return in search username results -@index_bp.route("/", methods=['POST']) +@index_bp.post("/") def index(): if _ts: try: @@ -65,7 +65,7 @@ def index(): return jsonify(props) -@index_bp.route("/current-status/", methods=['POST']) +@index_bp.post("/current-status/") @web_listenstore_needed def current_status(): load = "%.2f %.2f %.2f" % os.getloadavg() @@ -103,7 +103,7 @@ def current_status(): return jsonify(data) -@index_bp.route("/recent/", methods=['POST']) +@index_bp.post("/recent/") def recent_listens(): recent = [] for listen in _redis.get_recent_listens(NUMBER_OF_RECENT_LISTENS): @@ -172,7 +172,7 @@ def gdpr_notice(): return jsonify({'status': 'not_agreed'}), 400 -@index_bp.route('/search/', methods=['POST', 'OPTIONS']) +@index_bp.post("/search/") def search(): search_term = request.args.get("search_term") user_id = current_user.id if current_user.is_authenticated else None @@ -187,7 +187,7 @@ def search(): }) -@index_bp.route('/feed/', methods=['POST', 'OPTIONS']) +@index_bp.post("/feed/") @login_required def feed(): user_id = current_user.id @@ -216,7 +216,7 @@ def feed(): }) -@index_bp.route('/delete-user/') +@index_bp.get("/delete-user/") def mb_user_deleter(musicbrainz_row_id): """ This endpoint is used by MusicBrainz to delete accounts once they are deleted on MusicBrainz too. @@ -270,8 +270,8 @@ def _get_user_count(): return user_count -@index_bp.route("/", defaults={'path': ''}) -@index_bp.route('//') +@index_bp.get("/", defaults={'path': ''}) +@index_bp.get('//') @web_listenstore_needed def index_pages(path): # this is a catch-all route, all unmatched urls match this route instead of raising a 404 diff --git a/listenbrainz/webserver/views/login.py b/listenbrainz/webserver/views/login.py index de3a2346ed..e5f296fbf3 100644 --- a/listenbrainz/webserver/views/login.py +++ b/listenbrainz/webserver/views/login.py @@ -13,7 +13,7 @@ login_bp = Blueprint('login', __name__) -@login_bp.route('/') +@login_bp.get('/') @web_musicbrainz_needed @web_listenstore_needed @login_forbidden @@ -21,7 +21,7 @@ def index(): return render_template('index.html') -@login_bp.route('/musicbrainz/') +@login_bp.get('/musicbrainz/') @web_musicbrainz_needed @web_listenstore_needed @login_forbidden @@ -30,7 +30,7 @@ def musicbrainz(): return redirect(provider.get_authentication_uri()) -@login_bp.route('/musicbrainz/post/') +@login_bp.get('/musicbrainz/post/') @web_musicbrainz_needed @web_listenstore_needed @login_forbidden @@ -68,7 +68,7 @@ def musicbrainz_post(): return redirect(url_for('index.index_pages', path='')) -@login_bp.route('/logout/') +@login_bp.get('/logout/') @login_required def logout(): session.clear() diff --git a/listenbrainz/webserver/views/metadata_api.py b/listenbrainz/webserver/views/metadata_api.py index 61bdc7dd4c..d131f8ef4e 100644 --- a/listenbrainz/webserver/views/metadata_api.py +++ b/listenbrainz/webserver/views/metadata_api.py @@ -81,7 +81,7 @@ def fetch_release_group_metadata(release_group_mbids, incs): return result -@metadata_bp.route("/recording/", methods=["GET"]) +@metadata_bp.get("/recording/") @crossdomain @ratelimit() def metadata_recording(): @@ -124,7 +124,7 @@ def metadata_recording(): return jsonify(result) -@metadata_bp.route("/recording/", methods=["POST"]) +@metadata_bp.post("/recording/") @crossdomain @ratelimit() def metadata_recording_post(): @@ -178,7 +178,7 @@ def metadata_recording_post(): return jsonify(result) -@metadata_bp.route("/release_group/", methods=["GET"]) +@metadata_bp.get("/release_group/") @crossdomain @ratelimit() def metadata_release_group(): @@ -237,7 +237,7 @@ def process_results(match, metadata, incs): return result -@metadata_bp.route("/lookup/", methods=["GET"]) +@metadata_bp.get("/lookup/") @crossdomain @ratelimit() def get_mbid_mapping(): @@ -369,7 +369,7 @@ def process_bulk_lookup_results(all_results, all_params, query, make_input): return all_results, all_params -@metadata_bp.route("/lookup/", methods=["POST"]) +@metadata_bp.post("/lookup/") @crossdomain @ratelimit() def get_mbid_mapping_post(): @@ -449,7 +449,7 @@ def get_mbid_mapping_post(): raise APIInternalServerError("Server failed to lookup recording") -@metadata_bp.route("/submit_manual_mapping/", methods=["POST"]) +@metadata_bp.post("/submit_manual_mapping/") @crossdomain @ratelimit() def submit_manual_mapping(): @@ -492,7 +492,7 @@ def submit_manual_mapping(): return jsonify({"status": "ok"}) -@metadata_bp.route("/get_manual_mapping/", methods=["GET"]) +@metadata_bp.get("/get_manual_mapping/") @crossdomain @ratelimit() def get_manual_mapping(): @@ -522,7 +522,7 @@ def get_manual_mapping(): return jsonify({"status": "none"}), 404 -@metadata_bp.route("/artist/", methods=["GET"]) +@metadata_bp.get("/artist/") @crossdomain @ratelimit() def metadata_artist(): diff --git a/listenbrainz/webserver/views/metadata_viewer.py b/listenbrainz/webserver/views/metadata_viewer.py index 5f07898b99..312bf03c67 100644 --- a/listenbrainz/webserver/views/metadata_viewer.py +++ b/listenbrainz/webserver/views/metadata_viewer.py @@ -7,14 +7,14 @@ metadata_viewer_bp = Blueprint("metadata_viewer", __name__) -@metadata_viewer_bp.route("/", defaults={'path': ''}) -@metadata_viewer_bp.route('//') +@metadata_viewer_bp.get("/", defaults={'path': ''}) +@metadata_viewer_bp.get('//') @login_required def playing_now_metadata_page(path): return render_template("index.html") -@metadata_viewer_bp.route("/", methods=["POST"]) +@metadata_viewer_bp.post("/") @web_listenstore_needed @login_required def playing_now_metadata_viewer(): diff --git a/listenbrainz/webserver/views/missing_musicbrainz_data_api.py b/listenbrainz/webserver/views/missing_musicbrainz_data_api.py index 80ab4f67ce..9075712406 100644 --- a/listenbrainz/webserver/views/missing_musicbrainz_data_api.py +++ b/listenbrainz/webserver/views/missing_musicbrainz_data_api.py @@ -33,7 +33,7 @@ missing_musicbrainz_data_api_bp = Blueprint('missing_musicbrainz_data_v1', __name__) -@missing_musicbrainz_data_api_bp.route("/user//", methods=['GET']) +@missing_musicbrainz_data_api_bp.get("/user//") @crossdomain @ratelimit() def get_missing_musicbrainz_data(user_name): diff --git a/listenbrainz/webserver/views/pinned_recording_api.py b/listenbrainz/webserver/views/pinned_recording_api.py index 7c3f480560..cf5badd7b5 100644 --- a/listenbrainz/webserver/views/pinned_recording_api.py +++ b/listenbrainz/webserver/views/pinned_recording_api.py @@ -21,7 +21,7 @@ pinned_recording_api_bp = Blueprint("pinned_rec_api_bp_v1", __name__) -@pinned_recording_api_bp.route("/pin", methods=["POST"]) +@pinned_recording_api_bp.post("/pin") @crossdomain @ratelimit() def pin_recording_for_user(): @@ -73,7 +73,7 @@ def pin_recording_for_user(): return jsonify({"pinned_recording": recording_to_pin_with_id.to_api()}) -@pinned_recording_api_bp.route("/pin/unpin", methods=["POST"]) +@pinned_recording_api_bp.post("/pin/unpin") @crossdomain @ratelimit() def unpin_recording_for_user(): @@ -101,7 +101,7 @@ def unpin_recording_for_user(): return jsonify({"status": "ok"}) -@pinned_recording_api_bp.route("/pin/delete/", methods=["POST"]) +@pinned_recording_api_bp.post("/pin/delete/") @crossdomain @ratelimit() def delete_pin_for_user(row_id): @@ -131,7 +131,7 @@ def delete_pin_for_user(row_id): return jsonify({"status": "ok"}) -@pinned_recording_api_bp.route("//pins", methods=["GET"]) +@pinned_recording_api_bp.get("//pins") @crossdomain @ratelimit() def get_pins_for_user(user_name): @@ -209,7 +209,7 @@ def get_pins_for_user(user_name): ) -@pinned_recording_api_bp.route("//pins/following", methods=["GET"]) +@pinned_recording_api_bp.get("//pins/following") @crossdomain @ratelimit() def get_pins_for_user_following(user_name): @@ -282,7 +282,7 @@ def get_pins_for_user_following(user_name): ) -@pinned_recording_api_bp.route("//pins/current", methods=["GET"]) +@pinned_recording_api_bp.get("//pins/current") @crossdomain @ratelimit() def get_current_pin_for_user(user_name): @@ -331,7 +331,7 @@ def get_current_pin_for_user(user_name): }) -@pinned_recording_api_bp.route("/pin/update/", methods=["POST"]) +@pinned_recording_api_bp.post("/pin/update/") @crossdomain @ratelimit() def update_blurb_content_pinned_recording(row_id): diff --git a/listenbrainz/webserver/views/player.py b/listenbrainz/webserver/views/player.py index 7762f2e349..8f59120aba 100644 --- a/listenbrainz/webserver/views/player.py +++ b/listenbrainz/webserver/views/player.py @@ -17,7 +17,7 @@ player_bp = Blueprint("player", __name__) -@player_bp.route("/", methods=["POST"]) +@player_bp.post("/") def load_instant(): """ This endpoint takes in a list of recording_mbids and optional desc/name arguments and then loads @@ -69,7 +69,7 @@ def load_instant(): return jsonify({"playlist": playlist.serialize_jspf()}) -@player_bp.route("/release//", methods=["POST"]) +@player_bp.post("/release//") def load_release(release_mbid): """ This endpoint takes a release mbid, loads the tracks for this release and makes a playlist from it and @@ -124,7 +124,7 @@ def load_release(release_mbid): return jsonify({"playlist": playlist.serialize_jspf() if playlist is not None else {}}) -@player_bp.route('/', defaults={'path': ''}) -@player_bp.route('//') +@player_bp.get('/', defaults={'path': ''}) +@player_bp.get('//') def index(path): return render_template("index.html") diff --git a/listenbrainz/webserver/views/playlist.py b/listenbrainz/webserver/views/playlist.py index 44ac0b984a..ce381600e8 100644 --- a/listenbrainz/webserver/views/playlist.py +++ b/listenbrainz/webserver/views/playlist.py @@ -10,13 +10,13 @@ playlist_bp = Blueprint("playlist", __name__) -@playlist_bp.route("/", defaults={'path': ''}) -@playlist_bp.route('//') +@playlist_bp.get("/", defaults={'path': ''}) +@playlist_bp.get('//') def playlist_page(path): return render_template("index.html") -@playlist_bp.route("//", methods=["POST"]) +@playlist_bp.post("//") @web_listenstore_needed def load_playlist(playlist_mbid: str): """Load a single playlist by id diff --git a/listenbrainz/webserver/views/playlist_api.py b/listenbrainz/webserver/views/playlist_api.py index 915d8aa33a..12327b5267 100644 --- a/listenbrainz/webserver/views/playlist_api.py +++ b/listenbrainz/webserver/views/playlist_api.py @@ -276,7 +276,7 @@ def fetch_playlist_recording_metadata(playlist: Playlist): raise APIInternalServerError("Failed to fetch metadata for a playlist. Please try again.") -@playlist_api_bp.route("/create", methods=["POST"]) +@playlist_api_bp.post("/create") @crossdomain @ratelimit() @api_listenstore_needed @@ -400,7 +400,7 @@ def create_playlist(): return jsonify({'status': 'ok', 'playlist_mbid': playlist.mbid}) -@playlist_api_bp.route("/search", methods=["GET"]) +@playlist_api_bp.get("/search") @crossdomain @ratelimit() @api_listenstore_needed @@ -428,7 +428,7 @@ def search_playlist(): return jsonify(serialize_playlists(playlists, playlist_count, count, offset)) -@playlist_api_bp.route("/edit/", methods=["POST"]) +@playlist_api_bp.post("/edit/") @crossdomain @ratelimit() @api_listenstore_needed @@ -508,7 +508,7 @@ def edit_playlist(playlist_mbid): return jsonify({'status': 'ok'}) -@playlist_api_bp.route("/", methods=["GET"]) +@playlist_api_bp.get("/") @crossdomain @ratelimit() @api_listenstore_needed @@ -548,7 +548,7 @@ def get_playlist(playlist_mbid): return jsonify(playlist.serialize_jspf()) -@playlist_api_bp.route("//xspf", methods=["GET"]) +@playlist_api_bp.get("//xspf") @crossdomain @ratelimit() @api_listenstore_needed @@ -601,8 +601,8 @@ def get_playlist_xspf(playlist_mbid): raise PlaylistAPIXMLError("Internal server error occurred.", status_code=500) -@playlist_api_bp.route("//item/add/", methods=["POST"]) -@playlist_api_bp.route("//item/add", methods=["POST"], defaults={'offset': None}) +@playlist_api_bp.post("//item/add/") +@playlist_api_bp.post("//item/add", defaults={'offset': None}) @crossdomain @ratelimit() @api_listenstore_needed @@ -663,7 +663,7 @@ def add_playlist_item(playlist_mbid, offset): return jsonify({'status': 'ok'}) -@playlist_api_bp.route("//item/move", methods=["POST"]) +@playlist_api_bp.post("//item/move") @crossdomain @ratelimit() @api_listenstore_needed @@ -715,7 +715,7 @@ def move_playlist_item(playlist_mbid): return jsonify({'status': 'ok'}) -@playlist_api_bp.route("//item/delete", methods=["POST"]) +@playlist_api_bp.post("//item/delete") @crossdomain @ratelimit() @api_listenstore_needed @@ -765,7 +765,7 @@ def delete_playlist_item(playlist_mbid): return jsonify({'status': 'ok'}) -@playlist_api_bp.route("//delete", methods=["POST"]) +@playlist_api_bp.post("//delete") @crossdomain @ratelimit() @api_listenstore_needed @@ -803,7 +803,7 @@ def delete_playlist(playlist_mbid): return jsonify({'status': 'ok'}) -@playlist_api_bp.route("//copy", methods=["POST"]) +@playlist_api_bp.post("//copy") @crossdomain @ratelimit() @api_listenstore_needed @@ -838,7 +838,7 @@ def copy_playlist(playlist_mbid): return jsonify({'status': 'ok', 'playlist_mbid': new_playlist.mbid}) -@playlist_api_bp.route("//export/", methods=["POST"]) +@playlist_api_bp.post("//export/") @crossdomain @ratelimit() @api_listenstore_needed @@ -882,7 +882,7 @@ def export_playlist(playlist_mbid, service): raise APIError(error.get("error") or exc.response.reason, exc.response.status_code) -@playlist_api_bp.route("/import/", methods=["GET"]) +@playlist_api_bp.get("/import/") @crossdomain @ratelimit() @api_listenstore_needed @@ -934,7 +934,7 @@ def import_playlist_from_music_service(service): raise APIError(error.get("error") or exc.response.reason, exc.response.status_code) -@playlist_api_bp.route("/spotify//tracks", methods=["GET"]) +@playlist_api_bp.get("/spotify//tracks") @crossdomain @ratelimit() @api_listenstore_needed @@ -970,7 +970,7 @@ def import_tracks_from_spotify_playlist(playlist_id): raise APIError(error.get("error") or exc.response.reason, exc.response.status_code) -@playlist_api_bp.route("/apple_music//tracks", methods=["GET"]) +@playlist_api_bp.get("/apple_music//tracks") @crossdomain @ratelimit() @api_listenstore_needed @@ -1006,7 +1006,7 @@ def import_tracks_from_apple_playlist(playlist_id): raise APIError(error.get("error") or exc.response.reason, exc.response.status_code) -@playlist_api_bp.route("/export-jspf/", methods=["POST"]) +@playlist_api_bp.post("/export-jspf/") @crossdomain @ratelimit() @api_listenstore_needed diff --git a/listenbrainz/webserver/views/popularity_api.py b/listenbrainz/webserver/views/popularity_api.py index a22eef1943..44eac6ceef 100644 --- a/listenbrainz/webserver/views/popularity_api.py +++ b/listenbrainz/webserver/views/popularity_api.py @@ -10,7 +10,7 @@ popularity_api_bp = Blueprint('popularity_api_v1', __name__) -@popularity_api_bp.route("/top-recordings-for-artist/", methods=["GET"]) +@popularity_api_bp.get("/top-recordings-for-artist/") @crossdomain @ratelimit() def top_recordings_for_artist(artist_mbid): @@ -55,7 +55,7 @@ def top_recordings_for_artist(artist_mbid): raise APIInternalServerError("Failed to fetch metadata for recordings. Please try again.") -@popularity_api_bp.route("/top-release-groups-for-artist/", methods=["GET"]) +@popularity_api_bp.get("/top-release-groups-for-artist/") @crossdomain @ratelimit() def top_release_groups_for_artist(artist_mbid): @@ -136,7 +136,7 @@ def fetch_entity_popularity_counts(entity): return popularity_data -@popularity_api_bp.route("/recording", methods=["POST"]) +@popularity_api_bp.post("/recording") @crossdomain @ratelimit() def popularity_recording(): @@ -178,7 +178,7 @@ def popularity_recording(): return fetch_entity_popularity_counts("recording") -@popularity_api_bp.route("/artist", methods=["POST"]) +@popularity_api_bp.post("/artist") @crossdomain @ratelimit() def popularity_artist(): @@ -220,7 +220,7 @@ def popularity_artist(): return fetch_entity_popularity_counts("artist") -@popularity_api_bp.route("/release", methods=["POST"]) +@popularity_api_bp.post("/release") @crossdomain @ratelimit() def popularity_release(): @@ -262,7 +262,7 @@ def popularity_release(): return fetch_entity_popularity_counts("release") -@popularity_api_bp.route("/release-group", methods=["POST"]) +@popularity_api_bp.post("/release-group") @crossdomain @ratelimit() def popularity_release_group(): diff --git a/listenbrainz/webserver/views/recommendations_cf_recording.py b/listenbrainz/webserver/views/recommendations_cf_recording.py index ac985af0c1..ba6d18a63e 100644 --- a/listenbrainz/webserver/views/recommendations_cf_recording.py +++ b/listenbrainz/webserver/views/recommendations_cf_recording.py @@ -12,7 +12,7 @@ SERVER_URL = "https://labs.api.listenbrainz.org/recording-mbid-lookup/json" -@recommendations_cf_recording_bp.route("//", methods=["POST"]) +@recommendations_cf_recording_bp.post("//") def info(user_name): """ Show info about the recommended tracks """ @@ -29,7 +29,7 @@ def info(user_name): }) -@recommendations_cf_recording_bp.route("//raw/", methods=["POST"]) +@recommendations_cf_recording_bp.post("//raw/") def raw(user_name: str): """ Show raw track recommendations """ user = _get_user(user_name) @@ -154,7 +154,7 @@ def _get_playable_recommendations_list(mbids_and_ratings_list): return recommendations -@recommendations_cf_recording_bp.route('/', defaults={'path': ''}) -@recommendations_cf_recording_bp.route('//') +@recommendations_cf_recording_bp.get('/', defaults={'path': ''}) +@recommendations_cf_recording_bp.get('//') def index(path): return render_template("index.html") diff --git a/listenbrainz/webserver/views/recommendations_cf_recording_api.py b/listenbrainz/webserver/views/recommendations_cf_recording_api.py index 4bd5173a56..d7629fefa9 100644 --- a/listenbrainz/webserver/views/recommendations_cf_recording_api.py +++ b/listenbrainz/webserver/views/recommendations_cf_recording_api.py @@ -18,7 +18,7 @@ class RecommendationArtistType(Enum): raw = 'raw' -@recommendations_cf_recording_api_bp.route("/user//recording") +@recommendations_cf_recording_api_bp.get("/user//recording") @crossdomain @ratelimit() def get_recommendations(user_name): diff --git a/listenbrainz/webserver/views/recommendations_cf_recording_feedback_api.py b/listenbrainz/webserver/views/recommendations_cf_recording_feedback_api.py index 1692c62d0e..a47d5b356a 100644 --- a/listenbrainz/webserver/views/recommendations_cf_recording_feedback_api.py +++ b/listenbrainz/webserver/views/recommendations_cf_recording_feedback_api.py @@ -27,7 +27,7 @@ recommendation_feedback_api_bp = Blueprint('recommendation_feedback_api_v1', __name__) -@recommendation_feedback_api_bp.route("submit", methods=["POST"]) +@recommendation_feedback_api_bp.post("submit") @crossdomain @ratelimit() def submit_recommendation_feedback(): @@ -76,7 +76,7 @@ def submit_recommendation_feedback(): return jsonify({'status': 'ok'}) -@recommendation_feedback_api_bp.route("delete", methods=["POST"]) +@recommendation_feedback_api_bp.post("delete") @crossdomain @ratelimit() def delete_recommendation_feedback(): @@ -121,7 +121,7 @@ def delete_recommendation_feedback(): return jsonify({'status': 'ok'}) -@recommendation_feedback_api_bp.route("/user/", methods=["GET"]) +@recommendation_feedback_api_bp.get("/user/") @crossdomain @ratelimit() def get_feedback_for_user(user_name): @@ -198,7 +198,7 @@ def get_feedback_for_user(user_name): }) -@recommendation_feedback_api_bp.route("/user//recordings", methods=["GET"]) +@recommendation_feedback_api_bp.get("/user//recordings") @crossdomain @ratelimit() def get_feedback_for_recordings_for_user(user_name): diff --git a/listenbrainz/webserver/views/settings.py b/listenbrainz/webserver/views/settings.py index 15611d645c..967b437c78 100644 --- a/listenbrainz/webserver/views/settings.py +++ b/listenbrainz/webserver/views/settings.py @@ -28,7 +28,7 @@ settings_bp = Blueprint("settings", __name__) -@settings_bp.route("/resettoken/", methods=["POST"]) +@settings_bp.post("/resettoken/") @api_login_required def reset_token(): try: @@ -38,7 +38,7 @@ def reset_token(): raise APIInternalServerError("Something went wrong! Unable to reset token right now.") -@settings_bp.route("/select_timezone/", methods=["POST"]) +@settings_bp.post("/select_timezone/") @api_login_required def select_timezone(): pg_timezones = db_usersetting.get_pg_timezone(db_conn) @@ -51,7 +51,7 @@ def select_timezone(): return jsonify(data) -@settings_bp.route("/troi/", methods=["POST"]) +@settings_bp.post("/troi/") @login_required def set_troi_prefs(): current_troi_prefs = db_usersetting.get_troi_prefs(db_conn, current_user.id) @@ -61,7 +61,7 @@ def set_troi_prefs(): return jsonify(data) -@settings_bp.route("/import/", methods=["POST"]) +@settings_bp.post("/import/") @api_login_required def import_data(): """ Displays the import page to user, giving various options """ @@ -86,7 +86,7 @@ def import_data(): return jsonify(data) -@settings_bp.route('/delete/', methods=['POST']) +@settings_bp.post('/delete/') @api_login_required @web_listenstore_needed def delete(): @@ -107,7 +107,7 @@ def delete(): raise APIInternalServerError(f'Error while deleting user {current_user.musicbrainz_id}, please try again later.') -@settings_bp.route('/delete-listens/', methods=['POST']) +@settings_bp.post('/delete-listens/') @api_login_required @web_listenstore_needed def delete_listens(): @@ -153,7 +153,7 @@ def _get_service_or_raise_404(name: str, include_mb=False, exclude_apple=False) raise NotFound("Service %s is invalid." % (name,)) -@settings_bp.route('/music-services/details/', methods=['POST']) +@settings_bp.post('/music-services/details/') @api_login_required def music_services_details(): spotify_service = SpotifyService() @@ -203,7 +203,7 @@ def music_services_details(): return jsonify(data) -@settings_bp.route('/music-services//callback/') +@settings_bp.get('/music-services//callback/') @login_required def music_services_callback(service_name: str): service = _get_service_or_raise_404(service_name, exclude_apple=True) @@ -217,7 +217,7 @@ def music_services_callback(service_name: str): return redirect(url_for('settings.index', path='music-services/details')) -@settings_bp.route('/music-services//refresh/', methods=['POST']) +@settings_bp.post('/music-services//refresh/') @api_login_required def refresh_service_token(service_name: str): service = _get_service_or_raise_404(service_name, include_mb=True, exclude_apple=True) @@ -237,7 +237,7 @@ def refresh_service_token(service_name: str): return jsonify({"access_token": user["access_token"]}) -@settings_bp.route('/music-services//connect/', methods=['POST']) +@settings_bp.post('/music-services//connect/') @api_login_required def music_services_connect(service_name: str): """ Connect last.fm/libre.fm account to ListenBrainz user. """ @@ -265,7 +265,7 @@ def music_services_connect(service_name: str): return jsonify({"success": True}) -@settings_bp.route('/music-services//disconnect/', methods=['POST']) +@settings_bp.post('/music-services//disconnect/') @api_login_required def music_services_disconnect(service_name: str): service = _get_service_or_raise_404(service_name) @@ -306,7 +306,7 @@ def music_services_disconnect(service_name: str): raise BadRequest('Invalid action') -@settings_bp.route('/music-services//set-token/', methods=['POST']) +@settings_bp.post('/music-services//set-token/') @api_login_required def music_services_set_token(service_name: str): if service_name != 'apple': @@ -323,7 +323,7 @@ def music_services_set_token(service_name: str): return jsonify({"success": True}) -@settings_bp.route('/link-listens/', methods=['POST']) +@settings_bp.post('/link-listens/') @api_login_required def link_listens(): """ Returns a list of unlinked listens for the user """ @@ -335,8 +335,8 @@ def link_listens(): return jsonify(data) -@settings_bp.route('/', defaults={'path': ''}) -@settings_bp.route('//') +@settings_bp.get('/', defaults={'path': ''}) +@settings_bp.get('//') @login_required def index(path): return render_template("index.html") diff --git a/listenbrainz/webserver/views/social_api.py b/listenbrainz/webserver/views/social_api.py index be1e4ed034..1cda098c8d 100644 --- a/listenbrainz/webserver/views/social_api.py +++ b/listenbrainz/webserver/views/social_api.py @@ -12,7 +12,7 @@ social_api_bp = Blueprint('social_api_v1', __name__) -@social_api_bp.route("/user//followers", methods=["GET"]) +@social_api_bp.get("/user//followers") @crossdomain @ratelimit() def get_followers(user_name: str): @@ -44,7 +44,7 @@ def get_followers(user_name: str): return jsonify({"followers": followers, "user": user["musicbrainz_id"]}) -@social_api_bp.route("/user//following", methods=["GET"]) +@social_api_bp.get("/user//following") @crossdomain @ratelimit() def get_following(user_name: str): @@ -76,7 +76,7 @@ def get_following(user_name: str): return jsonify({"following": following, "user": user["musicbrainz_id"]}) -@social_api_bp.route("/user//follow", methods=["POST"]) +@social_api_bp.post("/user//follow") @crossdomain @ratelimit() def follow_user(user_name: str): @@ -114,7 +114,7 @@ def follow_user(user_name: str): return jsonify({"status": "ok"}) -@social_api_bp.route("/user//unfollow", methods=["POST"]) +@social_api_bp.post("/user//unfollow") @crossdomain @ratelimit() def unfollow_user(user_name: str): diff --git a/listenbrainz/webserver/views/stats_api.py b/listenbrainz/webserver/views/stats_api.py index 0aff31904e..a39a4c755f 100644 --- a/listenbrainz/webserver/views/stats_api.py +++ b/listenbrainz/webserver/views/stats_api.py @@ -32,7 +32,7 @@ stats_api_bp = Blueprint('stats_api_v1', __name__) -@stats_api_bp.route("/user//artists") +@stats_api_bp.get("/user//artists") @crossdomain @ratelimit() def get_artist(user_name): @@ -95,7 +95,7 @@ def get_artist(user_name): return _get_entity_stats(user_name, "artists", "total_artist_count") -@stats_api_bp.route("/user//releases") +@stats_api_bp.get("/user//releases") @crossdomain @ratelimit() def get_release(user_name): @@ -163,7 +163,7 @@ def get_release(user_name): return _get_entity_stats(user_name, "releases", "total_release_count") -@stats_api_bp.route("/user//release-groups") +@stats_api_bp.get("/user//release-groups") @crossdomain @ratelimit() def get_release_group(user_name): @@ -234,7 +234,7 @@ def get_release_group(user_name): return _get_entity_stats(user_name, "release_groups", "total_release_group_count") -@stats_api_bp.route("/user//recordings") +@stats_api_bp.get("/user//recordings") @crossdomain @ratelimit() def get_recording(user_name): @@ -334,7 +334,7 @@ def get_entity_stats_last_updated(user_name: str, entity: str, count_key: str): entity_list, total_entity_count = _process_user_entity(stats, 0, 1) return stats.last_updated -@stats_api_bp.route("/user//listening-activity") +@stats_api_bp.get("/user//listening-activity") @crossdomain @ratelimit() def get_listening_activity(user_name: str): @@ -409,7 +409,7 @@ def get_listening_activity(user_name: str): }}) -@stats_api_bp.route("/user//daily-activity") +@stats_api_bp.get("/user//daily-activity") @crossdomain @ratelimit() def get_daily_activity(user_name: str): @@ -491,7 +491,7 @@ def get_daily_activity(user_name: str): }}) -@stats_api_bp.route("/user//artist-map") +@stats_api_bp.get("/user//artist-map") @crossdomain @ratelimit() def get_artist_map(user_name: str): @@ -558,7 +558,7 @@ def get_artist_map(user_name: str): }) -@stats_api_bp.route("/artist//listeners") +@stats_api_bp.get("/artist//listeners") @crossdomain @ratelimit() def get_artist_listeners(artist_mbid): @@ -619,7 +619,7 @@ def get_artist_listeners(artist_mbid): return _get_entity_listeners("artists", artist_mbid) -@stats_api_bp.route("/release-group//listeners") +@stats_api_bp.get("/release-group//listeners") @crossdomain @ratelimit() def get_release_group_listeners(release_group_mbid): @@ -725,7 +725,7 @@ def _get_entity_listeners(entity, mbid): return jsonify({"payload": stats}) -@stats_api_bp.route("/sitewide/artists") +@stats_api_bp.get("/sitewide/artists") @crossdomain @ratelimit() def get_sitewide_artist(): @@ -782,7 +782,7 @@ def get_sitewide_artist(): return _get_sitewide_stats("artists") -@stats_api_bp.route("/sitewide/releases") +@stats_api_bp.get("/sitewide/releases") @crossdomain @ratelimit() def get_sitewide_release(): @@ -849,7 +849,7 @@ def get_sitewide_release(): return _get_sitewide_stats("releases") -@stats_api_bp.route("/sitewide/release-groups") +@stats_api_bp.get("/sitewide/release-groups") @crossdomain @ratelimit() def get_sitewide_release_group(): @@ -918,7 +918,7 @@ def get_sitewide_release_group(): return _get_sitewide_stats("release_groups") -@stats_api_bp.route("/sitewide/recordings") +@stats_api_bp.get("/sitewide/recordings") @crossdomain @ratelimit() def get_sitewide_recording(): @@ -1011,7 +1011,7 @@ def _get_sitewide_stats(entity: str): }) -@stats_api_bp.route("/sitewide/listening-activity") +@stats_api_bp.get("/sitewide/listening-activity") @crossdomain @ratelimit() def get_sitewide_listening_activity(): @@ -1084,7 +1084,7 @@ def get_sitewide_listening_activity(): }) -@stats_api_bp.route("/sitewide/artist-map") +@stats_api_bp.get("/sitewide/artist-map") @crossdomain @ratelimit() def get_sitewide_artist_map(): @@ -1225,8 +1225,8 @@ def _get_artist_map_stats(user_id, stats_range): return stats -@stats_api_bp.route("/user//year-in-music") -@stats_api_bp.route("/user//year-in-music/") +@stats_api_bp.get("/user//year-in-music") +@stats_api_bp.get("/user//year-in-music/") @crossdomain def year_in_music(user_name: str, year: int = 2024): """ Get data for year in music stuff """ diff --git a/listenbrainz/webserver/views/status_api.py b/listenbrainz/webserver/views/status_api.py index bac2269172..f2f6b61277 100644 --- a/listenbrainz/webserver/views/status_api.py +++ b/listenbrainz/webserver/views/status_api.py @@ -26,7 +26,7 @@ status_api_bp = Blueprint("status_api_v1", __name__) -@status_api_bp.route("/get-dump-info", methods=["GET"]) +@status_api_bp.get("/get-dump-info") @crossdomain @ratelimit() def get_dump_info(): @@ -237,7 +237,7 @@ def get_playlist_status(): } -@status_api_bp.route("/service-status", methods=["GET"]) +@status_api_bp.get("/service-status") @crossdomain @ratelimit() def service_status(): @@ -260,7 +260,7 @@ def service_status(): return jsonify(get_service_status()) -@status_api_bp.route("/playlist-status", methods=["GET"]) +@status_api_bp.get("/playlist-status") @crossdomain @ratelimit() def playlist_status(): diff --git a/listenbrainz/webserver/views/user.py b/listenbrainz/webserver/views/user.py index bd5836e15d..481a2e1b77 100644 --- a/listenbrainz/webserver/views/user.py +++ b/listenbrainz/webserver/views/user.py @@ -42,7 +42,7 @@ def index(path): return render_template("index.html", user=current_user) -@user_bp.route("//", methods=['POST']) +@user_bp.post("//") @web_listenstore_needed def profile(user_name): # Which database to use to showing user listens. @@ -118,9 +118,9 @@ def profile(user_name): return jsonify(data) -@user_bp.route("//stats/top-artists/", methods=['POST']) -@user_bp.route("//stats/top-albums/", methods=['POST']) -@user_bp.route("//stats/top-tracks/", methods=['POST']) +@user_bp.post("//stats/top-artists/") +@user_bp.post("//stats/top-albums/") +@user_bp.post("//stats/top-tracks/") def charts(user_name): """ Show the top entitys for the user. """ user = _get_user(user_name) @@ -140,7 +140,7 @@ def charts(user_name): return jsonify(props) -@user_bp.route("//stats/", methods=['POST']) +@user_bp.post("//stats/") def stats(user_name: str): """ Show user stats """ user = _get_user(user_name) @@ -160,7 +160,7 @@ def stats(user_name: str): return jsonify(data) -@user_bp.route("//playlists/", methods=['POST']) +@user_bp.post("//playlists/") @web_listenstore_needed def playlists(user_name: str): """ Show user playlists """ @@ -194,7 +194,7 @@ def playlists(user_name: str): return jsonify(data) -@user_bp.route("//recommendations/", methods=['POST']) +@user_bp.post("//recommendations/") @web_listenstore_needed def recommendation_playlists(user_name: str): """ Show playlists created for user """ @@ -235,7 +235,7 @@ def recommendation_playlists(user_name: str): return jsonify(data) -@user_bp.route("//report-user/", methods=['POST']) +@user_bp.post("//report-user/") @api_login_required def report_abuse(user_name): data = request.json @@ -279,7 +279,7 @@ def logged_in_user_follows_user(user): return None -@user_bp.route("//taste/", methods=['POST']) +@user_bp.post("//taste/") @web_listenstore_needed def taste(user_name: str): """ Show user feedback(love/hate) and pins. @@ -401,8 +401,8 @@ def create_node(id): } -@user_bp.route("//year-in-music/", methods=['POST']) -@user_bp.route("//year-in-music//", methods=['POST']) +@user_bp.post("//year-in-music/") +@user_bp.post("//year-in-music//") def year_in_music(user_name, year: int = 2024): """ Year in Music """ if year not in (2021, 2022, 2023, 2024): @@ -445,8 +445,8 @@ def year_in_music(user_name, year: int = 2024): }) -@user_bp.route("//", defaults={'path': ''}) -@user_bp.route('///') +@user_bp.get("//", defaults={'path': ''}) +@user_bp.get('///') @web_listenstore_needed def index(user_name, path): user = _get_user(user_name) diff --git a/listenbrainz/webserver/views/user_settings_api.py b/listenbrainz/webserver/views/user_settings_api.py index 82f897808d..94ef3e41af 100644 --- a/listenbrainz/webserver/views/user_settings_api.py +++ b/listenbrainz/webserver/views/user_settings_api.py @@ -31,7 +31,7 @@ ] -@user_settings_api_bp.route("/flair", methods=["POST"]) +@user_settings_api_bp.post("/flair") @crossdomain @ratelimit() def update_flair(): @@ -56,7 +56,7 @@ def update_flair(): return jsonify({"success": True}) -@user_settings_api_bp.route('/timezone', methods=["POST"]) +@user_settings_api_bp.post('/timezone') @crossdomain @ratelimit() def reset_timezone(): @@ -87,7 +87,7 @@ def reset_timezone(): return jsonify({"status": "ok"}) -@user_settings_api_bp.route('/troi', methods=["POST"]) +@user_settings_api_bp.post('/troi') @crossdomain @ratelimit() def update_troi_prefs(): @@ -131,7 +131,7 @@ def update_troi_prefs(): } -@user_settings_api_bp.route('/brainzplayer', methods=["POST"]) +@user_settings_api_bp.post('/brainzplayer') @crossdomain @ratelimit() def update_brainzplayer_prefs(): diff --git a/listenbrainz/webserver/views/user_timeline_event_api.py b/listenbrainz/webserver/views/user_timeline_event_api.py index 7a8975fa74..bb94218c7b 100644 --- a/listenbrainz/webserver/views/user_timeline_event_api.py +++ b/listenbrainz/webserver/views/user_timeline_event_api.py @@ -54,7 +54,7 @@ user_timeline_event_api_bp = Blueprint('user_timeline_event_api_bp', __name__) -@user_timeline_event_api_bp.route('/user//timeline-event/create/recording', methods=['POST', 'OPTIONS']) +@user_timeline_event_api_bp.post('/user//timeline-event/create/recording') @crossdomain @ratelimit() def create_user_recording_recommendation_event(user_name): @@ -108,7 +108,7 @@ def create_user_recording_recommendation_event(user_name): return jsonify(event_data) -@user_timeline_event_api_bp.route('/user//timeline-event/create/notification', methods=['POST', 'OPTIONS']) +@user_timeline_event_api_bp.post('/user//timeline-event/create/notification') @crossdomain @ratelimit() def create_user_notification_event(user_name): @@ -164,7 +164,7 @@ def create_user_notification_event(user_name): return jsonify(event_data) -@user_timeline_event_api_bp.route('/user//timeline-event/create/review', methods=['POST', 'OPTIONS']) +@user_timeline_event_api_bp.post('/user//timeline-event/create/review') @crossdomain @ratelimit() def create_user_cb_review_event(user_name): @@ -231,7 +231,7 @@ def create_user_cb_review_event(user_name): return jsonify(event_data) -@user_timeline_event_api_bp.route('/user//feed/events', methods=['OPTIONS', 'GET']) +@user_timeline_event_api_bp.get('/user//feed/events') @crossdomain @ratelimit() @api_listenstore_needed @@ -284,7 +284,7 @@ def user_feed(user_name: str): }}) -@user_timeline_event_api_bp.route('/user//feed/events/listens/following', methods=['OPTIONS', 'GET']) +@user_timeline_event_api_bp.get('/user//feed/events/listens/following') @crossdomain @ratelimit() @api_listenstore_needed @@ -334,7 +334,7 @@ def user_feed_listens_following(user_name: str): }}) -@user_timeline_event_api_bp.route('/user//feed/events/listens/similar', methods=['OPTIONS', 'GET']) +@user_timeline_event_api_bp.get('/user//feed/events/listens/similar') @crossdomain @ratelimit() @api_listenstore_needed @@ -392,7 +392,7 @@ def user_feed_listens_similar(user_name: str): }) -@user_timeline_event_api_bp.route("/user//feed/events/delete", methods=['OPTIONS', 'POST']) +@user_timeline_event_api_bp.post("/user//feed/events/delete") @crossdomain @ratelimit() def delete_feed_events(user_name): @@ -450,7 +450,7 @@ def delete_feed_events(user_name): raise APIBadRequest(f"Invalid JSON: {str(e)}") -@user_timeline_event_api_bp.route("/user//feed/events/hide", methods=['OPTIONS', 'POST']) +@user_timeline_event_api_bp.post("/user//feed/events/hide") @crossdomain @ratelimit() def hide_user_timeline_event(user_name): @@ -518,7 +518,7 @@ def hide_user_timeline_event(user_name): raise APIUnauthorized("You cannot hide events of this user") -@user_timeline_event_api_bp.route("/user//feed/events/unhide", methods=['OPTIONS', 'POST']) +@user_timeline_event_api_bp.post("/user//feed/events/unhide") @crossdomain @ratelimit() def unhide_user_timeline_event(user_name): @@ -560,7 +560,7 @@ def unhide_user_timeline_event(user_name): return jsonify({"status": "ok"}) -@user_timeline_event_api_bp.route('/user//timeline-event/create/recommend-personal', methods=['POST', 'OPTIONS']) +@user_timeline_event_api_bp.post('/user//timeline-event/create/recommend-personal') @crossdomain @ratelimit() def create_personal_recommendation_event(user_name):