From a2ea6573bdef301222d79ddd7137b5cb6c70833c Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 20 Aug 2023 21:47:20 +0100 Subject: [PATCH] Add Collections API --- app/blueprints/api/endpoints.py | 42 ++++++++++++++++++++++++++++++++- app/flatpages/help/api.md | 30 +++++++++++++++++++++++ app/models/collections.py | 32 ++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/app/blueprints/api/endpoints.py b/app/blueprints/api/endpoints.py index eb36754d..c9e80f46 100644 --- a/app/blueprints/api/endpoints.py +++ b/app/blueprints/api/endpoints.py @@ -778,4 +778,44 @@ def hypertext(): if request.content_type == "text/markdown": html = render_markdown(html) - return jsonify(html_to_minetest(html, formspec_version, include_images)) \ No newline at end of file + return jsonify(html_to_minetest(html, formspec_version, include_images)) + + +@bp.route("/api/collections/") +@cors_allowed +def collection_list(): + if "author" in request.args: + user = User.query.filter_by(username=request.args["author"]).one_or_404() + query = user.collections + else: + query = Collection.query.order_by(db.asc(Collection.title)) + + if "package" in request.args: + id_ = request.args["package"] + package = Package.get_by_key(id_) + if package is None: + error(404, f"Package {id_} not found") + + query = query.filter(Collection.packages.contains(package)) + + collections = [x.as_short_dict() for x in query.all() if not x.private] + return jsonify(collections) + + +@bp.route("/api/collections///") +@cors_allowed +def collection_view(author, name): + collection = Collection.query \ + .filter(Collection.name == name, Collection.author.has(username=author)) \ + .one_or_404() + + if not collection.check_perm(current_user, Permission.VIEW_COLLECTION): + error(404, "Collection not found") + + items = collection.items + if collection.check_perm(current_user, Permission.EDIT_COLLECTION): + items = [x for x in items if x.package.check_perm(current_user, Permission.VIEW_PACKAGE)] + + ret = collection.as_dict() + ret["items"] = [x.as_dict() for x in items] + return jsonify(ret) diff --git a/app/flatpages/help/api.md b/app/flatpages/help/api.md index cde757ec..1862ed32 100644 --- a/app/flatpages/help/api.md +++ b/app/flatpages/help/api.md @@ -413,6 +413,36 @@ Supported query parameters: * `show_discarded`: Show topics marked as discarded. * `limit`: Return at most `limit` topics. + +## Collections + +* GET `/api/collections/` + * Query args: + * `author`: collection author username. + * `package`: collections that contain the package. + * Returns JSON array of collection entries: + * `author`: author username. + * `name`: collection name. + * `title` + * `short_description` + * `created_at`: creation time in iso format. + * `private`: whether collection is private, boolean. + * `package_count`: number of packages, integer. +* GET `/api/collections///` + * Returns JSON object for collection: + * `author`: author username. + * `name`: collection name. + * `title` + * `short_description` + * `long_description` + * `created_at`: creation time in iso format. + * `private`: whether collection is private, boolean. + * `items`: array of item objects: + * `package`: short info about the package. + * `description`: custom short description. + * `created_at`: when the package was added to the collection. + * `order`: integer. + ## Types ### Tags diff --git a/app/models/collections.py b/app/models/collections.py index 27c0d81d..113c5639 100644 --- a/app/models/collections.py +++ b/app/models/collections.py @@ -16,7 +16,7 @@ import datetime -from flask import url_for +from flask import url_for, current_app from . import db, Permission, User, UserRank @@ -34,6 +34,14 @@ class CollectionPackage(db.Model): collection_description_nonempty = db.CheckConstraint("description = NULL OR description != ''") + def as_dict(self): + return { + "package": self.package.as_short_dict(current_app.config["BASE_URL"]), + "order": self.order, + "description": self.description, + "created_at": self.created_at.isoformat(), + } + class Collection(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -58,6 +66,28 @@ class Collection(db.Model): def get_url(self, endpoint, **kwargs): return url_for(endpoint, author=self.author.username, name=self.name, **kwargs) + def as_short_dict(self): + return { + "author": self.author.username, + "name": self.name, + "title": self.title, + "short_description": self.short_description, + "created_at": self.created_at.isoformat(), + "private": self.private, + "package_count": len(self.packages) + } + + def as_dict(self): + return { + "author": self.author.username, + "name": self.name, + "title": self.title, + "short_description": self.short_description, + "long_description": self.long_description, + "created_at": self.created_at.isoformat(), + "private": self.private, + } + def check_perm(self, user: User, perm): if type(perm) == str: perm = Permission[perm]