1 import copy
2 import datetime
3 import os
4 import json
5 import base64
6 import uuid
7 from fnmatch import fnmatch
8
9 from sqlalchemy import outerjoin
10 from sqlalchemy.ext.associationproxy import association_proxy
11 from sqlalchemy.orm import column_property, validates
12 from six.moves.urllib.parse import urljoin
13 from libravatar import libravatar_url
14 import zlib
15
16 from copr_common.enums import ActionTypeEnum, BackendResultEnum, FailTypeEnum, ModuleStatusEnum, StatusEnum
17 from coprs import constants
18 from coprs import db
19 from coprs import helpers
20 from coprs import app
21
22 import itertools
23 import operator
24 from coprs.helpers import JSONEncodedDict
25
26 import gi
27 gi.require_version('Modulemd', '1.0')
28 from gi.repository import Modulemd
34
59
62 """
63 Records all the private information for a user.
64 """
65
66 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True,
67 nullable=False)
68
69
70 mail = db.Column(db.String(150), nullable=False)
71
72
73 timezone = db.Column(db.String(50), nullable=True)
74
75
76 api_login = db.Column(db.String(40), nullable=False, default="abc")
77 api_token = db.Column(db.String(40), nullable=False, default="abc")
78 api_token_expiration = db.Column(
79 db.Date, nullable=False, default=datetime.date(2000, 1, 1))
80
81
82 -class User(db.Model, helpers.Serializer):
83 __table__ = outerjoin(_UserPublic.__table__, _UserPrivate.__table__)
84 id = column_property(_UserPublic.__table__.c.id, _UserPrivate.__table__.c.user_id)
85
86 @property
88 """
89 Return the short username of the user, e.g. bkabrda
90 """
91
92 return self.username
93
95 """
96 Get permissions of this user for the given copr.
97 Caches the permission during one request,
98 so use this if you access them multiple times
99 """
100
101 if not hasattr(self, "_permissions_for_copr"):
102 self._permissions_for_copr = {}
103 if copr.name not in self._permissions_for_copr:
104 self._permissions_for_copr[copr.name] = (
105 CoprPermission.query
106 .filter_by(user=self)
107 .filter_by(copr=copr)
108 .first()
109 )
110 return self._permissions_for_copr[copr.name]
111
131
132 @property
138
139 @property
142
144 """
145 :type group: Group
146 """
147 if group.fas_name in self.user_teams:
148 return True
149 else:
150 return False
151
170
171 @property
173
174 return ["id", "name"]
175
176 @property
178 """
179 Get number of coprs for this user.
180 """
181
182 return (Copr.query.filter_by(user=self).
183 filter_by(deleted=False).
184 filter_by(group_id=None).
185 count())
186
187 @property
189 """
190 Return url to libravatar image.
191 """
192
193 try:
194 return libravatar_url(email=self.mail, https=True)
195 except IOError:
196 return ""
197
198
199 -class _CoprPublic(db.Model, helpers.Serializer, CoprSearchRelatedData):
200 """
201 Represents public part of a single copr (personal repo with builds, mock
202 chroots, etc.).
203 """
204
205 __tablename__ = "copr"
206 __table_args__ = (
207 db.Index('copr_name_group_id_idx', 'name', 'group_id'),
208 )
209
210 id = db.Column(db.Integer, primary_key=True)
211
212 name = db.Column(db.String(100), nullable=False)
213 homepage = db.Column(db.Text)
214 contact = db.Column(db.Text)
215
216
217 repos = db.Column(db.Text)
218
219 created_on = db.Column(db.Integer)
220
221 description = db.Column(db.Text)
222 instructions = db.Column(db.Text)
223 deleted = db.Column(db.Boolean, default=False)
224 playground = db.Column(db.Boolean, default=False)
225
226
227 auto_createrepo = db.Column(db.Boolean, default=True)
228
229
230 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True)
231 group_id = db.Column(db.Integer, db.ForeignKey("group.id"))
232 forked_from_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
233
234
235 build_enable_net = db.Column(db.Boolean, default=True,
236 server_default="1", nullable=False)
237
238 unlisted_on_hp = db.Column(db.Boolean, default=False, nullable=False)
239
240
241 latest_indexed_data_update = db.Column(db.Integer)
242
243
244 persistent = db.Column(db.Boolean, default=False, nullable=False, server_default="0")
245
246
247 auto_prune = db.Column(db.Boolean, default=True, nullable=False, server_default="1")
248
249
250 use_bootstrap_container = db.Column(db.Boolean, default=False, nullable=False, server_default="0")
251
252
253 follow_fedora_branching = db.Column(db.Boolean, default=True, nullable=False, server_default="1")
254
255
256 scm_repo_url = db.Column(db.Text)
257 scm_api_type = db.Column(db.Text)
258
259
260 delete_after = db.Column(db.DateTime, index=True, nullable=True)
261
262 __mapper_args__ = {
263 "order_by": created_on.desc()
264 }
265
268 """
269 Represents private part of a single copr (personal repo with builds, mock
270 chroots, etc.).
271 """
272
273 __table_args__ = (
274 db.Index('copr_private_webhook_secret', 'webhook_secret'),
275 )
276
277
278 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), index=True,
279 nullable=False, primary_key=True)
280
281
282 webhook_secret = db.Column(db.String(100))
283
284
285 scm_api_auth_json = db.Column(db.Text)
286
287
288 -class Copr(db.Model, helpers.Serializer):
289 """
290 Represents private a single copr (personal repo with builds, mock chroots,
291 etc.).
292 """
293
294
295
296 __table__ = outerjoin(_CoprPublic.__table__, _CoprPrivate.__table__)
297 id = column_property(
298 _CoprPublic.__table__.c.id,
299 _CoprPrivate.__table__.c.copr_id
300 )
301
302
303 user = db.relationship("User", backref=db.backref("coprs"))
304 group = db.relationship("Group", backref=db.backref("groups"))
305 mock_chroots = association_proxy("copr_chroots", "mock_chroot")
306 forked_from = db.relationship("Copr",
307 remote_side=_CoprPublic.id,
308 foreign_keys=[_CoprPublic.forked_from_id],
309 backref=db.backref("forks"))
310
311 @property
312 - def main_dir(self):
313 """
314 Return main copr dir for a Copr
315 """
316 return CoprDir.query.filter(CoprDir.copr_id==self.id).filter(CoprDir.main==True).one()
317
318 @property
323
324 @property
326 """
327 Return True if copr belongs to a group
328 """
329 return self.group is not None
330
331 @property
337
338 @property
344
345 @property
347 """
348 Return repos of this copr as a list of strings
349 """
350 return self.repos.split()
351
352 @property
358
359 @property
361 """
362 :rtype: list of CoprChroot
363 """
364 return [c for c in self.copr_chroots if c.is_active]
365
366 @property
368 """
369 Return list of active mock_chroots of this copr
370 """
371 return sorted(self.active_chroots, key=lambda ch: ch.name)
372
373 @property
377
378 @property
380 """
381 Return list of active mock_chroots of this copr
382 """
383 chroots = [("{} {}".format(c.os_release, c.os_version), c.arch) for c in self.active_chroots_sorted]
384 output = []
385 for os, chs in itertools.groupby(chroots, operator.itemgetter(0)):
386 output.append((os, [ch[1] for ch in chs]))
387
388 return output
389
390 @property
392 """
393 Return number of builds in this copr
394 """
395 return len(self.builds)
396
397 @property
400
401 @disable_createrepo.setter
404
405 @property
408
409 @property
421
427
428 @property
431
432 @property
435
436 @property
441
442 @property
444 return "-".join([self.owner_name.replace("@", "group_"), self.name])
445
446 @property
448 return "/".join([self.repo_url, "modules"])
449
450 - def to_dict(self, private=False, show_builds=True, show_chroots=True):
451 result = {}
452 for key in ["id", "name", "description", "instructions"]:
453 result[key] = str(copy.copy(getattr(self, key)))
454 result["owner"] = self.owner_name
455 return result
456
457 @property
462
465
466 @property
469
470 @enable_net.setter
473
476
477 @property
479 if self.delete_after is None:
480 return None
481
482 delta = self.delete_after - datetime.datetime.now()
483 return delta.days if delta.days > 0 else 0
484
485 @delete_after_days.setter
494
495 @property
500
501 @property
508
510 """
511 Association class for Copr<->Permission relation
512 """
513
514
515
516 copr_builder = db.Column(db.SmallInteger, default=0)
517
518 copr_admin = db.Column(db.SmallInteger, default=0)
519
520
521 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True)
522 user = db.relationship("User", backref=db.backref("copr_permissions"))
523 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
524 copr = db.relationship("Copr", backref=db.backref("copr_permissions"))
525
527 if name == 'admin':
528 self.copr_admin = value
529 elif name == 'builder':
530 self.copr_builder = value
531 else:
532 raise KeyError("{0} is not a valid copr permission".format(name))
533
540
543 """
544 Represents one of data directories for a copr.
545 """
546 id = db.Column(db.Integer, primary_key=True)
547
548 name = db.Column(db.Text, index=True)
549 main = db.Column(db.Boolean, default=False, server_default="0", nullable=False)
550
551 ownername = db.Column(db.Text, index=True, nullable=False)
552
553 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), index=True, nullable=False)
554 copr = db.relationship("Copr", backref=db.backref("dirs"))
555
556 __table_args__ = (
557 db.Index('only_one_main_copr_dir', copr_id, main,
558 unique=True, postgresql_where=(main==True)),
559
560 db.UniqueConstraint('ownername', 'name',
561 name='ownername_copr_dir_uniq'),
562 )
563
568
569 @property
572
573 @property
576
577 @property
581
582 @property
588
589
590 -class Package(db.Model, helpers.Serializer, CoprSearchRelatedData):
591 """
592 Represents a single package in a project_dir.
593 """
594
595 __table_args__ = (
596 db.UniqueConstraint('copr_dir_id', 'name', name='packages_copr_dir_pkgname'),
597 db.Index('package_webhook_sourcetype', 'webhook_rebuild', 'source_type'),
598 )
599
604
605 id = db.Column(db.Integer, primary_key=True)
606 name = db.Column(db.String(100), nullable=False)
607
608 source_type = db.Column(db.Integer, default=helpers.BuildSourceEnum("unset"))
609
610 source_json = db.Column(db.Text)
611
612 webhook_rebuild = db.Column(db.Boolean, default=False)
613
614 enable_net = db.Column(db.Boolean, default=False, server_default="0", nullable=False)
615
616
617 max_builds = db.Column(db.Integer, index=True)
618
619 @validates('max_builds')
621 return None if value == 0 else value
622
623 builds = db.relationship("Build", order_by="Build.id")
624
625
626 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), index=True)
627 copr = db.relationship("Copr", backref=db.backref("packages"))
628
629 copr_dir_id = db.Column(db.Integer, db.ForeignKey("copr_dir.id"), index=True)
630 copr_dir = db.relationship("CoprDir", backref=db.backref("packages"))
631
632
633
634 chroot_blacklist_raw = db.Column(db.Text)
635
636 @property
639
640 @property
645
646 @property
649
650 @property
652 """
653 Package's source type (and source_json) is being derived from its first build, which works except
654 for "link" and "upload" cases. Consider these being equivalent to source_type being unset.
655 """
656 return self.source_type and self.source_type_text != "link" and self.source_type_text != "upload"
657
658 @property
663
664 @property
670
676
677 - def to_dict(self, with_latest_build=False, with_latest_succeeded_build=False, with_all_builds=False):
678 package_dict = super(Package, self).to_dict()
679 package_dict['source_type'] = helpers.BuildSourceEnum(package_dict['source_type'])
680
681 if with_latest_build:
682 build = self.last_build(successful=False)
683 package_dict['latest_build'] = build.to_dict(with_chroot_states=True) if build else None
684 if with_latest_succeeded_build:
685 build = self.last_build(successful=True)
686 package_dict['latest_succeeded_build'] = build.to_dict(with_chroot_states=True) if build else None
687 if with_all_builds:
688 package_dict['builds'] = [build.to_dict(with_chroot_states=True) for build in reversed(self.builds)]
689
690 return package_dict
691
694
695
696 @property
698 if not self.chroot_blacklist_raw:
699 return []
700
701 blacklisted = []
702 for pattern in self.chroot_blacklist_raw.split(','):
703 pattern = pattern.strip()
704 if not pattern:
705 continue
706 blacklisted.append(pattern)
707
708 return blacklisted
709
710
711 @staticmethod
713 for pattern in patterns:
714 if fnmatch(chroot.name, pattern):
715 return True
716 return False
717
718
719 @property
720 - def main_pkg(self):
721 if self.copr_dir.main:
722 return self
723
724 main_pkg = Package.query.filter_by(
725 name=self.name,
726 copr_dir_id=self.copr.main_dir.id
727 ).first()
728 return main_pkg
729
730
731 @property
743
744
745 -class Build(db.Model, helpers.Serializer):
746 """
747 Representation of one build in one copr
748 """
749
750 SCM_COMMIT = 'commit'
751 SCM_PULL_REQUEST = 'pull-request'
752
753 __table_args__ = (db.Index('build_canceled', "canceled"),
754 db.Index('build_order', "is_background", "id"),
755 db.Index('build_filter', "source_type", "canceled"),
756 db.Index('build_canceled_is_background_source_status_id_idx', 'canceled', "is_background", "source_status", "id"),
757 )
758
772
773 id = db.Column(db.Integer, primary_key=True)
774
775 pkgs = db.Column(db.Text)
776
777 built_packages = db.Column(db.Text)
778
779 pkg_version = db.Column(db.Text)
780
781 canceled = db.Column(db.Boolean, default=False)
782
783 repos = db.Column(db.Text)
784
785
786 submitted_on = db.Column(db.Integer, nullable=False)
787
788 result_dir = db.Column(db.Text, default='', server_default='', nullable=False)
789
790 memory_reqs = db.Column(db.Integer, default=constants.DEFAULT_BUILD_MEMORY)
791
792 timeout = db.Column(db.Integer, default=constants.DEFAULT_BUILD_TIMEOUT)
793
794 enable_net = db.Column(db.Boolean, default=False,
795 server_default="0", nullable=False)
796
797 source_type = db.Column(db.Integer, default=helpers.BuildSourceEnum("unset"))
798
799 source_json = db.Column(db.Text)
800
801 fail_type = db.Column(db.Integer, default=FailTypeEnum("unset"))
802
803 is_background = db.Column(db.Boolean, default=False, server_default="0", nullable=False)
804
805 source_status = db.Column(db.Integer, default=StatusEnum("waiting"))
806 srpm_url = db.Column(db.Text)
807
808
809 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), index=True)
810 user = db.relationship("User", backref=db.backref("builds"))
811 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), index=True)
812 copr = db.relationship("Copr", backref=db.backref("builds"))
813 package_id = db.Column(db.Integer, db.ForeignKey("package.id"), index=True)
814 package = db.relationship("Package")
815
816 chroots = association_proxy("build_chroots", "mock_chroot")
817
818 batch_id = db.Column(db.Integer, db.ForeignKey("batch.id"))
819 batch = db.relationship("Batch", backref=db.backref("builds"))
820
821 module_id = db.Column(db.Integer, db.ForeignKey("module.id"), index=True)
822 module = db.relationship("Module", backref=db.backref("builds"))
823
824 copr_dir_id = db.Column(db.Integer, db.ForeignKey("copr_dir.id"), index=True)
825 copr_dir = db.relationship("CoprDir", backref=db.backref("builds"))
826
827
828 scm_object_id = db.Column(db.Text)
829 scm_object_type = db.Column(db.Text)
830 scm_object_url = db.Column(db.Text)
831
832
833 update_callback = db.Column(db.Text)
834
835 @property
838
839 @property
842
843 @property
846
847 @property
850
851 @property
854
855 @property
856 - def fail_type_text(self):
857 return FailTypeEnum(self.fail_type)
858
859 @property
861 if self.repos is None:
862 return list()
863 else:
864 return self.repos.split()
865
866 @property
869
870 @property
872 return "{:08d}".format(self.id)
873
879
880 @property
882 if app.config["COPR_DIST_GIT_LOGS_URL"]:
883 return "{}/{}.log".format(app.config["COPR_DIST_GIT_LOGS_URL"],
884 self.task_id.replace('/', '_'))
885 return None
886
887 @property
893
894 @property
899
900 @property
903
904 @property
912
913 @property
916
917 @property
924
925 @property
928
929 @property
932
933 @property
936
937 @property
946
947 @property
950
952 """
953 Get build chroots with states which present in `states` list
954 If states == None, function returns build_chroots
955 """
956 chroot_states_map = dict(zip(self.build_chroots, self.chroot_states))
957 if statuses is not None:
958 statuses = set(statuses)
959 else:
960 return self.build_chroots
961
962 return [
963 chroot for chroot, status in chroot_states_map.items()
964 if status in statuses
965 ]
966
967 @property
969 return {b.name: b for b in self.build_chroots}
970
971 @property
973 """
974 Return build status.
975 """
976 if self.canceled:
977 return StatusEnum("canceled")
978
979 use_src_statuses = ["starting", "pending", "running", "failed"]
980 if self.source_status in [StatusEnum(s) for s in use_src_statuses]:
981 return self.source_status
982
983 for state in ["running", "starting", "pending", "failed", "succeeded", "skipped", "forked", "waiting"]:
984 if StatusEnum(state) in self.chroot_states:
985 if state == "waiting":
986 return self.source_status
987 else:
988 return StatusEnum(state)
989
990 return None
991
992 @property
994 """
995 Return text representation of status of this build.
996 """
997 if self.status != None:
998 return StatusEnum(self.status)
999 return "unknown"
1000
1001 @property
1003 """
1004 Find out if this build is cancelable.
1005 """
1006 return not self.finished and self.status != StatusEnum("starting")
1007
1008 @property
1010 """
1011 Find out if this build is repeatable.
1012
1013 Build is repeatable only if sources has been imported.
1014 """
1015 return self.source_status == StatusEnum("succeeded")
1016
1017 @property
1019 """
1020 Find out if this build is in finished state.
1021
1022 Build is finished only if all its build_chroots are in finished state or
1023 the build was canceled.
1024 """
1025 if self.canceled:
1026 return True
1027 if not self.build_chroots:
1028 return StatusEnum(self.source_status) in helpers.FINISHED_STATUSES
1029 return all([chroot.finished for chroot in self.build_chroots])
1030
1031 @property
1034
1035 @property
1037 """
1038 Find out if this build is persistent.
1039
1040 This property is inherited from the project.
1041 """
1042 return self.copr.persistent
1043
1044 @property
1046 try:
1047 return self.package.name
1048 except:
1049 return None
1050
1051 - def to_dict(self, options=None, with_chroot_states=False):
1064
1067 """
1068 1:N mapping: branch -> chroots
1069 """
1070
1071
1072 name = db.Column(db.String(50), primary_key=True)
1073
1074
1075 -class MockChroot(db.Model, helpers.Serializer):
1076 """
1077 Representation of mock chroot
1078 """
1079
1080 __table_args__ = (
1081 db.UniqueConstraint('os_release', 'os_version', 'arch', name='mock_chroot_uniq'),
1082 )
1083
1084 id = db.Column(db.Integer, primary_key=True)
1085
1086 os_release = db.Column(db.String(50), nullable=False)
1087
1088 os_version = db.Column(db.String(50), nullable=False)
1089
1090 arch = db.Column(db.String(50), nullable=False)
1091 is_active = db.Column(db.Boolean, default=True)
1092
1093
1094 distgit_branch_name = db.Column(db.String(50),
1095 db.ForeignKey("dist_git_branch.name"),
1096 nullable=False)
1097
1098 distgit_branch = db.relationship("DistGitBranch",
1099 backref=db.backref("chroots"))
1100
1101
1102
1103 final_prunerepo_done = db.Column(db.Boolean, default=False, server_default="0", nullable=False)
1104
1105 @classmethod
1114
1115 @property
1117 """
1118 Textual representation of name of this chroot
1119 """
1120 return "{}-{}-{}".format(self.os_release, self.os_version, self.arch)
1121
1122 @property
1124 """
1125 Textual representation of name of this or release
1126 """
1127 return "{}-{}".format(self.os_release, self.os_version)
1128
1129 @property
1131 """
1132 Textual representation of the operating system name
1133 """
1134 return "{0} {1}".format(self.os_release, self.os_version)
1135
1136 @property
1141
1142
1143 -class CoprChroot(db.Model, helpers.Serializer):
1144 """
1145 Representation of Copr<->MockChroot relation
1146 """
1147
1148 buildroot_pkgs = db.Column(db.Text)
1149 repos = db.Column(db.Text, default="", server_default="", nullable=False)
1150 mock_chroot_id = db.Column(
1151 db.Integer, db.ForeignKey("mock_chroot.id"), primary_key=True)
1152 mock_chroot = db.relationship(
1153 "MockChroot", backref=db.backref("copr_chroots"))
1154 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), primary_key=True)
1155 copr = db.relationship("Copr",
1156 backref=db.backref(
1157 "copr_chroots",
1158 single_parent=True,
1159 cascade="all,delete,delete-orphan"))
1160
1161 comps_zlib = db.Column(db.LargeBinary(), nullable=True)
1162 comps_name = db.Column(db.String(127), nullable=True)
1163
1164 module_md_zlib = db.Column(db.LargeBinary(), nullable=True)
1165 module_md_name = db.Column(db.String(127), nullable=True)
1166
1167 with_opts = db.Column(db.Text, default="", server_default="", nullable=False)
1168 without_opts = db.Column(db.Text, default="", server_default="", nullable=False)
1169
1170
1171
1172 delete_after = db.Column(db.DateTime, index=True)
1173 delete_notify = db.Column(db.DateTime, index=True)
1174
1176 if isinstance(comps_xml, str):
1177 data = comps_xml.encode("utf-8")
1178 else:
1179 data = comps_xml
1180 self.comps_zlib = zlib.compress(data)
1181
1183 if isinstance(module_md_yaml, str):
1184 data = module_md_yaml.encode("utf-8")
1185 else:
1186 data = module_md_yaml
1187 self.module_md_zlib = zlib.compress(data)
1188
1189 @property
1192
1193 @property
1195 return (self.repos or "").split()
1196
1197 @property
1201
1202 @property
1206
1207 @property
1213
1214 @property
1220
1221 @property
1224
1225 @property
1228
1229 @property
1231 if not self.delete_after:
1232 return None
1233 now = datetime.datetime.now()
1234 days = (self.delete_after - now).days
1235 return days if days > 0 else 0
1236
1238 options = {"__columns_only__": [
1239 "buildroot_pkgs", "repos", "comps_name", "copr_id", "with_opts", "without_opts"
1240 ]}
1241 d = super(CoprChroot, self).to_dict(options=options)
1242 d["mock_chroot"] = self.mock_chroot.name
1243 return d
1244
1247 """
1248 Representation of Build<->MockChroot relation
1249 """
1250
1251 __table_args__ = (db.Index('build_chroot_status_started_on_idx', "status", "started_on"),)
1252
1253 mock_chroot_id = db.Column(db.Integer, db.ForeignKey("mock_chroot.id"),
1254 primary_key=True)
1255 mock_chroot = db.relationship("MockChroot", backref=db.backref("builds"))
1256 build_id = db.Column(db.Integer, db.ForeignKey("build.id"),
1257 primary_key=True)
1258 build = db.relationship("Build", backref=db.backref("build_chroots"))
1259 git_hash = db.Column(db.String(40))
1260 status = db.Column(db.Integer, default=StatusEnum("waiting"))
1261
1262 started_on = db.Column(db.Integer, index=True)
1263 ended_on = db.Column(db.Integer, index=True)
1264
1265
1266 result_dir = db.Column(db.Text, default='', server_default='', nullable=False)
1267
1268 build_requires = db.Column(db.Text)
1269
1270 @property
1272 """
1273 Textual representation of name of this chroot
1274 """
1275 return self.mock_chroot.name
1276
1277 @property
1279 """
1280 Return text representation of status of this build chroot
1281 """
1282 if self.status is not None:
1283 return StatusEnum(self.status)
1284 return "unknown"
1285
1286 @property
1289
1290 @property
1293
1294 @property
1306
1307 @property
1313
1314
1315 -class LegalFlag(db.Model, helpers.Serializer):
1316 id = db.Column(db.Integer, primary_key=True)
1317
1318 raise_message = db.Column(db.Text)
1319
1320 raised_on = db.Column(db.Integer)
1321
1322 resolved_on = db.Column(db.Integer)
1323
1324
1325 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"), nullable=True)
1326
1327 copr = db.relationship(
1328 "Copr", backref=db.backref("legal_flags", cascade="all"))
1329
1330 reporter_id = db.Column(db.Integer, db.ForeignKey("user.id"))
1331 reporter = db.relationship("User",
1332 backref=db.backref("legal_flags_raised"),
1333 foreign_keys=[reporter_id],
1334 primaryjoin="LegalFlag.reporter_id==User.id")
1335
1336 resolver_id = db.Column(
1337 db.Integer, db.ForeignKey("user.id"), nullable=True)
1338 resolver = db.relationship("User",
1339 backref=db.backref("legal_flags_resolved"),
1340 foreign_keys=[resolver_id],
1341 primaryjoin="LegalFlag.resolver_id==User.id")
1342
1343
1344 -class Action(db.Model, helpers.Serializer):
1345 """
1346 Representation of a custom action that needs
1347 backends cooperation/admin attention/...
1348 """
1349
1350 id = db.Column(db.Integer, primary_key=True)
1351
1352 action_type = db.Column(db.Integer, nullable=False)
1353
1354 object_type = db.Column(db.String(20))
1355
1356 object_id = db.Column(db.Integer)
1357
1358 old_value = db.Column(db.String(255))
1359 new_value = db.Column(db.String(255))
1360
1361 data = db.Column(db.Text)
1362
1363 result = db.Column(
1364 db.Integer, default=BackendResultEnum("waiting"))
1365
1366 message = db.Column(db.Text)
1367
1368 created_on = db.Column(db.Integer)
1369
1370 ended_on = db.Column(db.Integer)
1371
1374
1383
1396
1397
1398 -class Krb5Login(db.Model, helpers.Serializer):
1399 """
1400 Represents additional user information for kerberos authentication.
1401 """
1402
1403 __tablename__ = "krb5_login"
1404
1405
1406 user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
1407
1408
1409 config_name = db.Column(db.String(30), nullable=False, primary_key=True)
1410
1411
1412 primary = db.Column(db.String(80), nullable=False, primary_key=True)
1413
1414 user = db.relationship("User", backref=db.backref("krb5_logins"))
1415
1418 """
1419 Generic store for simple statistics.
1420 """
1421
1422 name = db.Column(db.String(127), primary_key=True)
1423 counter_type = db.Column(db.String(30))
1424
1425 counter = db.Column(db.Integer, default=0, server_default="0")
1426
1427
1428 -class Group(db.Model, helpers.Serializer):
1429
1430 """
1431 Represents FAS groups and their aliases in Copr
1432 """
1433
1434 id = db.Column(db.Integer, primary_key=True)
1435 name = db.Column(db.String(127))
1436
1437
1438 fas_name = db.Column(db.String(127))
1439
1440 @property
1442 return u"@{}".format(self.name)
1443
1446
1449
1450
1451 -class Batch(db.Model):
1452 id = db.Column(db.Integer, primary_key=True)
1453 blocked_by_id = db.Column(db.Integer, db.ForeignKey("batch.id"), nullable=True)
1454 blocked_by = db.relationship("Batch", remote_side=[id])
1455
1456 @property
1459
1460
1461 -class Module(db.Model, helpers.Serializer):
1462 id = db.Column(db.Integer, primary_key=True)
1463 name = db.Column(db.String(100), nullable=False)
1464 stream = db.Column(db.String(100), nullable=False)
1465 version = db.Column(db.BigInteger, nullable=False)
1466 summary = db.Column(db.String(100), nullable=False)
1467 description = db.Column(db.Text)
1468 created_on = db.Column(db.Integer, nullable=True)
1469
1470
1471
1472
1473
1474
1475
1476 yaml_b64 = db.Column(db.Text)
1477
1478
1479 copr_id = db.Column(db.Integer, db.ForeignKey("copr.id"))
1480 copr = db.relationship("Copr", backref=db.backref("modules"))
1481
1482 __table_args__ = (
1483 db.UniqueConstraint("copr_id", "name", "stream", "version", name="copr_name_stream_version_uniq"),
1484 )
1485
1486 @property
1488 return base64.b64decode(self.yaml_b64)
1489
1490 @property
1492 mmd = Modulemd.ModuleStream()
1493 mmd.import_from_string(self.yaml.decode("utf-8"))
1494 return mmd
1495
1496 @property
1499
1500 @property
1503
1504 @property
1507
1508 @property
1510 """
1511 Return numeric representation of status of this build
1512 """
1513 if any(b for b in self.builds if b.status == StatusEnum("failed")):
1514 return ModuleStatusEnum("failed")
1515 return self.action.result if self.action else ModuleStatusEnum("pending")
1516
1517 @property
1519 """
1520 Return text representation of status of this build
1521 """
1522 return ModuleStatusEnum(self.status)
1523
1524 @property
1527
1528 @property
1531
1532 @property
1534 return {k: v.get_rpms().get() for k, v in self.modulemd.get_profiles().items()}
1535
1542