Skip to content

Commit

Permalink
Add release notes and long titles to releases
Browse files Browse the repository at this point in the history
Fixes #492 and fixes #480
  • Loading branch information
rubenwardy committed Jun 22, 2024
1 parent 4147e5e commit 019cd66
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 52 deletions.
8 changes: 4 additions & 4 deletions app/blueprints/api/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def markdown():
def list_all_releases():
query = PackageRelease.query.filter_by(approved=True) \
.filter(PackageRelease.package.has(state=PackageState.APPROVED)) \
.order_by(db.desc(PackageRelease.releaseDate))
.order_by(db.desc(PackageRelease.created_at))

if "author" in request.args:
author = User.query.filter_by(username=request.args["author"]).first()
Expand Down Expand Up @@ -333,7 +333,7 @@ def create_release(token, package):
if option not in data:
error(400, option + " is required in the POST data")

return api_create_vcs_release(token, package, data["title"], data["ref"])
return api_create_vcs_release(token, package, data["title"], data["title"], data.get("release_notes"), data["ref"])

elif request.files:
file = request.files.get("file")
Expand All @@ -342,7 +342,7 @@ def create_release(token, package):

commit_hash = data.get("commit")

return api_create_zip_release(token, package, data["title"], file, None, None, "API", commit_hash)
return api_create_zip_release(token, package, data["title"], data["title"], data.get("release_notes"), file, None, None, "API", commit_hash)

else:
error(400, "Unknown release-creation method. Specify the method or provide a file.")
Expand Down Expand Up @@ -622,7 +622,7 @@ def homepage():

updated = db.session.query(Package).select_from(PackageRelease).join(Package) \
.filter_by(state=PackageState.APPROVED) \
.order_by(db.desc(PackageRelease.releaseDate)) \
.order_by(db.desc(PackageRelease.created_at)) \
.limit(20).all()
updated = updated[:4]

Expand Down
10 changes: 5 additions & 5 deletions app/blueprints/api/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.


from typing import Optional
from flask import jsonify, abort, make_response, url_for, current_app

from app.logic.packages import do_edit_package
Expand All @@ -38,14 +38,14 @@ def ret(*args, **kwargs):
return ret


