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