roundabout,
created on Monday, 25 December 2023, 15:50:49 (1703519449),
received on Wednesday, 31 July 2024, 06:54:40 (1722408880)
Author identity: vlad <vlad.muntoiu@gmail.com>
872b642119b0343f8066d3e056802c04959d3d4c
app.py
@@ -33,6 +33,7 @@ app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app) bcrypt = Bcrypt(app) migrate = Migrate(app, db) from models import *def gitCommand(repo, data, *args):
@@ -60,194 +61,6 @@ def onlyChars(string, chars):
return True with app.app_context():class RepoAccess(db.Model):id = db.Column(db.Integer, primary_key=True)userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)repoRoute = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)accessLevel = db.Column(db.SmallInteger(), nullable=False) # 0 read-only, 1 read-write, 2 adminuser = db.relationship("User", back_populates="repoAccess")repo = db.relationship("Repo", back_populates="repoAccess")__table_args__ = (db.UniqueConstraint("userUsername", "repoRoute", name="_user_repo_uc"),)def __init__(self, user, repo, level):self.userUsername = user.usernameself.repoRoute = repo.routeself.accessLevel = levelclass RepoFavourite(db.Model):id = db.Column(db.Integer, primary_key=True)userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)repoRoute = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)user = db.relationship("User", back_populates="favourites")repo = db.relationship("Repo", back_populates="favourites")__table_args__ = (db.UniqueConstraint("userUsername", "repoRoute", name="_user_repo_uc1"),)def __init__(self, user, repo):self.userUsername = user.usernameself.repoRoute = repo.routeclass PostVote(db.Model):id = db.Column(db.Integer, primary_key=True)userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)postIdentifier = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=False)voteScore = db.Column(db.SmallInteger(), nullable=False)user = db.relationship("User", back_populates="votes")post = db.relationship("Post", back_populates="votes")__table_args__ = (db.UniqueConstraint("userUsername", "postIdentifier", name="_user_post_uc"),)def __init__(self, user, post, score):self.userUsername = user.usernameself.postIdentifier = post.identifierself.voteScore = scoreclass User(db.Model):username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True)displayName = db.Column(db.Unicode(128), unique=False, nullable=True)bio = db.Column(db.Unicode(512), unique=False, nullable=True)passwordHashed = db.Column(db.String(60), nullable=False)email = db.Column(db.String(254), nullable=True)company = db.Column(db.Unicode(64), nullable=True)companyURL = db.Column(db.String(256), nullable=True)URL = db.Column(db.String(256), nullable=True)showMail = db.Column(db.Boolean, default=False, nullable=False)location = db.Column(db.Unicode(64), nullable=True)creationDate = db.Column(db.DateTime, default=datetime.utcnow)repositories = db.relationship("Repo", back_populates="owner")repoAccess = db.relationship("RepoAccess", back_populates="user")votes = db.relationship("PostVote", back_populates="user")favourites = db.relationship("RepoFavourite", back_populates="user")commits = db.relationship("Commit", back_populates="owner")posts = db.relationship("Post", back_populates="owner")def __init__(self, username, password, email=None, displayName=None):self.username = usernameself.passwordHashed = bcrypt.generate_password_hash(password, config.HASHING_ROUNDS).decode("utf-8")self.email = emailself.displayName = displayName# Create the user's directoryif not os.path.exists(os.path.join(config.REPOS_PATH, username)):os.makedirs(os.path.join(config.REPOS_PATH, username))if not os.path.exists(os.path.join(config.USERDATA_PATH, username)):os.makedirs(os.path.join(config.USERDATA_PATH, username))avatarName = random.choice(os.listdir(config.DEFAULT_AVATARS_PATH))if os.path.join(config.DEFAULT_AVATARS_PATH, avatarName).endswith(".svg"):cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatarName),write_to="/tmp/roundabout-avatar.png")avatar = Image.open("/tmp/roundabout-avatar.png")else:avatar = Image.open(os.path.join(config.DEFAULT_AVATARS_PATH, avatarName))avatar.thumbnail(config.AVATAR_SIZE)avatar.save(os.path.join(config.USERDATA_PATH, username, "avatar.png"))class Repo(db.Model):route = db.Column(db.String(98), unique=True, nullable=False, primary_key=True)ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)name = db.Column(db.String(64), nullable=False)owner = db.relationship("User", back_populates="repositories")visibility = db.Column(db.SmallInteger(), nullable=False)info = db.Column(db.Unicode(512), nullable=True)URL = db.Column(db.String(256), nullable=True)creationDate = db.Column(db.DateTime, default=datetime.utcnow)defaultBranch = db.Column(db.String(64), nullable=True, default="")commits = db.relationship("Commit", back_populates="repo")posts = db.relationship("Post", back_populates="repo")repoAccess = db.relationship("RepoAccess", back_populates="repo")favourites = db.relationship("RepoFavourite", back_populates="repo")lastPostID = db.Column(db.Integer, nullable=False, default=0)def __init__(self, owner, name, visibility):self.route = f"/{owner.username}/{name}"self.name = nameself.ownerName = owner.usernameself.owner = ownerself.visibility = visibility# Add the owner as an adminrepoAccess = RepoAccess(owner, self, 2)db.session.add(repoAccess)class Commit(db.Model):identifier = db.Column(db.String(227), unique=True, nullable=False, primary_key=True)sha = db.Column(db.String(128), nullable=False)repoName = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)ownerIdentity = db.Column(db.String(321))receiveDate = db.Column(db.DateTime, default=datetime.now)authorDate = db.Column(db.DateTime)message = db.Column(db.UnicodeText)repo = db.relationship("Repo", back_populates="commits")owner = db.relationship("User", back_populates="commits")def __init__(self, sha, owner, repo, date, message, ownerIdentity):self.identifier = f"{repo.route}/{sha}"self.sha = shaself.repoName = repo.routeself.repo = repoself.ownerName = owner.usernameself.owner = ownerself.authorDate = datetime.fromtimestamp(int(date))self.message = messageself.ownerIdentity = ownerIdentityclass Post(db.Model):identifier = db.Column(db.String(109), unique=True, nullable=False, primary_key=True)number = db.Column(db.Integer, nullable=False)repoName = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)votes = db.relationship("PostVote", back_populates="post")voteSum = db.Column(db.Integer, nullable=False, default=0)parentID = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=True)state = db.Column(db.SmallInteger, nullable=True, default=1)date = db.Column(db.DateTime, default=datetime.now)lastUpdated = db.Column(db.DateTime, default=datetime.now)subject = db.Column(db.Unicode(384))message = db.Column(db.UnicodeText)repo = db.relationship("Repo", back_populates="posts")owner = db.relationship("User", back_populates="posts")parent = db.relationship("Post", back_populates="children", remote_side="Post.identifier")children = db.relationship("Post", back_populates="parent", remote_side="Post.parentID")def __init__(self, owner, repo, parent, subject, message):self.identifier = f"{repo.route}/{repo.lastPostID}"self.number = repo.lastPostIDself.repoName = repo.routeself.repo = repoself.ownerName = owner.usernameself.owner = ownerself.subject = subjectself.message = messageself.parent = parentrepo.lastPostID += 1def updateDate(self):self.lastUpdated = datetime.now()with db.session.no_autoflush:if self.parent is not None:self.parent.updateDate()def getPermissionLevel(loggedIn, username, repository): user = User.query.filter_by(username=loggedIn).first() repo = Repo.query.filter_by(route=f"/{username}/{repository}").first()
gitHTTP.py
@@ -1,6 +1,7 @@
import uuid from app import app, gitCommand, User, Repo, Commit, RepoAccess, getPermissionLevel, getVisibility, db, bcryptfrom models import * from app import app, gitCommand, getPermissionLevel, getVisibility, db, bcryptimport os import shutil import config
models.py
@@ -0,0 +1,193 @@
from app import app, db import git from datetime import datetime from enum import Enum from PIL import Image from cairosvg import svg2png with app.app_context(): class RepoAccess(db.Model): id = db.Column(db.Integer, primary_key=True) userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) repoRoute = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) accessLevel = db.Column(db.SmallInteger(), nullable=False) # 0 read-only, 1 read-write, 2 admin user = db.relationship("User", back_populates="repoAccess") repo = db.relationship("Repo", back_populates="repoAccess") __table_args__ = (db.UniqueConstraint("userUsername", "repoRoute", name="_user_repo_uc"),) def __init__(self, user, repo, level): self.userUsername = user.username self.repoRoute = repo.route self.accessLevel = level class RepoFavourite(db.Model): id = db.Column(db.Integer, primary_key=True) userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) repoRoute = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) user = db.relationship("User", back_populates="favourites") repo = db.relationship("Repo", back_populates="favourites") __table_args__ = (db.UniqueConstraint("userUsername", "repoRoute", name="_user_repo_uc1"),) def __init__(self, user, repo): self.userUsername = user.username self.repoRoute = repo.route class PostVote(db.Model): id = db.Column(db.Integer, primary_key=True) userUsername = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) postIdentifier = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=False) voteScore = db.Column(db.SmallInteger(), nullable=False) user = db.relationship("User", back_populates="votes") post = db.relationship("Post", back_populates="votes") __table_args__ = (db.UniqueConstraint("userUsername", "postIdentifier", name="_user_post_uc"),) def __init__(self, user, post, score): self.userUsername = user.username self.postIdentifier = post.identifier self.voteScore = score class User(db.Model): username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True) displayName = db.Column(db.Unicode(128), unique=False, nullable=True) bio = db.Column(db.Unicode(512), unique=False, nullable=True) passwordHashed = db.Column(db.String(60), nullable=False) email = db.Column(db.String(254), nullable=True) company = db.Column(db.Unicode(64), nullable=True) companyURL = db.Column(db.String(256), nullable=True) URL = db.Column(db.String(256), nullable=True) showMail = db.Column(db.Boolean, default=False, nullable=False) location = db.Column(db.Unicode(64), nullable=True) creationDate = db.Column(db.DateTime, default=datetime.utcnow) repositories = db.relationship("Repo", back_populates="owner") repoAccess = db.relationship("RepoAccess", back_populates="user") votes = db.relationship("PostVote", back_populates="user") favourites = db.relationship("RepoFavourite", back_populates="user") commits = db.relationship("Commit", back_populates="owner") posts = db.relationship("Post", back_populates="owner") def __init__(self, username, password, email=None, displayName=None): self.username = username self.passwordHashed = bcrypt.generate_password_hash(password, config.HASHING_ROUNDS).decode("utf-8") self.email = email self.displayName = displayName # Create the user's directory if not os.path.exists(os.path.join(config.REPOS_PATH, username)): os.makedirs(os.path.join(config.REPOS_PATH, username)) if not os.path.exists(os.path.join(config.USERDATA_PATH, username)): os.makedirs(os.path.join(config.USERDATA_PATH, username)) avatarName = random.choice(os.listdir(config.DEFAULT_AVATARS_PATH)) if os.path.join(config.DEFAULT_AVATARS_PATH, avatarName).endswith(".svg"): cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatarName), write_to="/tmp/roundabout-avatar.png") avatar = Image.open("/tmp/roundabout-avatar.png") else: avatar = Image.open(os.path.join(config.DEFAULT_AVATARS_PATH, avatarName)) avatar.thumbnail(config.AVATAR_SIZE) avatar.save(os.path.join(config.USERDATA_PATH, username, "avatar.png")) class Repo(db.Model): route = db.Column(db.String(98), unique=True, nullable=False, primary_key=True) ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) name = db.Column(db.String(64), nullable=False) owner = db.relationship("User", back_populates="repositories") visibility = db.Column(db.SmallInteger(), nullable=False) info = db.Column(db.Unicode(512), nullable=True) URL = db.Column(db.String(256), nullable=True) creationDate = db.Column(db.DateTime, default=datetime.utcnow) defaultBranch = db.Column(db.String(64), nullable=True, default="") commits = db.relationship("Commit", back_populates="repo") posts = db.relationship("Post", back_populates="repo") repoAccess = db.relationship("RepoAccess", back_populates="repo") favourites = db.relationship("RepoFavourite", back_populates="repo") lastPostID = db.Column(db.Integer, nullable=False, default=0) def __init__(self, owner, name, visibility): self.route = f"/{owner.username}/{name}" self.name = name self.ownerName = owner.username self.owner = owner self.visibility = visibility # Add the owner as an admin repoAccess = RepoAccess(owner, self, 2) db.session.add(repoAccess) class Commit(db.Model): identifier = db.Column(db.String(227), unique=True, nullable=False, primary_key=True) sha = db.Column(db.String(128), nullable=False) repoName = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) ownerIdentity = db.Column(db.String(321)) receiveDate = db.Column(db.DateTime, default=datetime.now) authorDate = db.Column(db.DateTime) message = db.Column(db.UnicodeText) repo = db.relationship("Repo", back_populates="commits") owner = db.relationship("User", back_populates="commits") def __init__(self, sha, owner, repo, date, message, ownerIdentity): self.identifier = f"{repo.route}/{sha}" self.sha = sha self.repoName = repo.route self.repo = repo self.ownerName = owner.username self.owner = owner self.authorDate = datetime.fromtimestamp(int(date)) self.message = message self.ownerIdentity = ownerIdentity class Post(db.Model): identifier = db.Column(db.String(109), unique=True, nullable=False, primary_key=True) number = db.Column(db.Integer, nullable=False) repoName = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) ownerName = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) votes = db.relationship("PostVote", back_populates="post") voteSum = db.Column(db.Integer, nullable=False, default=0) parentID = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=True) state = db.Column(db.SmallInteger, nullable=True, default=1) date = db.Column(db.DateTime, default=datetime.now) lastUpdated = db.Column(db.DateTime, default=datetime.now) subject = db.Column(db.Unicode(384)) message = db.Column(db.UnicodeText) repo = db.relationship("Repo", back_populates="posts") owner = db.relationship("User", back_populates="posts") parent = db.relationship("Post", back_populates="children", remote_side="Post.identifier") children = db.relationship("Post", back_populates="parent", remote_side="Post.parentID") def __init__(self, owner, repo, parent, subject, message): self.identifier = f"{repo.route}/{repo.lastPostID}" self.number = repo.lastPostID self.repoName = repo.route self.repo = repo self.ownerName = owner.username self.owner = owner self.subject = subject self.message = message self.parent = parent repo.lastPostID += 1 def updateDate(self): self.lastUpdated = datetime.now() with db.session.no_autoflush: if self.parent is not None: self.parent.updateDate()