def api_create_vcs_release(token: APIToken, package: Package, title: str, ref: str,
def api_create_vcs_release(token: APIToken, package: Package, name: str, title: Optional[str], release_notes: Optional[str], ref: str,
min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason="API"):
if not token.can_operate_on_package(package):
error(403, "API token does not have access to the package")

reason += ", token=" + token.name

rel = guard(do_create_vcs_release)(token.owner, package, title, ref, min_v, max_v, reason)
rel = guard(do_create_vcs_release)(token.owner, package, name, title, release_notes, ref, min_v, max_v, reason)

return jsonify({
"success": True,
Expand All @@ -54,14 +54,14 @@ def api_create_vcs_release(token: APIToken, package: Package, title: str, ref: s
})


def api_create_zip_release(token: APIToken, package: Package, title: str, file,
def api_create_zip_release(token: APIToken, package: Package, name: str, title: Optional[str], release_notes: Optional[str], file,
min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason="API", commit_hash: str = None):
if not token.can_operate_on_package(package):
error(403, "API token does not have access to the package")

reason += ", token=" + token.name

rel = guard(do_create_zip_release)(token.owner, package, title, file, min_v, max_v, reason, commit_hash)
rel = guard(do_create_zip_release)(token.owner, package, name, title, release_notes, file, min_v, max_v, reason, commit_hash)

return jsonify({
"success": True,
Expand Down
2 changes: 1 addition & 1 deletion app/blueprints/homepage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def review_load(query):
recent_releases_query = (
db.session.query(
Package.id,
func.max(PackageRelease.releaseDate).label("max_created_at")
func.max(PackageRelease.created_at).label("max_created_at")
)
.join(PackageRelease, Package.releases)
.group_by(Package.id)
Expand Down
2 changes: 1 addition & 1 deletion app/blueprints/packages/game_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def join(query):

updated = db.session.query(Package).select_from(PackageRelease).join(Package) \
.filter(Package.supported_games.any(game=package, supports=True), Package.state==PackageState.APPROVED) \
.order_by(db.desc(PackageRelease.releaseDate)) \
.order_by(db.desc(PackageRelease.created_at)) \
.limit(20).all()
updated = updated[:4]

Expand Down
35 changes: 21 additions & 14 deletions app/blueprints/packages/releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from flask_login import login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField, RadioField, FileField
from wtforms.fields.simple import TextAreaField
from wtforms.validators import InputRequired, Length, Optional
from wtforms_sqlalchemy.fields import QuerySelectField

Expand All @@ -28,7 +29,7 @@
PackageRelease, PackageUpdateTrigger, PackageUpdateConfig
from app.rediscache import has_key, set_temp_key, make_download_key
from app.tasks.importtasks import check_update_config
from app.utils import is_user_bot, is_package_page, nonempty_or_none
from app.utils import is_user_bot, is_package_page, nonempty_or_none, normalize_line_endings
from . import bp, get_package_tabs


Expand All @@ -51,19 +52,25 @@ def get_mt_releases(is_max):


class CreatePackageReleaseForm(FlaskForm):
title = StringField(lazy_gettext("Title"), [InputRequired(), Length(1, 30)])
uploadOpt = RadioField(lazy_gettext("Method"), choices=[("upload", lazy_gettext("File Upload"))], default="upload")
vcsLabel = StringField(lazy_gettext("Git reference (ie: commit hash, branch, or tag)"), default=None)
name = StringField(lazy_gettext("Name"), [InputRequired(), Length(1, 30)])
title = StringField(lazy_gettext("Title"), [Optional(), Length(1, 100)], filters=[nonempty_or_none])
release_notes = TextAreaField(lazy_gettext("Release Notes"), [Optional(), Length(1, 100)],
filters=[nonempty_or_none, normalize_line_endings])
upload_mode = RadioField(lazy_gettext("Method"), choices=[("upload", lazy_gettext("File Upload"))], default="upload")
vcs_label = StringField(lazy_gettext("Git reference (ie: commit hash, branch, or tag)"), default=None)
file_upload = FileField(lazy_gettext("File Upload"))
min_rel = QuerySelectField(lazy_gettext("Minimum Minetest Version"), [InputRequired()],
query_factory=lambda: get_mt_releases(False), get_pk=lambda a: a.id, get_label=lambda a: a.name)
max_rel = QuerySelectField(lazy_gettext("Maximum Minetest Version"), [InputRequired()],
max_rel = QuerySelectField(lazy_gettext("Maximum Minetest Version"), [InputRequired()],
query_factory=lambda: get_mt_releases(True), get_pk=lambda a: a.id, get_label=lambda a: a.name)
submit = SubmitField(lazy_gettext("Save"))
submit = SubmitField(lazy_gettext("Save"))


class EditPackageReleaseForm(FlaskForm):
title = StringField(lazy_gettext("Title"), [InputRequired(), Length(1, 30)])
name = StringField(lazy_gettext("Name"), [InputRequired(), Length(1, 30)])
title = StringField(lazy_gettext("Title"), [Optional(), Length(1, 30)], filters=[nonempty_or_none])
release_notes = TextAreaField(lazy_gettext("Release Notes"), [Optional(), Length(1, 100)],
filters=[nonempty_or_none, normalize_line_endings])
url = StringField(lazy_gettext("URL"), [Optional()])
task_id = StringField(lazy_gettext("Task ID"), filters = [lambda x: x or None])
approved = BooleanField(lazy_gettext("Is Approved"))
Expand All @@ -88,21 +95,21 @@ def create_release(package):
# Initial form class from post data and default data
form = CreatePackageReleaseForm()
if package.repo is not None:
form["uploadOpt"].choices = [("vcs", gettext("Import from Git")), ("upload", gettext("Upload .zip file"))]
form.upload_mode.choices = [("vcs", gettext("Import from Git")), ("upload", gettext("Upload .zip file"))]
if request.method == "GET":
form["uploadOpt"].data = "vcs"
form.vcsLabel.data = request.args.get("ref")
form.upload_mode.data = "vcs"
form.vcs_label.data = request.args.get("ref")

if request.method == "GET":
form.title.data = request.args.get("title")

if form.validate_on_submit():
try:
if form["uploadOpt"].data == "vcs":
rel = do_create_vcs_release(current_user, package, form.title.data,
form.vcsLabel.data, form.min_rel.data.get_actual(), form.max_rel.data.get_actual())
if form.upload_mode.data == "vcs":
rel = do_create_vcs_release(current_user, package, form.name.data, form.title.data, form.release_notes.data,
form.vcs_label.data, form.min_rel.data.get_actual(), form.max_rel.data.get_actual())
else:
rel = do_create_zip_release(current_user, package, form.title.data,
rel = do_create_zip_release(current_user, package, form.name.data, form.title.data, form.release_notes.data,
form.file_upload.data, form.min_rel.data.get_actual(), form.max_rel.data.get_actual())
return redirect(url_for("tasks.check", id=rel.task_id, r=rel.get_edit_url()))
except LogicError as e:
Expand Down
2 changes: 1 addition & 1 deletion app/blueprints/vcs/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def github_webhook():
if package.releases.filter_by(commit_hash=ref).count() > 0:
return

return api_create_vcs_release(token, package, title, ref, reason="Webhook")
return api_create_vcs_release(token, package, title, title, None, ref, reason="Webhook")

return jsonify({
"success": False,
Expand Down
2 changes: 1 addition & 1 deletion app/blueprints/vcs/gitlab.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def webhook_impl():
if package.releases.filter_by(commit_hash=ref).count() > 0:
continue

return api_create_vcs_release(token, package, title, ref, reason="Webhook")
return api_create_vcs_release(token, package, title, title, None, ref, reason="Webhook")

return jsonify({
"success": False,
Expand Down
3 changes: 3 additions & 0 deletions app/flatpages/help/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,9 @@ Format query parameters:
* `maintainer`: Filter by maintainer
* Returns array of release dictionaries with keys:
* `id`: release ID
* `name`: short release name
* `title`: human-readable title
* `release_notes`: string or null, what's new in this release
* `release_date`: Date released
* `url`: download URL
* `commit`: commit hash or null
Expand All @@ -248,6 +250,7 @@ Format query parameters:
* Requires authentication.
* Body can be JSON or multipart form data. Zip uploads must be multipart form data.
* `title`: human-readable name of the release.
* `release_notes`: string or null, what's new in this release.
* For Git release creation:
* `method`: must be `git`.
* `ref`: (Optional) git reference, eg: `master`.
Expand Down
15 changes: 10 additions & 5 deletions app/logic/releases.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import datetime
import re
from typing import Optional

from celery import uuid
from flask_babel import lazy_gettext
Expand All @@ -32,18 +33,20 @@ def check_can_create_release(user: User, package: Package):
raise LogicError(403, lazy_gettext("You don't have permission to make releases"))

five_minutes_ago = datetime.datetime.now() - datetime.timedelta(minutes=5)
count = package.releases.filter(PackageRelease.releaseDate > five_minutes_ago).count()
count = package.releases.filter(PackageRelease.created_at > five_minutes_ago).count()
if count >= 5:
raise LogicError(429, lazy_gettext("You've created too many releases for this package in the last 5 minutes, please wait before trying again"))


def do_create_vcs_release(user: User, package: Package, title: str, ref: str,
def do_create_vcs_release(user: User, package: Package, name: str, title: Optional[str], release_notes: Optional[str], ref: str,
min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason: str = None):
check_can_create_release(user, package)

rel = PackageRelease()
rel.package = package
rel.title = title
rel.name = name
rel.title = title or name
rel.release_notes = release_notes
rel.url = ""
rel.task_id = uuid()
rel.min_rel = min_v
Expand All @@ -63,7 +66,7 @@ def do_create_vcs_release(user: User, package: Package, title: str, ref: str,
return rel


def do_create_zip_release(user: User, package: Package, title: str, file,
def do_create_zip_release(user: User, package: Package, name: str, title: Optional[str], release_notes: Optional[str], file,
min_v: MinetestRelease = None, max_v: MinetestRelease = None, reason: str = None,
commit_hash: str = None):
check_can_create_release(user, package)
Expand All @@ -77,7 +80,9 @@ def do_create_zip_release(user: User, package: Package, title: str, file,

rel = PackageRelease()
rel.package = package
rel.title = title
rel.name = name
rel.title = title or name
rel.release_notes = release_notes
rel.url = uploaded_url
rel.task_id = uuid()
rel.commit_hash = commit_hash
Expand Down
14 changes: 9 additions & 5 deletions app/models/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ def donate_url_actual(self):
content_warnings = db.relationship("ContentWarning", secondary=ContentWarnings, back_populates="packages")

releases = db.relationship("PackageRelease", back_populates="package",
lazy="dynamic", order_by=db.desc("package_release_releaseDate"), cascade="all, delete, delete-orphan")
lazy="dynamic", order_by=db.desc("package_release_created_at"), cascade="all, delete, delete-orphan")

screenshots = db.relationship("PackageScreenshot", back_populates="package", foreign_keys="PackageScreenshot.package_id",
lazy="dynamic", order_by=db.asc("package_screenshot_order"), cascade="all, delete, delete-orphan")
Expand Down Expand Up @@ -1085,13 +1085,15 @@ class PackageRelease(db.Model):
package_id = db.Column(db.Integer, db.ForeignKey("package.id"))
package = db.relationship("Package", back_populates="releases", foreign_keys=[package_id])

name = db.Column(db.String(30), nullable=False)
title = db.Column(db.String(100), nullable=False)
releaseDate = db.Column(db.DateTime, nullable=False)
created_at = db.Column(db.DateTime, nullable=False)
url = db.Column(db.String(200), nullable=False, default="")
approved = db.Column(db.Boolean, nullable=False, default=False)
task_id = db.Column(db.String(37), nullable=True)
commit_hash = db.Column(db.String(41), nullable=True, default=None)
downloads = db.Column(db.Integer, nullable=False, default=0)
release_notes = db.Column(db.UnicodeText, nullable=True, default=None)

min_rel_id = db.Column(db.Integer, db.ForeignKey("minetest_release.id"), nullable=True, server_default=None)
min_rel = db.relationship("MinetestRelease", foreign_keys=[min_rel_id])
Expand Down Expand Up @@ -1126,9 +1128,11 @@ def file_size(self):
def as_dict(self):
return {
"id": self.id,
"name": self.name,
"title": self.title,
"release_notes": self.release_notes,
"url": self.url if self.url != "" else None,
"release_date": self.releaseDate.isoformat(),
"release_date": self.created_at.isoformat(),
"commit": self.commit_hash,
"downloads": self.downloads,
"min_minetest_version": self.min_rel and self.min_rel.as_dict(),
Expand All @@ -1141,7 +1145,7 @@ def as_long_dict(self):
"id": self.id,
"title": self.title,
"url": self.url if self.url != "" else None,
"release_date": self.releaseDate.isoformat(),
"release_date": self.created_at.isoformat(),
"commit": self.commit_hash,
"downloads": self.downloads,
"min_minetest_version": self.min_rel and self.min_rel.as_dict(),
Expand Down Expand Up @@ -1169,7 +1173,7 @@ def get_download_url(self):
id=self.id)

def __init__(self):
self.releaseDate = datetime.datetime.now()
self.created_at = datetime.datetime.now()

def get_download_filename(self):
return f"{self.package.name}_{self.id}.zip"
Expand Down
8 changes: 4 additions & 4 deletions app/public/static/js/release_new.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

window.addEventListener("load", () => {
function check_opt() {
if (document.querySelector("input[name='uploadOpt']:checked").value === "vcs") {
if (document.querySelector("input[name='upload_mode']:checked").value === "vcs") {
document.getElementById("file_upload").parentElement.classList.add("d-none");
document.getElementById("vcsLabel").parentElement.classList.remove("d-none");
document.getElementById("vcs_label").parentElement.classList.remove("d-none");
} else {
document.getElementById("file_upload").parentElement.classList.remove("d-none");
document.getElementById("vcsLabel").parentElement.classList.add("d-none");
document.getElementById("vcs_label").parentElement.classList.add("d-none");
}
}

document.querySelectorAll("input[name='uploadOpt']").forEach(x => x.addEventListener("change", check_opt));
document.querySelectorAll("input[name='upload_mode']").forEach(x => x.addEventListener("change", check_opt));
check_opt();
});
2 changes: 1 addition & 1 deletion app/querybuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def order_package_query(self, query):
elif self.order_by == "approved_at" or self.order_by == "date":
to_order = Package.approved_at
elif self.order_by == "last_release":
to_order = PackageRelease.releaseDate
to_order = PackageRelease.created_at
else:
abort(400)

Expand Down
6 changes: 3 additions & 3 deletions app/templates/macros/releases.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
[{{ rel.commit_hash | truncate(5, end='') }}]
{% endif %}

{{ _("created %(date)s", date=rel.releaseDate | date) }}.
{{ _("created %(date)s", date=rel.created_at | date) }}.
</small>
</a>
{% endfor %}
Expand Down Expand Up @@ -50,7 +50,7 @@
[{{ rel.commit_hash | truncate(5, end='') }}]
{% endif %}

{{ _("created %(date)s", date=rel.releaseDate | date) }}.
{{ _("created %(date)s", date=rel.created_at | date) }}.
</small>
</a>
{% endif %}
Expand Down Expand Up @@ -96,7 +96,7 @@
[{{ rel.commit_hash | truncate(5, end='') }}]
{% endif %}

{{ _("created %(date)s", date=rel.releaseDate | date) }}.
{{ _("created %(date)s", date=rel.created_at | date) }}.
</small>
{% if (package.check_perm(current_user, "MAKE_RELEASE") or rel.check_perm(current_user, "APPROVE_RELEASE")) and rel.task_id %}
<a href="{{ url_for('tasks.check', id=rel.task_id, r=package.get_url('packages.view')) }}">
Expand Down
12 changes: 10 additions & 2 deletions app/templates/packages/release_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@ <h1>{{ self.title() }}</h1>
{{ form.hidden_tag() }}

{% if package.check_perm(current_user, "MAKE_RELEASE") %}
{{ render_field(form.title) }}
{{ render_field(form.name, hint=_("Release short name. Eg: 1.0.0 or 2018-05-28")) }}
{{ render_field(form.title, hint=_("Human-readable name. Eg: 1.0.0 - The Trains Update")) }}
{{ render_field(form.release_notes) }}
{% else %}
{{ _("Title") }}: {{ release.title }}
<p>
{{ _("Name") }}: {{ release.name }}<br>
{{ _("Title") }}: {{ release.title }}
</p>
<p>
{{ release.release_notes }}
</p>
{% endif %}

{% if package.check_perm(current_user, "CHANGE_RELEASE_URL") %}
Expand Down
Loading

0 comments on commit 019cd66

Please sign in to comment.