api.py
Python script, ASCII text executable
1
"""
2
This module provides an XML API for accessing data from Roundabout.
3
4
Roundabout - git hosting for everyone <https://roundabout-host.com>
5
Copyright (C) 2023-2025 Roundabout developers <root@roundabout-host.com>
6
7
This program is free software: you can redistribute it and/or modify
8
it under the terms of the GNU Affero General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
11
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU Affero General Public License for more details.
16
17
You should have received a copy of the GNU Affero General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
"""
20
21
import uuid
22
from models import *
23
from app import app, db, bcrypt
24
from misc_utils import *
25
from common import git_command
26
import os
27
import shutil
28
import config
29
import flask
30
import git
31
import subprocess
32
from flask_httpauth import HTTPBasicAuth
33
import zlib
34
import re
35
import datetime
36
37
auth = HTTPBasicAuth(realm=config.AUTH_REALM + " Data API")
38
39
api_app = flask.Blueprint("api_app", __name__, template_folder="templates/api/", url_prefix="/data-api/")
40
41
42
@auth.verify_password
43
def verify_password(username, password):
44
user = User.query.filter_by(username=username).first()
45
46
if user and bcrypt.check_password_hash(user.password_hashed, password):
47
flask.g.user = username
48
return True
49
50
return False
51
52
53
@api_app.route("/", methods=["GET"])
54
def welcome():
55
response = flask.make_response(flask.render_template("welcome.xml"))
56
response.headers["Content-Type"] = "application/xml"
57
return response
58
59
60
@api_app.route("/user/<username>/", methods=["GET"])
61
def get_user(username):
62
response = flask.make_response(flask.render_template("user.xml", user=db.session.get(User, username)))
63
response.headers["Content-Type"] = "application/xml"
64
return response
65
66
67
@api_app.route("/user/<username>/repositories", methods=["GET"])
68
@auth.login_required(optional=True)
69
def get_user_repositories(username):
70
user = db.session.get(User, username)
71
page = flask.request.args.get("page", 1)
72
page_size = flask.request.args.get("page_size", 64)
73
if hasattr(flask.g, "user") and flask.g.user == username:
74
repositories = Repo.query.filter_by(owner=user).paginate(page=page, per_page=page_size)
75
else:
76
repositories = Repo.query.filter_by(owner=user, visibility=2).paginate(page=page, per_page=page_size)
77
response = flask.make_response(
78
flask.render_template("user-repositories.xml", user=user,
79
repositories=repositories.items, page=page, page_size=page_size)
80
)
81
response.headers["Content-Type"] = "application/xml"
82
return response
83
84
85
@api_app.route("/repo/<username>/<repository>/", methods=["GET"])
86
@auth.login_required(optional=True)
87
def get_repository(username, repository):
88
user = db.session.get(User, username)
89
repo_data = db.session.get(Repo, f"/{username}/{repository}")
90
91
if not (repo_data.visibility or RepoAccess.query.filter_by(user=user, repo=repo_data).first()):
92
return flask.Response("", 401, content_type="text/plain")
93
94
response = flask.make_response(flask.render_template("repository.xml", repository=repo_data))
95
response.headers["Content-Type"] = "application/xml"
96
return response
97
98
99
100
@api_app.route("/commit/<username>/<repository>/<commit_sha>", methods=["GET"])
101
@auth.login_required(optional=True)
102
def get_commit(username, repository, commit_sha):
103
user = db.session.get(User, username)
104
repo_data = db.session.get(Repo, f"/{username}/{repository}")
105
commit = db.session.get(Commit, f"/{username}/{repository}/{commit_sha}")
106
107
if not (repo_data.visibility or RepoAccess.query.filter_by(user=user, repo=repo_data).first()):
108
return flask.Response("", 401, content_type="text/plain")
109
110
response = flask.make_response(flask.render_template("api/commit.xml", commit=commit))
111
response.headers["Content-Type"] = "application/xml"
112
return response
113
114
app.register_blueprint(api_app)
115