diff --git a/app/blueprints/admin/tagseditor.py b/app/blueprints/admin/tagseditor.py index 14a6d6c6..ad0d731f 100644 --- a/app/blueprints/admin/tagseditor.py +++ b/app/blueprints/admin/tagseditor.py @@ -44,6 +44,7 @@ class TagForm(FlaskForm): title = StringField("Title", [InputRequired(), Length(3,100)]) description = TextAreaField("Description", [Optional(), Length(0, 500)]) name = StringField("Name", [Optional(), Length(1, 20), Regexp("^[a-z0-9_]", 0, "Lower case letters (a-z), digits (0-9), and underscores (_) only")]) + is_protected = BooleanField("Is Protected") submit = SubmitField("Save") @bp.route("/tags/new/", methods=["GET", "POST"]) @@ -59,14 +60,16 @@ def create_edit_tag(name=None): if not Permission.checkPerm(current_user, Permission.EDIT_TAGS if tag else Permission.CREATE_TAG): abort(403) - form = TagForm(formdata=request.form, obj=tag) + form = TagForm( obj=tag) if form.validate_on_submit(): if tag is None: tag = Tag(form.title.data) tag.description = form.description.data + tag.is_protected = form.is_protected.data db.session.add(tag) else: form.populate_obj(tag) + db.session.commit() if Permission.EDIT_TAGS.check(current_user): diff --git a/app/blueprints/api/endpoints.py b/app/blueprints/api/endpoints.py index 6fcfe3ee..4610515c 100644 --- a/app/blueprints/api/endpoints.py +++ b/app/blueprints/api/endpoints.py @@ -364,6 +364,8 @@ def homepage(): query = Package.query.filter_by(state=PackageState.APPROVED) count = query.count() + featured = Package.query.filter(Package.tags.any(name="featured")).order_by( + func.random()).limit(6).all() new = query.order_by(db.desc(Package.approved_at)).limit(4).all() pop_mod = query.filter_by(type=PackageType.MOD).order_by(db.desc(Package.score)).limit(8).all() pop_gam = query.filter_by(type=PackageType.GAME).order_by(db.desc(Package.score)).limit(8).all() @@ -386,6 +388,7 @@ def homepage(): return { "count": count, "downloads": downloads, + "featured": featured, "new": mapPackages(new), "updated": mapPackages(updated), "pop_mod": mapPackages(pop_mod), diff --git a/app/blueprints/homepage/__init__.py b/app/blueprints/homepage/__init__.py index 3e2e79ab..a768590d 100644 --- a/app/blueprints/homepage/__init__.py +++ b/app/blueprints/homepage/__init__.py @@ -18,6 +18,8 @@ def home(): query = Package.query.filter_by(state=PackageState.APPROVED) count = query.count() + featured = Package.query.filter(Package.tags.any(name="featured")).order_by(func.random()).limit(6).all() + new = join(query.order_by(db.desc(Package.approved_at))).limit(4).all() pop_mod = join(query.filter_by(type=PackageType.MOD).order_by(db.desc(Package.score))).limit(8).all() pop_gam = join(query.filter_by(type=PackageType.GAME).order_by(db.desc(Package.score))).limit(8).all() @@ -39,5 +41,5 @@ def home(): 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() - return render_template("index.html", count=count, downloads=downloads, tags=tags, + return render_template("index.html", count=count, downloads=downloads, tags=tags, featured=featured, new=new, updated=updated, pop_mod=pop_mod, pop_txp=pop_txp, pop_gam=pop_gam, high_reviewed=high_reviewed, reviews=reviews) diff --git a/app/logic/packages.py b/app/logic/packages.py index 6284b053..d478c782 100644 --- a/app/logic/packages.py +++ b/app/logic/packages.py @@ -19,7 +19,7 @@ import re import validators from app.logic.LogicError import LogicError -from app.models import User, Package, PackageType, MetaPackage, Tag, ContentWarning, db, Permission, AuditSeverity, License +from app.models import User, Package, PackageType, MetaPackage, Tag, ContentWarning, db, Permission, AuditSeverity, License, UserRank from app.utils import addAuditLog @@ -134,15 +134,20 @@ def do_edit_package(user: User, package: Package, was_new: bool, data: dict, rea package.provides.append(m) if "tags" in data: + old_tags = package.tags package.tags.clear() for tag_id in data["tags"]: if is_int(tag_id): - package.tags.append(Tag.query.get(tag_id)) + tag = Tag.query.get(tag_id) else: tag = Tag.query.filter_by(name=tag_id).first() if tag is None: raise LogicError(400, "Unknown tag: " + tag_id) - package.tags.append(tag) + + if tag.is_protected and tag not in old_tags and not user.rank.atLeast(UserRank.EDITOR): + raise LogicError(400, f"Unable to add protected tag {tag.title} to package") + + package.tags.append(tag) if "content_warnings" in data: package.content_warnings.clear() diff --git a/app/models/packages.py b/app/models/packages.py index 0fb845bd..d2e64445 100644 --- a/app/models/packages.py +++ b/app/models/packages.py @@ -744,6 +744,7 @@ class Tag(db.Model): backgroundColor = db.Column(db.String(6), nullable=False) textColor = db.Column(db.String(6), nullable=False) views = db.Column(db.Integer, nullable=False, default=0) + is_protected = db.Column(db.Boolean, nullable=False, default=False) packages = db.relationship("Package", back_populates="tags", secondary=Tags) diff --git a/app/scss/custom.scss b/app/scss/custom.scss index cafab726..989339bc 100644 --- a/app/scss/custom.scss +++ b/app/scss/custom.scss @@ -173,4 +173,12 @@ pre code { } } +.fs-2 { + font-size: calc(1.325rem + .9vw) !important; +} + +.text-shadow { + text-shadow: 3px 3px 3px rgba(10,10,10,0.2); +} + @import "dracula.scss"; diff --git a/app/tasks/importtasks.py b/app/tasks/importtasks.py index f20c08c2..2532ce80 100644 --- a/app/tasks/importtasks.py +++ b/app/tasks/importtasks.py @@ -70,6 +70,23 @@ def getMeta(urlstr, author): return result +def get_edit_data_from_dir(dir: str): + data = {} + for path in [os.path.join(dir, ".cdb.json"), os.path.join(dir, ".cdb", "meta.json")]: + if os.path.isfile(path): + with open(path, "r") as f: + data = json.loads(f.read()) + break + + for path in [os.path.join(dir, ".cdb.md"), os.path.join(dir, ".cdb", "long_description.md")]: + if os.path.isfile(path): + with open(path, "r") as f: + data["long_description"] = f.read().replace("\r\n", "\n") + break + + return data + + def postReleaseCheckUpdate(self, release: PackageRelease, path): try: tree = build_tree(path, expected_type=ContentType[release.package.type.name], @@ -117,13 +134,11 @@ def postReleaseCheckUpdate(self, release: PackageRelease, path): release.max_rel = MinetestRelease.get(tree.meta["max_minetest_version"], None) try: - with open(os.path.join(tree.baseDir, ".cdb.json"), "r") as f: - data = json.loads(f.read()) + data = get_edit_data_from_dir(tree.baseDir) + if data != {}: # Not sure if this will actually work to check not empty, probably not do_edit_package(package.author, package, False, data, "Post release hook") except LogicError as e: raise TaskError(e.message) - except IOError: - pass return tree diff --git a/app/templates/admin/tags/edit.html b/app/templates/admin/tags/edit.html index bb8d4625..75a0c76f 100644 --- a/app/templates/admin/tags/edit.html +++ b/app/templates/admin/tags/edit.html @@ -12,7 +12,7 @@ New Tag Back to list - {% from "macros/forms.html" import render_field, render_submit_field %} + {% from "macros/forms.html" import render_field, render_submit_field, render_checkbox_field %}
{% endblock %} diff --git a/app/templates/index.html b/app/templates/index.html index 05ea8243..c4a840ea 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -21,7 +21,69 @@ {% block content %} {% from "macros/packagegridtile.html" import render_pkggrid %} - + {{ _("See more") }} @@ -76,7 +138,7 @@ {{ _("See more") }} -