1 import datetime
2
3 from sqlalchemy.ext.associationproxy import association_proxy
4 from libravatar import libravatar_url
5
6 from coprs import constants
7 from coprs import db
8 from coprs import helpers
9
10
11 -class User(db.Model, helpers.Serializer):
12
13 """
14 Represents user of the copr frontend
15 """
16
17 id = db.Column(db.Integer, primary_key=True)
18
19 openid_name = db.Column(db.String(100), nullable=False)
20
21 mail = db.Column(db.String(150), nullable=False)
22
23 timezone = db.Column(db.String(50), nullable=True)
24
25
26 proven = db.Column(db.Boolean, default=False)
27
28 admin = db.Column(db.Boolean, default=False)
29
30 api_login = db.Column(db.String(40), nullable=False, default="abc")
31 api_token = db.Column(db.String(40), nullable=False, default="abc")
32 api_token_expiration = db.Column(
33 db.Date, nullable=False, default=datetime.date(2000, 1, 1))
34
35 @property
37 """
38 Return the short username of the user, e.g. bkabrda
39 """
40
41 return self.openid_name.replace(
42 ".id.fedoraproject.org/", "").replace("http://", "")
43
45 """
46 Get permissions of this user for the given copr.
47 Caches the permission during one request,
48 so use this if you access them multiple times
49 """
50
51 if not hasattr(self, "_permissions_for_copr"):
52 self._permissions_for_copr = {}
53 if not copr.name in self._permissions_for_copr:
54 self._permissions_for_copr[copr.name] = (CoprPermission.query
55 .filter_by(user=self).filter_by(copr=copr).first())
56 return self._permissions_for_copr[copr.name]
57
73
89
90 @classmethod
92 """
93 Create proper openid_name from short name.
94
95 >>> user.openid_name == User.openidize_name(user.name)
96 True
97 """
98
99 return "http://{0}.id.fedoraproject.org/".format(name)
100
101 @property
103
104 return ["id", "name"]
105
106 @property
108 """
109 Get number of coprs for this user.
110 """
111
112 return (Copr.query.filter_by(owner=self).
113 filter_by(deleted=False).
114 count())
115
116 @property
118 """
119 Return url to libravatar image.
120 """
121
122 try:
123 return libravatar_url(email=self.mail, https=True)
124 except IOError:
125 return ""
126
127
128 -class Copr(db.Model, helpers.Serializer):
129
130 """
131 Represents a single copr (private repo with builds, mock chroots, etc.).
132 """
133
134 id = db.Column(db.Integer, primary_key=True)
135
136 name = db.Column(db.String(100), nullable=False)
137
138
139 repos = db.Column(db.Text)
140
141 created_on = db.Column(db.Integer)
142
143 description = db.Column(db.Text)
144 instructions = db.Column(db.Text)
145 deleted = db.Column(db.Boolean, default=False)
146 playground = db.Column(db.Boolean, default=False)
147
148
149 owner_id = db.Column(db.Integer, db.ForeignKey("user.id"))
150 owner = db.relationship("User", backref=db.backref("coprs"))
151 mock_chroots = association_proxy("copr_chroots", "mock_chroot")
152
153 __mapper_args__ = {
154 "order_by": created_on.desc()
155 }
156
157 @property
159 """
160 Return repos of this copr as a list of strings
161 """
162 return self.repos.split()
163
164 @property
166 """
167 Return list of active mock_chroots of this copr
168 """
169
170 return filter(lambda x: x.is_active, self.mock_chroots)
171
172 @property
174 """
175 Return number of builds in this copr
176 """
177
178 return len(self.builds)
179
181 """
182 Return object of chroot, if is related to our copr or None
183 """
184
185 result = None
186
187
188 for copr_chroot in self.copr_chroots:
189 if copr_chroot.mock_chroot_id == chroot.id:
190 result = copr_chroot
191 break
192 return result
193
206
207 @property
217
220
221 """
222 Association class for Copr<->Permission relation
223 """
224
225
226
227 copr_builder = db.Column(db.SmallInteger, default=0)
228
229 copr_admin = db.Column(db.SmallInteger, default=0)
230
231
232 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
233 user = db.relationship("User", backref=db.backref("copr_permissions"))
234 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
235 copr = db.relationship("Copr", backref=db.backref("copr_permissions"))
236
237
238 -class Build(db.Model, helpers.Serializer):
239
240 """
241 Representation of one build in one copr
242 """
243
244 id = db.Column(db.Integer, primary_key=True)
245
246 pkgs = db.Column(db.Text)
247
248 built_packages = db.Column(db.Text)
249
250 pkg_version = db.Column(db.Text)
251
252 canceled = db.Column(db.Boolean, default=False)
253
254 repos = db.Column(db.Text)
255
256
257 submitted_on = db.Column(db.Integer, nullable=False)
258 started_on = db.Column(db.Integer)
259 ended_on = db.Column(db.Integer)
260
261 results = db.Column(db.Text)
262
263 memory_reqs = db.Column(db.Integer, default=constants.DEFAULT_BUILD_MEMORY)
264
265 timeout = db.Column(db.Integer, default=constants.DEFAULT_BUILD_TIMEOUT)
266
267
268 user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
269 user = db.relationship("User", backref=db.backref("builds"))
270 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
271 copr = db.relationship("Copr", backref=db.backref("builds"))
272
273 chroots = association_proxy("build_chroots", "mock_chroot")
274
275 @property
277 return map(lambda chroot: chroot.status, self.build_chroots)
278
279 @property
286
287 @property
292
293 @property
305
306 @property
308 """
309 Return text representation of status of this build
310 """
311
312 if self.status is not None:
313 return helpers.StatusEnum(self.status)
314
315 return "unknown"
316
317 @property
319 """
320 Find out if this build is cancelable.
321
322 Build is cancelabel only when it's pending (not started)
323 """
324
325 return self.status == helpers.StatusEnum("pending")
326
327 @property
338
339 @property
341 """
342 Find out if this build is deletable.
343
344 Build is deletable only when it's finished. (also means cancelled)
345 It is important to remember that "failed" state doesn't ultimately
346 mean it's finished - so we need to check whether the "ended_on"
347 property has been set.
348 """
349
350 return self.state in ["succeeded", "canceled", "skipped"] or \
351 (self.state == "failed" and self.ended_on is not None)
352
353
354 -class MockChroot(db.Model, helpers.Serializer):
355
356 """
357 Representation of mock chroot
358 """
359
360 id = db.Column(db.Integer, primary_key=True)
361
362 os_release = db.Column(db.String(50), nullable=False)
363
364 os_version = db.Column(db.String(50), nullable=False)
365
366 arch = db.Column(db.String(50), nullable=False)
367 is_active = db.Column(db.Boolean, default=True)
368
369 @property
371 """
372 Textual representation of name of this chroot
373 """
374 return "{0}-{1}-{2}".format(
375 self.os_release, self.os_version, self.arch)
376
377 @property
379 """
380 Textual representation of the operating system name
381 """
382 return "{0} {1}".format(self.os_release, self.os_version)
383
384
385 -class CoprChroot(db.Model, helpers.Serializer):
386
387 """
388 Representation of Copr<->MockChroot relation
389 """
390
391 buildroot_pkgs = db.Column(db.Text)
392 mock_chroot_id = db.Column(
393 db.Integer, db.ForeignKey("mock_chroot.id"), primary_key=True)
394 mock_chroot = db.relationship(
395 "MockChroot", backref=db.backref("copr_chroots"))
396 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
397 copr = db.relationship("Copr",
398 backref=db.backref(
399 "copr_chroots",
400 single_parent=True,
401 cascade="all,delete,delete-orphan"))
402
405
406 """
407 Representation of Build<->MockChroot relation
408 """
409
410 mock_chroot_id = db.Column(db.Integer, db.ForeignKey("mock_chroot.id"),
411 primary_key=True)
412 mock_chroot = db.relationship("MockChroot", backref=db.backref("builds"))
413 build_id = db.Column(db.Integer, db.ForeignKey("build.id"),
414 primary_key=True)
415 build = db.relationship("Build", backref=db.backref("build_chroots"))
416 status = db.Column(db.Integer, default=helpers.StatusEnum("pending"))
417
418 @property
420 """
421 Textual representation of name of this chroot
422 """
423
424 return self.mock_chroot.name
425
426 @property
428 """
429 Return text representation of status of this build chroot
430 """
431
432 if self.status is not None:
433 return helpers.StatusEnum(self.status)
434
435 return "unknown"
436
437
438 -class LegalFlag(db.Model, helpers.Serializer):
439 id = db.Column(db.Integer, primary_key=True)
440
441 raise_message = db.Column(db.Text)
442
443 raised_on = db.Column(db.Integer)
444
445 resolved_on = db.Column(db.Integer)
446
447
448 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), nullable=True)
449
450 copr = db.relationship(
451 "Copr", backref=db.backref("legal_flags", cascade="all"))
452
453 reporter_id = db.Column(db.Integer, db.ForeignKey("user.id"))
454 reporter = db.relationship("User",
455 backref=db.backref("legal_flags_raised"),
456 foreign_keys=[reporter_id],
457 primaryjoin="LegalFlag.reporter_id==User.id")
458
459 resolver_id = db.Column(
460 db.Integer, db.ForeignKey("user.id"), nullable=True)
461 resolver = db.relationship("User",
462 backref=db.backref("legal_flags_resolved"),
463 foreign_keys=[resolver_id],
464 primaryjoin="LegalFlag.resolver_id==User.id")
465
466
467 -class Action(db.Model, helpers.Serializer):
511