Add ability to reorder screenshots

This commit is contained in:
rubenwardy 2020-12-06 03:35:25 +00:00
parent 2910fcc1a4
commit f93a2d8717
9 changed files with 152 additions and 35 deletions

@ -37,6 +37,32 @@ class EditScreenshotForm(FlaskForm):
delete = BooleanField("Delete") delete = BooleanField("Delete")
submit = SubmitField("Save") submit = SubmitField("Save")
@bp.route("/packages/<author>/<name>/screenshots/", methods=["GET", "POST"])
@login_required
@is_package_page
def screenshots(package):
if not package.checkPerm(current_user, Permission.ADD_SCREENSHOTS):
return redirect(package.getDetailsURL())
if request.method == "POST":
order = request.form.get("order")
if order:
lookup = {}
for screenshot in package.screenshots:
lookup[str(screenshot.id)] = screenshot
counter = 1
for id in order.split(","):
lookup[id].order = counter
counter += 1
db.session.commit()
return redirect(package.getDetailsURL())
return render_template("packages/screenshots.html", package=package)
@bp.route("/packages/<author>/<name>/screenshots/new/", methods=["GET", "POST"]) @bp.route("/packages/<author>/<name>/screenshots/new/", methods=["GET", "POST"])
@login_required @login_required
@is_package_page @is_package_page
@ -61,7 +87,7 @@ def create_screenshot(package):
.format(ss.title) .format(ss.title)
addNotification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg, package.getDetailsURL(), package) addNotification(package.maintainers, current_user, NotificationType.PACKAGE_EDIT, msg, package.getDetailsURL(), package)
db.session.commit() db.session.commit()
return redirect(package.getDetailsURL()) return redirect(package.getEditScreenshotsURL())
return render_template("packages/screenshot_new.html", package=package, form=form) return render_template("packages/screenshot_new.html", package=package, form=form)
@ -76,7 +102,7 @@ def edit_screenshot(package, id):
canEdit = package.checkPerm(current_user, Permission.ADD_SCREENSHOTS) canEdit = package.checkPerm(current_user, Permission.ADD_SCREENSHOTS)
canApprove = package.checkPerm(current_user, Permission.APPROVE_SCREENSHOT) canApprove = package.checkPerm(current_user, Permission.APPROVE_SCREENSHOT)
if not (canEdit or canApprove): if not (canEdit or canApprove):
return redirect(package.getDetailsURL()) return redirect(package.getEditScreenshotsURL())
# Initial form class from post data and default data # Initial form class from post data and default data
form = EditScreenshotForm(formdata=request.form, obj=screenshot) form = EditScreenshotForm(formdata=request.form, obj=screenshot)
@ -101,6 +127,6 @@ def edit_screenshot(package, id):
screenshot.approved = wasApproved screenshot.approved = wasApproved
db.session.commit() db.session.commit()
return redirect(package.getDetailsURL()) return redirect(package.getEditScreenshotsURL())
return render_template("packages/screenshot_edit.html", package=package, screenshot=screenshot, form=form) return render_template("packages/screenshot_edit.html", package=package, screenshot=screenshot, form=form)

@ -714,7 +714,7 @@ class Package(db.Model):
lazy="dynamic", order_by=db.desc("package_release_releaseDate")) lazy="dynamic", order_by=db.desc("package_release_releaseDate"))
screenshots = db.relationship("PackageScreenshot", backref="package", screenshots = db.relationship("PackageScreenshot", backref="package",
lazy="dynamic", order_by=db.asc("package_screenshot_id")) lazy="dynamic", order_by=db.asc("package_screenshot_order"))
requests = db.relationship("EditRequest", backref="package", requests = db.relationship("EditRequest", backref="package",
lazy="dynamic") lazy="dynamic")
@ -885,6 +885,10 @@ class Package(db.Model):
return url_for("packages.create_screenshot", return url_for("packages.create_screenshot",
author=self.author.username, name=self.name) author=self.author.username, name=self.name)
def getEditScreenshotsURL(self):
return url_for("packages.screenshots",
author=self.author.username, name=self.name)
def getCreateReleaseURL(self): def getCreateReleaseURL(self):
return url_for("packages.create_release", return url_for("packages.create_release",
author=self.author.username, name=self.name) author=self.author.username, name=self.name)
@ -1259,16 +1263,10 @@ class PackageRelease(db.Model):
raise Exception("Permission {} is not related to releases".format(perm.name)) raise Exception("Permission {} is not related to releases".format(perm.name))
# class PackageReview(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# package_id = db.Column(db.Integer, db.ForeignKey("package.id"))
# thread_id = db.Column(db.Integer, db.ForeignKey("thread.id"), nullable=False)
# recommend = db.Column(db.Boolean, nullable=False, default=True)
class PackageScreenshot(db.Model): class PackageScreenshot(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
package_id = db.Column(db.Integer, db.ForeignKey("package.id")) package_id = db.Column(db.Integer, db.ForeignKey("package.id"))
order = db.Column(db.Integer, nullable=False, default=0)
title = db.Column(db.String(100), nullable=False) title = db.Column(db.String(100), nullable=False)
url = db.Column(db.String(100), nullable=False) url = db.Column(db.String(100), nullable=False)
approved = db.Column(db.Boolean, nullable=False, default=False) approved = db.Column(db.Boolean, nullable=False, default=False)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -122,3 +122,7 @@
background-color: #222 !important; background-color: #222 !important;
color: white !important; color: white !important;
} }
.sortable {
user-select: none;
}

