1 import datetime
2 import time
3
4 import sqlalchemy
5 from sqlalchemy.ext.associationproxy import association_proxy
6 from libravatar import libravatar_url
7
8 from coprs import constants
9 from coprs import db
10 from coprs import helpers
14 """Usage:
15 SQLAlchObject.to_dict() => returns a flat dict of the object
16 SQLAlchObject.to_dict({'foo': {}}) => returns a dict of the object and will include a
17 flat dict of object foo inside of that
18 SQLAlchObject.to_dict({'foo': {'bar': {}}, 'spam': {}}) => returns a dict of the object,
19 which will include dict of foo (which will include dict of bar) and dict of spam
20
21 Options can also contain two special values: __columns_only__ and __columns_except__
22 If present, the first makes only specified fiels appear, the second removes specified fields.
23 Both of these fields must be either strings (only works for one field) or lists (for one and more fields).
24 SQLAlchObject.to_dict({'foo': {'__columns_except__': ['id']}, '__columns_only__': 'name'}) =>
25 The SQLAlchObject will only put its 'name' into the resulting dict, while 'foo' all of its fields except 'id'.
26
27 Options can also specify whether to include foo_id when displaying related foo object
28 (__included_ids__, defaults to True). This doesn't apply when __columns_only__ is specified.
29 """
30 result = {}
31 columns = self.serializable_attributes
32
33 if options.has_key('__columns_only__'):
34 columns = options['__columns_only__']
35 else:
36 columns = set(columns)
37 if options.has_key('__columns_except__'):
38 columns_except = options['__columns_except__'] if isinstance(options['__columns_except__'], list) else [options['__columns_except__']]
39 columns -= set(columns_except)
40 if options.has_key('__included_ids__') and options['__included_ids__'] == False:
41 related_objs_ids = [r + '_id' for r, o in options.items() if not r.startswith('__')]
42 columns -= set(related_objs_ids)
43
44 columns = list(columns)
45
46 for column in columns:
47 result[column] = getattr(self, column)
48
49 for related, values in options.items():
50 if hasattr(self, related):
51 result[related] = getattr(self, related).to_dict(values)
52 return result
53
54 @property
56 return map(lambda x: x.name, self.__table__.columns)
57
58 -class User(db.Model, Serializer):
59 """Represents user of the copr frontend"""
60 id = db.Column(db.Integer, primary_key = True)
61
62 openid_name = db.Column(db.String(100), nullable = False)
63
64 mail = db.Column(db.String(150), nullable = False)
65
66 proven = db.Column(db.Boolean, default = False)
67
68 admin = db.Column(db.Boolean, default = False)
69
70 api_login = db.Column(db.String(40), nullable = False, default = 'abc')
71 api_token = db.Column(db.String(40), nullable = False, default = 'abc')
72 api_token_expiration = db.Column(db.Date, nullable = False, default = datetime.date(2000, 1, 1))
73
74 @property
76 """Returns the short username of the user, e.g. bkabrda"""
77 return self.openid_name.replace('.id.fedoraproject.org/', '').replace('http://', '')
78
80 """Get permissions of this user for the given copr.
81 Caches the permission during one request, so use this if you access them multiple times
82 """
83 if not hasattr(self, '_permissions_for_copr'):
84 self._permissions_for_copr = {}
85 if not copr.name in self._permissions_for_copr:
86 self._permissions_for_copr[copr.name] = CoprPermission.query.filter_by(user = self).filter_by(copr = copr).first()
87 return self._permissions_for_copr[copr.name]
88
98
108
109 @classmethod
111 """Creates proper openid_name from short name.
112
113 >>> user.openid_name == User.openidize_name(user.name)
114 True
115 """
116 return 'http://{0}.id.fedoraproject.org/'.format(name)
117
118 @property
120
121 return ['id', 'name']
122
123 @property
125 """Get number of coprs for this user."""
126 return Copr.query.filter_by(owner=self).\
127 filter_by(deleted=False).\
128 count()
129
130 @property
132 """Return url to libravatar image."""
133 return libravatar_url(email = self.mail)
134
135
136 -class Copr(db.Model, Serializer):
137 """Represents a single copr (private repo with builds, mock chroots, etc.)."""
138 id = db.Column(db.Integer, primary_key = True)
139
140 name = db.Column(db.String(100), nullable = False)
141
142
143 repos = db.Column(db.Text)
144
145 created_on = db.Column(db.Integer)
146
147 description = db.Column(db.Text)
148 instructions = db.Column(db.Text)
149
150 build_count = db.Column(db.Integer, default = 0)
151 deleted = db.Column(db.Boolean, default=False)
152
153
154 owner_id = db.Column(db.Integer, db.ForeignKey('user.id'))
155 owner = db.relationship('User', backref = db.backref('coprs'))
156 mock_chroots = association_proxy('copr_chroots', 'mock_chroot')
157
158 __mapper_args__ = {
159 'order_by' : created_on.desc()
160 }
161
162 @property
164 """Returns repos of this copr as a list of strings"""
165 return self.repos.split()
166
167 @property
169 return self.description or 'Description not filled in by author.'
170
171 @property
173 return self.instructions or 'Instructions not filled in by author.'
174
175 @property
177 """Returns list of active mock_chroots of this copr"""
178 return filter(lambda x: x.is_active, self.mock_chroots)
179
181 """Association class for Copr<->Permission relation"""
182
183
184 copr_builder = db.Column(db.SmallInteger, default = 0)
185
186 copr_admin = db.Column(db.SmallInteger, default = 0)
187
188
189 user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key = True)
190 user = db.relationship('User', backref = db.backref('copr_permissions'))
191 copr_id = db.Column(db.Integer, db.ForeignKey('copr.id'), primary_key = True)
192 copr = db.relationship('Copr', backref = db.backref('copr_permissions'))
193
194 -class Build(db.Model, Serializer):
195 """Representation of one build in one copr"""
196 id = db.Column(db.Integer, primary_key = True)
197
198 pkgs = db.Column(db.Text)
199
200 canceled = db.Column(db.Boolean, default = False)
201
202
203
204 chroots = db.Column(db.Text, nullable = False)
205
206 repos = db.Column(db.Text)
207
208
209 submitted_on = db.Column(db.Integer, nullable = False)
210 started_on = db.Column(db.Integer)
211 ended_on = db.Column(db.Integer)
212
213 results = db.Column(db.Text)
214
215
216 status = db.Column(db.Integer)
217
218 memory_reqs = db.Column(db.Integer, default = constants.DEFAULT_BUILD_MEMORY)
219
220 timeout = db.Column(db.Integer, default = constants.DEFAULT_BUILD_TIMEOUT)
221
222
223 user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
224 user = db.relationship('User', backref = db.backref('builds'))
225 copr_id = db.Column(db.Integer, db.ForeignKey('copr.id'))
226 copr = db.relationship('Copr', backref = db.backref('builds'))
227
228 @property
230 """Return text representation of status of this build"""
231 if self.status == 1:
232 return 'succeeded'
233 elif self.status == 0:
234 return 'failed'
235 if self.canceled:
236 return 'canceled'
237 if not self.ended_on and self.started_on:
238 return 'running'
239 return 'pending'
240
241 @property
243 """Find out if this build is cancelable.
244
245 ATM, build is cancelable only if it wasn't grabbed by backend.
246 """
247 return self.state == 'pending'
248
250 """Representation of mock chroot"""
251 id = db.Column(db.Integer, primary_key = True)
252
253 os_release = db.Column(db.String(50), nullable = False)
254
255 os_version = db.Column(db.String(50), nullable = False)
256
257 arch = db.Column(db.String(50), nullable = False)
258 is_active = db.Column(db.Boolean, default = True)
259
260 @property
262 """Textual representation of name of this chroot"""
263 if self.os_version:
264 format_string = '{rel}-{ver}-{arch}'
265 else:
266 format_string = '{rel}-{arch}'
267 return format_string.format(rel=self.os_release,
268 ver=self.os_version,
269 arch=self.arch)
270
272 """Representation of Copr<->MockChroot relation"""
273 mock_chroot_id = db.Column(db.Integer, db.ForeignKey('mock_chroot.id'), primary_key = True)
274 mock_chroot = db.relationship('MockChroot', backref = db.backref('copr_chroots'))
275 copr_id = db.Column(db.Integer, db.ForeignKey('copr.id'), primary_key = True)
276 copr = db.relationship('Copr', backref = db.backref('copr_chroots',
277 single_parent=True,
278 cascade='all,delete,delete-orphan'))
279
281 id = db.Column(db.Integer, primary_key=True)
282
283 raise_message = db.Column(db.Text)
284
285 raised_on = db.Column(db.Integer)
286
287 resolved_on = db.Column(db.Integer)
288
289
290 copr_id = db.Column(db.Integer, db.ForeignKey('copr.id'), nullable=True)
291
292 copr = db.relationship('Copr', backref=db.backref('legal_flags', cascade='all'))
293
294 reporter_id = db.Column(db.Integer, db.ForeignKey('user.id'))
295 reporter = db.relationship('User',
296 backref=db.backref('legal_flags_raised'),
297 foreign_keys=[reporter_id],
298 primaryjoin='LegalFlag.reporter_id==User.id')
299
300 resolver_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True)
301 resolver = db.relationship('User',
302 backref=db.backref('legal_flags_resolved'),
303 foreign_keys=[resolver_id],
304 primaryjoin='LegalFlag.resolver_id==User.id')
305
306
307 -class Action(db.Model, Serializer):
345