roundabout,
created on Wednesday, 14 August 2024, 11:42:02 (1723635722),
received on Thursday, 15 August 2024, 07:42:21 (1723707741)
Author identity: vlad <vlad.muntoiu@gmail.com>
5a5988e04bd78522f4a7aec6b9f9a7cfff476be1
.gitignore
@@ -1,2 +1,3 @@
.venv/
secrets.env
data/
app.py
@@ -1,3 +1,6 @@
from datetime import datetime
from email.policy import default
import flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
@@ -5,6 +8,9 @@ from flask_httpauth import HTTPBasicAuth
from markupsafe import escape, Markup
from flask_migrate import Migrate
from jinja2_fragments.flask import render_block
from sqlalchemy.orm import backref
import sqlalchemy.dialects.postgresql
import config
import markdown
@@ -26,17 +32,154 @@ def split(value, separator=None, maxsplit=-1):
return value.split(separator, maxsplit)
with app.app_context():
class User(db.Model):
username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True)
password_hashed = db.Column(db.String(60), nullable=False)
def __init__(self, username, real_name, password):
def __init__(self, username, password):
self.username = username
self.real_name = real_name
self.password_hashed = bcrypt.generate_password_hash(password).decode("utf-8")
class Licence(db.Model):
id = db.Column(db.String(32), primary_key=True) # SPDX identifier
title = db.Column(db.UnicodeText, nullable=False) # the official name of the licence
description = db.Column(db.UnicodeText, nullable=False) # brief description of its permissions and restrictions
legal_text = db.Column(db.UnicodeText, nullable=False) # the full legal text of the licence
url = db.Column(db.String(2048), nullable=True) # the URL to a page with the full text of the licence and more information
pictures = db.relationship("PictureLicence", back_populates="licence")
def __init__(self, id, title, description, legal_text, url):
self.id = id
self.title = title
self.description = description
self.legal_text = legal_text
self.url = url
class PictureLicence(db.Model):
resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), primary_key=True)
licence_id = db.Column(db.String(32), db.ForeignKey("licence.id"), primary_key=True)
resource = db.relationship("PictureResource", back_populates="licences")
licence = db.relationship("Licence", back_populates="pictures")
def __init__(self, resource_id, licence_id):
self.resource_id = resource_id
self.licence_id = licence_id
class Resource(db.Model):
__abstract__ = True
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.UnicodeText, nullable=False)
description = db.Column(db.UnicodeText, nullable=False)
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
origin_url = db.Column(db.String(2048), nullable=True) # should be left empty if it's original or the source is unknown but public domain
class PictureNature(db.Model):
# Examples:
# "photo", "paper-scan", "2d-art-photo", "sculpture-photo", "computer-3d", "computer-painting",
# "computer-line-art", "diagram", "infographic", "text", "map", "chart-graph", "screen-capture",
# "screen-photo", "pattern", "collage", "ai", and so on
id = db.Column(db.String(64), primary_key=True)
description = db.Column(db.UnicodeText, nullable=False)
resources = db.relationship("PictureResource", backref="nature")
def __init__(self, id, description):
self.id = id
self.description = description
class PictureObjectInheritance(db.Model):
parent_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"),
primary_key=True)
child_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"),
primary_key=True)
parent = db.relationship("PictureObject", foreign_keys=[parent_id],
backref="child_links")
child = db.relationship("PictureObject", foreign_keys=[child_id],
backref="parent_links")
def __init__(self, parent, child):
self.parent = parent
self.child = child
class PictureObject(db.Model):
id = db.Column(db.String(64), primary_key=True)
description = db.Column(db.UnicodeText, nullable=False)
child_links = db.relationship("PictureObjectInheritance",
foreign_keys=[PictureObjectInheritance.parent_id],
backref="parent")
parent_links = db.relationship("PictureObjectInheritance",
foreign_keys=[PictureObjectInheritance.child_id],
backref="child")
def __init__(self, id, description):
self.id = id
self.description = description
class PictureRegion(db.Model):
# This is for picture region annotations
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
json = db.Column(sqlalchemy.dialects.postgresql.JSONB, nullable=False)
resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=False)
object_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"), nullable=False)
resource = db.relationship("PictureResource", backref="regions")
object = db.relationship("PictureObject", backref="regions")
def __init__(self, json, resource, object):
self.json = json
self.resource = resource
self.object = object
class PictureResource(Resource):
# This is only for bitmap pictures. Vectors will be stored under a different model
# File name is the ID in the picture directory under data, without an extension
file_format = db.Column(db.String(64), nullable=False) # MIME type
width = db.Column(db.Integer, nullable=False)
height = db.Column(db.Integer, nullable=False)
nature_id = db.Column(db.String(32), db.ForeignKey("picture_nature.id"), nullable=False)
nature = db.relationship("PictureNature", back_populates="resources")
replaces_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=True)
replaced_by_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=True) # if this is set, this resource is obsolete and hidden from search results, only available if asked for
replaces = db.relationship("PictureResource", foreign_keys=[replaces_id], backref="replaced_by")
replaced_by = db.relationship("PictureResource", foreign_keys=[replaced_by_id], backref="replaces")
licences = db.relationship("ResourceLicence", # a work can be under multiple licences; at least one must be free, but others can be proprietary
back_populates="resource")
def __init__(self, title, description, origin_url, licence_ids, mime, size, nature, replaces=None):
self.title = title
self.description = description
self.origin_url = origin_url
self.file_format = mime
self.width, self.height = size
self.nature = nature
db.session.add(self)
db.session.commit()
for licence_id in licence_ids:
joiner = PictureLicence(self.id, licence_id)
db.session.add(joiner)
if replaces is not None:
self.replaces = replaces
replaces.replaced_by = self
@app.route("/")
def index():
return flask.render_template("home.html")
config.py
@@ -5,3 +5,4 @@ dotenv.load_dotenv("secrets.env")
DB_PASSWORD = environ["DB_PASSWORD"]
DB_URI = f"postgresql://gigadata:{DB_PASSWORD}@localhost:5432/gigadata"
DATA_PATH = "./data"