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