diff --git a/app/api/pages.py b/app/api/pages.py index 2bc3e3cc..9f977755 100644 --- a/app/api/pages.py +++ b/app/api/pages.py @@ -9,7 +9,7 @@ from flask_openapi3 import APIBlueprint from pydantic import BaseModel, Field from app.db.userdata import PageTable -from app.lib.pagelib import recover_page_items, validate_page_items +from app.lib.pagelib import recover_page_items, remove_page_items, validate_page_items from app.utils.auth import get_current_userid bp_tag = Tag(name="Pages", description="Pages") @@ -32,7 +32,7 @@ def create_page(body: CreatePageBody): """ Create a new page. """ - items = validate_page_items(body.items) + items = validate_page_items(body.items, existing=[]) if len(items) == 0: return {"error": "No items to add"}, 400 @@ -46,41 +46,11 @@ def create_page(body: CreatePageBody): }, } - print(payload) PageTable.insert_one(payload) return {"message": "Page created"}, 201 -class AddPageItemsBody(BaseModel): - items: list[dict[str, Any]] = Field( - description="The items to add to the page", - example=[{"type": "album", "hash": "1234567890"}], - ) - - -class AddPageItemsPath(BaseModel): - page_id: int = Field(description="The ID of the page to add items to", example=1) - - -@api.post("//items") -def add_page_items(path: AddPageItemsPath, body: AddPageItemsBody): - """ - Add items to a page. - """ - new_items = validate_page_items(body.items) - - page = PageTable.get_by_id(path.page_id) - - if page is None: - return {"error": "Page not found"}, 404 - - page["items"].extend(new_items) - PageTable.update_items(page["id"], page["items"]) - - return {"message": "Items added to page"} - - @api.get("") def get_pages(): """ @@ -89,6 +59,65 @@ def get_pages(): return PageTable.get_all() +class AddPageItemBody(BaseModel): + item: dict[str, Any] = Field( + description="The item to add to the page", + example={"type": "album", "hash": "1234567890"}, + ) + + +class AddPageItemPath(BaseModel): + page_id: int = Field(description="The ID of the page to add items to", example=1) + + +@api.post("//items") +def add_page_item(path: AddPageItemPath, body: AddPageItemBody): + """ + Add an item to a page. + """ + page = PageTable.get_by_id(path.page_id) + + if page is None: + return {"error": "Page not found"}, 404 + + new_items = validate_page_items([body.item], existing=page["items"]) + + if len(new_items) == 0: + return {"error": "items already in page"}, 400 + + page["items"].extend(new_items) + PageTable.update_items(page["id"], page["items"]) + + return {"message": "Items added to page"} + + +class RemovePageItemBody(BaseModel): + item: dict[str, Any] = Field( + description="The item to remove from the page", + example={"type": "album", "hash": "1234567890"}, + ) + + +class RemovePageItemPath(BaseModel): + page_id: int = Field(description="The ID of the page to remove items from") + + +@api.delete("//items") +def remove_page_item(path: RemovePageItemPath, body: RemovePageItemBody): + """ + Remove an item from a page. + """ + page = PageTable.get_by_id(path.page_id) + + if page is None: + return {"error": "Page not found"}, 404 + + remaining = remove_page_items(page["items"], body.item) + PageTable.update_items(page["id"], remaining) + + return {"message": "Item removed from page"} + + class GetPageBody(BaseModel): page_id: int = Field(description="The ID of the page to get", example=1) diff --git a/app/lib/pagelib.py b/app/lib/pagelib.py index 8d57eee0..1d1f58f9 100644 --- a/app/lib/pagelib.py +++ b/app/lib/pagelib.py @@ -1,17 +1,23 @@ +import json from typing import Any from app.serializers.album import serialize_for_card from app.serializers.artist import serialize_for_card as serialize_artist from app.store.albums import AlbumStore from app.store.artists import ArtistStore +from app.utils.hashing import create_hash -def validate_page_items(items: list[dict[str, str]]): +def validate_page_items(items: list[dict[str, str]], existing: list[dict[str, str]]): """ Validate the items in a page before adding them to the database. """ validated: list[dict[str, str]] = [] + indexed = set(create_hash(json.dumps(item)) for item in existing) for item in items: + if create_hash(json.dumps(item)) in indexed: + continue + if item["type"] == "album": album = AlbumStore.albummap.get(item["hash"]) @@ -28,7 +34,15 @@ def validate_page_items(items: list[dict[str, str]]): return validated -def recover_page_items(items: list[dict[str, str]]): +def remove_page_items(existing: list[dict[str, str]], item: dict[str, str]): + return [ + i + for i in existing + if create_hash(json.dumps(i)) != create_hash(json.dumps(item)) + ] + + +def recover_page_items(items: list[dict[str, str]], for_homepage: bool = False): """ Recover the items in a page. """ @@ -39,16 +53,24 @@ def recover_page_items(items: list[dict[str, str]]): album = AlbumStore.albummap.get(item["hash"]) if album is not None: - recovered.append( - {"item": serialize_for_card(album.album), "type": "album"} - ) + item = serialize_for_card(album.album) + + if for_homepage: + del item["type"] + item = {"item": item, "type": "album"} + + recovered.append(item) elif item["type"] == "artist": artist = ArtistStore.artistmap.get(item["hash"]) if artist is not None: - recovered.append( - {"item": serialize_artist(artist.artist), "type": "artist"} - ) + item = serialize_artist(artist.artist) + + if for_homepage: + del item["type"] + item = {"item": item, "type": "artist"} + + recovered.append(item) recovered.reverse() return recovered diff --git a/app/serializers/album.py b/app/serializers/album.py index 4e4c5183..ce3518db 100644 --- a/app/serializers/album.py +++ b/app/serializers/album.py @@ -16,6 +16,7 @@ def album_serializer(album: Album, to_remove: set[str]) -> dict: for artist in album_dict["albumartists"]: artist.pop("image", None) + album_dict["type"] = "album" return album_dict diff --git a/app/serializers/artist.py b/app/serializers/artist.py index fd5b1074..adf19321 100644 --- a/app/serializers/artist.py +++ b/app/serializers/artist.py @@ -30,6 +30,7 @@ def serialize_for_card(artist: Artist): for key in props_to_remove: artist_dict.pop(key, None) + artist_dict["type"] = "artist" return artist_dict diff --git a/app/store/homepage.py b/app/store/homepage.py index c6605114..2b0f66a9 100644 --- a/app/store/homepage.py +++ b/app/store/homepage.py @@ -75,7 +75,7 @@ class HomepageStore: "id": page["id"], "title": page["name"], "description": page["extra"]["description"], - "items": recover_page_items(page["items"]), + "items": recover_page_items(page["items"], for_homepage=True), "url": f"pages/{page['id']}", } }