By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 models.py

View raw Download
text/x-script.python • 13.19 kiB
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
13
__all__ = [
14
"RepoAccess",
15
"RepoFavourite",
16
"Repo",
17
"UserFollow",
18
"UserNotification",
19
"User",
20
"Notification",
21
"PostVote",
22
"Post",
23
"Commit",
24
"PullRequest",
25
]
26
27
with (app.app_context()):
28
class RepoAccess(db.Model):
29
id = db.Column(db.Integer, primary_key=True)
30
user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
31
repo_route = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)
32
access_level = db.Column(db.SmallInteger(), nullable=False) # 0 read-only, 1 read-write, 2 admin
33
34
user = db.relationship("User", back_populates="repo_access")
35
repo = db.relationship("Repo", back_populates="repo_access")
36
37
__table_args__ = (db.UniqueConstraint("user_username", "repo_route", name="_user_repo_uc"),)
38
39
def __init__(self, user, repo, level):
40
self.user_username = user.username
41
self.repo_route = repo.route
42
self.access_level = level
43
44
45
class RepoFavourite(db.Model):
46
id = db.Column(db.Integer, primary_key=True)
47
user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
48
repo_route = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)
49
50
notify_commit = db.Column(db.Boolean)
51
52
user = db.relationship("User", back_populates="favourites")
53
repo = db.relationship("Repo", back_populates="favourites")
54
55
__table_args__ = (db.UniqueConstraint("user_username", "repo_route", name="_user_repo_uc1"),)
56
57
def __init__(self, user, repo):
58
self.user_username = user.username
59
self.repo_route = repo.route
60
61
62
class PostVote(db.Model):
63
id = db.Column(db.Integer, primary_key=True)
64
user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
65
post_identifier = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=False)
66
vote_score = db.Column(db.SmallInteger(), nullable=False)
67
68
user = db.relationship("User", back_populates="votes")
69
post = db.relationship("Post", back_populates="votes")
70
71
__table_args__ = (db.UniqueConstraint("user_username", "post_identifier", name="_user_post_uc"),)
72
73
def __init__(self, user, post, score):
74
self.user_username = user.username
75
self.post_identifier = post.identifier
76
self.vote_score = score
77
78
79
class User(db.Model):
80
username = db.Column(db.String(32), unique=True, nullable=False, primary_key=True)
81
display_name = db.Column(db.Unicode(128), unique=False, nullable=True)
82
bio = db.Column(db.Unicode(16384), unique=False, nullable=True)
83
password_hashed = db.Column(db.String(60), nullable=False)
84
email = db.Column(db.String(254), nullable=True)
85
company = db.Column(db.Unicode(64), nullable=True)
86
company_url = db.Column(db.String(256), nullable=True)
87
url = db.Column(db.String(256), nullable=True)
88
show_mail = db.Column(db.Boolean, default=False, nullable=False)
89
location = db.Column(db.Unicode(64), nullable=True)
90
creation_date = db.Column(db.DateTime, default=datetime.utcnow)
91
92
repositories = db.relationship("Repo", back_populates="owner")
93
followers = db.relationship("UserFollow", back_populates="followed", foreign_keys="[UserFollow.followed_username]")
94
follows = db.relationship("UserFollow", back_populates="follower", foreign_keys="[UserFollow.follower_username]")
95
repo_access = db.relationship("RepoAccess", back_populates="user")
96
votes = db.relationship("PostVote", back_populates="user")
97
favourites = db.relationship("RepoFavourite", back_populates="user")
98
99
commits = db.relationship("Commit", back_populates="owner")
100
posts = db.relationship("Post", back_populates="owner")
101
prs = db.relationship("PullRequest", back_populates="owner")
102
notifications = db.relationship("UserNotification", back_populates="user")
103
104
def __init__(self, username, password, email=None, display_name=None):
105
self.username = username
106
self.password_hashed = bcrypt.generate_password_hash(password, config.HASHING_ROUNDS).decode("utf-8")
107
self.email = email
108
self.display_name = display_name
109
110
# Create the user's directory
111
if not os.path.exists(os.path.join(config.REPOS_PATH, username)):
112
os.makedirs(os.path.join(config.REPOS_PATH, username))
113
if not os.path.exists(os.path.join(config.USERDATA_PATH, username)):
114
os.makedirs(os.path.join(config.USERDATA_PATH, username))
115
116
avatar_name = random.choice(os.listdir(config.DEFAULT_AVATARS_PATH))
117
if os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name).endswith(".svg"):
118
cairosvg.svg2png(url=os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name),
119
write_to="/tmp/roundabout-avatar.png")
120
avatar = Image.open("/tmp/roundabout-avatar.png")
121
else:
122
avatar = Image.open(os.path.join(config.DEFAULT_AVATARS_PATH, avatar_name))
123
avatar.thumbnail(config.AVATAR_SIZE)
124
avatar.save(os.path.join(config.USERDATA_PATH, username, "avatar.png"))
125
126
127
class Repo(db.Model):
128
route = db.Column(db.String(98), unique=True, nullable=False, primary_key=True)
129
owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
130
name = db.Column(db.String(64), nullable=False)
131
owner = db.relationship("User", back_populates="repositories")
132
visibility = db.Column(db.SmallInteger(), nullable=False)
133
info = db.Column(db.Unicode(512), nullable=True)
134
url = db.Column(db.String(256), nullable=True)
135
creation_date = db.Column(db.DateTime, default=datetime.utcnow)
136
137
default_branch = db.Column(db.String(64), nullable=True, default="")
138
139
commits = db.relationship("Commit", back_populates="repo")
140
posts = db.relationship("Post", back_populates="repo")
141
repo_access = db.relationship("RepoAccess", back_populates="repo")
142
favourites = db.relationship("RepoFavourite", back_populates="repo")
143
heads = db.relationship("PullRequest", back_populates="head", foreign_keys="[PullRequest.head_route]")
144
bases = db.relationship("PullRequest", back_populates="base", foreign_keys="[PullRequest.base_route]")
145
146
last_post_id = db.Column(db.Integer, nullable=False, default=0)
147
148
def __init__(self, owner, name, visibility):
149
self.route = f"/{owner.username}/{name}"
150
self.name = name
151
self.owner_name = owner.username
152
self.owner = owner
153
self.visibility = visibility
154
155
# Add the owner as an admin
156
repo_access = RepoAccess(owner, self, 2)
157
db.session.add(repo_access)
158
159
160
class Commit(db.Model):
161
identifier = db.Column(db.String(227), unique=True, nullable=False, primary_key=True)
162
sha = db.Column(db.String(128), nullable=False)
163
repo_name = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)
164
owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
165
owner_identity = db.Column(db.String(321))
166
receive_date = db.Column(db.DateTime, default=datetime.now)
167
author_date = db.Column(db.DateTime)
168
message = db.Column(db.UnicodeText)
169
repo = db.relationship("Repo", back_populates="commits")
170
owner = db.relationship("User", back_populates="commits")
171
172
def __init__(self, sha, owner, repo, date, message, owner_identity):
173
self.identifier = f"{repo.route}/{sha}"
174
self.sha = sha
175
self.repo_name = repo.route
176
self.repo = repo
177
self.owner_name = owner.username
178
self.owner = owner
179
self.author_date = datetime.fromtimestamp(int(date))
180
self.message = message
181
self.owner_identity = owner_identity
182
183
184
class Post(db.Model):
185
identifier = db.Column(db.String(109), unique=True, nullable=False, primary_key=True)
186
number = db.Column(db.Integer, nullable=False)
187
repo_name = db.Column(db.String(98), db.ForeignKey("repo.route"), nullable=False)
188
owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
189
votes = db.relationship("PostVote", back_populates="post")
190
vote_sum = db.Column(db.Integer, nullable=False, default=0)
191
192
parent_id = db.Column(db.String(109), db.ForeignKey("post.identifier"), nullable=True)
193
state = db.Column(db.SmallInteger, nullable=True, default=1)
194
195
date = db.Column(db.DateTime, default=datetime.now)
196
last_updated = db.Column(db.DateTime, default=datetime.now)
197
subject = db.Column(db.Unicode(384))
198
message = db.Column(db.UnicodeText)
199
repo = db.relationship("Repo", back_populates="posts")
200
owner = db.relationship("User", back_populates="posts")
201
parent = db.relationship("Post", back_populates="children", remote_side="Post.identifier")
202
children = db.relationship("Post", back_populates="parent", remote_side="Post.parent_id")
203
204
def __init__(self, owner, repo, parent, subject, message):
205
self.identifier = f"{repo.route}/{repo.last_post_id}"
206
self.number = repo.last_post_id
207
self.repo_name = repo.route
208
self.repo = repo
209
self.owner_name = owner.username
210
self.owner = owner
211
self.subject = subject
212
self.message = message
213
self.parent = parent
214
repo.last_post_id += 1
215
216
def update_date(self):
217
self.last_updated = datetime.now()
218
with db.session.no_autoflush:
219
if self.parent is not None:
220
self.parent.update_date()
221
222
223
class UserNotification(db.Model):
224
id = db.Column(db.Integer, primary_key=True)
225
user_username = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
226
notification_id = db.Column(db.BigInteger, db.ForeignKey("notification.id"))
227
attention_level = db.Column(db.SmallInteger, nullable=False) # 0 is read
228
read_time = db.Column(db.DateTime, nullable=True)
229
230
user = db.relationship("User", back_populates="notifications")
231
notification = db.relationship("Notification", back_populates="notifications")
232
233
__table_args__ = (db.UniqueConstraint("user_username", "notification_id", name="_user_notification_uc"),)
234
235
def __init__(self, user, notification, level):
236
self.user_username = user.username
237
self.notification_id = notification.id
238
self.attention_level = level
239
240
def read(self):
241
self.read_time = datetime.utcnow
242
self.attention_level = 0
243
244
245
class UserFollow(db.Model):
246
id = db.Column(db.Integer, primary_key=True)
247
follower_username = db.Column(db.String(32), db.ForeignKey("user.username", ondelete="CASCADE"), nullable=False)
248
followed_username = db.Column(db.String(32), db.ForeignKey("user.username", ondelete="CASCADE"), nullable=False)
249
250
follower = db.relationship("User", back_populates="followers", foreign_keys=[follower_username])
251
followed = db.relationship("User", back_populates="follows", foreign_keys=[followed_username])
252
253
def __init__(self, follower_username, followed_username):
254
self.follower_username = follower_username
255
self.followed_username = followed_username
256
257
258
class Notification(db.Model):
259
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
260
data = db.Column(db.dialects.postgresql.JSONB, nullable=False, default={})
261
notifications = db.relationship("UserNotification", back_populates="notification")
262
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now)
263
264
def __init__(self, json):
265
self.data = json
266
267
268
class PullRequest(db.Model):
269
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
270
head_route = db.Column(db.String(98), db.ForeignKey("repo.route", ondelete="CASCADE"), nullable=False)
271
base_route = db.Column(db.String(98), db.ForeignKey("repo.route", ondelete="CASCADE"), nullable=False)
272
owner_name = db.Column(db.String(32), db.ForeignKey("user.username"), nullable=False)
273
274
head = db.relationship("Repo", back_populates="heads", foreign_keys=[head_route])
275
base = db.relationship("Repo", back_populates="bases", foreign_keys=[base_route])
276
277
head_branch = db.Column(db.String(64), nullable=False)
278
base_branch = db.Column(db.String(64), nullable=False)
279
280
owner = db.relationship("User", back_populates="prs")
281
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now)
282
283
def __init__(self, head, head_branch, base, base_branch, owner):
284
self.head = head
285
self.base = base
286
self.head_branch = head_branch
287
self.base_branch = base_branch
288
self.owner = owner
289