roundabout,
created on Monday, 9 September 2024, 14:10:29 (1725891029),
received on Monday, 9 September 2024, 14:10:32 (1725891032)
Author identity: vlad <vlad.muntoiu@gmail.com>
40f27cd24041b1d4408482743783551a3d0a525a
app.py
@@ -76,6 +76,7 @@ with app.app_context():
admin = db.Column(db.Boolean, nullable=False, default=False, server_default="false") pictures = db.relationship("PictureResource", back_populates="author") joined_timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) galleries = db.relationship("Gallery", back_populates="owner")def __init__(self, username, password): self.username = username
@@ -224,6 +225,7 @@ with app.app_context():
backref="copies", foreign_keys=[copied_from_id]) licences = db.relationship("PictureLicence", back_populates="resource") galleries = db.relationship("PictureInGallery", back_populates="resource")def __init__(self, title, author, description, origin_url, licence_ids, mime, nature=None): self.title = title
@@ -256,6 +258,34 @@ with app.app_context():
db.session.add(region_row) class PictureInGallery(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=False) gallery_id = db.Column(db.Integer, db.ForeignKey("gallery.id"), nullable=False) resource = db.relationship("PictureResource") gallery = db.relationship("Gallery") def __init__(self, resource, gallery): self.resource = resource self.gallery = gallery class Gallery(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.UnicodeText, nullable=False) description = db.Column(db.UnicodeText, nullable=False) pictures = db.relationship("PictureInGallery", back_populates="gallery") owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) owner = db.relationship("User", back_populates="galleries") def __init__(self, title, description, owner): self.title = title self.description = description self.owner = owner @app.route("/") def index(): return flask.render_template("home.html", resources=PictureResource.query.order_by(db.func.random()).limit(10).all())
@@ -575,7 +605,7 @@ def delete_picture(id):
@app.route("/picture/<int:id>/mark-replacement", methods=["POST"]) def mark_replacement(id):def mark_picture_replacement(id):resource = db.session.get(PictureResource, id) if resource is None: flask.abort(404)
@@ -596,7 +626,7 @@ def mark_replacement(id):
@app.route("/picture/<int:id>/remove-replacement", methods=["POST"]) def remove_replacement(id):def remove_picture_replacement(id):resource = db.session.get(PictureResource, id) if resource is None: flask.abort(404)
@@ -722,6 +752,78 @@ def copy_picture(id):
return flask.redirect("/picture/" + str(new_resource.id)) @app.route("/gallery/<int:id>/") def gallery(id): gallery = db.session.get(Gallery, id) if gallery is None: flask.abort(404) return flask.render_template("gallery.html", gallery=gallery) @app.route("/create-gallery") def create_gallery(): if "username" not in flask.session: flask.flash("Log in to create galleries.") return flask.redirect("/accounts") return flask.render_template("create-gallery.html") @app.route("/create-gallery", methods=["POST"]) def create_gallery_post(): if not flask.session.get("username"): flask.abort(401) if not flask.request.form.get("title"): flask.flash("Enter a title") return flask.redirect(flask.request.url) description = flask.request.form.get("description", "") gallery = Gallery(flask.request.form["title"], description, db.session.get(User, flask.session["username"])) db.session.add(gallery) db.session.commit() return flask.redirect("/gallery/" + str(gallery.id)) @app.route("/gallery/<int:id>/add-picture", methods=["POST"]) def gallery_add_picture(id): gallery = db.session.get(Gallery, id) if gallery is None: flask.abort(404) if "username" not in flask.session: flask.abort(401) if flask.session["username"] != gallery.owner_name and not db.session.get(User, flask.session["username"]).admin: flask.abort(403) picture_id = flask.request.form.get("picture_id") if "/" in picture_id: # also allow full URLs picture_id = picture_id.rstrip("/").rpartition("/")[1] if not picture_id: flask.flash("Select a picture") return flask.redirect("/gallery/" + str(gallery.id)) picture_id = int(picture_id) picture = db.session.get(PictureResource, picture_id) if picture is None: flask.flash("Invalid picture") return flask.redirect("/gallery/" + str(gallery.id)) if PictureInGallery.query.filter_by(resource=picture, gallery=gallery).first(): flask.flash("This picture is already in the gallery") return flask.redirect("/gallery/" + str(gallery.id)) db.session.add(PictureInGallery(picture, gallery)) db.session.commit() return flask.redirect("/gallery/" + str(gallery.id)) def get_picture_query(query_data): query = db.session.query(PictureResource)
templates/create-gallery.html
@@ -0,0 +1,23 @@
{% extends "default.html" %} {% block title %}Create gallery | gigadata{% endblock %} {% block content %} <x-frame style="--width: 768px"> <form method="POST" class="vbox"> <h1>Create gallery</h1> <p> You can add content later. </p> <label> <span class="required-asterisk">Title</span> <input type="text" name="title" required> </label> <label> Description <textarea name="description" rows="4"></textarea> </label> <button type="submit">Create</button> </form> </x-frame> {% endblock %}
templates/gallery.html
@@ -0,0 +1,53 @@
{% extends "default.html" %} {% block title %}Gallery {{ gallery.title }} | gigadata{% endblock %} {% block content %} <x-frame style="--width: 768px" class="vbox"> <h1>{{ gallery.title }}</h1> <p>{{ gallery.description }}</p> <form class="buttonbox" method="POST" action="/gallery/{{ gallery.id }}/add-picture"> <input name="picture_id" type="text" placeholder="Picture ID" required aria-label="Picture ID"> <button type="submit">Add picture</button> </form> <h2>Pictures</h2> <ul class="thumbnail-list"> {% for picture in gallery.pictures %} <li> <a href="/picture/{{ picture.resource.id }}"> <div class="annotation-zone"> <img src="/raw/picture/{{ picture.resource.id }}" alt="{{ picture.resource.title }}"> {% for region in picture.resource.regions %} {% if region.json.type == "bbox" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <rect x="{{ region.json.shape.x * picture.resource.width }}" y="{{ region.json.shape.y * picture.resource.height }}" width="{{ region.json.shape.w * picture.resource.width }}" height="{{ region.json.shape.h * picture.resource.height }}" fill="none" class="shape-bbox shape" ></rect> </svg> {% elif region.json.type == "polygon" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <polygon points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polygon shape"></polygon> </svg> {% elif region.json.type == "polyline" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <polyline points="{% for point in region.json.shape %}{{ point.x * picture.resource.width }},{{ point.y * picture.resource.height }} {% endfor %}" fill="none" class="shape-polyline shape"></polyline> </svg> {% elif region.json.type == "point" %} <svg class="shape-container" viewBox="0 0 {{ picture.resource.width }} {{ picture.resource.height }}"> <circle cx="{{ region.json.shape.x * picture.resource.width }}" cy="{{ region.json.shape.y * picture.resource.height }}" r="0" fill="none" class="shape-point shape"></circle> </svg> {% endif %} {% endfor %} </div> <div class="list-detail"> {{ picture.resource.title }} </div> </a> </li> {% endfor %} </ul> </x-frame> {% endblock %}