Stability improvements for pushing
Allow higher payload
Fix receiving multiple commits
Begin work on commit details/diff page
By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.
Allow higher payload
Fix receiving multiple commits
Begin work on commit details/diff page
roundabout,
created on Saturday, 23 March 2024, 12:03:24 (1711195404),
received on Wednesday, 31 July 2024, 06:54:42 (1722408882)
Author identity: vlad <vlad.muntoiu@gmail.com>
a17bef1eb7b9db27553507cb05f15af1799276fd
import flask
import cairosvg
import celery
import shlex
from functools import wraps
from datetime import datetime
from enum import Enum
app.config["SQLALCHEMY_DATABASE_URI"] = config.DB_URI
app.config["SECRET_KEY"] = config.DB_PASSWORD
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['BABEL_TRANSLATION_DIRECTORIES'] = "i18n"
app.config["BABEL_TRANSLATION_DIRECTORIES"] = "i18n"
app.config["MAX_CONTENT_LENGTH"] = config.MAX_PAYLOAD_SIZE
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
from celery import Celery, Task
import celery_integration
babel = Babel(app)
babel.init_app(app, locale_selector=get_locale)
with app.app_context():
locale_names = {}
for language in config.available_locales:
# NOTE: Translate this to the language's name in that language, for example in French you would use français
locale_names[language] = gettext("English")
worker = celery_integration.init_celery_app(app)
repositories = flask.Blueprint("repository", __name__, template_folder="templates/repository/")
@app.route("/language", methods=["POST"])
def set_locale():
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/", code=303)
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/",
code=303)
if not flask.request.form.get("language"):
response.delete_cookie("language")
else:
@app.route("/cookie-dismiss")
def dismiss_banner():
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/", code=303)
response = flask.redirect(flask.request.referrer if flask.request.referrer else "/",
code=303)
response.set_cookie("cookie-banner", "1")
return response
user.URL = flask.request.form["url"]
user.company = flask.request.form["company"]
user.company_URL = flask.request.form["companyurl"]
user.email = flask.request.form.get("email") if flask.request.form.get("email") else None
user.email = flask.request.form.get("email") if flask.request.form.get(
"email") else None
user.location = flask.request.form["location"]
user.show_mail = True if flask.request.form.get("showmail") else False
user.bio = flask.request.form.get("bio")
db.session.commit()
flask.flash(Markup("<iconify-icon icon='mdi:check'></iconify-icon>" + _("Settings saved")), category="success")
flask.flash(
Markup("<iconify-icon icon='mdi:check'></iconify-icon>" + _("Settings saved")),
category="success")
return flask.redirect(f"/{flask.session.get('username')}", code=303)
if not flask.session.get("username"):
flask.abort(401)
if flask.request.method == "GET":
relationships = RepoFavourite.query.filter_by(user_username=flask.session.get("username"))
relationships = RepoFavourite.query.filter_by(
user_username=flask.session.get("username"))
return flask.render_template("favourites.html", favourites=relationships)
if not flask.session.get("username"):
flask.abort(401)
if flask.request.method == "GET":
return flask.render_template("notifications.html", notifications=UserNotification.query.filter_by(
user_username=flask.session.get("username")))
return flask.render_template("notifications.html",
notifications=UserNotification.query.filter_by(
user_username=flask.session.get("username")))
@app.route("/accounts/", methods=["GET", "POST"])
if user and bcrypt.check_password_hash(user.password_hashed, password):
flask.session["username"] = user.username
flask.flash(
Markup("<iconify-icon icon='mdi:account'></iconify-icon>" + _("Successfully logged in as {username}").format(username=username)),
Markup("<iconify-icon icon='mdi:account'></iconify-icon>" + _(
"Successfully logged in as {username}").format(username=username)),
category="success")
return flask.redirect("/", code=303)
elif not user:
flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>" + _("User not found")),
flask.flash(Markup(
"<iconify-icon icon='mdi:account-question'></iconify-icon>" + _(
"User not found")),
category="alert")
return flask.render_template("login.html")
else:
flask.flash(Markup("<iconify-icon icon='mdi:account-question'></iconify-icon>" + _("Invalid password")),
flask.flash(Markup(
"<iconify-icon icon='mdi:account-question'></iconify-icon>" + _(
"Invalid password")),
category="error")
return flask.render_template("login.html")
if "signup" in flask.request.form:
email2 = flask.request.form.get("email2") # repeat email is a honeypot
name = flask.request.form.get("name")
if not only_chars(username, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
if not only_chars(username,
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
flask.flash(Markup(
_("Usernames may only contain Latin alphabet, numbers, '-' and '_'")),
category="error")
if username in config.RESERVED_NAMES:
flask.flash(
Markup(
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _("Sorry, {username} is a system path").format(username=username)),
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _(
"Sorry, {username} is a system path").format(
username=username)),
category="error")
return flask.render_template("login.html")
if user_check:
flask.flash(
Markup(
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _("The username {username} is taken").format(username=username)),
"<iconify-icon icon='mdi:account-error'></iconify-icon>" + _(
"The username {username} is taken").format(
username=username)),
category="error")
return flask.render_template("login.html")
if password2 != password:
flask.flash(Markup("<iconify-icon icon='mdi:key-alert'></iconify-icon>" + _("Make sure the passwords match")),
flask.flash(Markup("<iconify-icon icon='mdi:key-alert'></iconify-icon>" + _(
"Make sure the passwords match")),
category="error")
return flask.render_template("login.html")
db.session.commit()
flask.session["username"] = user.username
flask.flash(Markup(
"<iconify-icon icon='mdi:account'></iconify-icon>" + _("Successfully created and logged in as {username}").format(username=username)),
"<iconify-icon icon='mdi:account'></iconify-icon>" + _(
"Successfully created and logged in as {username}").format(
username=username)),
category="success")
notification = Notification({"type": "welcome"})
name = flask.request.form["name"]
visibility = int(flask.request.form["visibility"])
if not only_chars(name, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
if not only_chars(name,
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"):
flask.flash(Markup(
"<iconify-icon icon='mdi:error'></iconify-icon>" + _("Repository names may only contain Latin alphabet, numbers, '-' and '_'")),
"<iconify-icon icon='mdi:error'></iconify-icon>" + _(
"Repository names may only contain Latin alphabet, numbers, '-' and '_'")),
category="error")
return flask.render_template("new-repo.html")
@app.route("/logout")
def logout():
flask.session.clear()
flask.flash(Markup("<iconify-icon icon='mdi:account'></iconify-icon>" + _("Successfully logged out")), category="info")
flask.flash(Markup(
"<iconify-icon icon='mdi:account'></iconify-icon>" + _("Successfully logged out")),
category="info")
return flask.redirect("/", code=303)
@app.route("/<username>/", methods=["GET", "POST"])
def user_profile(username):
old_relationship = UserFollow.query.filter_by(follower_username=flask.session.get("username"),
followed_username=username).first()
old_relationship = UserFollow.query.filter_by(
follower_username=flask.session.get("username"),
followed_username=username).first()
if flask.request.method == "GET":
user = User.query.filter_by(username=username).first()
match flask.request.args.get("action"):
case "repositories":
repos = Repo.query.filter_by(owner_name=username, visibility=2)
return flask.render_template("user-profile-repositories.html", user=user, repos=repos,
return flask.render_template("user-profile-repositories.html", user=user,
repos=repos,
relationship=old_relationship)
case "followers":
return flask.render_template("user-profile-followers.html", user=user, relationship=old_relationship)
return flask.render_template("user-profile-followers.html", user=user,
relationship=old_relationship)
case "follows":
return flask.render_template("user-profile-follows.html", user=user, relationship=old_relationship)
return flask.render_template("user-profile-follows.html", user=user,
relationship=old_relationship)
case _:
return flask.render_template("user-profile-overview.html", user=user, relationship=old_relationship)
return flask.render_template("user-profile-overview.html", user=user,
relationship=old_relationship)
elif flask.request.method == "POST":
match flask.request.args.get("action"):
db.session.add(notification)
db.session.commit()
result = celery_tasks.send_notification.delay(notification.id, [username], 1)
result = celery_tasks.send_notification.delay(notification.id, [username],
1)
db.session.commit()
return flask.redirect("?", code=303)
@app.route("/<username>/<repository>/raw/<branch>/<path:subpath>")
def repository_raw(username, repository, branch, subpath):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository)
except git.exc.GitCommandError:
return flask.render_template("not-found.html"), 404
return flask.send_from_directory(config.REPOS_PATH, os.path.join(username, repository, subpath))
return flask.send_from_directory(config.REPOS_PATH,
os.path.join(username, repository, subpath))
@repositories.route("/<username>/<repository>/tree/", defaults={"branch": None, "subpath": ""})
@repositories.route("/<username>/<repository>/tree/<branch>/", defaults={"subpath": ""})
@repositories.route("/<username>/<repository>/tree/<branch>/<path:subpath>")
def repository_tree(username, repository, branch, subpath):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
path = os.path.join(server_repo_location, file)
mimetype = guess_mime(path)
text = git_command(server_repo_location, None, "log", "--format='%H\n'", file).decode()
text = git_command(server_repo_location, None, "log", "--format='%H\n'",
shlex.quote(file)).decode()
sha = text.split("\n")[0]
identifier = f"/{username}/{repository}/{sha}"
last_commit = Commit.query.filter_by(identifier=identifier).first()
last_commit = db.session.get(Commit, identifier)
info = {
"name": os.path.basename(file),
)
@repositories.route("/<username>/<repository>/commit/<sha>")
def repository_commit(username, repository, sha):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
app.logger.info(f"Loading {server_repo_location}")
if not os.path.exists(server_repo_location):
app.logger.error(f"Cannot load {server_repo_location}")
return flask.render_template("not-found.html"), 404
repo = git.Repo(server_repo_location)
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
files = git_command(os.path.join(server_repo_location, ".git"), None, "diff-tree", "-r",
"--name-only", "--no-commit-id", sha).decode().split("\n")
return flask.render_template(
"repo-commit.html",
username=username,
repository=repository,
remote=f"http{'s' if config.suggest_https else ''}://{config.BASE_DOMAIN}/git/{username}/{repository}",
is_favourite=get_favourite(flask.session.get("username"), username, repository),
diff={file: git_command(os.path.join(server_repo_location, ".git"), None, "diff",
str(sha), str(sha) + "^", file).decode().split("\n") for
file in files}
)
@repositories.route("/<username>/<repository>/forum/")
def repository_forum(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
@repositories.route("/<username>/<repository>/forum/topic/<int:id>")
def repository_forum_topic(username, repository, id):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
@repositories.route("/<username>/<repository>/forum/new", methods=["POST", "GET"])
def repository_forum_new(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository)
relationships = RepoAccess.query.filter_by(repo=repoData)
userRelationship = RepoAccess.query.filter_by(repo=repoData, user=user).first()
post = Post(user, repoData, None, flask.request.form["subject"], flask.request.form["message"])
post = Post(user, repoData, None, flask.request.form["subject"],
flask.request.form["message"])
db.session.add(post)
db.session.commit()
return flask.redirect(
flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post.number),
flask.url_for(".repository_forum_thread", username=username, repository=repository,
post_id=post.number),
code=303)
@repositories.route("/<username>/<repository>/forum/<int:post_id>")
def repository_forum_thread(username, repository, post_id):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
@repositories.route("/<username>/<repository>/forum/<int:post_id>/reply", methods=["POST"])
def repository_forum_reply(username, repository, post_id):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
flask.abort(401)
parent = Post.query.filter_by(identifier=f"/{username}/{repository}/{post_id}").first()
post = Post(user, repo_data, parent, flask.request.form["subject"], flask.request.form["message"])
post = Post(user, repo_data, parent, flask.request.form["subject"],
flask.request.form["message"])
db.session.add(post)
post.update_date()
db.session.commit()
return flask.redirect(
flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post_id),
flask.url_for(".repository_forum_thread", username=username, repository=repository,
post_id=post_id),
code=303)
@repositories.route("/<username>/<repository>/forum/<int:post_id>/voteup", defaults={"score": 1})
@repositories.route("/<username>/<repository>/forum/<int:post_id>/votedown", defaults={"score": -1})
@repositories.route("/<username>/<repository>/forum/<int:post_id>/voteup",
defaults={"score": 1})
@repositories.route("/<username>/<repository>/forum/<int:post_id>/votedown",
defaults={"score": -1})
@repositories.route("/<username>/<repository>/forum/<int:post_id>/votes", defaults={"score": 0})
def repository_forum_vote(username, repository, post_id, score):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
db.session.commit()
user_vote = PostVote.query.filter_by(user_username=user.username, post_identifier=post.identifier).first()
response = flask.make_response(str(post.vote_sum) + " " + str(user_vote.vote_score if user_vote else 0))
user_vote = PostVote.query.filter_by(user_username=user.username,
post_identifier=post.identifier).first()
response = flask.make_response(
str(post.vote_sum) + " " + str(user_vote.vote_score if user_vote else 0))
response.content_type = "text/plain"
return response
@repositories.route("/<username>/<repository>/favourite")
def repository_favourite(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
if not user:
flask.abort(401)
old_relationship = RepoFavourite.query.filter_by(user_username=user.username, repo_route=repo_data.route).first()
old_relationship = RepoFavourite.query.filter_by(user_username=user.username,
repo_route=repo_data.route).first()
if old_relationship:
db.session.delete(old_relationship)
else:
@repositories.route("/<username>/<repository>/users/", methods=["GET", "POST"])
def repository_users(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
if flask.request.form.get("new-username"):
# Create new relationship
new_user = User.query.filter_by(username=flask.request.form.get("new-username")).first()
new_user = User.query.filter_by(
username=flask.request.form.get("new-username")).first()
relationship = RepoAccess(new_user, repo_data, flask.request.form.get("new-level"))
db.session.add(relationship)
db.session.commit()
if flask.request.form.get("update-username"):
# Create new relationship
updated_user = User.query.filter_by(username=flask.request.form.get("update-username")).first()
updated_user = User.query.filter_by(
username=flask.request.form.get("update-username")).first()
relationship = RepoAccess.query.filter_by(repo=repo_data, user=updated_user).first()
if flask.request.form.get("update-level") == -1:
relationship.delete()
relationship.access_level = flask.request.form.get("update-level")
db.session.commit()
return flask.redirect(app.url_for(".repository_users", username=username, repository=repository))
return flask.redirect(
app.url_for(".repository_users", username=username, repository=repository))
@repositories.route("/<username>/<repository>/branches/")
def repository_branches(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
@repositories.route("/<username>/<repository>/log/", defaults={"branch": None})
@repositories.route("/<username>/<repository>/log/<branch>/")
def repository_log(username, repository, branch):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
all_refs.append((ref, "tag"))
commit_list = [f"/{username}/{repository}/{sha}" for sha in
git_command(server_repo_location, None, "log", "--format='%H'").decode().split("\n")]
git_command(server_repo_location, None, "log",
"--format='%H'").decode().split("\n")]
commits = Commit.query.filter(Commit.identifier.in_(commit_list))
@repositories.route("/<username>/<repository>/prs/", methods=["GET", "POST"])
def repository_prs(username, repository):
if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username,
repository) is not None):
if not (get_visibility(username, repository) or get_permission_level(
flask.session.get("username"), username,
repository) is not None):
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository)
head_data = db.session.get(Repo, head_route)
if not head_data.visibility:
flask.flash(Markup(
"<iconify-icon icon='mdi:error'></iconify-icon>" + _("Head can't be restricted")),
"<iconify-icon icon='mdi:error'></iconify-icon>" + _(
"Head can't be restricted")),
category="error")
return flask.redirect(".", 303)
pull_request = PullRequest(repo_data, head, head_data, base, db.session.get(User, flask.session["username"]))
pull_request = PullRequest(repo_data, head, head_data, base,
db.session.get(User, flask.session["username"]))
db.session.add(pull_request)
db.session.commit()
if __name__ == "__main__":
app.run(debug=True, port=8080, host="0.0.0.0")
app.register_blueprint(repositories)
app.register_blueprint(repositories)
BASE_DOMAIN: str = "localhost"
SERVER_IPS: set = {"127.0.0.1", "localhost", "0.0.0.0"}
AUTH_REALM: str = "roundabout"
MAX_PAYLOAD_SIZE: int = 4 * 1024**3
AVATAR_SIZE: tuple = (192, 192)
auth = HTTPBasicAuth(realm=config.AUTH_REALM)
auth_required = flask.Response("Unauthorized Access", 401, {"WWW-Authenticate": 'Basic realm="Login Required"'})
auth_required = flask.Response("Unauthorized Access", 401,
{"WWW-Authenticate": 'Basic realm="Login Required"'})
@auth.verify_password
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository, ".git")
text = git_command(server_repo_location, flask.request.data, "upload-pack", "--stateless-rpc", ".")
text = git_command(server_repo_location, flask.request.data, "upload-pack",
"--stateless-rpc", ".")
return flask.Response(text, content_type="application/x-git-upload-pack-result")
flask.abort(403)
server_repo_location = os.path.join(config.REPOS_PATH, username, repository, ".git")
text = git_command(server_repo_location, flask.request.data, "receive-pack", "--stateless-rpc", ".")
text = git_command(server_repo_location, flask.request.data, "receive-pack",
"--stateless-rpc", ".")
if flask.request.data == b"0000":
return flask.Response("", content_type="application/x-git-receive-pack-result")
push_info = flask.request.data.split(b"\x00")[1].split(b" ")[0].decode()
old_sha, new_sha, _ = push_info.split()
commits_list = subprocess.check_output(["git", "rev-list", f"{old_sha}..{new_sha}"], cwd=server_repo_location).decode().strip().split("\n")
sha = flask.request.data.split(b" ", 2)[1].decode()
info = git_command(server_repo_location, None, "show", "-s", "--format='%H%n%at%n%cn <%ce>%n%B'", sha).decode()
if re.match("^[0-9a-fA-F]{40}$", info[:40]):
for sha in commits_list:
info = git_command(server_repo_location, None, "show", "-s",
"--format='%H%n%at%n%cn <%ce>%n%B'", sha).decode()
print(info.split("\n", 3))
sha, time, identity, body = info.split("\n", 3)
login = flask.g.user
repo.git.checkout("-f", repo_data.default_branch)
if auth.current_user() is None and (
not get_visibility(username, repository) or flask.request.args.get("service") == "git-receive-pack"):
not get_visibility(username, repository) or flask.request.args.get(
"service") == "git-receive-pack"):
return auth_required
try:
if not (get_visibility(username, repository) or get_permission_level(flask.g.user, username,
if not (get_visibility(username, repository) or get_permission_level(flask.g.user,
username,
repository) is not None):
flask.abort(403)
except AttributeError:
service_line = (f"{len(service_line) + 4:04x}" + service_line).encode()
if service == "upload-pack":
text = service_line + b"0000" + git_command(server_repo_location, None, "upload-pack", "--stateless-rpc",
"--advertise-refs", "--http-backend-info-refs", ".")
text = service_line + b"0000" + git_command(server_repo_location, None, "upload-pack",
"--stateless-rpc",
"--advertise-refs",
"--http-backend-info-refs", ".")
elif service == "receive-pack":
refs = git_command(server_repo_location, None, "receive-pack", "--http-backend-info-refs", ".")
refs = git_command(server_repo_location, None, "receive-pack",
"--http-backend-info-refs", ".")
text = service_line + b"0000" + refs
else:
flask.abort(403)
response = flask.Response(text, content_type=f"application/x-git-{service}-advertisement")
response.headers["Cache-Control"] = "no-cache"
return response
return response
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-03-19 18:02+0200\n"
"POT-Creation-Date: 2024-03-21 16:33+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
msgid "Successfully logged out"
msgstr ""
#: app.py:1004
#: app.py:1033
msgid "Bad branch name"
msgstr ""
#: app.py:1011
#: app.py:1040
msgid "Head can't be restricted"
msgstr ""
msgid "When you add favourite repositories, you can manage them from here."
msgstr ""
#: templates/file-view.html:5
msgid "View raw"
msgstr ""
#: templates/file-view.html:6 templates/no-home.html:39
msgid "Download"
msgstr ""
#: templates/file-view.html:58 templates/file-view.html:63
msgid "Your browser does not support HTML5 multimedia."
msgstr ""
#: templates/file-view.html:59 templates/file-view.html:64
msgid "Download file"
msgstr ""
#: templates/forbidden.html:3
msgid "403"
msgstr ""
msgid "FAQs"
msgstr ""
#: templates/home.html:3 templates/repository/repo-file.html:25
#: templates/home.html:3 templates/repository/repo-file.html:24
#: templates/repository/repo-tree.html:24
msgid "Home"
msgstr ""
msgstr ""
#: templates/no-home.html:33
msgid "The roundabout to all your code"
msgid "Welcome to the roundabout"
msgstr ""
#: templates/no-home.html:34
msgid "Git repository hosting, made simple. Powered by free software."
msgstr ""
#: templates/no-home.html:39
msgid "Download"
msgid "Easy git repository hosting, with free software"
msgstr ""
#: templates/no-home.html:40
msgid "Remove favourite"
msgstr ""
#: templates/task-monitor.html:3
#, python-format
msgid "Task monitor for %(result_id)s"
msgstr ""
#: templates/task-monitor.html:6
#, python-format
msgid "Task %(result_id)s"
msgstr ""
#: templates/task-monitor.html:11
msgid "Task results"
msgstr ""
#: templates/task-monitor.html:15
msgid "Done"
msgstr ""
#: templates/task-monitor.html:18
msgid "Running..."
msgstr ""
#: templates/task-monitor.html:24
msgid "Info"
msgstr ""
#: templates/task-monitor.html:28
msgid "Errors"
msgstr ""
#: templates/task-monitor.html:33
msgid "Cannot merge your branches"
msgstr ""
#: templates/task-monitor.html:35
msgid ""
"Since we can't help you with this yet, you'll need to resolve the merge "
"conflicts on your own computer."
msgstr ""
#: templates/task-monitor.html:38
msgid "In a shell inside your repository execute:"
msgstr ""
#: templates/task-monitor.html:47
msgid "Then fix your conflicts, merge, and finally, run:"
msgstr ""
#: templates/task-monitor.html:50
msgid "git remote rm UPSTREAM"
msgstr ""
#: templates/task-monitor.html:52
msgid "and push the changes."
msgstr ""
#: templates/task-monitor.html:59
msgid "Resolve your conflicts and merge, then push."
msgstr ""
#: templates/task-monitor.html:63
msgid "Merge simulation went well; continue?"
msgstr ""
#: templates/repository/repo-prs.html:58 templates/task-monitor.html:64
msgid "Merge"
msgstr ""
#: templates/teapot.html:3
msgid "418"
msgstr ""
msgid "Tags"
msgstr ""
#: templates/repository/repo-commit.html:6
#: templates/repository/repo-file.html:5
#, python-format
msgid "%(basename)s in %(username)s/%(repository)s"
msgstr ""
#: templates/repository/repo-file.html:16
#: templates/repository/repo-file.html:15
#: templates/repository/repo-tree.html:15
msgid "Back"
msgstr ""
#: templates/repository/repo-file.html:19
#: templates/repository/repo-file.html:18
#: templates/repository/repo-tree.html:18
msgid "Forwards"
msgstr ""
#: templates/repository/repo-file.html:22
#: templates/repository/repo-file.html:21
#: templates/repository/repo-tree.html:21
msgid "Up"
msgstr ""
#: templates/repository/repo-file.html:28
#: templates/repository/repo-file.html:27
#: templates/repository/repo-tree.html:27
msgid "Refresh"
msgstr ""
msgid "Deny"
msgstr ""
#: templates/repository/repo-prs.html:58
msgid "Merge"
msgstr ""
#: templates/repository/repo-tree.html:5
#, python-format
msgid "Tree of %(username)s/%(repository)s"
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-03-19 18:02+0200\n"
"PO-Revision-Date: 2024-03-19 18:05+0200\n"
"POT-Creation-Date: 2024-03-21 16:33+0200\n"
"PO-Revision-Date: 2024-03-21 16:39+0200\n"
"Last-Translator: roundabout <root@roundabout-host.com>\n"
"Language-Team: ro_RO <LL@li.org>\n"
"Language: ro_RO\n"
msgid "Successfully logged out"
msgstr "Ieșit din cont cu succes"
#: app.py:1004
#: app.py:1033
msgid "Bad branch name"
msgstr "Nume de ramificație greșit"
#: app.py:1011
#: app.py:1040
msgid "Head can't be restricted"
msgstr "Vârful nu poate fi restricționat"
msgid "When you add favourite repositories, you can manage them from here."
msgstr "Când adaugi depozite preferate, le poți gestiona de aici."
#: templates/file-view.html:5
msgid "View raw"
msgstr "Vezi versiunea brută"
#: templates/file-view.html:6 templates/no-home.html:39
msgid "Download"
msgstr "Descarcă"
#: templates/file-view.html:58 templates/file-view.html:63
msgid "Your browser does not support HTML5 multimedia."
msgstr "Navigatorul tău nu acceptă formatele multimedia HTML5."
#: templates/file-view.html:59 templates/file-view.html:64
msgid "Download file"
msgstr "Descarcă fișierul"
#: templates/forbidden.html:3
msgid "403"
msgstr "403"
msgid "FAQs"
msgstr "Întrebări frecvente"
#: templates/home.html:3 templates/repository/repo-file.html:25
#: templates/home.html:3 templates/repository/repo-file.html:24
#: templates/repository/repo-tree.html:24
msgid "Home"
msgstr "Acasă"
msgstr "Bine ai venit"
#: templates/no-home.html:33
msgid "The roundabout to all your code"
msgstr "Giratoriul către tot codul tău"
msgid "Welcome to the roundabout"
msgstr "Bine ai venit la giratoriu"
#: templates/no-home.html:34
msgid "Git repository hosting, made simple. Powered by free software."
msgstr "Găzduirea depozitelor de git, acum ușoară. Alimentat de programe libere."
#: templates/no-home.html:39
msgid "Download"
msgstr "Descarcă"
msgid "Easy git repository hosting, with free software"
msgstr "Găzduirea depozitelor git ușoară, cu programe libere"
#: templates/no-home.html:40
msgid "for setting up your own instance"
msgid "Remove favourite"
msgstr "Elimină preferatul"
#: templates/task-monitor.html:3
#, python-format
msgid "Task monitor for %(result_id)s"
msgstr "Monitorul sarcinii %(result_id)s"
#: templates/task-monitor.html:6
#, python-format
msgid "Task %(result_id)s"
msgstr "Sarcina %(result_id)s"
#: templates/task-monitor.html:11
msgid "Task results"
msgstr "Rezultatele sarcinii"
#: templates/task-monitor.html:15
msgid "Done"
msgstr "Gata"
#: templates/task-monitor.html:18
msgid "Running..."
msgstr "Se execută..."
#: templates/task-monitor.html:24
msgid "Info"
msgstr "Informații"
#: templates/task-monitor.html:28
msgid "Errors"
msgstr "Erori"
#: templates/task-monitor.html:33
msgid "Cannot merge your branches"
msgstr "Nu-ți putem îmbina ramificațiile"
#: templates/task-monitor.html:35
msgid ""
"Since we can't help you with this yet, you'll need to resolve the merge "
"conflicts on your own computer."
msgstr ""
"Pentru că nu te putem ajuta încă cu aceasta, va trebui să rezolvi conflictele "
"pe propriul calculator."
#: templates/task-monitor.html:38
msgid "In a shell inside your repository execute:"
msgstr "Într-un terminal în depozitul tău execută:"
#: templates/task-monitor.html:47
msgid "Then fix your conflicts, merge, and finally, run:"
msgstr "Apoi rezolvă-ți conflictele, îmbină, și rulează:"
#: templates/task-monitor.html:50
msgid "git remote rm UPSTREAM"
msgstr ""
#: templates/task-monitor.html:52
msgid "and push the changes."
msgstr "și trimite schimbările."
#: templates/task-monitor.html:59
msgid "Resolve your conflicts and merge, then push."
msgstr "Rezolvă-ți conflictele și îmbină, apoi trimite."
#: templates/task-monitor.html:63
msgid "Merge simulation went well; continue?"
msgstr "Simularea îmbinării a funcționat; continui?"
#: templates/repository/repo-prs.html:58 templates/task-monitor.html:64
msgid "Merge"
msgstr "Îmbină"
#: templates/teapot.html:3
msgid "418"
msgstr "418"
msgid "Tags"
msgstr "Etichete"
#: templates/repository/repo-file.html:5
#: templates/repository/repo-commit.html:6 templates/repository/repo-file.html:5
#, python-format
msgid "%(basename)s in %(username)s/%(repository)s"
msgstr "%(basename)s în %(username)s/%(repository)s"
#: templates/repository/repo-file.html:16 templates/repository/repo-tree.html:15
#: templates/repository/repo-file.html:15 templates/repository/repo-tree.html:15
msgid "Back"
msgstr "Înapoi"
#: templates/repository/repo-file.html:19 templates/repository/repo-tree.html:18
#: templates/repository/repo-file.html:18 templates/repository/repo-tree.html:18
msgid "Forwards"
msgstr "Înainte"
#: templates/repository/repo-file.html:22 templates/repository/repo-tree.html:21
#: templates/repository/repo-file.html:21 templates/repository/repo-tree.html:21
msgid "Up"
msgstr "Sus"
#: templates/repository/repo-file.html:28 templates/repository/repo-tree.html:27
#: templates/repository/repo-file.html:27 templates/repository/repo-tree.html:27
msgid "Refresh"
msgstr "Reîncarcă"
msgid "Deny"
msgstr "Respinge"
#: templates/repository/repo-prs.html:58
msgid "Merge"
msgstr "Îmbină"
#: templates/repository/repo-tree.html:5
#, python-format
msgid "Tree of %(username)s/%(repository)s"
#: templates/repository/repo-users.html:81
msgid "Add"
msgstr "Adaugă"
#~ msgid "The roundabout to all your code"
#~ msgstr "Giratoriul către tot codul tău"
{% extends "default.html" %}
{% set active_page = "log" %}
{% block title %}
{% trans basename=basename, username=username, repository=repository %}{{ basename }} in {{ username }}/{{ repository }}{% endtrans %}
{% endblock %}
{% block content %}
<x-vbox>
<x-frame style="--width: 896px;" class="flexible-space">
{% for line in diff | decode | split("\n") %}
{% if line[0] == "+" %}
<ins>{{ line[1:] }}</ins>
{% endif %}
{% endfor %}
</x-frame>
</x-vbox>
{% endblock %}
{% trans basename=basename, username=username, repository=repository %}{{ basename }} in {{ username }}/{{ repository }}{% endtrans %}
{% endblock %}
{% block content %}
<x-vbox>
<x-frame style="--width: 896px;" class="flexible-space">
<article class="card">
{% trans %}Then fix your conflicts, merge, and finally, run:{% endtrans %}
</p>
<pre>
<span class="decorative-dollar">{% trans %}git remote rm UPSTREAM{% endtrans %}</span></pre>
<span class="decorative-dollar">git remote rm UPSTREAM</span></pre>
<p>
{% trans %}and push the changes.{% endtrans %}
</p>
<td>{{ file.mimetype }}</td>
<td style="text-align: right;">{{ file.size[0] }} {{ file.size[1] }}</td>
<td>
<x-hbox style="align-items: baseline; gap: 0.5ch;">
<code>{{ file.commit.sha[:file.shaSize] }}</code>
<span class="commit-message">{{ file.commit.message }}</span>
</x-hbox>
{% if file.commit %}
<a href="/{{ username }}/{{ repository }}/commit/{{ file.commit.sha }}" class="file-link">
<x-hbox style="align-items: baseline; gap: 0.5ch;">
<code>{{ file.commit.sha[:file.shaSize] }}</code>
<span class="commit-message">{{ file.commit.message }}</span>
</x-hbox>
</a>
{% else %}
???
{% endif %}
</td>
</tr>
{% endfor %}