mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-22 22:12:24 +01:00
Add API to delete releases
This commit is contained in:
parent
e1fe63ab19
commit
912ebbc409
@ -83,9 +83,6 @@ def homepage():
|
||||
downloads_result = db.session.query(func.sum(Package.downloads)).one_or_none()
|
||||
downloads = 0 if not downloads_result or not downloads_result[0] else downloads_result[0]
|
||||
|
||||
tags = db.session.query(func.count(Tags.c.tag_id), Tag) \
|
||||
.select_from(Tag).outerjoin(Tags).group_by(Tag.id).order_by(db.asc(Tag.title)).all()
|
||||
|
||||
def mapPackages(packages):
|
||||
return [pkg.getAsDictionaryKey() for pkg in packages]
|
||||
|
||||
@ -97,7 +94,7 @@ def homepage():
|
||||
"pop_mod": mapPackages(pop_mod),
|
||||
"pop_txp": mapPackages(pop_txp),
|
||||
"pop_game": mapPackages(pop_gam),
|
||||
"high_reviewed": mapPackages(high_reviewed),
|
||||
"high_reviewed": mapPackages(high_reviewed)
|
||||
}
|
||||
|
||||
|
||||
@ -113,9 +110,6 @@ def resolve_package_deps(out, package, only_hard):
|
||||
if only_hard and dep.optional:
|
||||
continue
|
||||
|
||||
name = None
|
||||
fulfilled_by = None
|
||||
|
||||
if dep.package:
|
||||
name = dep.package.name
|
||||
fulfilled_by = [ dep.package.getId() ]
|
||||
@ -174,7 +168,7 @@ def topic_set_discard():
|
||||
|
||||
@bp.route("/api/minetest_versions/")
|
||||
def versions():
|
||||
return jsonify([{ "name": rel.name, "protocol_version": rel.protocol }\
|
||||
return jsonify([rel.getAsDictionary() \
|
||||
for rel in MinetestRelease.query.all() if rel.getActual() is not None])
|
||||
|
||||
|
||||
@ -196,8 +190,7 @@ def markdown():
|
||||
@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 ])
|
||||
return jsonify([ rel.getAsDictionary() for rel in package.releases.all() ])
|
||||
|
||||
|
||||
@bp.route("/api/packages/<author>/<name>/releases/new/", methods=["POST"])
|
||||
@ -215,14 +208,11 @@ def create_release(token, package):
|
||||
if "title" not in data:
|
||||
error(400, "Title is required in the POST data")
|
||||
|
||||
if request.json:
|
||||
if data.get("method") == "git":
|
||||
for option in ["method", "ref"]:
|
||||
if option not in data:
|
||||
error(400, option + " is required in the POST data")
|
||||
|
||||
if data["method"].lower() != "git":
|
||||
error(400, "Release-creation methods other than git are not supported")
|
||||
|
||||
return api_create_vcs_release(token, package, data["title"], data["ref"])
|
||||
|
||||
elif request.files:
|
||||
@ -232,6 +222,43 @@ def create_release(token, package):
|
||||
|
||||
return api_create_zip_release(token, package, data["title"], file)
|
||||
|
||||
else:
|
||||
error(400, "Unknown release-creation method. Specify the method or provide a file.")
|
||||
|
||||
|
||||
@bp.route("/api/packages/<author>/<name>/releases/<int:id>/")
|
||||
@is_package_page
|
||||
def release(package: Package, id: int):
|
||||
release = PackageRelease.query.get(id)
|
||||
if release is None or release.package != package:
|
||||
error(404, "Release not found")
|
||||
|
||||
return jsonify(release.getAsDictionary())
|
||||
|
||||
|
||||
@bp.route("/api/packages/<author>/<name>/releases/<int:id>/", methods=["DELETE"])
|
||||
@csrf.exempt
|
||||
@is_package_page
|
||||
@is_api_authd
|
||||
def delete_release(token: APIToken, package: Package, id: int):
|
||||
release = PackageRelease.query.get(id)
|
||||
if release is None or release.package != package:
|
||||
error(404, "Release not found")
|
||||
|
||||
if not token:
|
||||
error(401, "Authentication needed")
|
||||
|
||||
if not token.canOperateOnPackage(package):
|
||||
error(403, "API token does not have access to the package")
|
||||
|
||||
if not release.checkPerm(token.owner, Permission.DELETE_RELEASE):
|
||||
error(403, "Unable to delete the release, make sure there's a newer release available")
|
||||
|
||||
db.session.delete(release)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({"success": True})
|
||||
|
||||
|
||||
@bp.route("/api/packages/<author>/<name>/screenshots/")
|
||||
@is_package_page
|
||||
|
@ -15,7 +15,7 @@ Tokens can be attained by visiting [Settings > API Tokens](/user/tokens/).
|
||||
|
||||
### Misc
|
||||
|
||||
* GET `/api/whoami/` - Json dictionary with the following keys:
|
||||
* GET `/api/whoami/` - JSON dictionary with the following keys:
|
||||
* `is_authenticated` - True on successful API authentication
|
||||
* `username` - Username of the user authenticated as, null otherwise.
|
||||
* 4xx status codes will be thrown on unsupported authentication type, invalid access token, or other errors.
|
||||
@ -40,13 +40,24 @@ Tokens can be attained by visiting [Settings > API Tokens](/user/tokens/).
|
||||
* `pop_txp` - popular textures
|
||||
* `pop_game` - popular games
|
||||
* `high_reviewed` - highest reviewed
|
||||
* `tags`
|
||||
|
||||
### Releases
|
||||
|
||||
* GET `/api/packages/<username>/<name>/releases/` (List)
|
||||
* Returns array of release dictionaries with keys:
|
||||
* `id`: release ID
|
||||
* `title`: human-readable title
|
||||
* `release_date`: Date released
|
||||
* `url`: download URL
|
||||
* `commit`: commit hash or null
|
||||
* `downloads`: number of downloads
|
||||
* `min_minetest_version`: dict or null, minimum supported minetest version (inclusive).
|
||||
* `max_minetest_version`: dict or null, minimum supported minetest version (inclusive).
|
||||
* GET `/api/packages/<username>/<name>/releases/<id>/` (Read)
|
||||
* POST `/api/packages/<username>/<name>/releases/new/` (Create)
|
||||
* Requires authentication.
|
||||
* Body is multipart form if zip upload, JSON otherwise.
|
||||
* Body can be JSON or multipart form data. Zip uploads must be multipart form data.
|
||||
* `title`: human-readable name of the release.
|
||||
* For Git release creation:
|
||||
* `method`: must be `git`.
|
||||
@ -54,7 +65,10 @@ Tokens can be attained by visiting [Settings > API Tokens](/user/tokens/).
|
||||
* For zip upload release creation:
|
||||
* `file`: multipart file to upload, like `<input type=file>`.
|
||||
* You can set min and max Minetest Versions [using the content's .conf file](/help/package_config/).
|
||||
|
||||
* DELETE `/api/packages/<username>/<name>/releases/<id>/` (Delete)
|
||||
* Requires authentication.
|
||||
* Deletes release.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
@ -64,9 +78,13 @@ curl -X POST https://content.minetest.net/api/packages/username/name/releases/ne
|
||||
-d "{\"method\": \"git\", \"title\": \"My Release\", \"ref\": \"master\" }"
|
||||
|
||||
# Create release from zip upload
|
||||
curl https://content.minetest.net/api/packages/username/name/releases/new/ \
|
||||
curl -X POST https://content.minetest.net/api/packages/username/name/releases/new/ \
|
||||
-H "Authorization: Bearer YOURTOKEN" \
|
||||
-F title="My Release" -F file=@path/to/file.zip
|
||||
|
||||
# Delete release
|
||||
curl -X DELETE https://content.minetest.net/api/packages/username/name/releases/3/ \
|
||||
-H "Authorization: Bearer YOURTOKEN"
|
||||
```
|
||||
|
||||
### Screenshots
|
||||
@ -96,7 +114,7 @@ Examples:
|
||||
|
||||
```bash
|
||||
# Create screenshots
|
||||
curl https://content.minetest.net/api/packages/username/name/screenshots/new/ \
|
||||
curl -X POST https://content.minetest.net/api/packages/username/name/screenshots/new/ \
|
||||
-H "Authorization: Bearer YOURTOKEN" \
|
||||
-F title="My Release" -F file=@path/to/screnshot.png
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from werkzeug.exceptions import abort
|
||||
import datetime
|
||||
|
||||
from app.logic.LogicError import LogicError
|
||||
from app.logic.uploads import upload_file
|
||||
@ -7,10 +7,15 @@ from app.utils import addNotification
|
||||
|
||||
|
||||
def do_create_screenshot(user: User, package: Package, title: str, file):
|
||||
thirty_minutes_ago = datetime.datetime.now() - datetime.timedelta(minutes=30)
|
||||
count = package.screenshots.filter(PackageScreenshot.created_at > thirty_minutes_ago).count()
|
||||
if count >= 20:
|
||||
raise LogicError(429, "Too many requests, please wait before trying again")
|
||||
|
||||
uploaded_url, uploaded_path = upload_file(file, "image", "a PNG or JPG image file")
|
||||
|
||||
counter = 1
|
||||
for screenshot in package.screenshots:
|
||||
for screenshot in package.screenshots.all():
|
||||
screenshot.order = counter
|
||||
counter += 1
|
||||
|
||||
|
@ -759,6 +759,13 @@ class MinetestRelease(db.Model):
|
||||
def getActual(self):
|
||||
return None if self.name == "None" else self
|
||||
|
||||
def getAsDictionary(self):
|
||||
return {
|
||||
"name": self.name,
|
||||
"protocol_version": self.protocol,
|
||||
"is_dev": "-dev" in self.name,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get(cls, version, protocol_num):
|
||||
if version:
|
||||
@ -810,8 +817,8 @@ class PackageRelease(db.Model):
|
||||
"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
|
||||
"min_minetest_version": self.min_rel and self.min_rel.getAsDictionary(),
|
||||
"max_minetest_version": self.max_rel and self.max_rel.getAsDictionary(),
|
||||
}
|
||||
|
||||
def getEditURL(self):
|
||||
|
Loading…
Reference in New Issue
Block a user