mirror of
https://github.com/minetest/contentdb.git
synced 2025-01-11 07:27:36 +01:00
Add API to create releases
This commit is contained in:
parent
6f1472addb
commit
14faae3fd1
@ -19,6 +19,7 @@ from flask import *
|
|||||||
from flask_user import *
|
from flask_user import *
|
||||||
from . import bp
|
from . import bp
|
||||||
from .auth import is_api_authd
|
from .auth import is_api_authd
|
||||||
|
from .support import error, handleCreateRelease
|
||||||
from app import csrf
|
from app import csrf
|
||||||
from app.models import *
|
from app.models import *
|
||||||
from app.utils import is_package_page
|
from app.utils import is_package_page
|
||||||
@ -71,6 +72,13 @@ def package_dependencies(package):
|
|||||||
return jsonify(ret)
|
return jsonify(ret)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/api/packages/<author>/<name>/releases/")
|
||||||
|
@is_package_page
|
||||||
|
def list_releases(package):
|
||||||
|
releases = package.releases.filter_by(approved=True).all()
|
||||||
|
return jsonify([ rel.getAsDictionary() for rel in releases ])
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/api/topics/")
|
@bp.route("/api/topics/")
|
||||||
def topics():
|
def topics():
|
||||||
qb = QueryBuilder(request.args)
|
qb = QueryBuilder(request.args)
|
||||||
@ -113,5 +121,25 @@ def whoami(token):
|
|||||||
|
|
||||||
@bp.route("/api/markdown/", methods=["POST"])
|
@bp.route("/api/markdown/", methods=["POST"])
|
||||||
@csrf.exempt
|
@csrf.exempt
|
||||||
def clean_markdown():
|
def markdown():
|
||||||
return render_markdown(request.data.decode("utf-8"))
|
return render_markdown(request.data.decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/api/packages/<author>/<name>/releases/new/", methods=["POST"])
|
||||||
|
@csrf.exempt
|
||||||
|
@is_package_page
|
||||||
|
@is_api_authd
|
||||||
|
def create_release(token, package):
|
||||||
|
json = request.json
|
||||||
|
if json is None:
|
||||||
|
return error(400, "JSON post data is required")
|
||||||
|
|
||||||
|
for option in ["method", "title", "ref"]:
|
||||||
|
if json.get(option) is None:
|
||||||
|
return error(400, option + " is required in the POST data")
|
||||||
|
|
||||||
|
|
||||||
|
if json["method"].lower() != "vcs":
|
||||||
|
return error(400, "Release-creation methods other than VCS are not supported")
|
||||||
|
|
||||||
|
return handleCreateRelease(token, package, json["title"], json["ref"])
|
||||||
|
40
app/blueprints/api/support.py
Normal file
40
app/blueprints/api/support.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
from app.models import PackageRelease, db, Permission
|
||||||
|
from app.tasks.importtasks import makeVCSRelease
|
||||||
|
from celery import uuid
|
||||||
|
from flask import jsonify, make_response, url_for
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def error(status, message):
|
||||||
|
return make_response(jsonify({ "success": False, "error": message }), status)
|
||||||
|
|
||||||
|
|
||||||
|
def handleCreateRelease(token, package, title, ref):
|
||||||
|
if not token.canOperateOnPackage(package):
|
||||||
|
return error(403, "API token does not have access to the package")
|
||||||
|
|
||||||
|
if not package.checkPerm(token.owner, Permission.MAKE_RELEASE):
|
||||||
|
return error(403, "Permission denied. Missing MAKE_RELEASE permission")
|
||||||
|
|
||||||
|
five_minutes_ago = datetime.datetime.now() - datetime.timedelta(minutes=5)
|
||||||
|
count = package.releases.filter(PackageRelease.releaseDate > five_minutes_ago).count()
|
||||||
|
if count >= 2:
|
||||||
|
return error(429, "Too many requests, please wait before trying again")
|
||||||
|
|
||||||
|
rel = PackageRelease()
|
||||||
|
rel.package = package
|
||||||
|
rel.title = title
|
||||||
|
rel.url = ""
|
||||||
|
rel.task_id = uuid()
|
||||||
|
rel.min_rel = None
|
||||||
|
rel.max_rel = None
|
||||||
|
db.session.add(rel)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
makeVCSRelease.apply_async((rel.id, ref), task_id=rel.task_id)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"task": url_for("tasks.check", id=rel.task_id),
|
||||||
|
"release": rel.getAsDictionary()
|
||||||
|
})
|
@ -23,6 +23,19 @@ You can use the `/api/whoami` to check authentication.
|
|||||||
* GET `/api/packages/` - See [Package Queries](#package-queries)
|
* GET `/api/packages/` - See [Package Queries](#package-queries)
|
||||||
* GET `/api/packages/<username>/<name>/`
|
* GET `/api/packages/<username>/<name>/`
|
||||||
|
|
||||||
|
### Releases
|
||||||
|
|
||||||
|
* GET `/api/packages/<username>/<name>/releases/`
|
||||||
|
* POST `/api/packages/<username>/<name>/releases/`
|
||||||
|
* Requires authentication.
|
||||||
|
* `title`: human-readable name of the release.
|
||||||
|
* `method`: Must be `vcs`.
|
||||||
|
* `min_protocol`: minimum Minetest protocol version. See [Minetest](#minetest).
|
||||||
|
* `min_protocol`: maximum Minetest protocol version. See [Minetest](#minetest).
|
||||||
|
* If `vcs` release-creation method:
|
||||||
|
* `ref` - git reference.
|
||||||
|
|
||||||
|
|
||||||
### Topics
|
### Topics
|
||||||
|
|
||||||
* GET `/api/topics/` - Supports [Package Queries](#package-queries), and the following two options:
|
* GET `/api/topics/` - Supports [Package Queries](#package-queries), and the following two options:
|
||||||
|
@ -522,7 +522,7 @@ class Package(db.Model):
|
|||||||
"short_description": self.short_desc,
|
"short_description": self.short_desc,
|
||||||
"desc": self.desc,
|
"desc": self.desc,
|
||||||
"type": self.type.toName(),
|
"type": self.type.toName(),
|
||||||
"created_at": self.created_at,
|
"created_at": self.created_at.isoformat(),
|
||||||
|
|
||||||
"license": self.license.name,
|
"license": self.license.name,
|
||||||
"media_license": self.media_license.name,
|
"media_license": self.media_license.name,
|
||||||
@ -773,6 +773,18 @@ class PackageRelease(db.Model):
|
|||||||
# If the release is approved, then the task_id must be null and the url must be present
|
# If the release is approved, then the task_id must be null and the url must be present
|
||||||
CK_approval_valid = db.CheckConstraint("not approved OR (task_id IS NULL AND (url = '') IS NOT FALSE)")
|
CK_approval_valid = db.CheckConstraint("not approved OR (task_id IS NULL AND (url = '') IS NOT FALSE)")
|
||||||
|
|
||||||
|
def getAsDictionary(self):
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"title": self.title,
|
||||||
|
"url": self.url if self.url != "" else None,
|
||||||
|
"release_date": self.releaseDate.isoformat(),
|
||||||
|
"commit": self.commit_hash,
|
||||||
|
"downloads": self.downloads,
|
||||||
|
"min_protocol": self.min_rel and self.min_rel.protocol,
|
||||||
|
"max_protocol": self.max_rel and self.max_rel.protocol
|
||||||
|
}
|
||||||
|
|
||||||
def getEditURL(self):
|
def getEditURL(self):
|
||||||
return url_for("packages.edit_release",
|
return url_for("packages.edit_release",
|
||||||
author=self.package.author.username,
|
author=self.package.author.username,
|
||||||
@ -875,10 +887,10 @@ class APIToken(db.Model):
|
|||||||
package = db.relationship("Package", foreign_keys=[package_id])
|
package = db.relationship("Package", foreign_keys=[package_id])
|
||||||
|
|
||||||
def canOperateOnPackage(self, package):
|
def canOperateOnPackage(self, package):
|
||||||
if self.package and self.package != None:
|
if self.package and self.package != package:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return package.owner == self.owner
|
return package.author == self.owner
|
||||||
|
|
||||||
|
|
||||||
class EditRequest(db.Model):
|
class EditRequest(db.Model):
|
||||||
|
Loading…
Reference in New Issue
Block a user