@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title> <title>{% block title %}title{% endblock %} - {{ config.USER_APP_NAME }}</title>
<link rel="stylesheet" type="text/css" href="/static/bootstrap.css"> <link rel="stylesheet" type="text/css" href="/static/bootstrap.css">
<link rel="stylesheet" type="text/css" href="/static/custom.css?v=15"> <link rel="stylesheet" type="text/css" href="/static/custom.css?v=16">
<link rel="search" type="application/opensearchdescription+xml" href="/static/opensearch.xml" title="ContentDB" /> <link rel="search" type="application/opensearchdescription+xml" href="/static/opensearch.xml" title="ContentDB" />
<link rel="shortcut icon" href="/favicon-16.png" sizes="16x16"> <link rel="shortcut icon" href="/favicon-16.png" sizes="16x16">
<link rel="icon" href="/favicon-128.png" sizes="128x128"> <link rel="icon" href="/favicon-128.png" sizes="128x128">

@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}
Screenshots | {{ package.title }}
{% endblock %}
{% block content %}
<h1 class="mb-5"><a href="{{ package.getDetailsURL() }}">{{ package.title }}</a></h1>
{% if package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
<a href="{{ package.getNewScreenshotURL() }}" class="btn btn-primary float-right">
{{ _("Add Image") }}
</a>
{% endif %}
<h2 class="mt-0">Screenshots</h2>
<ul class="list-group sortable">
{% for ss in package.screenshots %}
{% if ss.approved or package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
<li class="list-group-item" data-id="{{ ss.id }}">
<div class="row">
<div class="col-auto text-muted pr-2">
<i class="fas fa-bars"></i>
</div>
<div class="col-auto">
<img class="img-fluid" style="max-height: 64px;"
src="{{ ss.getThumbnailURL() }}" alt="{{ ss.title }}" />
</div>
<span class="col">
{{ ss.title }}
</span>
<div class="col-auto text-right">
<a class="btn btn-sm btn-primary" href="{{ ss.getEditURL() }}">
<i class="fas fa-edit"></i>
</a>
</div>
</div>
</li>
{% endif %}
{% endfor %}
</ul>
<form action="" method="POST" class="form mt-4" role="form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="order" value="" />
<input type="submit" value="{{ _("Update Order") }}" class="btn btn-primary">
</form>
<noscript>
<p class="alert alert-warning mt-5">
{{ _("Reordering requires JavaScript.") }}
</p>
</noscript>
{% endblock %}
{% block scriptextra %}
<script src="/static/jquery-ui.min.js"></script>
<script>
function update() {
const elements = Array.from(document.getElementsByClassName("sortable")[0].children);
const ids = elements.map(x => x.dataset.id).filter(x => x);
$("input[name='order']").val(ids.join(","))
}
update();
$(function() {
$(".sortable").sortable({
update: update
});
});
</script>
{% endblock %}

@ -380,23 +380,23 @@
{% endif %} {% endif %}
</aside> </aside>
{% if package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
<a href="{{ package.getEditScreenshotsURL() }}" class="btn btn-primary float-right">
<i class="fas fa-edit"></i>
Edit
</a>
{% endif %}
<ul class="screenshot_list mb-4"> <ul class="screenshot_list mb-4">
{% for ss in package.screenshots %} {% for ss in package.screenshots %}
{% if ss.approved or package.checkPerm(current_user, "ADD_SCREENSHOTS") %} {% if ss.approved or package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
<li> <li>
<a href="{% if package.checkPerm(current_user, 'ADD_SCREENSHOTS') %}{{ ss.getEditURL() }}{% else %}{{ ss.url }}{% endif %}"> <a href="{{ ss.url }}">
<img src="{{ ss.getThumbnailURL() }}" alt="{{ ss.title }}" /> <img src="{{ ss.getThumbnailURL() }}" alt="{{ ss.title }}" />
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if package.checkPerm(current_user, "EDIT_PACKAGE") %}
<li>
<a href="{{ package.getNewScreenshotURL() }}">
<div class="fas fa-plus screenshot-add"></div>
</a>
</li>
{% endif %}
</ul> </ul>
{{ package.desc | markdown }} {{ package.desc | markdown }}

@ -0,0 +1,26 @@
"""empty message
Revision ID: e1bf78a597a2
Revises: 06d23947e7ef
Create Date: 2020-12-06 03:16:59.988464
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e1bf78a597a2'
down_revision = '06d23947e7ef'
branch_labels = None
depends_on = None
def upgrade():
op.add_column('package_screenshot', sa.Column('order', sa.Integer(), nullable=True))
op.execute("""UPDATE package_screenshot SET "order" = id""")
op.alter_column('package_screenshot', 'order', nullable=False)
def downgrade():
op.drop_column('package_screenshot', 'order')