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 • 54.74 kiB
Python script, Unicode text, UTF-8 text executable
        
            
1
__version__ = "0.1.2"
2
3
import os
4
import shutil
5
import random
6
import subprocess
7
import platform
8
import git
9
import mimetypes
10
import magic
11
import flask
12
import cairosvg
13
import celery
14
import shlex
15
from functools import wraps
16
from datetime import datetime
17
from enum import Enum
18
from cairosvg import svg2png
19
from flask_sqlalchemy import SQLAlchemy
20
from flask_bcrypt import Bcrypt
21
from markupsafe import escape, Markup
22
from flask_migrate import Migrate
23
from PIL import Image
24
from flask_httpauth import HTTPBasicAuth
25
import config
26
from flask_babel import Babel, gettext, ngettext, force_locale
27
28
_ = gettext
29
n_ = gettext
30
31
app = flask.Flask(__name__)
32
app.config.from_mapping(
33
CELERY=dict(
34
broker_url=config.REDIS_URI,
35
result_backend=config.REDIS_URI,
36
task_ignore_result=True,
37
),
38
)
39
40
auth = HTTPBasicAuth()
41
42
app.config["SQLALCHEMY_DATABASE_URI"] = config.DB_URI
43
app.config["SECRET_KEY"] = config.DB_PASSWORD
44
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
45
app.config["BABEL_TRANSLATION_DIRECTORIES"] = "i18n"
46
app.config["MAX_CONTENT_LENGTH"] = config.MAX_PAYLOAD_SIZE
47
48
db = SQLAlchemy(app)
49
bcrypt = Bcrypt(app)
50
migrate = Migrate(app, db)
51
52
from models import *
53
from misc_utils import *
54
55
import git_http
56
import jinja_utils
57
import celery_tasks
58
from celery import Celery, Task
59
import celery_integration
60
import pathlib
61
62
babel = Babel(app)
63
64
65
def get_locale():
66
if flask.request.cookies.get("language"):
67
return flask.request.cookies.get("language")
68
return flask.request.accept_languages.best_match(config.available_locales)
69
70
71
babel.init_app(app, locale_selector=get_locale)
72
73
with app.app_context():
74
locale_names = {}
75
for language in config.available_locales:
76
with force_locale(language):
77
# NOTE: Translate this to the language's name in that language, for example in French you would use français
78
locale_names[language] = gettext("English")
79
80
worker = celery_integration.init_celery_app(app)
81
82
repositories = flask.Blueprint("repository", __name__, template_folder="templates/repository/")
83
84
app.jinja_env.add_extension("jinja2.ext.do")
85
app.jinja_env.add_extension("jinja2.ext.loopcontrols")
86
app.jinja_env.add_extension("jinja2.ext.debug")
87
88
89
@app.context_processor
90
def default():
91
username = flask.session.get("username")
92
93
user_object = User.query.filter_by(username=username).first()
94
95
return {
96
"logged_in_user": username,
97
"user_object": user_object,
98
"Notification": Notification,
99
"unread": UserNotification.query.filter_by(user_username=username).filter(
100
UserNotification.attention_level > 0).count(),
101
"config": config,
102
"Markup": Markup,
103
"locale_names": locale_names,
104
}
105
106
107
@app.route("/")
108
def main():
109
if flask.session.get("username"):
110
return flask.render_template("home.html")
111
else:
112
return flask.render_template("no-home.html")
113
114
115
@app.route("/userstyle")
116
def userstyle():
117
if flask.session.get("username") and os.path.exists(os.path.join(config.REPOS_PATH, flask.session.get("username"), ".config", "theme.css")):
118
return flask.send_from_directory(os.path.join(config.REPOS_PATH, flask.session.get("username"), ".config"), "theme.css")
119
else:
120
return flask.Response("", mimetype="text/css")
121
122
123
@app.route("/about/")
124
def about():
125
return flask.render_template("about.html", platform=platform, version=__version__)
126
127
128
@app.route("/language", methods=["POST"])
129
def set_locale():
130
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/",
131
code=303)
132
if not flask.request.form.get("language"):
133
response.delete_cookie("language")
134
else:
135
response.set_cookie("language", flask.request.form.get("language"))
136
137
return response
138
139
140
@app.route("/cookie-dismiss")
141
def dismiss_banner():
142
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/",
143
code=303)
144
response.set_cookie("cookie-banner", "1")
145
return response
146
147
148
@app.route("/help/")
149
def help_index():
150
return flask.render_template("help.html", faqs=config.faqs)
151
152
153
@app.route("/settings/", methods=["GET", "POST"])
154
def settings():
155
if not flask.session.get("username"):
156
flask.abort(401)
157
if flask.request.method == "GET":
158
user = User.query.filter_by(username=flask.session.get("username")).first()
159
160
return flask.render_template("user-settings.html", user=user)
161
else:
162
user = User.query.filter_by(username=flask.session.get("username")).first()
163
164
user.display_name = flask.request.form["displayname"]
165
user.URL = flask.request.form["url"]
166
user.company = flask.request.form["company"]
167
user.company_URL = flask.request.form["companyurl"]
168
user.email = flask.request.form.get("email") if flask.request.form.get(
169
"email") else None
170
user.location = flask.request.form["location"]
171
user.show_mail = True if flask.request.form.get("showmail") else False
172
user.bio = flask.request.form.get("bio")
173
174
db.session.commit()
175
176
flask.flash(
177
Markup("<iconify-icon icon='mdi:check'></iconify-icon>" + _("Settings saved")),
178
category="success")
179
return flask.redirect(f"/{flask.session.get('username')}", code=303)
180
181
182
@app.route("/favourites/", methods=["GET", "POST"])
183
def favourites():
184
if not flask.session.get("username"):
185
flask.abort(401)
186
if flask.request.method == "GET":
187
relationships = RepoFavourite.query.filter_by(
188
user_username=flask.session.get("username"))
189
190
return flask.render_template("favourites.html", favourites=relationships)
191
192
193
@app.route("/favourites/<int:id>", methods=["POST"])
194
def favourite_edit(id):
195
if not flask.session.get("username"):
196
flask.abort(401)
197
favourite = db.session.get(RepoFavourite, id)
198
if favourite.user_username != flask.session.get("username"):
199
flask.abort(403)
200
data = flask.request.form
201
print(data)
202
favourite.notify_commit = js_to_bool(data.get("commit"))
203
favourite.notify_forum = js_to_bool(data.get("forum"))
204
favourite.notify_pr = js_to_bool(data.get("pull_request"))
205
favourite.notify_admin = js_to_bool(data.get("administrative"))
206
print(favourite.notify_commit, favourite.notify_forum, favourite.notify_pr, favourite.notify_admin)
207
db.session.commit()
208
return flask.render_template_string(
209
"""
210
<tr hx-post="/favourites/{{ favourite.id }}" hx-trigger="change" hx-include="#commit-{{ favourite.id }}, #forum-{{ favourite.id }}, #pull_request-{{ favourite.id }}, #administrative-{{ favourite.id }}" hx-headers='{"Content-Type": "application/json"}' hx-swap="outerHTML">
211
<td><a href="{{ favourite.repo.route }}">{{ favourite.repo.owner.username }}/{{ favourite.repo.name }}</a></td>
212
<td style="text-align: center;"><input type="checkbox" name="commit" id="commit-{{ favourite.id }}" value="true" {% if favourite.notify_commit %}checked{% endif %}></td>
213
<td style="text-align: center;"><input type="checkbox" name="forum" id="forum-{{ favourite.id }}" value="true" {% if favourite.notify_forum %}checked{% endif %}></td>
214
<td style="text-align: center;"><input type="checkbox" name="pull_request" id="pull_request-{{ favourite.id }}" value="true" {% if favourite.notify_pr %}checked{% endif %}></td>
215
<td style="text-align: center;"><input type="checkbox" name="administrative" id="administrative-{{ favourite.id }}" value="true" {% if favourite.notify_admin %}checked{% endif %}></td>
216
</tr>
217
""",
218
favourite=favourite
219
)
220
221
222
@app.route("/notifications/", methods=["GET", "POST"])
223
def notifications():
224
if not flask.session.get("username"):
225
flask.abort(401)
226
if flask.request.method == "GET":
227
return flask.render_template("notifications.html",
228
notifications=UserNotification.query.filter_by(
229
user_username=flask.session.get("username")))
230
231
232
@app.route("/notifications/<int:notification_id>/read", methods=["POST"])
233
def mark_read(notification_id):
234
if not flask.session.get("username"):
235
flask.abort(401)
236
notification = UserNotification.query.filter_by(id=notification_id).first()
237
if notification.user_username != flask.session.get("username"):
238
flask.abort(403)
239
notification.mark_read()
240
db.session.commit()
241
return f"<button hx-post='/notifications/{ notification.id }/unread' hx-swap='outerHTML'>Mark as unread</button>", 200
242
243
244
@app.route("/notifications/<int:notification_id>/unread", methods=["POST"])
245
def mark_unread(notification_id):
246
if not flask.session.get("username"):
247
flask.abort(401)
248
notification = UserNotification.query.filter_by(id=notification_id).first()
249
if notification.user_username != flask.session.get("username"):
250
flask.abort(403)
251
notification.mark_unread()
252
db.session.commit()
253
return f"<button hx-post='/notifications/{ notification.id }/read' hx-swap='outerHTML'>Mark as read</button>", 200
254
255
256
@app.route("/notifications/mark-all-read", methods=["POST"])
257
def mark_all_read():
258
if not flask.session.get("username"):
259
flask.abort(401)
260
261
notifications = UserNotification.query.filter_by(
262
user_username=flask.session.get("username"))
263
for notification in notifications:
264
notification.mark_read()
265
db.session.commit()
266
return flask.redirect("/notifications/", code=303)
267
268
269
@app.route("/accounts/", methods=["GET", "POST"])
270
def login():
271
if flask.request.method == "GET":
272
return flask.render_template("login.html")
273
else:
274
if "login" in flask.request.form:
275
username = flask.request.form["username"]
276
password = flask.request.form["password"]
277
278
user = User.query.filter_by(username=username).first()
279
280
if user and bcrypt.check_password_hash(user.password_hashed, password):
281
flask.session["username"] = user.username
282
flask.flash(
283
Markup("<iconify-icon icon='mdi:account'></iconify-icon>" + _(
284
"Successfully logged in as {username}").format(username=username)),
285
category="success")
286
return flask.redirect("/", code=303)
287
elif not user:
288
flask.flash(Markup(
289
"<iconify-icon icon='mdi:account-question'></iconify-icon>" + _(
290
"User not found")),
291
category="alert")
292
return flask.render_template("login.html")
293
else:
294
flask.flash(Markup(
295
"<iconify-icon icon='mdi:account-question'></iconify-icon>" + _(
296
"Invalid password")),
297
category="error")
298
return flask.render_template("login.html")
299
if "signup" in flask.request.form:
300
username = flask.request.form["username"]
301
password = flask.request.form["password"]
302
password2 = flask.request.form["password2"]
303
email = flask.request.form.get("email")
304
email2 = flask.request.form.get("email2") # repeat email is a honeypot
305
name = flask.request.form.get("name")
306
307
if not only_chars(username,
308
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
309
flask.flash(Markup(
310
_("Usernames may only contain Latin alphabet, numbers, '-' and '_'")),
311
category="error")
312
return flask.render_template("login.html")
313
314
if username in config.RESERVED_NAMES:
315
flask.flash(
316
Markup(
317
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _(
318
"Sorry, {username} is a system path").format(
319
username=username)),
320
category="error")
321
return flask.render_template("login.html")
322
323
user_check = User.query.filter_by(username=username).first()
324
if user_check or email2: # make the honeypot look like a normal error
325
flask.flash(
326
Markup(
327
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _(
328
"The username {username} is taken").format(
329
username=username)),
330
category="error")
331
return flask.render_template("login.html")
332
333
if password2 != password:
334
flask.flash(Markup("<iconify-icon icon='mdi:key-alert'></iconify-icon>" + _(
335
"Make sure the passwords match")),
336
category="error")
337
return flask.render_template("login.html")
338
339
user = User(username, password, email, name)
340
db.session.add(user)
341
db.session.commit()
342
flask.session["username"] = user.username
343
flask.flash(Markup(
344
"<iconify-icon icon='mdi:account'></iconify-icon>" + _(
345
"Successfully created and logged in as {username}").format(
346
username=username)),
347
category="success")
348
349
notification = Notification({"type": "welcome"})
350
db.session.add(notification)
351
db.session.commit()
352
353
result = celery_tasks.send_notification.delay(notification.id, [username], 1)
354
355
return flask.redirect("/", code=303)
356
357
358
@app.route("/newrepo/", methods=["GET", "POST"])
359
def new_repo():
360
if not flask.session.get("username"):
361
flask.abort(401)
362
if flask.request.method == "GET":
363
return flask.render_template("new-repo.html")
364
else:
365
name = flask.request.form["name"]
366
visibility = int(flask.request.form["visibility"])
367
368
if not only_chars(name,
369
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
370
flask.flash(Markup(
371
"<iconify-icon icon='mdi:error'></iconify-icon>" + _(
372
"Repository names may only contain Latin alphabet, numbers, '-' and '_'")),
373
category="error")
374
return flask.render_template("new-repo.html")
375
376
user = User.query.filter_by(username=flask.session.get("username")).first()
377
378
repo = Repo(user, name, visibility)
379
db.session.add(repo)
380
db.session.commit()
381
382
flask.flash(Markup(_("Successfully created repository {name}").format(name=name)),
383
category="success")
384
return flask.redirect(repo.route, code=303)
385
386
387
@app.route("/logout")
388
def logout():
389
flask.session.clear()
390
flask.flash(Markup(
391
"<iconify-icon icon='mdi:account'></iconify-icon>" + _("Successfully logged out")),
392
category="info")
393
return flask.redirect("/", code=303)
394
395
396
@app.route("/<username>/", methods=["GET", "POST"])
397
def user_profile(username):
398
old_relationship = UserFollow.query.filter_by(
399
follower_username=flask.session.get("username"),
400
followed_username=username).first()
401
if flask.request.method == "GET":
402
user = User.query.filter_by(username=username).first()
403
match flask.request.args.get("action"):
404
case "repositories":
405
repos = Repo.query.filter_by(owner_name=username, visibility=2)
406
return flask.render_template("user-profile-repositories.html", user=user,
407
repos=repos,
408
relationship=old_relationship)
409
case "followers":
410
return flask.render_template("user-profile-followers.html", user=user,
411
relationship=old_relationship)
412
case "follows":
413
return flask.render_template("user-profile-follows.html", user=user,
414
relationship=old_relationship)
415
case _:
416
return flask.render_template("user-profile-overview.html", user=user,
417
relationship=old_relationship)
418
419
elif flask.request.method == "POST":
420
match flask.request.args.get("action"):
421
case "follow":
422
if username == flask.session.get("username"):
423
flask.abort(403)
424
if old_relationship:
425
db.session.delete(old_relationship)
426
else:
427
relationship = UserFollow(
428
flask.session.get("username"),
429
username
430
)
431
db.session.add(relationship)
432
db.session.commit()
433
434
user = db.session.get(User, username)
435
author = db.session.get(User, flask.session.get("username"))
436
notification = Notification({"type": "update", "version": "0.0.0"})
437
db.session.add(notification)
438
db.session.commit()
439
440
result = celery_tasks.send_notification.delay(notification.id, [username],
441
1)
442
443
db.session.commit()
444
return flask.redirect("?", code=303)
445
446
447
@app.route("/<username>/<repository>/")
448
def repository_index(username, repository):
449
return flask.redirect("./tree", code=302)
450
451
452
@app.route("/info/<username>/avatar")
453
def user_avatar(username):
454
serverUserdataLocation = os.path.join(config.USERDATA_PATH, username)
455
456
if not os.path.exists(serverUserdataLocation):
457
return flask.render_template("not-found.html"), 404
458
459
return flask.send_from_directory(serverUserdataLocation, "avatar.png")
460
461
462
@app.route("/<username>/<repository>/raw/<branch>/<path:subpath>")
463
def repository_raw(username, repository, branch, subpath):
464
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
465
if not os.path.exists(server_repo_location):
466
app.logger.error(f"Cannot load {server_repo_location}")
467
flask.abort(404)
468
if not (get_visibility(username, repository) or get_permission_level(
469
flask.session.get("username"), username,
470
repository) is not None):
471
flask.abort(403)
472
473
app.logger.info(f"Loading {server_repo_location}")
474
475
if not os.path.exists(server_repo_location):
476
app.logger.error(f"Cannot load {server_repo_location}")
477
return flask.render_template("not-found.html"), 404
478
479
repo = git.Repo(server_repo_location)
480
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
481
if not repo_data.default_branch:
482
if repo.heads:
483
repo_data.default_branch = repo.heads[0].name
484
else:
485
return flask.render_template("empty.html",
486
remote=f"http://{config.BASE_DOMAIN}/git/{username}/{repository}"), 200
487
if not branch:
488
branch = repo_data.default_branch
489
return flask.redirect(f"./{branch}", code=302)
490
491
if branch.startswith("tag:"):
492
ref = f"tags/{branch[4:]}"
493
elif branch.startswith("~"):
494
ref = branch[1:]
495
else:
496
ref = f"heads/{branch}"
497
498
ref = ref.replace("~", "/") # encode slashes for URL support
499
500
try:
501
repo.git.checkout("-f", ref)
502
except git.exc.GitCommandError:
503
return flask.render_template("not-found.html"), 404
504
505
return flask.send_from_directory(config.REPOS_PATH,
506
os.path.join(username, repository, subpath))
507
508
509
@repositories.route("/<username>/<repository>/tree/", defaults={"branch": None, "subpath": ""})
510
@repositories.route("/<username>/<repository>/tree/<branch>/", defaults={"subpath": ""})
511
@repositories.route("/<username>/<repository>/tree/<branch>/<path:subpath>")
512
def repository_tree(username, repository, branch, subpath):
513
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
514
if not os.path.exists(server_repo_location):
515
app.logger.error(f"Cannot load {server_repo_location}")
516
flask.abort(404)
517
if not (get_visibility(username, repository) or get_permission_level(
518
flask.session.get("username"), username,
519
repository) is not None):
520
flask.abort(403)
521
522
app.logger.info(f"Loading {server_repo_location}")
523
524
repo = git.Repo(server_repo_location)
525
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
526
if not repo_data.default_branch:
527
if repo.heads:
528
repo_data.default_branch = repo.heads[0].name
529
else:
530
return flask.render_template("empty.html",
531
remote=f"{config.www_protocol}://{config.BASE_DOMAIN}/git/{username}/{repository}"), 200
532
if not branch:
533
branch = repo_data.default_branch
534
return flask.redirect(f"./{branch}", code=302)
535
536
if branch.startswith("tag:"):
537
ref = f"tags/{branch[4:]}"
538
elif branch.startswith("~"):
539
ref = branch[1:]
540
else:
541
ref = f"heads/{branch}"
542
543
ref = ref.replace("~", "/") # encode slashes for URL support
544
545
try:
546
repo.git.checkout("-f", ref)
547
except git.exc.GitCommandError:
548
return flask.render_template("not-found.html"), 404
549
550
branches = repo.heads
551
552
all_refs = []
553
for ref in repo.heads:
554
all_refs.append((ref, "head"))
555
for ref in repo.tags:
556
all_refs.append((ref, "tag"))
557
558
if os.path.isdir(os.path.join(server_repo_location, subpath)):
559
files = []
560
blobs = []
561
562
for entry in os.listdir(os.path.join(server_repo_location, subpath)):
563
if not os.path.basename(entry) == ".git":
564
files.append(os.path.join(subpath, entry))
565
566
infos = []
567
568
for file in files:
569
path = os.path.join(server_repo_location, file)
570
mimetype = guess_mime(path)
571
572
text = git_command(server_repo_location, None, "log", "--format='%H\n'",
573
shlex.quote(file)).decode()
574
575
sha = text.split("\n")[0]
576
identifier = f"/{username}/{repository}/{sha}"
577
578
last_commit = db.session.get(Commit, identifier)
579
580
info = {
581
"name": os.path.basename(file),
582
"serverPath": path,
583
"relativePath": file,
584
"link": os.path.join(f"/{username}/{repository}/tree/{branch}/", file),
585
"size": human_size(os.path.getsize(path)),
586
"mimetype": f"{mimetype}{f' ({mimetypes.guess_type(path)[1]})' if mimetypes.guess_type(path)[1] else ''}",
587
"commit": last_commit,
588
"shaSize": 7,
589
}
590
591
special_icon = config.match_icon(os.path.basename(file))
592
if special_icon:
593
info["icon"] = special_icon
594
elif os.path.isdir(path):
595
info["icon"] = config.folder_icon
596
elif mimetypes.guess_type(path)[0] in config.file_icons:
597
info["icon"] = config.file_icons[mimetypes.guess_type(path)[0]]
598
else:
599
info["icon"] = config.unknown_icon
600
601
if os.path.isdir(path):
602
infos.insert(0, info)
603
else:
604
infos.append(info)
605
606
return flask.render_template(
607
"repo-tree.html",
608
username=username,
609
repository=repository,
610
files=infos,
611
subpath=os.path.join("/", subpath),
612
branches=all_refs,
613
current=branch,
614
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
615
is_favourite=get_favourite(flask.session.get("username"), username, repository)
616
)
617
else:
618
path = os.path.join(server_repo_location, subpath)
619
620
if not os.path.exists(path):
621
return flask.render_template("not-found.html"), 404
622
623
mimetype = guess_mime(path)
624
mode = mimetype.split("/", 1)[0]
625
size = human_size(os.path.getsize(path))
626
627
special_icon = config.match_icon(os.path.basename(path))
628
if special_icon:
629
icon = special_icon
630
elif os.path.isdir(path):
631
icon = config.folder_icon
632
elif mimetypes.guess_type(path)[0] in config.file_icons:
633
icon = config.file_icons[mimetypes.guess_type(path)[0]]
634
else:
635
icon = config.unknown_icon
636
637
contents = None
638
if mode == "text":
639
contents = convert_to_html(path)
640
641
return flask.render_template(
642
"repo-file.html",
643
username=username,
644
repository=repository,
645
file=os.path.join(f"/{username}/{repository}/raw/{branch}/", subpath),
646
branches=all_refs,
647
current=branch,
648
mode=mode,
649
mimetype=mimetype,
650
detailedtype=magic.from_file(path),
651
size=size,
652
icon=icon,
653
subpath=os.path.join("/", subpath),
654
extension=pathlib.Path(path).suffix,
655
basename=os.path.basename(path),
656
contents=contents,
657
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
658
is_favourite=get_favourite(flask.session.get("username"), username, repository)
659
)
660
661
662
@repositories.route("/<username>/<repository>/commit/<sha>")
663
def repository_commit(username, repository, sha):
664
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
665
if not os.path.exists(server_repo_location):
666
app.logger.error(f"Cannot load {server_repo_location}")
667
flask.abort(404)
668
if not (get_visibility(username, repository) or get_permission_level(
669
flask.session.get("username"), username,
670
repository) is not None):
671
flask.abort(403)
672
673
app.logger.info(f"Loading {server_repo_location}")
674
675
if not os.path.exists(server_repo_location):
676
app.logger.error(f"Cannot load {server_repo_location}")
677
return flask.render_template("not-found.html"), 404
678
679
repo = git.Repo(server_repo_location)
680
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
681
682
files = git_command(os.path.join(server_repo_location, ".git"), None, "diff-tree", "-r",
683
"--name-only", "--no-commit-id", sha).decode().split("\n")[:-1]
684
685
print(files)
686
687
return flask.render_template(
688
"repo-commit.html",
689
username=username,
690
repository=repository,
691
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
692
is_favourite=get_favourite(flask.session.get("username"), username, repository),
693
diff={file: git_command(os.path.join(server_repo_location, ".git"), None, "diff",
694
str(sha) + "^!", "--", file).decode().split("\n") for
695
file in files},
696
data=db.session.get(Commit, f"/{username}/{repository}/{sha}"),
697
)
698
699
700
@repositories.route("/<username>/<repository>/forum/")
701
def repository_forum(username, repository):
702
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
703
if not os.path.exists(server_repo_location):
704
app.logger.error(f"Cannot load {server_repo_location}")
705
flask.abort(404)
706
if not (get_visibility(username, repository) or get_permission_level(
707
flask.session.get("username"), username,
708
repository) is not None):
709
flask.abort(403)
710
711
app.logger.info(f"Loading {server_repo_location}")
712
713
if not os.path.exists(server_repo_location):
714
app.logger.error(f"Cannot load {server_repo_location}")
715
return flask.render_template("not-found.html"), 404
716
717
repo = git.Repo(server_repo_location)
718
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
719
user = User.query.filter_by(username=flask.session.get("username")).first()
720
relationships = RepoAccess.query.filter_by(repo=repo_data)
721
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
722
723
return flask.render_template(
724
"repo-forum.html",
725
username=username,
726
repository=repository,
727
repo_data=repo_data,
728
relationships=relationships,
729
repo=repo,
730
user_relationship=user_relationship,
731
Post=Post,
732
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
733
is_favourite=get_favourite(flask.session.get("username"), username, repository),
734
default_branch=repo_data.default_branch
735
)
736
737
738
@repositories.route("/<username>/<repository>/forum/topic/<int:id>")
739
def repository_forum_topic(username, repository, id):
740
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
741
if not os.path.exists(server_repo_location):
742
app.logger.error(f"Cannot load {server_repo_location}")
743
flask.abort(404)
744
if not (get_visibility(username, repository) or get_permission_level(
745
flask.session.get("username"), username,
746
repository) is not None):
747
flask.abort(403)
748
749
app.logger.info(f"Loading {server_repo_location}")
750
751
if not os.path.exists(server_repo_location):
752
app.logger.error(f"Cannot load {server_repo_location}")
753
return flask.render_template("not-found.html"), 404
754
755
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
756
user = User.query.filter_by(username=flask.session.get("username")).first()
757
relationships = RepoAccess.query.filter_by(repo=repo_data)
758
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
759
760
post = Post.query.filter_by(id=id).first()
761
762
return flask.render_template(
763
"repo-topic.html",
764
username=username,
765
repository=repository,
766
repo_data=repo_data,
767
relationships=relationships,
768
user_relationship=user_relationship,
769
post=post,
770
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
771
is_favourite=get_favourite(flask.session.get("username"), username, repository),
772
default_branch=repo_data.default_branch
773
)
774
775
776
@repositories.route("/<username>/<repository>/forum/new", methods=["POST", "GET"])
777
def repository_forum_new(username, repository):
778
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
779
if not os.path.exists(server_repo_location):
780
app.logger.error(f"Cannot load {server_repo_location}")
781
flask.abort(404)
782
if not (get_visibility(username, repository) or get_permission_level(
783
flask.session.get("username"), username,
784
repository) is not None):
785
flask.abort(403)
786
787
app.logger.info(f"Loading {server_repo_location}")
788
789
if not os.path.exists(server_repo_location):
790
app.logger.error(f"Cannot load {server_repo_location}")
791
return flask.render_template("not-found.html"), 404
792
793
repo = git.Repo(server_repo_location)
794
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
795
user = User.query.filter_by(username=flask.session.get("username")).first()
796
relationships = RepoAccess.query.filter_by(repo=repo_data)
797
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
798
799
post = Post(user, repo_data, None, flask.request.form["subject"],
800
flask.request.form["message"])
801
802
db.session.add(post)
803
db.session.commit()
804
805
return flask.redirect(
806
flask.url_for(".repository_forum_thread", username=username, repository=repository,
807
post_id=post.number),
808
code=303)
809
810
811
@repositories.route("/<username>/<repository>/forum/<int:post_id>")
812
def repository_forum_thread(username, repository, post_id):
813
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
814
if not os.path.exists(server_repo_location):
815
app.logger.error(f"Cannot load {server_repo_location}")
816
flask.abort(404)
817
if not (get_visibility(username, repository) or get_permission_level(
818
flask.session.get("username"), username,
819
repository) is not None):
820
flask.abort(403)
821
822
app.logger.info(f"Loading {server_repo_location}")
823
824
if not os.path.exists(server_repo_location):
825
app.logger.error(f"Cannot load {server_repo_location}")
826
return flask.render_template("not-found.html"), 404
827
828
repo = git.Repo(server_repo_location)
829
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
830
user = User.query.filter_by(username=flask.session.get("username")).first()
831
relationships = RepoAccess.query.filter_by(repo=repo_data)
832
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
833
834
return flask.render_template(
835
"repo-forum-thread.html",
836
username=username,
837
repository=repository,
838
repo_data=repo_data,
839
relationships=relationships,
840
repo=repo,
841
Post=Post,
842
user_relationship=user_relationship,
843
post_id=post_id,
844
max_post_nesting=4,
845
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
846
is_favourite=get_favourite(flask.session.get("username"), username, repository),
847
parent=Post.query.filter_by(repo=repo_data, number=post_id).first(),
848
)
849
850
851
@repositories.route("/<username>/<repository>/forum/<int:post_id>/change-state", methods=["POST"])
852
def repository_forum_change_state(username, repository, post_id):
853
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
854
if not os.path.exists(server_repo_location):
855
app.logger.error(f"Cannot load {server_repo_location}")
856
flask.abort(404)
857
if not (get_visibility(username, repository) or get_permission_level(
858
flask.session.get("username"), username,
859
repository) is not None):
860
flask.abort(403)
861
862
app.logger.info(f"Loading {server_repo_location}")
863
864
repo = git.Repo(server_repo_location)
865
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
866
user = User.query.filter_by(username=flask.session.get("username")).first()
867
relationships = RepoAccess.query.filter_by(repo=repo_data)
868
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
869
870
post = Post.query.filter_by(identifier=f"/{username}/{repository}/{post_id}").first()
871
872
if not post:
873
flask.abort(404)
874
875
post.state = int(flask.request.form["new-state"])
876
877
db.session.commit()
878
879
return flask.redirect(
880
flask.url_for(".repository_forum_thread", username=username, repository=repository,
881
post_id=post_id),
882
code=303)
883
884
885
@repositories.route("/<username>/<repository>/forum/<int:post_id>/reply", methods=["POST"])
886
def repository_forum_reply(username, repository, post_id):
887
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
888
if not os.path.exists(server_repo_location):
889
app.logger.error(f"Cannot load {server_repo_location}")
890
flask.abort(404)
891
if not (get_visibility(username, repository) or get_permission_level(
892
flask.session.get("username"), username,
893
repository) is not None):
894
flask.abort(403)
895
896
app.logger.info(f"Loading {server_repo_location}")
897
898
if not os.path.exists(server_repo_location):
899
app.logger.error(f"Cannot load {server_repo_location}")
900
return flask.render_template("not-found.html"), 404
901
902
repo = git.Repo(server_repo_location)
903
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
904
user = User.query.filter_by(username=flask.session.get("username")).first()
905
relationships = RepoAccess.query.filter_by(repo=repo_data)
906
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
907
if not user:
908
flask.abort(401)
909
910
parent = Post.query.filter_by(identifier=f"/{username}/{repository}/{post_id}").first()
911
post = Post(user, repo_data, parent, flask.request.form["subject"],
912
flask.request.form["message"])
913
914
db.session.add(post)
915
post.update_date()
916
db.session.commit()
917
918
return flask.redirect(
919
flask.url_for(".repository_forum_thread", username=username, repository=repository,
920
post_id=post_id),
921
code=303)
922
923
924
@repositories.route("/<username>/<repository>/forum/<int:post_id>/voteup",
925
defaults={"score": 1})
926
@repositories.route("/<username>/<repository>/forum/<int:post_id>/votedown",
927
defaults={"score": -1})
928
@repositories.route("/<username>/<repository>/forum/<int:post_id>/votes", defaults={"score": 0})
929
def repository_forum_vote(username, repository, post_id, score):
930
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
931
if not os.path.exists(server_repo_location):
932
app.logger.error(f"Cannot load {server_repo_location}")
933
flask.abort(404)
934
if not (get_visibility(username, repository) or get_permission_level(
935
flask.session.get("username"), username,
936
repository) is not None):
937
flask.abort(403)
938
939
app.logger.info(f"Loading {server_repo_location}")
940
941
if not os.path.exists(server_repo_location):
942
app.logger.error(f"Cannot load {server_repo_location}")
943
return flask.render_template("not-found.html"), 404
944
945
repo = git.Repo(server_repo_location)
946
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
947
user = User.query.filter_by(username=flask.session.get("username")).first()
948
relationships = RepoAccess.query.filter_by(repo=repo_data)
949
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
950
if not user:
951
flask.abort(401)
952
953
post = Post.query.filter_by(identifier=f"/{username}/{repository}/{post_id}").first()
954
955
if score:
956
old_relationship = PostVote.query.filter_by(user_username=user.username,
957
post_identifier=post.identifier).first()
958
if old_relationship:
959
if score == old_relationship.vote_score:
960
db.session.delete(old_relationship)
961
post.vote_sum -= old_relationship.vote_score
962
else:
963
post.vote_sum -= old_relationship.vote_score
964
post.vote_sum += score
965
old_relationship.vote_score = score
966
else:
967
relationship = PostVote(user, post, score)
968
post.vote_sum += score
969
db.session.add(relationship)
970
971
db.session.commit()
972
973
user_vote = PostVote.query.filter_by(user_username=user.username,
974
post_identifier=post.identifier).first()
975
response = flask.make_response(
976
str(post.vote_sum) + " " + str(user_vote.vote_score if user_vote else 0))
977
response.content_type = "text/plain"
978
979
return response
980
981
982
@repositories.route("/<username>/<repository>/favourite")
983
def repository_favourite(username, repository):
984
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
985
if not os.path.exists(server_repo_location):
986
app.logger.error(f"Cannot load {server_repo_location}")
987
flask.abort(404)
988
if not (get_visibility(username, repository) or get_permission_level(
989
flask.session.get("username"), username,
990
repository) is not None):
991
flask.abort(403)
992
993
app.logger.info(f"Loading {server_repo_location}")
994
995
if not os.path.exists(server_repo_location):
996
app.logger.error(f"Cannot load {server_repo_location}")
997
return flask.render_template("not-found.html"), 404
998
999
repo = git.Repo(server_repo_location)
1000
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1001
user = User.query.filter_by(username=flask.session.get("username")).first()
1002
relationships = RepoAccess.query.filter_by(repo=repo_data)
1003
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
1004
if not user:
1005
flask.abort(401)
1006
1007
old_relationship = RepoFavourite.query.filter_by(user_username=user.username,
1008
repo_route=repo_data.route).first()
1009
if old_relationship:
1010
db.session.delete(old_relationship)
1011
else:
1012
relationship = RepoFavourite(user, repo_data)
1013
db.session.add(relationship)
1014
1015
db.session.commit()
1016
1017
return flask.redirect(flask.url_for("favourites"), code=303)
1018
1019
1020
@repositories.route("/<username>/<repository>/users/", methods=["GET", "POST"])
1021
def repository_users(username, repository):
1022
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1023
if not os.path.exists(server_repo_location):
1024
app.logger.error(f"Cannot load {server_repo_location}")
1025
flask.abort(404)
1026
if not (get_visibility(username, repository) or get_permission_level(
1027
flask.session.get("username"), username,
1028
repository) is not None):
1029
flask.abort(403)
1030
1031
app.logger.info(f"Loading {server_repo_location}")
1032
1033
if not os.path.exists(server_repo_location):
1034
app.logger.error(f"Cannot load {server_repo_location}")
1035
return flask.render_template("not-found.html"), 404
1036
1037
repo = git.Repo(server_repo_location)
1038
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1039
user = User.query.filter_by(username=flask.session.get("username")).first()
1040
relationships = RepoAccess.query.filter_by(repo=repo_data)
1041
user_relationship = RepoAccess.query.filter_by(repo=repo_data, user=user).first()
1042
1043
if flask.request.method == "GET":
1044
return flask.render_template(
1045
"repo-users.html",
1046
username=username,
1047
repository=repository,
1048
repo_data=repo_data,
1049
relationships=relationships,
1050
repo=repo,
1051
user_relationship=user_relationship,
1052
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
1053
is_favourite=get_favourite(flask.session.get("username"), username, repository)
1054
)
1055
else:
1056
if get_permission_level(flask.session.get("username"), username, repository) != 2:
1057
flask.abort(401)
1058
1059
if flask.request.form.get("new-username"):
1060
# Create new relationship
1061
new_user = User.query.filter_by(
1062
username=flask.request.form.get("new-username")).first()
1063
relationship = RepoAccess(new_user, repo_data, flask.request.form.get("new-level"))
1064
db.session.add(relationship)
1065
db.session.commit()
1066
if flask.request.form.get("update-username"):
1067
# Create new relationship
1068
updated_user = User.query.filter_by(
1069
username=flask.request.form.get("update-username")).first()
1070
relationship = RepoAccess.query.filter_by(repo=repo_data, user=updated_user).first()
1071
if flask.request.form.get("update-level") == -1:
1072
relationship.delete()
1073
else:
1074
relationship.access_level = flask.request.form.get("update-level")
1075
db.session.commit()
1076
1077
return flask.redirect(
1078
app.url_for(".repository_users", username=username, repository=repository))
1079
1080
1081
@repositories.route("/<username>/<repository>/branches/")
1082
def repository_branches(username, repository):
1083
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1084
if not os.path.exists(server_repo_location):
1085
app.logger.error(f"Cannot load {server_repo_location}")
1086
flask.abort(404)
1087
if not (get_visibility(username, repository) or get_permission_level(
1088
flask.session.get("username"), username,
1089
repository) is not None):
1090
flask.abort(403)
1091
1092
app.logger.info(f"Loading {server_repo_location}")
1093
1094
if not os.path.exists(server_repo_location):
1095
app.logger.error(f"Cannot load {server_repo_location}")
1096
return flask.render_template("not-found.html"), 404
1097
1098
repo = git.Repo(server_repo_location)
1099
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1100
1101
return flask.render_template(
1102
"repo-branches.html",
1103
username=username,
1104
repository=repository,
1105
repo_data=repo_data,
1106
repo=repo,
1107
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
1108
is_favourite=get_favourite(flask.session.get("username"), username, repository)
1109
)
1110
1111
1112
@repositories.route("/<username>/<repository>/log/", defaults={"branch": None})
1113
@repositories.route("/<username>/<repository>/log/<branch>/")
1114
def repository_log(username, repository, branch):
1115
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1116
if not os.path.exists(server_repo_location):
1117
app.logger.error(f"Cannot load {server_repo_location}")
1118
flask.abort(404)
1119
if not (get_visibility(username, repository) or get_permission_level(
1120
flask.session.get("username"), username,
1121
repository) is not None):
1122
flask.abort(403)
1123
1124
app.logger.info(f"Loading {server_repo_location}")
1125
1126
if not os.path.exists(server_repo_location):
1127
app.logger.error(f"Cannot load {server_repo_location}")
1128
return flask.render_template("not-found.html"), 404
1129
1130
repo = git.Repo(server_repo_location)
1131
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1132
if not repo_data.default_branch:
1133
if repo.heads:
1134
repo_data.default_branch = repo.heads[0].name
1135
else:
1136
return flask.render_template("empty.html",
1137
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}"), 200
1138
if not branch:
1139
branch = repo_data.default_branch
1140
return flask.redirect(f"./{branch}", code=302)
1141
1142
if branch.startswith("tag:"):
1143
ref = f"tags/{branch[4:]}"
1144
elif branch.startswith("~"):
1145
ref = branch[1:]
1146
else:
1147
ref = f"heads/{branch}"
1148
1149
ref = ref.replace("~", "/") # encode slashes for URL support
1150
1151
try:
1152
repo.git.checkout("-f", ref)
1153
except git.exc.GitCommandError:
1154
return flask.render_template("not-found.html"), 404
1155
1156
branches = repo.heads
1157
1158
all_refs = []
1159
for ref in repo.heads:
1160
all_refs.append((ref, "head"))
1161
for ref in repo.tags:
1162
all_refs.append((ref, "tag"))
1163
1164
commit_list = [f"/{username}/{repository}/{sha}" for sha in
1165
git_command(server_repo_location, None, "log",
1166
"--format='%H'").decode().split("\n")]
1167
1168
commits = Commit.query.filter(Commit.identifier.in_(commit_list))
1169
1170
return flask.render_template(
1171
"repo-log.html",
1172
username=username,
1173
repository=repository,
1174
branches=all_refs,
1175
current=branch,
1176
repo_data=repo_data,
1177
repo=repo,
1178
commits=commits,
1179
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
1180
is_favourite=get_favourite(flask.session.get("username"), username, repository)
1181
)
1182
1183
1184
@repositories.route("/<username>/<repository>/prs/", methods=["GET", "POST"])
1185
def repository_prs(username, repository):
1186
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1187
if not os.path.exists(server_repo_location):
1188
app.logger.error(f"Cannot load {server_repo_location}")
1189
flask.abort(404)
1190
if not (get_visibility(username, repository) or get_permission_level(
1191
flask.session.get("username"), username,
1192
repository) is not None):
1193
flask.abort(403)
1194
1195
app.logger.info(f"Loading {server_repo_location}")
1196
1197
if not os.path.exists(server_repo_location):
1198
app.logger.error(f"Cannot load {server_repo_location}")
1199
return flask.render_template("not-found.html"), 404
1200
1201
if flask.request.method == "GET":
1202
repo = git.Repo(server_repo_location)
1203
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1204
user = User.query.filter_by(username=flask.session.get("username")).first()
1205
1206
return flask.render_template(
1207
"repo-prs.html",
1208
username=username,
1209
repository=repository,
1210
repo_data=repo_data,
1211
repo=repo,
1212
PullRequest=PullRequest,
1213
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
1214
is_favourite=get_favourite(flask.session.get("username"), username, repository),
1215
default_branch=repo_data.default_branch,
1216
branches=repo.branches
1217
)
1218
1219
else:
1220
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1221
head = flask.request.form.get("head")
1222
head_route = flask.request.form.get("headroute")
1223
base = flask.request.form.get("base")
1224
1225
if not head and base and head_route:
1226
return flask.redirect(".", 400)
1227
1228
head_repo = git.Repo(os.path.join(config.REPOS_PATH, head_route.lstrip("/")))
1229
base_repo = git.Repo(server_repo_location)
1230
print(head_repo)
1231
1232
if head not in head_repo.branches or base not in base_repo.branches:
1233
flask.flash(Markup(
1234
"<iconify-icon icon='mdi:error'></iconify-icon>" + _("Bad branch name")),
1235
category="error")
1236
return flask.redirect(".", 303)
1237
1238
head_data = db.session.get(Repo, head_route)
1239
if not head_data.visibility:
1240
flask.flash(Markup(
1241
"<iconify-icon icon='mdi:error'></iconify-icon>" + _(
1242
"Head can't be restricted")),
1243
category="error")
1244
return flask.redirect(".", 303)
1245
1246
pull_request = PullRequest(repo_data, head, head_data, base,
1247
db.session.get(User, flask.session["username"]))
1248
1249
db.session.add(pull_request)
1250
db.session.commit()
1251
1252
return flask.redirect(".", 303)
1253
1254
1255
@repositories.route("/<username>/<repository>/prs/merge", methods=["POST"])
1256
def repository_prs_merge(username, repository):
1257
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1258
if not os.path.exists(server_repo_location):
1259
app.logger.error(f"Cannot load {server_repo_location}")
1260
flask.abort(404)
1261
if not (get_visibility(username, repository) or get_permission_level(
1262
flask.session.get("username"), username,
1263
repository) is not None):
1264
flask.abort(403)
1265
1266
if not get_permission_level(flask.session.get("username"), username, repository):
1267
flask.abort(401)
1268
1269
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1270
repo = git.Repo(server_repo_location)
1271
id = flask.request.form.get("id")
1272
1273
pull_request = db.session.get(PullRequest, id)
1274
1275
if pull_request:
1276
result = celery_tasks.merge_heads.delay(
1277
pull_request.head_route,
1278
pull_request.head_branch,
1279
pull_request.base_route,
1280
pull_request.base_branch,
1281
simulate=True
1282
)
1283
task_result = worker.AsyncResult(result.id)
1284
1285
return flask.redirect(f"/task/{result.id}?pr-id={id}", 303)
1286
# db.session.delete(pull_request)
1287
# db.session.commit()
1288
else:
1289
flask.abort(400)
1290
1291
1292
@repositories.route("/<username>/<repository>/prs/<int:id>/merge")
1293
def repository_prs_merge_stage_two(username, repository, id):
1294
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1295
if not os.path.exists(server_repo_location):
1296
app.logger.error(f"Cannot load {server_repo_location}")
1297
flask.abort(404)
1298
if not (get_visibility(username, repository) or get_permission_level(
1299
flask.session.get("username"), username,
1300
repository) is not None):
1301
flask.abort(403)
1302
1303
if not get_permission_level(flask.session.get("username"), username, repository):
1304
flask.abort(401)
1305
1306
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1307
repo = git.Repo(server_repo_location)
1308
1309
pull_request = db.session.get(PullRequest, id)
1310
1311
if pull_request:
1312
result = celery_tasks.merge_heads.delay(
1313
pull_request.head_route,
1314
pull_request.head_branch,
1315
pull_request.base_route,
1316
pull_request.base_branch,
1317
simulate=False
1318
)
1319
task_result = worker.AsyncResult(result.id)
1320
1321
pull_request.state = 1
1322
db.session.commit()
1323
1324
return flask.redirect(f"/task/{result.id}?pr-id={id}", 303)
1325
# db.session.delete(pull_request)
1326
else:
1327
flask.abort(400)
1328
1329
1330
@app.route("/task/<task_id>")
1331
def task_monitor(task_id):
1332
task_result = worker.AsyncResult(task_id)
1333
print(task_result.status)
1334
1335
return flask.render_template("task-monitor.html", result=task_result)
1336
1337
1338
@repositories.route("/<username>/<repository>/prs/delete", methods=["POST"])
1339
def repository_prs_delete(username, repository):
1340
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
1341
if not os.path.exists(server_repo_location):
1342
app.logger.error(f"Cannot load {server_repo_location}")
1343
flask.abort(404)
1344
if not (get_visibility(username, repository) or get_permission_level(
1345
flask.session.get("username"), username,
1346
repository) is not None):
1347
flask.abort(403)
1348
1349
if not get_permission_level(flask.session.get("username"), username, repository):
1350
flask.abort(401)
1351
1352
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
1353
repo = git.Repo(server_repo_location)
1354
id = flask.request.form.get("id")
1355
1356
pull_request = db.session.get(PullRequest, id)
1357
1358
if pull_request:
1359
pull_request.state = 2
1360
db.session.commit()
1361
1362
return flask.redirect(".", 303)
1363
1364
1365
@repositories.route("/<username>/<repository>/settings/")
1366
def repository_settings(username, repository):
1367
if get_permission_level(flask.session.get("username"), username, repository) != 2:
1368
flask.abort(401)
1369
1370
return flask.render_template("repo-settings.html", username=username, repository=repository)
1371
1372
1373
@app.errorhandler(404)
1374
def e404(error):
1375
return flask.render_template("not-found.html"), 404
1376
1377
1378
@app.errorhandler(401)
1379
def e401(error):
1380
return flask.render_template("unauthorised.html"), 401
1381
1382
1383
@app.errorhandler(403)
1384
def e403(error):
1385
return flask.render_template("forbidden.html"), 403
1386
1387
1388
@app.errorhandler(418)
1389
def e418(error):
1390
return flask.render_template("teapot.html"), 418
1391
1392
1393
@app.errorhandler(405)
1394
def e405(error):
1395
return flask.render_template("method-not-allowed.html"), 405
1396
1397
1398
if __name__ == "__main__":
1399
app.run(debug=True, port=8080, host="0.0.0.0")
1400
1401
app.register_blueprint(repositories)