Web platform for sharing free data for ML and research

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 app.py

View raw Download
text/x-script.python • 10.12 kiB
Python script, ASCII text executable
        
            
1
from datetime import datetime
2
from email.policy import default
3
4
import flask
5
from flask_sqlalchemy import SQLAlchemy
6
from flask_bcrypt import Bcrypt
7
from flask_httpauth import HTTPBasicAuth
8
from markupsafe import escape, Markup
9
from flask_migrate import Migrate
10
from jinja2_fragments.flask import render_block
11
from sqlalchemy.orm import backref
12
import sqlalchemy.dialects.postgresql
13
14
import config
15
import markdown
16
17
18
app = flask.Flask(__name__)
19
bcrypt = Bcrypt(app)
20
21
22
app.config["SQLALCHEMY_DATABASE_URI"] = config.DB_URI
23
app.config["SECRET_KEY"] = config.DB_PASSWORD
24
25
26
db = SQLAlchemy(app)
27
migrate = Migrate(app, db)
28
29
30
@app.template_filter("split")
31
def split(value, separator=None, maxsplit=-1):
32
return value.split(separator, maxsplit)
33
34
35
36
with app.app_context():
37
class User(db.Model):
38
username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True)
39
password_hashed = db.Column(db.String(60), nullable=False)
40
admin = db.Column(db.Boolean, nullable=False, default=False, server_default="false")
41
42
def __init__(self, username, password):
43
self.username = username
44
self.password_hashed = bcrypt.generate_password_hash(password).decode("utf-8")
45
46
47
class Licence(db.Model):
48
id = db.Column(db.String(32), primary_key=True) # SPDX identifier
49
title = db.Column(db.UnicodeText, nullable=False) # the official name of the licence
50
description = db.Column(db.UnicodeText, nullable=False) # brief description of its permissions and restrictions
51
legal_text = db.Column(db.UnicodeText, nullable=False) # the full legal text of the licence
52
url = db.Column(db.String(2048), nullable=True) # the URL to a page with the full text of the licence and more information
53
pictures = db.relationship("PictureLicence", back_populates="licence")
54
55
def __init__(self, id, title, description, legal_text, url):
56
self.id = id
57
self.title = title
58
self.description = description
59
self.legal_text = legal_text
60
self.url = url
61
62
63
class PictureLicence(db.Model):
64
resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), primary_key=True)
65
licence_id = db.Column(db.String(32), db.ForeignKey("licence.id"), primary_key=True)
66
67
resource = db.relationship("PictureResource", back_populates="licences")
68
licence = db.relationship("Licence", back_populates="pictures")
69
70
def __init__(self, resource_id, licence_id):
71
self.resource_id = resource_id
72
self.licence_id = licence_id
73
74
75
class Resource(db.Model):
76
__abstract__ = True
77
78
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
79
title = db.Column(db.UnicodeText, nullable=False)
80
description = db.Column(db.UnicodeText, nullable=False)
81
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
82
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
83
84
85
class PictureNature(db.Model):
86
# Examples:
87
# "photo", "paper-scan", "2d-art-photo", "sculpture-photo", "computer-3d", "computer-painting",
88
# "computer-line-art", "diagram", "infographic", "text", "map", "chart-graph", "screen-capture",
89
# "screen-photo", "pattern", "collage", "ai", and so on
90
id = db.Column(db.String(64), primary_key=True)
91
description = db.Column(db.UnicodeText, nullable=False)
92
resources = db.relationship("PictureResource", back_populates="nature")
93
94
def __init__(self, id, description):
95
self.id = id
96
self.description = description
97
98
99
class PictureObjectInheritance(db.Model):
100
parent_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"),
101
primary_key=True)
102
child_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"),
103
primary_key=True)
104
105
parent = db.relationship("PictureObject", foreign_keys=[parent_id],
106
back_populates="child_links")
107
child = db.relationship("PictureObject", foreign_keys=[child_id],
108
back_populates="parent_links")
109
110
def __init__(self, parent, child):
111
self.parent = parent
112
self.child = child
113
114
115
class PictureObject(db.Model):
116
id = db.Column(db.String(64), primary_key=True)
117
description = db.Column(db.UnicodeText, nullable=False)
118
119
child_links = db.relationship("PictureObjectInheritance",
120
foreign_keys=[PictureObjectInheritance.parent_id],
121
back_populates="parent")
122
parent_links = db.relationship("PictureObjectInheritance",
123
foreign_keys=[PictureObjectInheritance.child_id],
124
back_populates="child")
125
126
def __init__(self, id, description):
127
self.id = id
128
self.description = description
129
130
131
class PictureRegion(db.Model):
132
# This is for picture region annotations
133
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
134
json = db.Column(sqlalchemy.dialects.postgresql.JSONB, nullable=False)
135
136
resource_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=False)
137
object_id = db.Column(db.String(64), db.ForeignKey("picture_object.id"), nullable=False)
138
139
resource = db.relationship("PictureResource", backref="regions")
140
object = db.relationship("PictureObject", backref="regions")
141
142
def __init__(self, json, resource, object):
143
self.json = json
144
self.resource = resource
145
self.object = object
146
147
148
class PictureResource(Resource):
149
# This is only for bitmap pictures. Vectors will be stored under a different model
150
# File name is the ID in the picture directory under data, without an extension
151
file_format = db.Column(db.String(64), nullable=False) # MIME type
152
width = db.Column(db.Integer, nullable=False)
153
height = db.Column(db.Integer, nullable=False)
154
nature_id = db.Column(db.String(32), db.ForeignKey("picture_nature.id"), nullable=False)
155
156
nature = db.relationship("PictureNature", back_populates="resources")
157
158
replaces_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"), nullable=True)
159
replaced_by_id = db.Column(db.Integer, db.ForeignKey("picture_resource.id"),
160
nullable=True)
161
162
replaces = db.relationship("PictureResource", remote_side="PictureResource.id",
163
foreign_keys=[replaces_id], back_populates="replaced_by")
164
replaced_by = db.relationship("PictureResource", remote_side="PictureResource.id",
165
foreign_keys=[replaced_by_id])
166
167
licences = db.relationship("PictureLicence", back_populates="resource")
168
169
def __init__(self, title, description, origin_url, licence_ids, mime, size, nature,
170
replaces=None):
171
self.title = title
172
self.description = description
173
self.origin_url = origin_url
174
self.file_format = mime
175
self.width, self.height = size
176
self.nature = nature
177
db.session.add(self)
178
db.session.commit()
179
for licence_id in licence_ids:
180
joiner = PictureLicence(self.id, licence_id)
181
db.session.add(joiner)
182
if replaces is not None:
183
self.replaces = replaces
184
replaces.replaced_by = self
185
186
187
@app.route("/")
188
def index():
189
return flask.render_template("home.html")
190
191
192
@app.route("/accounts")
193
def accounts():
194
return flask.render_template("login.html")
195
196
197
@app.route("/login", methods=["POST"])
198
def login():
199
username = flask.request.form["username"]
200
password = flask.request.form["password"]
201
202
user = db.session.get(User, username)
203
204
if user is None:
205
flask.flash("This username is not registered.")
206
return flask.redirect("/accounts")
207
208
if not bcrypt.check_password_hash(user.password_hashed, password):
209
flask.flash("Incorrect password.")
210
return flask.redirect("/accounts")
211
212
flask.flash("You have been logged in.")
213
214
flask.session["username"] = username
215
return flask.redirect("/")
216
217
218
@app.route("/logout")
219
def logout():
220
flask.session.pop("username", None)
221
flask.flash("You have been logged out.")
222
return flask.redirect("/")
223
224
225
@app.route("/signup", methods=["POST"])
226
def signup():
227
username = flask.request.form["username"]
228
password = flask.request.form["password"]
229
230
if db.session.get(User, username) is not None:
231
flask.flash("This username is already taken.")
232
return flask.redirect("/accounts")
233
234
if set(username) > set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"):
235
flask.flash("Usernames can only contain the Latin alphabet, digits, hyphens, and underscores.")
236
return flask.redirect("/accounts")
237
238
if len(username) < 3 or len(username) > 32:
239
flask.flash("Usernames must be between 3 and 32 characters long.")
240
return flask.redirect("/accounts")
241
242
if len(password) < 6:
243
flask.flash("Passwords must be at least 6 characters long.")
244
return flask.redirect("/accounts")
245
246
user = User(username, None, password)
247
db.session.add(user)
248
db.session.commit()
249
250
flask.session["username"] = username
251
252
flask.flash("You have been registered and logged in.")
253
254
return flask.redirect("/")
255
256
257
@app.route("/profile", defaults={"username": None})
258
@app.route("/profile/<username>")
259
def profile(username):
260
if username is None:
261
if "username" in flask.session:
262
return flask.redirect("/profile/" + flask.session["username"])
263
else:
264
flask.flash("Please log in to perform this action.")
265
return flask.redirect("/accounts")
266
267
user = db.session.get(User, username)
268
if user is None:
269
return flask.abort(404)
270
271
return flask.render_template("profile.html", user=user)
272