Python script, ASCII text executable
        
            1
            from app import app, db 
        
            2
            import git 
        
            3
            from datetime import datetime 
        
            4
            from enum import Enum 
        
            5
            from PIL import Image 
        
            6
            from cairosvg import svg2png 
        
            7
            import os 
        
            8
            import config 
        
            9
            import bcrypt 
        
            10
            import cairosvg 
        
            11
            import random 
        
            12
            __all__ = [ 
        
            14
                "RepoAccess", 
        
            15
                "RepoFavourite", 
        
            16
                "Repo", 
        
            17
                "UserFollow", 
        
            18
                "UserNotification", 
        
            19
                "User", 
        
            20
                "Notification", 
        
            21
                "PostVote", 
        
            22
                "Post", 
        
            23
                "Commit", 
        
            24
            ] 
        
            25
            with app.app_context(): 
        
            27
                class RepoAccess(db.Model): 
        
            28
                    id = db.Column(db.Integer, primary_key=True) 
        
            29
                    user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            30
                    repo_route = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) 
        
            31
                    access_level = db.Column(db.SmallInteger(), nullable=False)  # 0 read-only, 1 read-write, 2 admin 
        
            32
                    user = db.relationship("User", back_populates="repo_access") 
        
            34
                    repo = db.relationship("Repo", back_populates="repo_access") 
        
            35
                    __table_args__ = (db.UniqueConstraint("user_username", "repo_route", name="_user_repo_uc"),) 
        
            37
                    def __init__(self, user, repo, level): 
        
            39
                        self.user_username = user.username 
        
            40
                        self.repo_route = repo.route 
        
            41
                        self.access_level = level 
        
            42
                class RepoFavourite(db.Model): 
        
            45
                    id = db.Column(db.Integer, primary_key=True) 
        
            46
                    user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            47
                    repo_route = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) 
        
            48
                    user = db.relationship("User", back_populates="favourites") 
        
            50
                    repo = db.relationship("Repo", back_populates="favourites") 
        
            51
                    __table_args__ = (db.UniqueConstraint("user_username", "repo_route", name="_user_repo_uc1"),) 
        
            53
                    def __init__(self, user, repo): 
        
            55
                        self.user_username = user.username 
        
            56
                        self.repo_route = repo.route 
        
            57
                class PostVote(db.Model): 
        
            60
                    id = db.Column(db.Integer, primary_key=True) 
        
            61
                    user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            62
                    post_identifier = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=False) 
        
            63
                    vote_score = db.Column(db.SmallInteger(), nullable=False) 
        
            64
                    user = db.relationship("User", back_populates="votes") 
        
            66
                    post = db.relationship("Post", back_populates="votes") 
        
            67
                    __table_args__ = (db.UniqueConstraint("user_username", "post_identifier", name="_user_post_uc"),) 
        
            69
                    def __init__(self, user, post, score): 
        
            71
                        self.user_username = user.username 
        
            72
                        self.post_identifier = post.identifier 
        
            73
                        self.vote_score = score 
        
            74
                class User(db.Model): 
        
            77
                    username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True) 
        
            78
                    display_name = db.Column(db.Unicode(128), unique=False, nullable=True) 
        
            79
                    bio = db.Column(db.Unicode(16384), unique=False, nullable=True) 
        
            80
                    password_hashed = db.Column(db.String(60), nullable=False) 
        
            81
                    email = db.Column(db.String(254), nullable=True) 
        
            82
                    company = db.Column(db.Unicode(64), nullable=True) 
        
            83
                    company_url = db.Column(db.String(256), nullable=True) 
        
            84
                    url = db.Column(db.String(256), nullable=True) 
        
            85
                    show_mail = db.Column(db.Boolean, default=False, nullable=False) 
        
            86
                    location = db.Column(db.Unicode(64), nullable=True) 
        
            87
                    creation_date = db.Column(db.DateTime, default=datetime.utcnow) 
        
            88
                    repositories = db.relationship("Repo", back_populates="owner") 
        
            90
                    followers = db.relationship("UserFollow", back_populates="followed", foreign_keys="[UserFollow.followed_username]") 
        
            91
                    follows = db.relationship("UserFollow", back_populates="follower", foreign_keys="[UserFollow.follower_username]") 
        
            92
                    repo_access = db.relationship("RepoAccess", back_populates="user") 
        
            93
                    votes = db.relationship("PostVote", back_populates="user") 
        
            94
                    favourites = db.relationship("RepoFavourite", back_populates="user") 
        
            95
                    commits = db.relationship("Commit", back_populates="owner") 
        
            97
                    posts = db.relationship("Post", back_populates="owner") 
        
            98
                    notifications = db.relationship("UserNotification", back_populates="user") 
        
            99
                    def __init__(self, username, password, email=None, display_name=None): 
        
            101
                        self.username = username 
        
            102
                        self.password_hashed = bcrypt.generate_password_hash(password, config.HASHING_ROUNDS).decode("utf-8") 
        
            103
                        self.email = email 
        
            104
                        self.display_name = display_name 
        
            105
                        # Create the user's directory 
        
            107
                        if not os.path.exists(os.path.join(config.REPOS_PATH, username)): 
        
            108
                            os.makedirs(os.path.join(config.REPOS_PATH, username)) 
        
            109
                        if not os.path.exists(os.path.join(config.USERDATA_PATH, username)): 
        
            110
                            os.makedirs(os.path.join(config.USERDATA_PATH, username)) 
        
            111
                        avatar_name = random.choice(os.listdir(config.DEFAULT_AVATARS_PATH)) 
        
            113
                        if os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name).endswith(".svg"): 
        
            114
                            cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name), 
        
            115
                                             write_to="/tmp/roundabout-avatar.png") 
        
            116
                            avatar = Image.open("/tmp/roundabout-avatar.png") 
        
            117
                        else: 
        
            118
                            avatar = Image.open(os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name)) 
        
            119
                        avatar.thumbnail(config.AVATAR_SIZE) 
        
            120
                        avatar.save(os.path.join(config.USERDATA_PATH, username, "avatar.png")) 
        
            121
                class Repo(db.Model): 
        
            124
                    route = db.Column(db.String(98), unique=True, nullable=False, primary_key=True) 
        
            125
                    owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            126
                    name = db.Column(db.String(64), nullable=False) 
        
            127
                    owner = db.relationship("User", back_populates="repositories") 
        
            128
                    visibility = db.Column(db.SmallInteger(), nullable=False) 
        
            129
                    info = db.Column(db.Unicode(512), nullable=True) 
        
            130
                    url = db.Column(db.String(256), nullable=True) 
        
            131
                    creation_date = db.Column(db.DateTime, default=datetime.utcnow) 
        
            132
                    default_branch = db.Column(db.String(64), nullable=True, default="") 
        
            134
                    commits = db.relationship("Commit", back_populates="repo") 
        
            136
                    posts = db.relationship("Post", back_populates="repo") 
        
            137
                    repo_access = db.relationship("RepoAccess", back_populates="repo") 
        
            138
                    favourites = db.relationship("RepoFavourite", back_populates="repo") 
        
            139
                    last_post_id = db.Column(db.Integer, nullable=False, default=0) 
        
            141
                    def __init__(self, owner, name, visibility): 
        
            143
                        self.route = f"/{owner.username}/{name}" 
        
            144
                        self.name = name 
        
            145
                        self.owner_name = owner.username 
        
            146
                        self.owner = owner 
        
            147
                        self.visibility = visibility 
        
            148
                        # Add the owner as an admin 
        
            150
                        repo_access = RepoAccess(owner, self, 2) 
        
            151
                        db.session.add(repo_access) 
        
            152
                class Commit(db.Model): 
        
            155
                    identifier = db.Column(db.String(227), unique=True, nullable=False, primary_key=True) 
        
            156
                    sha = db.Column(db.String(128), nullable=False) 
        
            157
                    repo_name = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) 
        
            158
                    owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            159
                    owner_identity = db.Column(db.String(321)) 
        
            160
                    receive_date = db.Column(db.DateTime, default=datetime.now) 
        
            161
                    author_date = db.Column(db.DateTime) 
        
            162
                    message = db.Column(db.UnicodeText) 
        
            163
                    repo = db.relationship("Repo", back_populates="commits") 
        
            164
                    owner = db.relationship("User", back_populates="commits") 
        
            165
                    def __init__(self, sha, owner, repo, date, message, owner_identity): 
        
            167
                        self.identifier = f"{repo.route}/{sha}" 
        
            168
                        self.sha = sha 
        
            169
                        self.repo_name = repo.route 
        
            170
                        self.repo = repo 
        
            171
                        self.owner_name = owner.username 
        
            172
                        self.owner = owner 
        
            173
                        self.author_date = datetime.fromtimestamp(int(date)) 
        
            174
                        self.message = message 
        
            175
                        self.owner_identity = owner_identity 
        
            176
                class Post(db.Model): 
        
            179
                    identifier = db.Column(db.String(109), unique=True, nullable=False, primary_key=True) 
        
            180
                    number = db.Column(db.Integer, nullable=False) 
        
            181
                    repo_name = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False) 
        
            182
                    owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            183
                    votes = db.relationship("PostVote", back_populates="post") 
        
            184
                    vote_sum = db.Column(db.Integer, nullable=False, default=0) 
        
            185
                    parent_id = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=True) 
        
            187
                    state = db.Column(db.SmallInteger, nullable=True, default=1) 
        
            188
                    date = db.Column(db.DateTime, default=datetime.now) 
        
            190
                    last_updated = db.Column(db.DateTime, default=datetime.now) 
        
            191
                    subject = db.Column(db.Unicode(384)) 
        
            192
                    message = db.Column(db.UnicodeText) 
        
            193
                    repo = db.relationship("Repo", back_populates="posts") 
        
            194
                    owner = db.relationship("User", back_populates="posts") 
        
            195
                    parent = db.relationship("Post", back_populates="children", remote_side="Post.identifier") 
        
            196
                    children = db.relationship("Post", back_populates="parent", remote_side="Post.parent_id") 
        
            197
                    def __init__(self, owner, repo, parent, subject, message): 
        
            199
                        self.identifier = f"{repo.route}/{repo.last_post_id}" 
        
            200
                        self.number = repo.last_post_id 
        
            201
                        self.repo_name = repo.route 
        
            202
                        self.repo = repo 
        
            203
                        self.owner_name = owner.username 
        
            204
                        self.owner = owner 
        
            205
                        self.subject = subject 
        
            206
                        self.message = message 
        
            207
                        self.parent = parent 
        
            208
                        repo.last_post_id += 1 
        
            209
                    def update_date(self): 
        
            211
                        self.last_updated = datetime.now() 
        
            212
                        with db.session.no_autoflush: 
        
            213
                            if self.parent is not None: 
        
            214
                                self.parent.update_date() 
        
            215
                class UserNotification(db.Model): 
        
            218
                    id = db.Column(db.Integer, primary_key=True) 
        
            219
                    user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False) 
        
            220
                    notification_id = db.Column(db.BigInteger, db.ForeignKey("notification.id")) 
        
            221
                    attention_level = db.Column(db.SmallInteger, nullable=False)  # 0 is read 
        
            222
                    read_time = db.Column(db.DateTime, nullable=True) 
        
            223
                    user = db.relationship("User", back_populates="notifications") 
        
            225
                    notification = db.relationship("Notification", back_populates="notifications") 
        
            226
                    __table_args__ = (db.UniqueConstraint("user_username", "notification_id", name="_user_notification_uc"),) 
        
            228
                    def __init__(self, user, notification, level): 
        
            230
                        self.user_username = user.username 
        
            231
                        self.notification_id = notification.id 
        
            232
                        self.attention_level = level 
        
            233
                    def read(self): 
        
            235
                        self.read_time = datetime.utcnow 
        
            236
                        self.attention_level = 0 
        
            237
                class UserFollow(db.Model): 
        
            240
                    id = db.Column(db.Integer, primary_key=True) 
        
            241
                    follower_username = db.Column(db.String(32), db.ForeignKey("user.username", ondelete="CASCADE"), nullable=False) 
        
            242
                    followed_username = db.Column(db.String(32), db.ForeignKey("user.username", ondelete="CASCADE"), nullable=False) 
        
            243
                    follower = db.relationship("User", back_populates="follows", foreign_keys=[followed_username]) 
        
            245
                    followed = db.relationship("User", back_populates="followers", foreign_keys=[follower_username]) 
        
            246
                    def __init__(self, follower_username, followed_username): 
        
            248
                        self.follower_username = follower_username 
        
            249
                        self.followed_username = followed_username 
        
            250
                class Notification(db.Model): 
        
            253
                    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True) 
        
            254
                    data = db.Column(db.dialects.postgresql.JSONB, nullable=False, default={}) 
        
            255
                    notifications = db.relationship("UserNotification", back_populates="notification") 
        
            256
                    timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now) 
        
            257
                    def __init__(self, json): 
        
            259
                        self.data = json 
        
            260