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