##// END OF EJS Templates
White space cleanup
marcink -
r2815:acc05c33 beta
parent child Browse files
Show More
@@ -1,594 +1,591
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.compat
3 rhodecode.lib.compat
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Python backward compatibility functions and common libs
6 Python backward compatibility functions and common libs
7
7
8
8
9 :created_on: Oct 7, 2011
9 :created_on: Oct 7, 2011
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2010 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2010 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 from rhodecode import __platform__, PLATFORM_WIN, __py_version__
28 from rhodecode import __platform__, PLATFORM_WIN, __py_version__
29
29
30 #==============================================================================
30 #==============================================================================
31 # json
31 # json
32 #==============================================================================
32 #==============================================================================
33 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.ext_json import json
34
34
35
35
36 #==============================================================================
36 #==============================================================================
37 # izip_longest
37 # izip_longest
38 #==============================================================================
38 #==============================================================================
39 try:
39 try:
40 from itertools import izip_longest
40 from itertools import izip_longest
41 except ImportError:
41 except ImportError:
42 import itertools
42 import itertools
43
43
44 def izip_longest(*args, **kwds):
44 def izip_longest(*args, **kwds):
45 fillvalue = kwds.get("fillvalue")
45 fillvalue = kwds.get("fillvalue")
46
46
47 def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
47 def sentinel(counter=([fillvalue] * (len(args) - 1)).pop):
48 yield counter() # yields the fillvalue, or raises IndexError
48 yield counter() # yields the fillvalue, or raises IndexError
49
49
50 fillers = itertools.repeat(fillvalue)
50 fillers = itertools.repeat(fillvalue)
51 iters = [itertools.chain(it, sentinel(), fillers)
51 iters = [itertools.chain(it, sentinel(), fillers)
52 for it in args]
52 for it in args]
53 try:
53 try:
54 for tup in itertools.izip(*iters):
54 for tup in itertools.izip(*iters):
55 yield tup
55 yield tup
56 except IndexError:
56 except IndexError:
57 pass
57 pass
58
58
59
59
60 #==============================================================================
60 #==============================================================================
61 # OrderedDict
61 # OrderedDict
62 #==============================================================================
62 #==============================================================================
63
63
64 # Python Software Foundation License
64 # Python Software Foundation License
65
65
66 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
66 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
67 # "!=" should be faster.
67 # "!=" should be faster.
68 class _Nil(object):
68 class _Nil(object):
69
69
70 def __repr__(self):
70 def __repr__(self):
71 return "nil"
71 return "nil"
72
72
73 def __eq__(self, other):
73 def __eq__(self, other):
74 if (isinstance(other, _Nil)):
74 if (isinstance(other, _Nil)):
75 return True
75 return True
76 else:
76 else:
77 return NotImplemented
77 return NotImplemented
78
78
79 def __ne__(self, other):
79 def __ne__(self, other):
80 if (isinstance(other, _Nil)):
80 if (isinstance(other, _Nil)):
81 return False
81 return False
82 else:
82 else:
83 return NotImplemented
83 return NotImplemented
84
84
85 _nil = _Nil()
85 _nil = _Nil()
86
86
87
87
88 class _odict(object):
88 class _odict(object):
89 """Ordered dict data structure, with O(1) complexity for dict operations
89 """Ordered dict data structure, with O(1) complexity for dict operations
90 that modify one element.
90 that modify one element.
91
91
92 Overwriting values doesn't change their original sequential order.
92 Overwriting values doesn't change their original sequential order.
93 """
93 """
94
94
95 def _dict_impl(self):
95 def _dict_impl(self):
96 return None
96 return None
97
97
98 def __init__(self, data=(), **kwds):
98 def __init__(self, data=(), **kwds):
99 """This doesn't accept keyword initialization as normal dicts to avoid
99 """This doesn't accept keyword initialization as normal dicts to avoid
100 a trap - inside a function or method the keyword args are accessible
100 a trap - inside a function or method the keyword args are accessible
101 only as a dict, without a defined order, so their original order is
101 only as a dict, without a defined order, so their original order is
102 lost.
102 lost.
103 """
103 """
104 if kwds:
104 if kwds:
105 raise TypeError("__init__() of ordered dict takes no keyword "
105 raise TypeError("__init__() of ordered dict takes no keyword "
106 "arguments to avoid an ordering trap.")
106 "arguments to avoid an ordering trap.")
107 self._dict_impl().__init__(self)
107 self._dict_impl().__init__(self)
108 # If you give a normal dict, then the order of elements is undefined
108 # If you give a normal dict, then the order of elements is undefined
109 if hasattr(data, "iteritems"):
109 if hasattr(data, "iteritems"):
110 for key, val in data.iteritems():
110 for key, val in data.iteritems():
111 self[key] = val
111 self[key] = val
112 else:
112 else:
113 for key, val in data:
113 for key, val in data:
114 self[key] = val
114 self[key] = val
115
115
116 # Double-linked list header
116 # Double-linked list header
117 def _get_lh(self):
117 def _get_lh(self):
118 dict_impl = self._dict_impl()
118 dict_impl = self._dict_impl()
119 if not hasattr(self, '_lh'):
119 if not hasattr(self, '_lh'):
120 dict_impl.__setattr__(self, '_lh', _nil)
120 dict_impl.__setattr__(self, '_lh', _nil)
121 return dict_impl.__getattribute__(self, '_lh')
121 return dict_impl.__getattribute__(self, '_lh')
122
122
123 def _set_lh(self, val):
123 def _set_lh(self, val):
124 self._dict_impl().__setattr__(self, '_lh', val)
124 self._dict_impl().__setattr__(self, '_lh', val)
125
125
126 lh = property(_get_lh, _set_lh)
126 lh = property(_get_lh, _set_lh)
127
127
128 # Double-linked list tail
128 # Double-linked list tail
129 def _get_lt(self):
129 def _get_lt(self):
130 dict_impl = self._dict_impl()
130 dict_impl = self._dict_impl()
131 if not hasattr(self, '_lt'):
131 if not hasattr(self, '_lt'):
132 dict_impl.__setattr__(self, '_lt', _nil)
132 dict_impl.__setattr__(self, '_lt', _nil)
133 return dict_impl.__getattribute__(self, '_lt')
133 return dict_impl.__getattribute__(self, '_lt')
134
134
135 def _set_lt(self, val):
135 def _set_lt(self, val):
136 self._dict_impl().__setattr__(self, '_lt', val)
136 self._dict_impl().__setattr__(self, '_lt', val)
137
137
138 lt = property(_get_lt, _set_lt)
138 lt = property(_get_lt, _set_lt)
139
139
140 def __getitem__(self, key):
140 def __getitem__(self, key):
141 return self._dict_impl().__getitem__(self, key)[1]
141 return self._dict_impl().__getitem__(self, key)[1]
142
142
143 def __setitem__(self, key, val):
143 def __setitem__(self, key, val):
144 dict_impl = self._dict_impl()
144 dict_impl = self._dict_impl()
145 try:
145 try:
146 dict_impl.__getitem__(self, key)[1] = val
146 dict_impl.__getitem__(self, key)[1] = val
147 except KeyError:
147 except KeyError:
148 new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
148 new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
149 dict_impl.__setitem__(self, key, new)
149 dict_impl.__setitem__(self, key, new)
150 if dict_impl.__getattribute__(self, 'lt') == _nil:
150 if dict_impl.__getattribute__(self, 'lt') == _nil:
151 dict_impl.__setattr__(self, 'lh', key)
151 dict_impl.__setattr__(self, 'lh', key)
152 else:
152 else:
153 dict_impl.__getitem__(
153 dict_impl.__getitem__(
154 self, dict_impl.__getattribute__(self, 'lt'))[2] = key
154 self, dict_impl.__getattribute__(self, 'lt'))[2] = key
155 dict_impl.__setattr__(self, 'lt', key)
155 dict_impl.__setattr__(self, 'lt', key)
156
156
157 def __delitem__(self, key):
157 def __delitem__(self, key):
158 dict_impl = self._dict_impl()
158 dict_impl = self._dict_impl()
159 pred, _, succ = self._dict_impl().__getitem__(self, key)
159 pred, _, succ = self._dict_impl().__getitem__(self, key)
160 if pred == _nil:
160 if pred == _nil:
161 dict_impl.__setattr__(self, 'lh', succ)
161 dict_impl.__setattr__(self, 'lh', succ)
162 else:
162 else:
163 dict_impl.__getitem__(self, pred)[2] = succ
163 dict_impl.__getitem__(self, pred)[2] = succ
164 if succ == _nil:
164 if succ == _nil:
165 dict_impl.__setattr__(self, 'lt', pred)
165 dict_impl.__setattr__(self, 'lt', pred)
166 else:
166 else:
167 dict_impl.__getitem__(self, succ)[0] = pred
167 dict_impl.__getitem__(self, succ)[0] = pred
168 dict_impl.__delitem__(self, key)
168 dict_impl.__delitem__(self, key)
169
169
170 def __contains__(self, key):
170 def __contains__(self, key):
171 return key in self.keys()
171 return key in self.keys()
172
172
173 def __len__(self):
173 def __len__(self):
174 return len(self.keys())
174 return len(self.keys())
175
175
176 def __str__(self):
176 def __str__(self):
177 pairs = ("%r: %r" % (k, v) for k, v in self.iteritems())
177 pairs = ("%r: %r" % (k, v) for k, v in self.iteritems())
178 return "{%s}" % ", ".join(pairs)
178 return "{%s}" % ", ".join(pairs)
179
179
180 def __repr__(self):
180 def __repr__(self):
181 if self:
181 if self:
182 pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems())
182 pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems())
183 return "odict([%s])" % ", ".join(pairs)
183 return "odict([%s])" % ", ".join(pairs)
184 else:
184 else:
185 return "odict()"
185 return "odict()"
186
186
187 def get(self, k, x=None):
187 def get(self, k, x=None):
188 if k in self:
188 if k in self:
189 return self._dict_impl().__getitem__(self, k)[1]
189 return self._dict_impl().__getitem__(self, k)[1]
190 else:
190 else:
191 return x
191 return x
192
192
193 def __iter__(self):
193 def __iter__(self):
194 dict_impl = self._dict_impl()
194 dict_impl = self._dict_impl()
195 curr_key = dict_impl.__getattribute__(self, 'lh')
195 curr_key = dict_impl.__getattribute__(self, 'lh')
196 while curr_key != _nil:
196 while curr_key != _nil:
197 yield curr_key
197 yield curr_key
198 curr_key = dict_impl.__getitem__(self, curr_key)[2]
198 curr_key = dict_impl.__getitem__(self, curr_key)[2]
199
199
200 iterkeys = __iter__
200 iterkeys = __iter__
201
201
202 def keys(self):
202 def keys(self):
203 return list(self.iterkeys())
203 return list(self.iterkeys())
204
204
205 def itervalues(self):
205 def itervalues(self):
206 dict_impl = self._dict_impl()
206 dict_impl = self._dict_impl()
207 curr_key = dict_impl.__getattribute__(self, 'lh')
207 curr_key = dict_impl.__getattribute__(self, 'lh')
208 while curr_key != _nil:
208 while curr_key != _nil:
209 _, val, curr_key = dict_impl.__getitem__(self, curr_key)
209 _, val, curr_key = dict_impl.__getitem__(self, curr_key)
210 yield val
210 yield val
211
211
212 def values(self):
212 def values(self):
213 return list(self.itervalues())
213 return list(self.itervalues())
214
214
215 def iteritems(self):
215 def iteritems(self):
216 dict_impl = self._dict_impl()
216 dict_impl = self._dict_impl()
217 curr_key = dict_impl.__getattribute__(self, 'lh')
217 curr_key = dict_impl.__getattribute__(self, 'lh')
218 while curr_key != _nil:
218 while curr_key != _nil:
219 _, val, next_key = dict_impl.__getitem__(self, curr_key)
219 _, val, next_key = dict_impl.__getitem__(self, curr_key)
220 yield curr_key, val
220 yield curr_key, val
221 curr_key = next_key
221 curr_key = next_key
222
222
223 def items(self):
223 def items(self):
224 return list(self.iteritems())
224 return list(self.iteritems())
225
225
226 def sort(self, cmp=None, key=None, reverse=False):
226 def sort(self, cmp=None, key=None, reverse=False):
227 items = [(k, v) for k, v in self.items()]
227 items = [(k, v) for k, v in self.items()]
228 if cmp is not None:
228 if cmp is not None:
229 items = sorted(items, cmp=cmp)
229 items = sorted(items, cmp=cmp)
230 elif key is not None:
230 elif key is not None:
231 items = sorted(items, key=key)
231 items = sorted(items, key=key)
232 else:
232 else:
233 items = sorted(items, key=lambda x: x[1])
233 items = sorted(items, key=lambda x: x[1])
234 if reverse:
234 if reverse:
235 items.reverse()
235 items.reverse()
236 self.clear()
236 self.clear()
237 self.__init__(items)
237 self.__init__(items)
238
238
239 def clear(self):
239 def clear(self):
240 dict_impl = self._dict_impl()
240 dict_impl = self._dict_impl()
241 dict_impl.clear(self)
241 dict_impl.clear(self)
242 dict_impl.__setattr__(self, 'lh', _nil)
242 dict_impl.__setattr__(self, 'lh', _nil)
243 dict_impl.__setattr__(self, 'lt', _nil)
243 dict_impl.__setattr__(self, 'lt', _nil)
244
244
245 def copy(self):
245 def copy(self):
246 return self.__class__(self)
246 return self.__class__(self)
247
247
248 def update(self, data=(), **kwds):
248 def update(self, data=(), **kwds):
249 if kwds:
249 if kwds:
250 raise TypeError("update() of ordered dict takes no keyword "
250 raise TypeError("update() of ordered dict takes no keyword "
251 "arguments to avoid an ordering trap.")
251 "arguments to avoid an ordering trap.")
252 if hasattr(data, "iteritems"):
252 if hasattr(data, "iteritems"):
253 data = data.iteritems()
253 data = data.iteritems()
254 for key, val in data:
254 for key, val in data:
255 self[key] = val
255 self[key] = val
256
256
257 def setdefault(self, k, x=None):
257 def setdefault(self, k, x=None):
258 try:
258 try:
259 return self[k]
259 return self[k]
260 except KeyError:
260 except KeyError:
261 self[k] = x
261 self[k] = x
262 return x
262 return x
263
263
264 def pop(self, k, x=_nil):
264 def pop(self, k, x=_nil):
265 try:
265 try:
266 val = self[k]
266 val = self[k]
267 del self[k]
267 del self[k]
268 return val
268 return val
269 except KeyError:
269 except KeyError:
270 if x == _nil:
270 if x == _nil:
271 raise
271 raise
272 return x
272 return x
273
273
274 def popitem(self):
274 def popitem(self):
275 try:
275 try:
276 dict_impl = self._dict_impl()
276 dict_impl = self._dict_impl()
277 key = dict_impl.__getattribute__(self, 'lt')
277 key = dict_impl.__getattribute__(self, 'lt')
278 return key, self.pop(key)
278 return key, self.pop(key)
279 except KeyError:
279 except KeyError:
280 raise KeyError("'popitem(): ordered dictionary is empty'")
280 raise KeyError("'popitem(): ordered dictionary is empty'")
281
281
282 def riterkeys(self):
282 def riterkeys(self):
283 """To iterate on keys in reversed order.
283 """To iterate on keys in reversed order.
284 """
284 """
285 dict_impl = self._dict_impl()
285 dict_impl = self._dict_impl()
286 curr_key = dict_impl.__getattribute__(self, 'lt')
286 curr_key = dict_impl.__getattribute__(self, 'lt')
287 while curr_key != _nil:
287 while curr_key != _nil:
288 yield curr_key
288 yield curr_key
289 curr_key = dict_impl.__getitem__(self, curr_key)[0]
289 curr_key = dict_impl.__getitem__(self, curr_key)[0]
290
290
291 __reversed__ = riterkeys
291 __reversed__ = riterkeys
292
292
293 def rkeys(self):
293 def rkeys(self):
294 """List of the keys in reversed order.
294 """List of the keys in reversed order.
295 """
295 """
296 return list(self.riterkeys())
296 return list(self.riterkeys())
297
297
298 def ritervalues(self):
298 def ritervalues(self):
299 """To iterate on values in reversed order.
299 """To iterate on values in reversed order.
300 """
300 """
301 dict_impl = self._dict_impl()
301 dict_impl = self._dict_impl()
302 curr_key = dict_impl.__getattribute__(self, 'lt')
302 curr_key = dict_impl.__getattribute__(self, 'lt')
303 while curr_key != _nil:
303 while curr_key != _nil:
304 curr_key, val, _ = dict_impl.__getitem__(self, curr_key)
304 curr_key, val, _ = dict_impl.__getitem__(self, curr_key)
305 yield val
305 yield val
306
306
307 def rvalues(self):
307 def rvalues(self):
308 """List of the values in reversed order.
308 """List of the values in reversed order.
309 """
309 """
310 return list(self.ritervalues())
310 return list(self.ritervalues())
311
311
312 def riteritems(self):
312 def riteritems(self):
313 """To iterate on (key, value) in reversed order.
313 """To iterate on (key, value) in reversed order.
314 """
314 """
315 dict_impl = self._dict_impl()
315 dict_impl = self._dict_impl()
316 curr_key = dict_impl.__getattribute__(self, 'lt')
316 curr_key = dict_impl.__getattribute__(self, 'lt')
317 while curr_key != _nil:
317 while curr_key != _nil:
318 pred_key, val, _ = dict_impl.__getitem__(self, curr_key)
318 pred_key, val, _ = dict_impl.__getitem__(self, curr_key)
319 yield curr_key, val
319 yield curr_key, val
320 curr_key = pred_key
320 curr_key = pred_key
321
321
322 def ritems(self):
322 def ritems(self):
323 """List of the (key, value) in reversed order.
323 """List of the (key, value) in reversed order.
324 """
324 """
325 return list(self.riteritems())
325 return list(self.riteritems())
326
326
327 def firstkey(self):
327 def firstkey(self):
328 if self:
328 if self:
329 return self._dict_impl().__getattribute__(self, 'lh')
329 return self._dict_impl().__getattribute__(self, 'lh')
330 else:
330 else:
331 raise KeyError("'firstkey(): ordered dictionary is empty'")
331 raise KeyError("'firstkey(): ordered dictionary is empty'")
332
332
333 def lastkey(self):
333 def lastkey(self):
334 if self:
334 if self:
335 return self._dict_impl().__getattribute__(self, 'lt')
335 return self._dict_impl().__getattribute__(self, 'lt')
336 else:
336 else:
337 raise KeyError("'lastkey(): ordered dictionary is empty'")
337 raise KeyError("'lastkey(): ordered dictionary is empty'")
338
338
339 def as_dict(self):
339 def as_dict(self):
340 return self._dict_impl()(self.items())
340 return self._dict_impl()(self.items())
341
341
342 def _repr(self):
342 def _repr(self):
343 """_repr(): low level repr of the whole data contained in the odict.
343 """_repr(): low level repr of the whole data contained in the odict.
344 Useful for debugging.
344 Useful for debugging.
345 """
345 """
346 dict_impl = self._dict_impl()
346 dict_impl = self._dict_impl()
347 form = "odict low level repr lh,lt,data: %r, %r, %s"
347 form = "odict low level repr lh,lt,data: %r, %r, %s"
348 return form % (dict_impl.__getattribute__(self, 'lh'),
348 return form % (dict_impl.__getattribute__(self, 'lh'),
349 dict_impl.__getattribute__(self, 'lt'),
349 dict_impl.__getattribute__(self, 'lt'),
350 dict_impl.__repr__(self))
350 dict_impl.__repr__(self))
351
351
352
352
353 class OrderedDict(_odict, dict):
353 class OrderedDict(_odict, dict):
354
354
355 def _dict_impl(self):
355 def _dict_impl(self):
356 return dict
356 return dict
357
357
358
358
359 #==============================================================================
359 #==============================================================================
360 # OrderedSet
360 # OrderedSet
361 #==============================================================================
361 #==============================================================================
362 from sqlalchemy.util import OrderedSet
362 from sqlalchemy.util import OrderedSet
363
363
364
364
365 #==============================================================================
365 #==============================================================================
366 # kill FUNCTIONS
366 # kill FUNCTIONS
367 #==============================================================================
367 #==============================================================================
368 if __platform__ in PLATFORM_WIN:
368 if __platform__ in PLATFORM_WIN:
369 import ctypes
369 import ctypes
370
370
371 def kill(pid, sig):
371 def kill(pid, sig):
372 """kill function for Win32"""
372 """kill function for Win32"""
373 kernel32 = ctypes.windll.kernel32
373 kernel32 = ctypes.windll.kernel32
374 handle = kernel32.OpenProcess(1, 0, pid)
374 handle = kernel32.OpenProcess(1, 0, pid)
375 return (0 != kernel32.TerminateProcess(handle, 0))
375 return (0 != kernel32.TerminateProcess(handle, 0))
376
376
377 else:
377 else:
378 kill = os.kill
378 kill = os.kill
379
379
380
380
381 #==============================================================================
381 #==============================================================================
382 # itertools.product
382 # itertools.product
383 #==============================================================================
383 #==============================================================================
384
384
385 try:
385 try:
386 from itertools import product
386 from itertools import product
387 except ImportError:
387 except ImportError:
388 def product(*args, **kwds):
388 def product(*args, **kwds):
389 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
389 # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
390 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
390 # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
391 pools = map(tuple, args) * kwds.get('repeat', 1)
391 pools = map(tuple, args) * kwds.get('repeat', 1)
392 result = [[]]
392 result = [[]]
393 for pool in pools:
393 for pool in pools:
394 result = [x + [y] for x in result for y in pool]
394 result = [x + [y] for x in result for y in pool]
395 for prod in result:
395 for prod in result:
396 yield tuple(prod)
396 yield tuple(prod)
397
397
398
398
399 #==============================================================================
399 #==============================================================================
400 # BytesIO
400 # BytesIO
401 #==============================================================================
401 #==============================================================================
402
402
403 try:
403 try:
404 from io import BytesIO
404 from io import BytesIO
405 except ImportError:
405 except ImportError:
406 from cStringIO import StringIO as BytesIO
406 from cStringIO import StringIO as BytesIO
407
407
408
408
409 #==============================================================================
409 #==============================================================================
410 # bytes
410 # bytes
411 #==============================================================================
411 #==============================================================================
412 if __py_version__ >= (2, 6):
412 if __py_version__ >= (2, 6):
413 _bytes = bytes
413 _bytes = bytes
414 else:
414 else:
415 # in py2.6 bytes is a synonim for str
415 # in py2.6 bytes is a synonim for str
416 _bytes = str
416 _bytes = str
417
417
418 #==============================================================================
418 #==============================================================================
419 # deque
419 # deque
420 #==============================================================================
420 #==============================================================================
421
421
422 if __py_version__ >= (2, 6):
422 if __py_version__ >= (2, 6):
423 from collections import deque
423 from collections import deque
424 else:
424 else:
425 #need to implement our own deque with maxlen
425 #need to implement our own deque with maxlen
426 class deque(object):
426 class deque(object):
427
427
428 def __init__(self, iterable=(), maxlen= -1):
428 def __init__(self, iterable=(), maxlen= -1):
429 if not hasattr(self, 'data'):
429 if not hasattr(self, 'data'):
430 self.left = self.right = 0
430 self.left = self.right = 0
431 self.data = {}
431 self.data = {}
432 self.maxlen = maxlen or -1
432 self.maxlen = maxlen or -1
433 self.extend(iterable)
433 self.extend(iterable)
434
434
435 def append(self, x):
435 def append(self, x):
436 self.data[self.right] = x
436 self.data[self.right] = x
437 self.right += 1
437 self.right += 1
438 if self.maxlen != -1 and len(self) > self.maxlen:
438 if self.maxlen != -1 and len(self) > self.maxlen:
439 self.popleft()
439 self.popleft()
440
440
441 def appendleft(self, x):
441 def appendleft(self, x):
442 self.left -= 1
442 self.left -= 1
443 self.data[self.left] = x
443 self.data[self.left] = x
444 if self.maxlen != -1 and len(self) > self.maxlen:
444 if self.maxlen != -1 and len(self) > self.maxlen:
445 self.pop()
445 self.pop()
446
446
447 def pop(self):
447 def pop(self):
448 if self.left == self.right:
448 if self.left == self.right:
449 raise IndexError('cannot pop from empty deque')
449 raise IndexError('cannot pop from empty deque')
450 self.right -= 1
450 self.right -= 1
451 elem = self.data[self.right]
451 elem = self.data[self.right]
452 del self.data[self.right]
452 del self.data[self.right]
453 return elem
453 return elem
454
454
455 def popleft(self):
455 def popleft(self):
456 if self.left == self.right:
456 if self.left == self.right:
457 raise IndexError('cannot pop from empty deque')
457 raise IndexError('cannot pop from empty deque')
458 elem = self.data[self.left]
458 elem = self.data[self.left]
459 del self.data[self.left]
459 del self.data[self.left]
460 self.left += 1
460 self.left += 1
461 return elem
461 return elem
462
462
463 def clear(self):
463 def clear(self):
464 self.data.clear()
464 self.data.clear()
465 self.left = self.right = 0
465 self.left = self.right = 0
466
466
467 def extend(self, iterable):
467 def extend(self, iterable):
468 for elem in iterable:
468 for elem in iterable:
469 self.append(elem)
469 self.append(elem)
470
470
471 def extendleft(self, iterable):
471 def extendleft(self, iterable):
472 for elem in iterable:
472 for elem in iterable:
473 self.appendleft(elem)
473 self.appendleft(elem)
474
474
475 def rotate(self, n=1):
475 def rotate(self, n=1):
476 if self:
476 if self:
477 n %= len(self)
477 n %= len(self)
478 for i in xrange(n):
478 for i in xrange(n):
479 self.appendleft(self.pop())
479 self.appendleft(self.pop())
480
480
481 def __getitem__(self, i):
481 def __getitem__(self, i):
482 if i < 0:
482 if i < 0:
483 i += len(self)
483 i += len(self)
484 try:
484 try:
485 return self.data[i + self.left]
485 return self.data[i + self.left]
486 except KeyError:
486 except KeyError:
487 raise IndexError
487 raise IndexError
488
488
489 def __setitem__(self, i, value):
489 def __setitem__(self, i, value):
490 if i < 0:
490 if i < 0:
491 i += len(self)
491 i += len(self)
492 try:
492 try:
493 self.data[i + self.left] = value
493 self.data[i + self.left] = value
494 except KeyError:
494 except KeyError:
495 raise IndexError
495 raise IndexError
496
496
497 def __delitem__(self, i):
497 def __delitem__(self, i):
498 size = len(self)
498 size = len(self)
499 if not (-size <= i < size):
499 if not (-size <= i < size):
500 raise IndexError
500 raise IndexError
501 data = self.data
501 data = self.data
502 if i < 0:
502 if i < 0:
503 i += size
503 i += size
504 for j in xrange(self.left + i, self.right - 1):
504 for j in xrange(self.left + i, self.right - 1):
505 data[j] = data[j + 1]
505 data[j] = data[j + 1]
506 self.pop()
506 self.pop()
507
507
508 def __len__(self):
508 def __len__(self):
509 return self.right - self.left
509 return self.right - self.left
510
510
511 def __cmp__(self, other):
511 def __cmp__(self, other):
512 if type(self) != type(other):
512 if type(self) != type(other):
513 return cmp(type(self), type(other))
513 return cmp(type(self), type(other))
514 return cmp(list(self), list(other))
514 return cmp(list(self), list(other))
515
515
516 def __repr__(self, _track=[]):
516 def __repr__(self, _track=[]):
517 if id(self) in _track:
517 if id(self) in _track:
518 return '...'
518 return '...'
519 _track.append(id(self))
519 _track.append(id(self))
520 r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
520 r = 'deque(%r, maxlen=%s)' % (list(self), self.maxlen)
521 _track.remove(id(self))
521 _track.remove(id(self))
522 return r
522 return r
523
523
524 def __getstate__(self):
524 def __getstate__(self):
525 return (tuple(self),)
525 return (tuple(self),)
526
526
527 def __setstate__(self, s):
527 def __setstate__(self, s):
528 self.__init__(s[0])
528 self.__init__(s[0])
529
529
530 def __hash__(self):
530 def __hash__(self):
531 raise TypeError
531 raise TypeError
532
532
533 def __copy__(self):
533 def __copy__(self):
534 return self.__class__(self)
534 return self.__class__(self)
535
535
536 def __deepcopy__(self, memo={}):
536 def __deepcopy__(self, memo={}):
537 from copy import deepcopy
537 from copy import deepcopy
538 result = self.__class__()
538 result = self.__class__()
539 memo[id(self)] = result
539 memo[id(self)] = result
540 result.__init__(deepcopy(tuple(self), memo))
540 result.__init__(deepcopy(tuple(self), memo))
541 return result
541 return result
542
542
543
543
544 #==============================================================================
544 #==============================================================================
545 # threading.Event
545 # threading.Event
546 #==============================================================================
546 #==============================================================================
547
547
548 if __py_version__ >= (2, 6):
548 if __py_version__ >= (2, 6):
549 from threading import Event, Thread
549 from threading import Event, Thread
550 else:
550 else:
551 from threading import _Verbose, Condition, Lock, Thread
551 from threading import _Verbose, Condition, Lock, Thread
552
552
553 def Event(*args, **kwargs):
553 def Event(*args, **kwargs):
554 return _Event(*args, **kwargs)
554 return _Event(*args, **kwargs)
555
555
556 class _Event(_Verbose):
556 class _Event(_Verbose):
557
557
558 # After Tim Peters' event class (without is_posted())
558 # After Tim Peters' event class (without is_posted())
559
559
560 def __init__(self, verbose=None):
560 def __init__(self, verbose=None):
561 _Verbose.__init__(self, verbose)
561 _Verbose.__init__(self, verbose)
562 self.__cond = Condition(Lock())
562 self.__cond = Condition(Lock())
563 self.__flag = False
563 self.__flag = False
564
564
565 def isSet(self):
565 def isSet(self):
566 return self.__flag
566 return self.__flag
567
567
568 is_set = isSet
568 is_set = isSet
569
569
570 def set(self):
570 def set(self):
571 self.__cond.acquire()
571 self.__cond.acquire()
572 try:
572 try:
573 self.__flag = True
573 self.__flag = True
574 self.__cond.notify_all()
574 self.__cond.notify_all()
575 finally:
575 finally:
576 self.__cond.release()
576 self.__cond.release()
577
577
578 def clear(self):
578 def clear(self):
579 self.__cond.acquire()
579 self.__cond.acquire()
580 try:
580 try:
581 self.__flag = False
581 self.__flag = False
582 finally:
582 finally:
583 self.__cond.release()
583 self.__cond.release()
584
584
585 def wait(self, timeout=None):
585 def wait(self, timeout=None):
586 self.__cond.acquire()
586 self.__cond.acquire()
587 try:
587 try:
588 if not self.__flag:
588 if not self.__flag:
589 self.__cond.wait(timeout)
589 self.__cond.wait(timeout)
590 finally:
590 finally:
591 self.__cond.release()
591 self.__cond.release()
592
593
594
@@ -1,1320 +1,1320
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db_1_3_0
3 rhodecode.model.db_1_3_0
4 ~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode <=1.3.X
6 Database Models for RhodeCode <=1.3.X
7
7
8 :created_on: Apr 08, 2010
8 :created_on: Apr 08, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import datetime
28 import datetime
29 import traceback
29 import traceback
30 from collections import defaultdict
30 from collections import defaultdict
31
31
32 from sqlalchemy import *
32 from sqlalchemy import *
33 from sqlalchemy.ext.hybrid import hybrid_property
33 from sqlalchemy.ext.hybrid import hybrid_property
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
34 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
35 from beaker.cache import cache_region, region_invalidate
35 from beaker.cache import cache_region, region_invalidate
36
36
37 from rhodecode.lib.vcs import get_backend
37 from rhodecode.lib.vcs import get_backend
38 from rhodecode.lib.vcs.utils.helpers import get_scm
38 from rhodecode.lib.vcs.utils.helpers import get_scm
39 from rhodecode.lib.vcs.exceptions import VCSError
39 from rhodecode.lib.vcs.exceptions import VCSError
40 from rhodecode.lib.vcs.utils.lazy import LazyProperty
40 from rhodecode.lib.vcs.utils.lazy import LazyProperty
41
41
42 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
42 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
43 safe_unicode
43 safe_unicode
44 from rhodecode.lib.compat import json
44 from rhodecode.lib.compat import json
45 from rhodecode.lib.caching_query import FromCache
45 from rhodecode.lib.caching_query import FromCache
46
46
47 from rhodecode.model.meta import Base, Session
47 from rhodecode.model.meta import Base, Session
48 import hashlib
48 import hashlib
49
49
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53 #==============================================================================
53 #==============================================================================
54 # BASE CLASSES
54 # BASE CLASSES
55 #==============================================================================
55 #==============================================================================
56
56
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
57 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
58
58
59
59
60 class ModelSerializer(json.JSONEncoder):
60 class ModelSerializer(json.JSONEncoder):
61 """
61 """
62 Simple Serializer for JSON,
62 Simple Serializer for JSON,
63
63
64 usage::
64 usage::
65
65
66 to make object customized for serialization implement a __json__
66 to make object customized for serialization implement a __json__
67 method that will return a dict for serialization into json
67 method that will return a dict for serialization into json
68
68
69 example::
69 example::
70
70
71 class Task(object):
71 class Task(object):
72
72
73 def __init__(self, name, value):
73 def __init__(self, name, value):
74 self.name = name
74 self.name = name
75 self.value = value
75 self.value = value
76
76
77 def __json__(self):
77 def __json__(self):
78 return dict(name=self.name,
78 return dict(name=self.name,
79 value=self.value)
79 value=self.value)
80
80
81 """
81 """
82
82
83 def default(self, obj):
83 def default(self, obj):
84
84
85 if hasattr(obj, '__json__'):
85 if hasattr(obj, '__json__'):
86 return obj.__json__()
86 return obj.__json__()
87 else:
87 else:
88 return json.JSONEncoder.default(self, obj)
88 return json.JSONEncoder.default(self, obj)
89
89
90
90
91 class BaseModel(object):
91 class BaseModel(object):
92 """
92 """
93 Base Model for all classess
93 Base Model for all classess
94 """
94 """
95
95
96 @classmethod
96 @classmethod
97 def _get_keys(cls):
97 def _get_keys(cls):
98 """return column names for this model """
98 """return column names for this model """
99 return class_mapper(cls).c.keys()
99 return class_mapper(cls).c.keys()
100
100
101 def get_dict(self):
101 def get_dict(self):
102 """
102 """
103 return dict with keys and values corresponding
103 return dict with keys and values corresponding
104 to this model data """
104 to this model data """
105
105
106 d = {}
106 d = {}
107 for k in self._get_keys():
107 for k in self._get_keys():
108 d[k] = getattr(self, k)
108 d[k] = getattr(self, k)
109
109
110 # also use __json__() if present to get additional fields
110 # also use __json__() if present to get additional fields
111 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
111 for k, val in getattr(self, '__json__', lambda: {})().iteritems():
112 d[k] = val
112 d[k] = val
113 return d
113 return d
114
114
115 def get_appstruct(self):
115 def get_appstruct(self):
116 """return list with keys and values tupples corresponding
116 """return list with keys and values tupples corresponding
117 to this model data """
117 to this model data """
118
118
119 l = []
119 l = []
120 for k in self._get_keys():
120 for k in self._get_keys():
121 l.append((k, getattr(self, k),))
121 l.append((k, getattr(self, k),))
122 return l
122 return l
123
123
124 def populate_obj(self, populate_dict):
124 def populate_obj(self, populate_dict):
125 """populate model with data from given populate_dict"""
125 """populate model with data from given populate_dict"""
126
126
127 for k in self._get_keys():
127 for k in self._get_keys():
128 if k in populate_dict:
128 if k in populate_dict:
129 setattr(self, k, populate_dict[k])
129 setattr(self, k, populate_dict[k])
130
130
131 @classmethod
131 @classmethod
132 def query(cls):
132 def query(cls):
133 return Session.query(cls)
133 return Session.query(cls)
134
134
135 @classmethod
135 @classmethod
136 def get(cls, id_):
136 def get(cls, id_):
137 if id_:
137 if id_:
138 return cls.query().get(id_)
138 return cls.query().get(id_)
139
139
140 @classmethod
140 @classmethod
141 def getAll(cls):
141 def getAll(cls):
142 return cls.query().all()
142 return cls.query().all()
143
143
144 @classmethod
144 @classmethod
145 def delete(cls, id_):
145 def delete(cls, id_):
146 obj = cls.query().get(id_)
146 obj = cls.query().get(id_)
147 Session.delete(obj)
147 Session.delete(obj)
148
148
149 def __repr__(self):
149 def __repr__(self):
150 if hasattr(self, '__unicode__'):
150 if hasattr(self, '__unicode__'):
151 # python repr needs to return str
151 # python repr needs to return str
152 return safe_str(self.__unicode__())
152 return safe_str(self.__unicode__())
153 return '<DB:%s>' % (self.__class__.__name__)
153 return '<DB:%s>' % (self.__class__.__name__)
154
154
155 class RhodeCodeSetting(Base, BaseModel):
155 class RhodeCodeSetting(Base, BaseModel):
156 __tablename__ = 'rhodecode_settings'
156 __tablename__ = 'rhodecode_settings'
157 __table_args__ = (
157 __table_args__ = (
158 UniqueConstraint('app_settings_name'),
158 UniqueConstraint('app_settings_name'),
159 {'extend_existing': True, 'mysql_engine':'InnoDB',
159 {'extend_existing': True, 'mysql_engine':'InnoDB',
160 'mysql_charset': 'utf8'}
160 'mysql_charset': 'utf8'}
161 )
161 )
162 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
162 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
163 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
163 app_settings_name = Column("app_settings_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
164 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
164 _app_settings_value = Column("app_settings_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
165
165
166 def __init__(self, k='', v=''):
166 def __init__(self, k='', v=''):
167 self.app_settings_name = k
167 self.app_settings_name = k
168 self.app_settings_value = v
168 self.app_settings_value = v
169
169
170 @validates('_app_settings_value')
170 @validates('_app_settings_value')
171 def validate_settings_value(self, key, val):
171 def validate_settings_value(self, key, val):
172 assert type(val) == unicode
172 assert type(val) == unicode
173 return val
173 return val
174
174
175 @hybrid_property
175 @hybrid_property
176 def app_settings_value(self):
176 def app_settings_value(self):
177 v = self._app_settings_value
177 v = self._app_settings_value
178 if self.app_settings_name == 'ldap_active':
178 if self.app_settings_name == 'ldap_active':
179 v = str2bool(v)
179 v = str2bool(v)
180 return v
180 return v
181
181
182 @app_settings_value.setter
182 @app_settings_value.setter
183 def app_settings_value(self, val):
183 def app_settings_value(self, val):
184 """
184 """
185 Setter that will always make sure we use unicode in app_settings_value
185 Setter that will always make sure we use unicode in app_settings_value
186
186
187 :param val:
187 :param val:
188 """
188 """
189 self._app_settings_value = safe_unicode(val)
189 self._app_settings_value = safe_unicode(val)
190
190
191 def __unicode__(self):
191 def __unicode__(self):
192 return u"<%s('%s:%s')>" % (
192 return u"<%s('%s:%s')>" % (
193 self.__class__.__name__,
193 self.__class__.__name__,
194 self.app_settings_name, self.app_settings_value
194 self.app_settings_name, self.app_settings_value
195 )
195 )
196
196
197 @classmethod
197 @classmethod
198 def get_by_name(cls, ldap_key):
198 def get_by_name(cls, ldap_key):
199 return cls.query()\
199 return cls.query()\
200 .filter(cls.app_settings_name == ldap_key).scalar()
200 .filter(cls.app_settings_name == ldap_key).scalar()
201
201
202 @classmethod
202 @classmethod
203 def get_app_settings(cls, cache=False):
203 def get_app_settings(cls, cache=False):
204
204
205 ret = cls.query()
205 ret = cls.query()
206
206
207 if cache:
207 if cache:
208 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
208 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
209
209
210 if not ret:
210 if not ret:
211 raise Exception('Could not get application settings !')
211 raise Exception('Could not get application settings !')
212 settings = {}
212 settings = {}
213 for each in ret:
213 for each in ret:
214 settings['rhodecode_' + each.app_settings_name] = \
214 settings['rhodecode_' + each.app_settings_name] = \
215 each.app_settings_value
215 each.app_settings_value
216
216
217 return settings
217 return settings
218
218
219 @classmethod
219 @classmethod
220 def get_ldap_settings(cls, cache=False):
220 def get_ldap_settings(cls, cache=False):
221 ret = cls.query()\
221 ret = cls.query()\
222 .filter(cls.app_settings_name.startswith('ldap_')).all()
222 .filter(cls.app_settings_name.startswith('ldap_')).all()
223 fd = {}
223 fd = {}
224 for row in ret:
224 for row in ret:
225 fd.update({row.app_settings_name:row.app_settings_value})
225 fd.update({row.app_settings_name:row.app_settings_value})
226
226
227 return fd
227 return fd
228
228
229
229
230 class RhodeCodeUi(Base, BaseModel):
230 class RhodeCodeUi(Base, BaseModel):
231 __tablename__ = 'rhodecode_ui'
231 __tablename__ = 'rhodecode_ui'
232 __table_args__ = (
232 __table_args__ = (
233 UniqueConstraint('ui_key'),
233 UniqueConstraint('ui_key'),
234 {'extend_existing': True, 'mysql_engine':'InnoDB',
234 {'extend_existing': True, 'mysql_engine':'InnoDB',
235 'mysql_charset': 'utf8'}
235 'mysql_charset': 'utf8'}
236 )
236 )
237
237
238 HOOK_UPDATE = 'changegroup.update'
238 HOOK_UPDATE = 'changegroup.update'
239 HOOK_REPO_SIZE = 'changegroup.repo_size'
239 HOOK_REPO_SIZE = 'changegroup.repo_size'
240 HOOK_PUSH = 'pretxnchangegroup.push_logger'
240 HOOK_PUSH = 'pretxnchangegroup.push_logger'
241 HOOK_PULL = 'preoutgoing.pull_logger'
241 HOOK_PULL = 'preoutgoing.pull_logger'
242
242
243 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
243 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
244 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
244 ui_section = Column("ui_section", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
245 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
245 ui_key = Column("ui_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
246 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
246 ui_value = Column("ui_value", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
247 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
247 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
248
248
249 @classmethod
249 @classmethod
250 def get_by_key(cls, key):
250 def get_by_key(cls, key):
251 return cls.query().filter(cls.ui_key == key)
251 return cls.query().filter(cls.ui_key == key)
252
252
253 @classmethod
253 @classmethod
254 def get_builtin_hooks(cls):
254 def get_builtin_hooks(cls):
255 q = cls.query()
255 q = cls.query()
256 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
256 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE,
257 cls.HOOK_REPO_SIZE,
257 cls.HOOK_REPO_SIZE,
258 cls.HOOK_PUSH, cls.HOOK_PULL]))
258 cls.HOOK_PUSH, cls.HOOK_PULL]))
259 return q.all()
259 return q.all()
260
260
261 @classmethod
261 @classmethod
262 def get_custom_hooks(cls):
262 def get_custom_hooks(cls):
263 q = cls.query()
263 q = cls.query()
264 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
264 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE,
265 cls.HOOK_REPO_SIZE,
265 cls.HOOK_REPO_SIZE,
266 cls.HOOK_PUSH, cls.HOOK_PULL]))
266 cls.HOOK_PUSH, cls.HOOK_PULL]))
267 q = q.filter(cls.ui_section == 'hooks')
267 q = q.filter(cls.ui_section == 'hooks')
268 return q.all()
268 return q.all()
269
269
270 @classmethod
270 @classmethod
271 def create_or_update_hook(cls, key, val):
271 def create_or_update_hook(cls, key, val):
272 new_ui = cls.get_by_key(key).scalar() or cls()
272 new_ui = cls.get_by_key(key).scalar() or cls()
273 new_ui.ui_section = 'hooks'
273 new_ui.ui_section = 'hooks'
274 new_ui.ui_active = True
274 new_ui.ui_active = True
275 new_ui.ui_key = key
275 new_ui.ui_key = key
276 new_ui.ui_value = val
276 new_ui.ui_value = val
277
277
278 Session.add(new_ui)
278 Session.add(new_ui)
279
279
280
280
281 class User(Base, BaseModel):
281 class User(Base, BaseModel):
282 __tablename__ = 'users'
282 __tablename__ = 'users'
283 __table_args__ = (
283 __table_args__ = (
284 UniqueConstraint('username'), UniqueConstraint('email'),
284 UniqueConstraint('username'), UniqueConstraint('email'),
285 {'extend_existing': True, 'mysql_engine':'InnoDB',
285 {'extend_existing': True, 'mysql_engine':'InnoDB',
286 'mysql_charset': 'utf8'}
286 'mysql_charset': 'utf8'}
287 )
287 )
288 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
288 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
289 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
289 username = Column("username", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
290 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
290 password = Column("password", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
291 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
291 active = Column("active", Boolean(), nullable=True, unique=None, default=None)
292 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
292 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
293 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
293 name = Column("name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
294 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
294 lastname = Column("lastname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
295 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
295 _email = Column("email", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
296 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
296 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
297 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
297 ldap_dn = Column("ldap_dn", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
298 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
298 api_key = Column("api_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
299
299
300 user_log = relationship('UserLog', cascade='all')
300 user_log = relationship('UserLog', cascade='all')
301 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
301 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
302
302
303 repositories = relationship('Repository')
303 repositories = relationship('Repository')
304 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
304 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
305 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
305 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
306 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
306 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
307
307
308 group_member = relationship('UsersGroupMember', cascade='all')
308 group_member = relationship('UsersGroupMember', cascade='all')
309
309
310 notifications = relationship('UserNotification', cascade='all')
310 notifications = relationship('UserNotification', cascade='all')
311 # notifications assigned to this user
311 # notifications assigned to this user
312 user_created_notifications = relationship('Notification', cascade='all')
312 user_created_notifications = relationship('Notification', cascade='all')
313 # comments created by this user
313 # comments created by this user
314 user_comments = relationship('ChangesetComment', cascade='all')
314 user_comments = relationship('ChangesetComment', cascade='all')
315
315
316 @hybrid_property
316 @hybrid_property
317 def email(self):
317 def email(self):
318 return self._email
318 return self._email
319
319
320 @email.setter
320 @email.setter
321 def email(self, val):
321 def email(self, val):
322 self._email = val.lower() if val else None
322 self._email = val.lower() if val else None
323
323
324 @property
324 @property
325 def full_name(self):
325 def full_name(self):
326 return '%s %s' % (self.name, self.lastname)
326 return '%s %s' % (self.name, self.lastname)
327
327
328 @property
328 @property
329 def full_name_or_username(self):
329 def full_name_or_username(self):
330 return ('%s %s' % (self.name, self.lastname)
330 return ('%s %s' % (self.name, self.lastname)
331 if (self.name and self.lastname) else self.username)
331 if (self.name and self.lastname) else self.username)
332
332
333 @property
333 @property
334 def full_contact(self):
334 def full_contact(self):
335 return '%s %s <%s>' % (self.name, self.lastname, self.email)
335 return '%s %s <%s>' % (self.name, self.lastname, self.email)
336
336
337 @property
337 @property
338 def short_contact(self):
338 def short_contact(self):
339 return '%s %s' % (self.name, self.lastname)
339 return '%s %s' % (self.name, self.lastname)
340
340
341 @property
341 @property
342 def is_admin(self):
342 def is_admin(self):
343 return self.admin
343 return self.admin
344
344
345 def __unicode__(self):
345 def __unicode__(self):
346 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
346 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
347 self.user_id, self.username)
347 self.user_id, self.username)
348
348
349 @classmethod
349 @classmethod
350 def get_by_username(cls, username, case_insensitive=False, cache=False):
350 def get_by_username(cls, username, case_insensitive=False, cache=False):
351 if case_insensitive:
351 if case_insensitive:
352 q = cls.query().filter(cls.username.ilike(username))
352 q = cls.query().filter(cls.username.ilike(username))
353 else:
353 else:
354 q = cls.query().filter(cls.username == username)
354 q = cls.query().filter(cls.username == username)
355
355
356 if cache:
356 if cache:
357 q = q.options(FromCache(
357 q = q.options(FromCache(
358 "sql_cache_short",
358 "sql_cache_short",
359 "get_user_%s" % _hash_key(username)
359 "get_user_%s" % _hash_key(username)
360 )
360 )
361 )
361 )
362 return q.scalar()
362 return q.scalar()
363
363
364 @classmethod
364 @classmethod
365 def get_by_api_key(cls, api_key, cache=False):
365 def get_by_api_key(cls, api_key, cache=False):
366 q = cls.query().filter(cls.api_key == api_key)
366 q = cls.query().filter(cls.api_key == api_key)
367
367
368 if cache:
368 if cache:
369 q = q.options(FromCache("sql_cache_short",
369 q = q.options(FromCache("sql_cache_short",
370 "get_api_key_%s" % api_key))
370 "get_api_key_%s" % api_key))
371 return q.scalar()
371 return q.scalar()
372
372
373 @classmethod
373 @classmethod
374 def get_by_email(cls, email, case_insensitive=False, cache=False):
374 def get_by_email(cls, email, case_insensitive=False, cache=False):
375 if case_insensitive:
375 if case_insensitive:
376 q = cls.query().filter(cls.email.ilike(email))
376 q = cls.query().filter(cls.email.ilike(email))
377 else:
377 else:
378 q = cls.query().filter(cls.email == email)
378 q = cls.query().filter(cls.email == email)
379
379
380 if cache:
380 if cache:
381 q = q.options(FromCache("sql_cache_short",
381 q = q.options(FromCache("sql_cache_short",
382 "get_api_key_%s" % email))
382 "get_api_key_%s" % email))
383 return q.scalar()
383 return q.scalar()
384
384
385 def update_lastlogin(self):
385 def update_lastlogin(self):
386 """Update user lastlogin"""
386 """Update user lastlogin"""
387 self.last_login = datetime.datetime.now()
387 self.last_login = datetime.datetime.now()
388 Session.add(self)
388 Session.add(self)
389 log.debug('updated user %s lastlogin' % self.username)
389 log.debug('updated user %s lastlogin' % self.username)
390
390
391 def __json__(self):
391 def __json__(self):
392 return dict(
392 return dict(
393 user_id=self.user_id,
393 user_id=self.user_id,
394 first_name=self.name,
394 first_name=self.name,
395 last_name=self.lastname,
395 last_name=self.lastname,
396 email=self.email,
396 email=self.email,
397 full_name=self.full_name,
397 full_name=self.full_name,
398 full_name_or_username=self.full_name_or_username,
398 full_name_or_username=self.full_name_or_username,
399 short_contact=self.short_contact,
399 short_contact=self.short_contact,
400 full_contact=self.full_contact
400 full_contact=self.full_contact
401 )
401 )
402
402
403
403
404 class UserLog(Base, BaseModel):
404 class UserLog(Base, BaseModel):
405 __tablename__ = 'user_logs'
405 __tablename__ = 'user_logs'
406 __table_args__ = (
406 __table_args__ = (
407 {'extend_existing': True, 'mysql_engine':'InnoDB',
407 {'extend_existing': True, 'mysql_engine':'InnoDB',
408 'mysql_charset': 'utf8'},
408 'mysql_charset': 'utf8'},
409 )
409 )
410 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
410 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
411 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
411 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
412 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
412 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
413 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
413 repository_name = Column("repository_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
414 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
414 user_ip = Column("user_ip", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
415 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
415 action = Column("action", UnicodeText(length=1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
416 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
416 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
417
417
418 @property
418 @property
419 def action_as_day(self):
419 def action_as_day(self):
420 return datetime.date(*self.action_date.timetuple()[:3])
420 return datetime.date(*self.action_date.timetuple()[:3])
421
421
422 user = relationship('User')
422 user = relationship('User')
423 repository = relationship('Repository', cascade='')
423 repository = relationship('Repository', cascade='')
424
424
425
425
426 class UsersGroup(Base, BaseModel):
426 class UsersGroup(Base, BaseModel):
427 __tablename__ = 'users_groups'
427 __tablename__ = 'users_groups'
428 __table_args__ = (
428 __table_args__ = (
429 {'extend_existing': True, 'mysql_engine':'InnoDB',
429 {'extend_existing': True, 'mysql_engine':'InnoDB',
430 'mysql_charset': 'utf8'},
430 'mysql_charset': 'utf8'},
431 )
431 )
432
432
433 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
433 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
434 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
434 users_group_name = Column("users_group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
435 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
435 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
436
436
437 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
437 members = relationship('UsersGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
438 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
438 users_group_to_perm = relationship('UsersGroupToPerm', cascade='all')
439 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
439 users_group_repo_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
440
440
441 def __unicode__(self):
441 def __unicode__(self):
442 return u'<userGroup(%s)>' % (self.users_group_name)
442 return u'<userGroup(%s)>' % (self.users_group_name)
443
443
444 @classmethod
444 @classmethod
445 def get_by_group_name(cls, group_name, cache=False,
445 def get_by_group_name(cls, group_name, cache=False,
446 case_insensitive=False):
446 case_insensitive=False):
447 if case_insensitive:
447 if case_insensitive:
448 q = cls.query().filter(cls.users_group_name.ilike(group_name))
448 q = cls.query().filter(cls.users_group_name.ilike(group_name))
449 else:
449 else:
450 q = cls.query().filter(cls.users_group_name == group_name)
450 q = cls.query().filter(cls.users_group_name == group_name)
451 if cache:
451 if cache:
452 q = q.options(FromCache(
452 q = q.options(FromCache(
453 "sql_cache_short",
453 "sql_cache_short",
454 "get_user_%s" % _hash_key(group_name)
454 "get_user_%s" % _hash_key(group_name)
455 )
455 )
456 )
456 )
457 return q.scalar()
457 return q.scalar()
458
458
459 @classmethod
459 @classmethod
460 def get(cls, users_group_id, cache=False):
460 def get(cls, users_group_id, cache=False):
461 users_group = cls.query()
461 users_group = cls.query()
462 if cache:
462 if cache:
463 users_group = users_group.options(FromCache("sql_cache_short",
463 users_group = users_group.options(FromCache("sql_cache_short",
464 "get_users_group_%s" % users_group_id))
464 "get_users_group_%s" % users_group_id))
465 return users_group.get(users_group_id)
465 return users_group.get(users_group_id)
466
466
467
467
468 class UsersGroupMember(Base, BaseModel):
468 class UsersGroupMember(Base, BaseModel):
469 __tablename__ = 'users_groups_members'
469 __tablename__ = 'users_groups_members'
470 __table_args__ = (
470 __table_args__ = (
471 {'extend_existing': True, 'mysql_engine':'InnoDB',
471 {'extend_existing': True, 'mysql_engine':'InnoDB',
472 'mysql_charset': 'utf8'},
472 'mysql_charset': 'utf8'},
473 )
473 )
474
474
475 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
475 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
476 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
476 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
477 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
477 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
478
478
479 user = relationship('User', lazy='joined')
479 user = relationship('User', lazy='joined')
480 users_group = relationship('UsersGroup')
480 users_group = relationship('UsersGroup')
481
481
482 def __init__(self, gr_id='', u_id=''):
482 def __init__(self, gr_id='', u_id=''):
483 self.users_group_id = gr_id
483 self.users_group_id = gr_id
484 self.user_id = u_id
484 self.user_id = u_id
485
485
486
486
487 class Repository(Base, BaseModel):
487 class Repository(Base, BaseModel):
488 __tablename__ = 'repositories'
488 __tablename__ = 'repositories'
489 __table_args__ = (
489 __table_args__ = (
490 UniqueConstraint('repo_name'),
490 UniqueConstraint('repo_name'),
491 {'extend_existing': True, 'mysql_engine':'InnoDB',
491 {'extend_existing': True, 'mysql_engine':'InnoDB',
492 'mysql_charset': 'utf8'},
492 'mysql_charset': 'utf8'},
493 )
493 )
494
494
495 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
495 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
496 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
496 repo_name = Column("repo_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
497 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
497 clone_uri = Column("clone_uri", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
498 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
498 repo_type = Column("repo_type", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default='hg')
499 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
499 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
500 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
500 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
501 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
501 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
502 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
502 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
503 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
503 description = Column("description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
504 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
504 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
505
505
506 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
506 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
507 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
507 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
508
508
509 user = relationship('User')
509 user = relationship('User')
510 fork = relationship('Repository', remote_side=repo_id)
510 fork = relationship('Repository', remote_side=repo_id)
511 group = relationship('RepoGroup')
511 group = relationship('RepoGroup')
512 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
512 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
513 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
513 users_group_to_perm = relationship('UsersGroupRepoToPerm', cascade='all')
514 stats = relationship('Statistics', cascade='all', uselist=False)
514 stats = relationship('Statistics', cascade='all', uselist=False)
515
515
516 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
516 followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id', cascade='all')
517
517
518 logs = relationship('UserLog')
518 logs = relationship('UserLog')
519
519
520 def __unicode__(self):
520 def __unicode__(self):
521 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
521 return u"<%s('%s:%s')>" % (self.__class__.__name__,self.repo_id,
522 self.repo_name)
522 self.repo_name)
523
523
524 @classmethod
524 @classmethod
525 def url_sep(cls):
525 def url_sep(cls):
526 return '/'
526 return '/'
527
527
528 @classmethod
528 @classmethod
529 def get_by_repo_name(cls, repo_name):
529 def get_by_repo_name(cls, repo_name):
530 q = Session.query(cls).filter(cls.repo_name == repo_name)
530 q = Session.query(cls).filter(cls.repo_name == repo_name)
531 q = q.options(joinedload(Repository.fork))\
531 q = q.options(joinedload(Repository.fork))\
532 .options(joinedload(Repository.user))\
532 .options(joinedload(Repository.user))\
533 .options(joinedload(Repository.group))
533 .options(joinedload(Repository.group))
534 return q.scalar()
534 return q.scalar()
535
535
536 @classmethod
536 @classmethod
537 def get_repo_forks(cls, repo_id):
537 def get_repo_forks(cls, repo_id):
538 return cls.query().filter(Repository.fork_id == repo_id)
538 return cls.query().filter(Repository.fork_id == repo_id)
539
539
540 @classmethod
540 @classmethod
541 def base_path(cls):
541 def base_path(cls):
542 """
542 """
543 Returns base path when all repos are stored
543 Returns base path when all repos are stored
544
544
545 :param cls:
545 :param cls:
546 """
546 """
547 q = Session.query(RhodeCodeUi)\
547 q = Session.query(RhodeCodeUi)\
548 .filter(RhodeCodeUi.ui_key == cls.url_sep())
548 .filter(RhodeCodeUi.ui_key == cls.url_sep())
549 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
549 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
550 return q.one().ui_value
550 return q.one().ui_value
551
551
552 @property
552 @property
553 def just_name(self):
553 def just_name(self):
554 return self.repo_name.split(Repository.url_sep())[-1]
554 return self.repo_name.split(Repository.url_sep())[-1]
555
555
556 @property
556 @property
557 def groups_with_parents(self):
557 def groups_with_parents(self):
558 groups = []
558 groups = []
559 if self.group is None:
559 if self.group is None:
560 return groups
560 return groups
561
561
562 cur_gr = self.group
562 cur_gr = self.group
563 groups.insert(0, cur_gr)
563 groups.insert(0, cur_gr)
564 while 1:
564 while 1:
565 gr = getattr(cur_gr, 'parent_group', None)
565 gr = getattr(cur_gr, 'parent_group', None)
566 cur_gr = cur_gr.parent_group
566 cur_gr = cur_gr.parent_group
567 if gr is None:
567 if gr is None:
568 break
568 break
569 groups.insert(0, gr)
569 groups.insert(0, gr)
570
570
571 return groups
571 return groups
572
572
573 @property
573 @property
574 def groups_and_repo(self):
574 def groups_and_repo(self):
575 return self.groups_with_parents, self.just_name
575 return self.groups_with_parents, self.just_name
576
576
577 @LazyProperty
577 @LazyProperty
578 def repo_path(self):
578 def repo_path(self):
579 """
579 """
580 Returns base full path for that repository means where it actually
580 Returns base full path for that repository means where it actually
581 exists on a filesystem
581 exists on a filesystem
582 """
582 """
583 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
583 q = Session.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
584 Repository.url_sep())
584 Repository.url_sep())
585 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
585 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
586 return q.one().ui_value
586 return q.one().ui_value
587
587
588 @property
588 @property
589 def repo_full_path(self):
589 def repo_full_path(self):
590 p = [self.repo_path]
590 p = [self.repo_path]
591 # we need to split the name by / since this is how we store the
591 # we need to split the name by / since this is how we store the
592 # names in the database, but that eventually needs to be converted
592 # names in the database, but that eventually needs to be converted
593 # into a valid system path
593 # into a valid system path
594 p += self.repo_name.split(Repository.url_sep())
594 p += self.repo_name.split(Repository.url_sep())
595 return os.path.join(*p)
595 return os.path.join(*p)
596
596
597 def get_new_name(self, repo_name):
597 def get_new_name(self, repo_name):
598 """
598 """
599 returns new full repository name based on assigned group and new new
599 returns new full repository name based on assigned group and new new
600
600
601 :param group_name:
601 :param group_name:
602 """
602 """
603 path_prefix = self.group.full_path_splitted if self.group else []
603 path_prefix = self.group.full_path_splitted if self.group else []
604 return Repository.url_sep().join(path_prefix + [repo_name])
604 return Repository.url_sep().join(path_prefix + [repo_name])
605
605
606 @property
606 @property
607 def _ui(self):
607 def _ui(self):
608 """
608 """
609 Creates an db based ui object for this repository
609 Creates an db based ui object for this repository
610 """
610 """
611 from mercurial import ui
611 from mercurial import ui
612 from mercurial import config
612 from mercurial import config
613 baseui = ui.ui()
613 baseui = ui.ui()
614
614
615 #clean the baseui object
615 #clean the baseui object
616 baseui._ocfg = config.config()
616 baseui._ocfg = config.config()
617 baseui._ucfg = config.config()
617 baseui._ucfg = config.config()
618 baseui._tcfg = config.config()
618 baseui._tcfg = config.config()
619
619
620 ret = RhodeCodeUi.query()\
620 ret = RhodeCodeUi.query()\
621 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
621 .options(FromCache("sql_cache_short", "repository_repo_ui")).all()
622
622
623 hg_ui = ret
623 hg_ui = ret
624 for ui_ in hg_ui:
624 for ui_ in hg_ui:
625 if ui_.ui_active:
625 if ui_.ui_active:
626 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
626 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
627 ui_.ui_key, ui_.ui_value)
627 ui_.ui_key, ui_.ui_value)
628 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
628 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
629
629
630 return baseui
630 return baseui
631
631
632 @classmethod
632 @classmethod
633 def is_valid(cls, repo_name):
633 def is_valid(cls, repo_name):
634 """
634 """
635 returns True if given repo name is a valid filesystem repository
635 returns True if given repo name is a valid filesystem repository
636
636
637 :param cls:
637 :param cls:
638 :param repo_name:
638 :param repo_name:
639 """
639 """
640 from rhodecode.lib.utils import is_valid_repo
640 from rhodecode.lib.utils import is_valid_repo
641
641
642 return is_valid_repo(repo_name, cls.base_path())
642 return is_valid_repo(repo_name, cls.base_path())
643
643
644 #==========================================================================
644 #==========================================================================
645 # SCM PROPERTIES
645 # SCM PROPERTIES
646 #==========================================================================
646 #==========================================================================
647
647
648 def get_changeset(self, rev):
648 def get_changeset(self, rev):
649 return get_changeset_safe(self.scm_instance, rev)
649 return get_changeset_safe(self.scm_instance, rev)
650
650
651 @property
651 @property
652 def tip(self):
652 def tip(self):
653 return self.get_changeset('tip')
653 return self.get_changeset('tip')
654
654
655 @property
655 @property
656 def author(self):
656 def author(self):
657 return self.tip.author
657 return self.tip.author
658
658
659 @property
659 @property
660 def last_change(self):
660 def last_change(self):
661 return self.scm_instance.last_change
661 return self.scm_instance.last_change
662
662
663 def comments(self, revisions=None):
663 def comments(self, revisions=None):
664 """
664 """
665 Returns comments for this repository grouped by revisions
665 Returns comments for this repository grouped by revisions
666
666
667 :param revisions: filter query by revisions only
667 :param revisions: filter query by revisions only
668 """
668 """
669 cmts = ChangesetComment.query()\
669 cmts = ChangesetComment.query()\
670 .filter(ChangesetComment.repo == self)
670 .filter(ChangesetComment.repo == self)
671 if revisions:
671 if revisions:
672 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
672 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
673 grouped = defaultdict(list)
673 grouped = defaultdict(list)
674 for cmt in cmts.all():
674 for cmt in cmts.all():
675 grouped[cmt.revision].append(cmt)
675 grouped[cmt.revision].append(cmt)
676 return grouped
676 return grouped
677
677
678 #==========================================================================
678 #==========================================================================
679 # SCM CACHE INSTANCE
679 # SCM CACHE INSTANCE
680 #==========================================================================
680 #==========================================================================
681
681
682 @property
682 @property
683 def invalidate(self):
683 def invalidate(self):
684 return CacheInvalidation.invalidate(self.repo_name)
684 return CacheInvalidation.invalidate(self.repo_name)
685
685
686 def set_invalidate(self):
686 def set_invalidate(self):
687 """
687 """
688 set a cache for invalidation for this instance
688 set a cache for invalidation for this instance
689 """
689 """
690 CacheInvalidation.set_invalidate(self.repo_name)
690 CacheInvalidation.set_invalidate(self.repo_name)
691
691
692 @LazyProperty
692 @LazyProperty
693 def scm_instance(self):
693 def scm_instance(self):
694 return self.__get_instance()
694 return self.__get_instance()
695
695
696 @property
696 @property
697 def scm_instance_cached(self):
697 def scm_instance_cached(self):
698 @cache_region('long_term')
698 @cache_region('long_term')
699 def _c(repo_name):
699 def _c(repo_name):
700 return self.__get_instance()
700 return self.__get_instance()
701 rn = self.repo_name
701 rn = self.repo_name
702 log.debug('Getting cached instance of repo')
702 log.debug('Getting cached instance of repo')
703 inv = self.invalidate
703 inv = self.invalidate
704 if inv is not None:
704 if inv is not None:
705 region_invalidate(_c, None, rn)
705 region_invalidate(_c, None, rn)
706 # update our cache
706 # update our cache
707 CacheInvalidation.set_valid(inv.cache_key)
707 CacheInvalidation.set_valid(inv.cache_key)
708 return _c(rn)
708 return _c(rn)
709
709
710 def __get_instance(self):
710 def __get_instance(self):
711 repo_full_path = self.repo_full_path
711 repo_full_path = self.repo_full_path
712 try:
712 try:
713 alias = get_scm(repo_full_path)[0]
713 alias = get_scm(repo_full_path)[0]
714 log.debug('Creating instance of %s repository' % alias)
714 log.debug('Creating instance of %s repository' % alias)
715 backend = get_backend(alias)
715 backend = get_backend(alias)
716 except VCSError:
716 except VCSError:
717 log.error(traceback.format_exc())
717 log.error(traceback.format_exc())
718 log.error('Perhaps this repository is in db and not in '
718 log.error('Perhaps this repository is in db and not in '
719 'filesystem run rescan repositories with '
719 'filesystem run rescan repositories with '
720 '"destroy old data " option from admin panel')
720 '"destroy old data " option from admin panel')
721 return
721 return
722
722
723 if alias == 'hg':
723 if alias == 'hg':
724
724
725 repo = backend(safe_str(repo_full_path), create=False,
725 repo = backend(safe_str(repo_full_path), create=False,
726 baseui=self._ui)
726 baseui=self._ui)
727 # skip hidden web repository
727 # skip hidden web repository
728 if repo._get_hidden():
728 if repo._get_hidden():
729 return
729 return
730 else:
730 else:
731 repo = backend(repo_full_path, create=False)
731 repo = backend(repo_full_path, create=False)
732
732
733 return repo
733 return repo
734
734
735
735
736 class RepoGroup(Base, BaseModel):
736 class RepoGroup(Base, BaseModel):
737 __tablename__ = 'groups'
737 __tablename__ = 'groups'
738 __table_args__ = (
738 __table_args__ = (
739 UniqueConstraint('group_name', 'group_parent_id'),
739 UniqueConstraint('group_name', 'group_parent_id'),
740 CheckConstraint('group_id != group_parent_id'),
740 CheckConstraint('group_id != group_parent_id'),
741 {'extend_existing': True, 'mysql_engine':'InnoDB',
741 {'extend_existing': True, 'mysql_engine':'InnoDB',
742 'mysql_charset': 'utf8'},
742 'mysql_charset': 'utf8'},
743 )
743 )
744 __mapper_args__ = {'order_by': 'group_name'}
744 __mapper_args__ = {'order_by': 'group_name'}
745
745
746 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
746 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
747 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
747 group_name = Column("group_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
748 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
748 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
749 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
749 group_description = Column("group_description", String(length=10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
750
750
751 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
751 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
752 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
752 users_group_to_perm = relationship('UsersGroupRepoGroupToPerm', cascade='all')
753
753
754 parent_group = relationship('RepoGroup', remote_side=group_id)
754 parent_group = relationship('RepoGroup', remote_side=group_id)
755
755
756 def __init__(self, group_name='', parent_group=None):
756 def __init__(self, group_name='', parent_group=None):
757 self.group_name = group_name
757 self.group_name = group_name
758 self.parent_group = parent_group
758 self.parent_group = parent_group
759
759
760 def __unicode__(self):
760 def __unicode__(self):
761 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
761 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.group_id,
762 self.group_name)
762 self.group_name)
763
763
764 @classmethod
764 @classmethod
765 def groups_choices(cls):
765 def groups_choices(cls):
766 from webhelpers.html import literal as _literal
766 from webhelpers.html import literal as _literal
767 repo_groups = [('', '')]
767 repo_groups = [('', '')]
768 sep = ' &raquo; '
768 sep = ' &raquo; '
769 _name = lambda k: _literal(sep.join(k))
769 _name = lambda k: _literal(sep.join(k))
770
770
771 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
771 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
772 for x in cls.query().all()])
772 for x in cls.query().all()])
773
773
774 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
774 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
775 return repo_groups
775 return repo_groups
776
776
777 @classmethod
777 @classmethod
778 def url_sep(cls):
778 def url_sep(cls):
779 return '/'
779 return '/'
780
780
781 @classmethod
781 @classmethod
782 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
782 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
783 if case_insensitive:
783 if case_insensitive:
784 gr = cls.query()\
784 gr = cls.query()\
785 .filter(cls.group_name.ilike(group_name))
785 .filter(cls.group_name.ilike(group_name))
786 else:
786 else:
787 gr = cls.query()\
787 gr = cls.query()\
788 .filter(cls.group_name == group_name)
788 .filter(cls.group_name == group_name)
789 if cache:
789 if cache:
790 gr = gr.options(FromCache(
790 gr = gr.options(FromCache(
791 "sql_cache_short",
791 "sql_cache_short",
792 "get_group_%s" % _hash_key(group_name)
792 "get_group_%s" % _hash_key(group_name)
793 )
793 )
794 )
794 )
795 return gr.scalar()
795 return gr.scalar()
796
796
797 @property
797 @property
798 def parents(self):
798 def parents(self):
799 parents_recursion_limit = 5
799 parents_recursion_limit = 5
800 groups = []
800 groups = []
801 if self.parent_group is None:
801 if self.parent_group is None:
802 return groups
802 return groups
803 cur_gr = self.parent_group
803 cur_gr = self.parent_group
804 groups.insert(0, cur_gr)
804 groups.insert(0, cur_gr)
805 cnt = 0
805 cnt = 0
806 while 1:
806 while 1:
807 cnt += 1
807 cnt += 1
808 gr = getattr(cur_gr, 'parent_group', None)
808 gr = getattr(cur_gr, 'parent_group', None)
809 cur_gr = cur_gr.parent_group
809 cur_gr = cur_gr.parent_group
810 if gr is None:
810 if gr is None:
811 break
811 break
812 if cnt == parents_recursion_limit:
812 if cnt == parents_recursion_limit:
813 # this will prevent accidental infinit loops
813 # this will prevent accidental infinit loops
814 log.error('group nested more than %s' %
814 log.error('group nested more than %s' %
815 parents_recursion_limit)
815 parents_recursion_limit)
816 break
816 break
817
817
818 groups.insert(0, gr)
818 groups.insert(0, gr)
819 return groups
819 return groups
820
820
821 @property
821 @property
822 def children(self):
822 def children(self):
823 return RepoGroup.query().filter(RepoGroup.parent_group == self)
823 return RepoGroup.query().filter(RepoGroup.parent_group == self)
824
824
825 @property
825 @property
826 def name(self):
826 def name(self):
827 return self.group_name.split(RepoGroup.url_sep())[-1]
827 return self.group_name.split(RepoGroup.url_sep())[-1]
828
828
829 @property
829 @property
830 def full_path(self):
830 def full_path(self):
831 return self.group_name
831 return self.group_name
832
832
833 @property
833 @property
834 def full_path_splitted(self):
834 def full_path_splitted(self):
835 return self.group_name.split(RepoGroup.url_sep())
835 return self.group_name.split(RepoGroup.url_sep())
836
836
837 @property
837 @property
838 def repositories(self):
838 def repositories(self):
839 return Repository.query()\
839 return Repository.query()\
840 .filter(Repository.group == self)\
840 .filter(Repository.group == self)\
841 .order_by(Repository.repo_name)
841 .order_by(Repository.repo_name)
842
842
843 @property
843 @property
844 def repositories_recursive_count(self):
844 def repositories_recursive_count(self):
845 cnt = self.repositories.count()
845 cnt = self.repositories.count()
846
846
847 def children_count(group):
847 def children_count(group):
848 cnt = 0
848 cnt = 0
849 for child in group.children:
849 for child in group.children:
850 cnt += child.repositories.count()
850 cnt += child.repositories.count()
851 cnt += children_count(child)
851 cnt += children_count(child)
852 return cnt
852 return cnt
853
853
854 return cnt + children_count(self)
854 return cnt + children_count(self)
855
855
856 def get_new_name(self, group_name):
856 def get_new_name(self, group_name):
857 """
857 """
858 returns new full group name based on parent and new name
858 returns new full group name based on parent and new name
859
859
860 :param group_name:
860 :param group_name:
861 """
861 """
862 path_prefix = (self.parent_group.full_path_splitted if
862 path_prefix = (self.parent_group.full_path_splitted if
863 self.parent_group else [])
863 self.parent_group else [])
864 return RepoGroup.url_sep().join(path_prefix + [group_name])
864 return RepoGroup.url_sep().join(path_prefix + [group_name])
865
865
866
866
867 class Permission(Base, BaseModel):
867 class Permission(Base, BaseModel):
868 __tablename__ = 'permissions'
868 __tablename__ = 'permissions'
869 __table_args__ = (
869 __table_args__ = (
870 {'extend_existing': True, 'mysql_engine':'InnoDB',
870 {'extend_existing': True, 'mysql_engine':'InnoDB',
871 'mysql_charset': 'utf8'},
871 'mysql_charset': 'utf8'},
872 )
872 )
873 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
873 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
874 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
874 permission_name = Column("permission_name", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
875 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
875 permission_longname = Column("permission_longname", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
876
876
877 def __unicode__(self):
877 def __unicode__(self):
878 return u"<%s('%s:%s')>" % (
878 return u"<%s('%s:%s')>" % (
879 self.__class__.__name__, self.permission_id, self.permission_name
879 self.__class__.__name__, self.permission_id, self.permission_name
880 )
880 )
881
881
882 @classmethod
882 @classmethod
883 def get_by_key(cls, key):
883 def get_by_key(cls, key):
884 return cls.query().filter(cls.permission_name == key).scalar()
884 return cls.query().filter(cls.permission_name == key).scalar()
885
885
886 @classmethod
886 @classmethod
887 def get_default_perms(cls, default_user_id):
887 def get_default_perms(cls, default_user_id):
888 q = Session.query(UserRepoToPerm, Repository, cls)\
888 q = Session.query(UserRepoToPerm, Repository, cls)\
889 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
889 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
890 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
890 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
891 .filter(UserRepoToPerm.user_id == default_user_id)
891 .filter(UserRepoToPerm.user_id == default_user_id)
892
892
893 return q.all()
893 return q.all()
894
894
895 @classmethod
895 @classmethod
896 def get_default_group_perms(cls, default_user_id):
896 def get_default_group_perms(cls, default_user_id):
897 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
897 q = Session.query(UserRepoGroupToPerm, RepoGroup, cls)\
898 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
898 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
899 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
899 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
900 .filter(UserRepoGroupToPerm.user_id == default_user_id)
900 .filter(UserRepoGroupToPerm.user_id == default_user_id)
901
901
902 return q.all()
902 return q.all()
903
903
904
904
905 class UserRepoToPerm(Base, BaseModel):
905 class UserRepoToPerm(Base, BaseModel):
906 __tablename__ = 'repo_to_perm'
906 __tablename__ = 'repo_to_perm'
907 __table_args__ = (
907 __table_args__ = (
908 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
908 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
909 {'extend_existing': True, 'mysql_engine':'InnoDB',
909 {'extend_existing': True, 'mysql_engine':'InnoDB',
910 'mysql_charset': 'utf8'}
910 'mysql_charset': 'utf8'}
911 )
911 )
912 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
912 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
913 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
913 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
914 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
914 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
915 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
915 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
916
916
917 user = relationship('User')
917 user = relationship('User')
918 repository = relationship('Repository')
918 repository = relationship('Repository')
919 permission = relationship('Permission')
919 permission = relationship('Permission')
920
920
921 @classmethod
921 @classmethod
922 def create(cls, user, repository, permission):
922 def create(cls, user, repository, permission):
923 n = cls()
923 n = cls()
924 n.user = user
924 n.user = user
925 n.repository = repository
925 n.repository = repository
926 n.permission = permission
926 n.permission = permission
927 Session.add(n)
927 Session.add(n)
928 return n
928 return n
929
929
930 def __unicode__(self):
930 def __unicode__(self):
931 return u'<user:%s => %s >' % (self.user, self.repository)
931 return u'<user:%s => %s >' % (self.user, self.repository)
932
932
933
933
934 class UserToPerm(Base, BaseModel):
934 class UserToPerm(Base, BaseModel):
935 __tablename__ = 'user_to_perm'
935 __tablename__ = 'user_to_perm'
936 __table_args__ = (
936 __table_args__ = (
937 UniqueConstraint('user_id', 'permission_id'),
937 UniqueConstraint('user_id', 'permission_id'),
938 {'extend_existing': True, 'mysql_engine':'InnoDB',
938 {'extend_existing': True, 'mysql_engine':'InnoDB',
939 'mysql_charset': 'utf8'}
939 'mysql_charset': 'utf8'}
940 )
940 )
941 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
941 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
942 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
942 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
943 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
943 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
944
944
945 user = relationship('User')
945 user = relationship('User')
946 permission = relationship('Permission', lazy='joined')
946 permission = relationship('Permission', lazy='joined')
947
947
948
948
949 class UsersGroupRepoToPerm(Base, BaseModel):
949 class UsersGroupRepoToPerm(Base, BaseModel):
950 __tablename__ = 'users_group_repo_to_perm'
950 __tablename__ = 'users_group_repo_to_perm'
951 __table_args__ = (
951 __table_args__ = (
952 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
952 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
953 {'extend_existing': True, 'mysql_engine':'InnoDB',
953 {'extend_existing': True, 'mysql_engine':'InnoDB',
954 'mysql_charset': 'utf8'}
954 'mysql_charset': 'utf8'}
955 )
955 )
956 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
956 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
957 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
957 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
958 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
958 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
959 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
959 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
960
960
961 users_group = relationship('UsersGroup')
961 users_group = relationship('UsersGroup')
962 permission = relationship('Permission')
962 permission = relationship('Permission')
963 repository = relationship('Repository')
963 repository = relationship('Repository')
964
964
965 @classmethod
965 @classmethod
966 def create(cls, users_group, repository, permission):
966 def create(cls, users_group, repository, permission):
967 n = cls()
967 n = cls()
968 n.users_group = users_group
968 n.users_group = users_group
969 n.repository = repository
969 n.repository = repository
970 n.permission = permission
970 n.permission = permission
971 Session.add(n)
971 Session.add(n)
972 return n
972 return n
973
973
974 def __unicode__(self):
974 def __unicode__(self):
975 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
975 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
976
976
977
977
978 class UsersGroupToPerm(Base, BaseModel):
978 class UsersGroupToPerm(Base, BaseModel):
979 __tablename__ = 'users_group_to_perm'
979 __tablename__ = 'users_group_to_perm'
980 __table_args__ = (
980 __table_args__ = (
981 UniqueConstraint('users_group_id', 'permission_id',),
981 UniqueConstraint('users_group_id', 'permission_id',),
982 {'extend_existing': True, 'mysql_engine':'InnoDB',
982 {'extend_existing': True, 'mysql_engine':'InnoDB',
983 'mysql_charset': 'utf8'}
983 'mysql_charset': 'utf8'}
984 )
984 )
985 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
985 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
986 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
986 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
987 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
987 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
988
988
989 users_group = relationship('UsersGroup')
989 users_group = relationship('UsersGroup')
990 permission = relationship('Permission')
990 permission = relationship('Permission')
991
991
992
992
993 class UserRepoGroupToPerm(Base, BaseModel):
993 class UserRepoGroupToPerm(Base, BaseModel):
994 __tablename__ = 'user_repo_group_to_perm'
994 __tablename__ = 'user_repo_group_to_perm'
995 __table_args__ = (
995 __table_args__ = (
996 UniqueConstraint('user_id', 'group_id', 'permission_id'),
996 UniqueConstraint('user_id', 'group_id', 'permission_id'),
997 {'extend_existing': True, 'mysql_engine':'InnoDB',
997 {'extend_existing': True, 'mysql_engine':'InnoDB',
998 'mysql_charset': 'utf8'}
998 'mysql_charset': 'utf8'}
999 )
999 )
1000
1000
1001 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1001 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1002 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1002 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1003 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1003 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1004 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1004 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1005
1005
1006 user = relationship('User')
1006 user = relationship('User')
1007 group = relationship('RepoGroup')
1007 group = relationship('RepoGroup')
1008 permission = relationship('Permission')
1008 permission = relationship('Permission')
1009
1009
1010
1010
1011 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1011 class UsersGroupRepoGroupToPerm(Base, BaseModel):
1012 __tablename__ = 'users_group_repo_group_to_perm'
1012 __tablename__ = 'users_group_repo_group_to_perm'
1013 __table_args__ = (
1013 __table_args__ = (
1014 UniqueConstraint('users_group_id', 'group_id'),
1014 UniqueConstraint('users_group_id', 'group_id'),
1015 {'extend_existing': True, 'mysql_engine':'InnoDB',
1015 {'extend_existing': True, 'mysql_engine':'InnoDB',
1016 'mysql_charset': 'utf8'}
1016 'mysql_charset': 'utf8'}
1017 )
1017 )
1018
1018
1019 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1019 users_group_repo_group_to_perm_id = Column("users_group_repo_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1020 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1020 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1021 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1021 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1022 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1022 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1023
1023
1024 users_group = relationship('UsersGroup')
1024 users_group = relationship('UsersGroup')
1025 permission = relationship('Permission')
1025 permission = relationship('Permission')
1026 group = relationship('RepoGroup')
1026 group = relationship('RepoGroup')
1027
1027
1028
1028
1029 class Statistics(Base, BaseModel):
1029 class Statistics(Base, BaseModel):
1030 __tablename__ = 'statistics'
1030 __tablename__ = 'statistics'
1031 __table_args__ = (
1031 __table_args__ = (
1032 UniqueConstraint('repository_id'),
1032 UniqueConstraint('repository_id'),
1033 {'extend_existing': True, 'mysql_engine':'InnoDB',
1033 {'extend_existing': True, 'mysql_engine':'InnoDB',
1034 'mysql_charset': 'utf8'}
1034 'mysql_charset': 'utf8'}
1035 )
1035 )
1036 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1036 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1037 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1037 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1038 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1038 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1039 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1039 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1040 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1040 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1041 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1041 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1042
1042
1043 repository = relationship('Repository', single_parent=True)
1043 repository = relationship('Repository', single_parent=True)
1044
1044
1045
1045
1046 class UserFollowing(Base, BaseModel):
1046 class UserFollowing(Base, BaseModel):
1047 __tablename__ = 'user_followings'
1047 __tablename__ = 'user_followings'
1048 __table_args__ = (
1048 __table_args__ = (
1049 UniqueConstraint('user_id', 'follows_repository_id'),
1049 UniqueConstraint('user_id', 'follows_repository_id'),
1050 UniqueConstraint('user_id', 'follows_user_id'),
1050 UniqueConstraint('user_id', 'follows_user_id'),
1051 {'extend_existing': True, 'mysql_engine':'InnoDB',
1051 {'extend_existing': True, 'mysql_engine':'InnoDB',
1052 'mysql_charset': 'utf8'}
1052 'mysql_charset': 'utf8'}
1053 )
1053 )
1054
1054
1055 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1055 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1056 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1056 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1057 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1057 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1058 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1058 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1059 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1059 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1060
1060
1061 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1061 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1062
1062
1063 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1063 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1064 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1064 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1065
1065
1066 @classmethod
1066 @classmethod
1067 def get_repo_followers(cls, repo_id):
1067 def get_repo_followers(cls, repo_id):
1068 return cls.query().filter(cls.follows_repo_id == repo_id)
1068 return cls.query().filter(cls.follows_repo_id == repo_id)
1069
1069
1070
1070
1071 class CacheInvalidation(Base, BaseModel):
1071 class CacheInvalidation(Base, BaseModel):
1072 __tablename__ = 'cache_invalidation'
1072 __tablename__ = 'cache_invalidation'
1073 __table_args__ = (
1073 __table_args__ = (
1074 UniqueConstraint('cache_key'),
1074 UniqueConstraint('cache_key'),
1075 {'extend_existing': True, 'mysql_engine':'InnoDB',
1075 {'extend_existing': True, 'mysql_engine':'InnoDB',
1076 'mysql_charset': 'utf8'},
1076 'mysql_charset': 'utf8'},
1077 )
1077 )
1078 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1078 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1079 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1079 cache_key = Column("cache_key", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1080 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1080 cache_args = Column("cache_args", String(length=255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1081 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1081 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1082
1082
1083 def __init__(self, cache_key, cache_args=''):
1083 def __init__(self, cache_key, cache_args=''):
1084 self.cache_key = cache_key
1084 self.cache_key = cache_key
1085 self.cache_args = cache_args
1085 self.cache_args = cache_args
1086 self.cache_active = False
1086 self.cache_active = False
1087
1087
1088 def __unicode__(self):
1088 def __unicode__(self):
1089 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1089 return u"<%s('%s:%s')>" % (self.__class__.__name__,
1090 self.cache_id, self.cache_key)
1090 self.cache_id, self.cache_key)
1091 @classmethod
1091 @classmethod
1092 def clear_cache(cls):
1092 def clear_cache(cls):
1093 cls.query().delete()
1093 cls.query().delete()
1094
1094
1095 @classmethod
1095 @classmethod
1096 def _get_key(cls, key):
1096 def _get_key(cls, key):
1097 """
1097 """
1098 Wrapper for generating a key, together with a prefix
1098 Wrapper for generating a key, together with a prefix
1099
1099
1100 :param key:
1100 :param key:
1101 """
1101 """
1102 import rhodecode
1102 import rhodecode
1103 prefix = ''
1103 prefix = ''
1104 iid = rhodecode.CONFIG.get('instance_id')
1104 iid = rhodecode.CONFIG.get('instance_id')
1105 if iid:
1105 if iid:
1106 prefix = iid
1106 prefix = iid
1107 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1107 return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
1108
1108
1109 @classmethod
1109 @classmethod
1110 def get_by_key(cls, key):
1110 def get_by_key(cls, key):
1111 return cls.query().filter(cls.cache_key == key).scalar()
1111 return cls.query().filter(cls.cache_key == key).scalar()
1112
1112
1113 @classmethod
1113 @classmethod
1114 def _get_or_create_key(cls, key, prefix, org_key):
1114 def _get_or_create_key(cls, key, prefix, org_key):
1115 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1115 inv_obj = Session.query(cls).filter(cls.cache_key == key).scalar()
1116 if not inv_obj:
1116 if not inv_obj:
1117 try:
1117 try:
1118 inv_obj = CacheInvalidation(key, org_key)
1118 inv_obj = CacheInvalidation(key, org_key)
1119 Session.add(inv_obj)
1119 Session.add(inv_obj)
1120 Session.commit()
1120 Session.commit()
1121 except Exception:
1121 except Exception:
1122 log.error(traceback.format_exc())
1122 log.error(traceback.format_exc())
1123 Session.rollback()
1123 Session.rollback()
1124 return inv_obj
1124 return inv_obj
1125
1125
1126 @classmethod
1126 @classmethod
1127 def invalidate(cls, key):
1127 def invalidate(cls, key):
1128 """
1128 """
1129 Returns Invalidation object if this given key should be invalidated
1129 Returns Invalidation object if this given key should be invalidated
1130 None otherwise. `cache_active = False` means that this cache
1130 None otherwise. `cache_active = False` means that this cache
1131 state is not valid and needs to be invalidated
1131 state is not valid and needs to be invalidated
1132
1132
1133 :param key:
1133 :param key:
1134 """
1134 """
1135
1135
1136 key, _prefix, _org_key = cls._get_key(key)
1136 key, _prefix, _org_key = cls._get_key(key)
1137 inv = cls._get_or_create_key(key, _prefix, _org_key)
1137 inv = cls._get_or_create_key(key, _prefix, _org_key)
1138
1138
1139 if inv and inv.cache_active is False:
1139 if inv and inv.cache_active is False:
1140 return inv
1140 return inv
1141
1141
1142 @classmethod
1142 @classmethod
1143 def set_invalidate(cls, key):
1143 def set_invalidate(cls, key):
1144 """
1144 """
1145 Mark this Cache key for invalidation
1145 Mark this Cache key for invalidation
1146
1146
1147 :param key:
1147 :param key:
1148 """
1148 """
1149
1149
1150 key, _prefix, _org_key = cls._get_key(key)
1150 key, _prefix, _org_key = cls._get_key(key)
1151 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1151 inv_objs = Session.query(cls).filter(cls.cache_args == _org_key).all()
1152 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1152 log.debug('marking %s key[s] %s for invalidation' % (len(inv_objs),
1153 _org_key))
1153 _org_key))
1154 try:
1154 try:
1155 for inv_obj in inv_objs:
1155 for inv_obj in inv_objs:
1156 if inv_obj:
1156 if inv_obj:
1157 inv_obj.cache_active = False
1157 inv_obj.cache_active = False
1158
1158
1159 Session.add(inv_obj)
1159 Session.add(inv_obj)
1160 Session.commit()
1160 Session.commit()
1161 except Exception:
1161 except Exception:
1162 log.error(traceback.format_exc())
1162 log.error(traceback.format_exc())
1163 Session.rollback()
1163 Session.rollback()
1164
1164
1165 @classmethod
1165 @classmethod
1166 def set_valid(cls, key):
1166 def set_valid(cls, key):
1167 """
1167 """
1168 Mark this cache key as active and currently cached
1168 Mark this cache key as active and currently cached
1169
1169
1170 :param key:
1170 :param key:
1171 """
1171 """
1172 inv_obj = cls.get_by_key(key)
1172 inv_obj = cls.get_by_key(key)
1173 inv_obj.cache_active = True
1173 inv_obj.cache_active = True
1174 Session.add(inv_obj)
1174 Session.add(inv_obj)
1175 Session.commit()
1175 Session.commit()
1176
1176
1177
1177
1178 class ChangesetComment(Base, BaseModel):
1178 class ChangesetComment(Base, BaseModel):
1179 __tablename__ = 'changeset_comments'
1179 __tablename__ = 'changeset_comments'
1180 __table_args__ = (
1180 __table_args__ = (
1181 {'extend_existing': True, 'mysql_engine':'InnoDB',
1181 {'extend_existing': True, 'mysql_engine':'InnoDB',
1182 'mysql_charset': 'utf8'},
1182 'mysql_charset': 'utf8'},
1183 )
1183 )
1184 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1184 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1185 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1185 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1186 revision = Column('revision', String(40), nullable=False)
1186 revision = Column('revision', String(40), nullable=False)
1187 line_no = Column('line_no', Unicode(10), nullable=True)
1187 line_no = Column('line_no', Unicode(10), nullable=True)
1188 f_path = Column('f_path', Unicode(1000), nullable=True)
1188 f_path = Column('f_path', Unicode(1000), nullable=True)
1189 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1189 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1190 text = Column('text', Unicode(25000), nullable=False)
1190 text = Column('text', Unicode(25000), nullable=False)
1191 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1191 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1192
1192
1193 author = relationship('User', lazy='joined')
1193 author = relationship('User', lazy='joined')
1194 repo = relationship('Repository')
1194 repo = relationship('Repository')
1195
1195
1196 @classmethod
1196 @classmethod
1197 def get_users(cls, revision):
1197 def get_users(cls, revision):
1198 """
1198 """
1199 Returns user associated with this changesetComment. ie those
1199 Returns user associated with this changesetComment. ie those
1200 who actually commented
1200 who actually commented
1201
1201
1202 :param cls:
1202 :param cls:
1203 :param revision:
1203 :param revision:
1204 """
1204 """
1205 return Session.query(User)\
1205 return Session.query(User)\
1206 .filter(cls.revision == revision)\
1206 .filter(cls.revision == revision)\
1207 .join(ChangesetComment.author).all()
1207 .join(ChangesetComment.author).all()
1208
1208
1209
1209
1210 class Notification(Base, BaseModel):
1210 class Notification(Base, BaseModel):
1211 __tablename__ = 'notifications'
1211 __tablename__ = 'notifications'
1212 __table_args__ = (
1212 __table_args__ = (
1213 {'extend_existing': True, 'mysql_engine':'InnoDB',
1213 {'extend_existing': True, 'mysql_engine':'InnoDB',
1214 'mysql_charset': 'utf8'},
1214 'mysql_charset': 'utf8'},
1215 )
1215 )
1216
1216
1217 TYPE_CHANGESET_COMMENT = u'cs_comment'
1217 TYPE_CHANGESET_COMMENT = u'cs_comment'
1218 TYPE_MESSAGE = u'message'
1218 TYPE_MESSAGE = u'message'
1219 TYPE_MENTION = u'mention'
1219 TYPE_MENTION = u'mention'
1220 TYPE_REGISTRATION = u'registration'
1220 TYPE_REGISTRATION = u'registration'
1221
1221
1222 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1222 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
1223 subject = Column('subject', Unicode(512), nullable=True)
1223 subject = Column('subject', Unicode(512), nullable=True)
1224 body = Column('body', Unicode(50000), nullable=True)
1224 body = Column('body', Unicode(50000), nullable=True)
1225 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1225 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
1226 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1226 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1227 type_ = Column('type', Unicode(256))
1227 type_ = Column('type', Unicode(256))
1228
1228
1229 created_by_user = relationship('User')
1229 created_by_user = relationship('User')
1230 notifications_to_users = relationship('UserNotification', lazy='joined',
1230 notifications_to_users = relationship('UserNotification', lazy='joined',
1231 cascade="all, delete, delete-orphan")
1231 cascade="all, delete, delete-orphan")
1232
1232
1233 @property
1233 @property
1234 def recipients(self):
1234 def recipients(self):
1235 return [x.user for x in UserNotification.query()\
1235 return [x.user for x in UserNotification.query()\
1236 .filter(UserNotification.notification == self).all()]
1236 .filter(UserNotification.notification == self).all()]
1237
1237
1238 @classmethod
1238 @classmethod
1239 def create(cls, created_by, subject, body, recipients, type_=None):
1239 def create(cls, created_by, subject, body, recipients, type_=None):
1240 if type_ is None:
1240 if type_ is None:
1241 type_ = Notification.TYPE_MESSAGE
1241 type_ = Notification.TYPE_MESSAGE
1242
1242
1243 notification = cls()
1243 notification = cls()
1244 notification.created_by_user = created_by
1244 notification.created_by_user = created_by
1245 notification.subject = subject
1245 notification.subject = subject
1246 notification.body = body
1246 notification.body = body
1247 notification.type_ = type_
1247 notification.type_ = type_
1248 notification.created_on = datetime.datetime.now()
1248 notification.created_on = datetime.datetime.now()
1249
1249
1250 for u in recipients:
1250 for u in recipients:
1251 assoc = UserNotification()
1251 assoc = UserNotification()
1252 assoc.notification = notification
1252 assoc.notification = notification
1253 u.notifications.append(assoc)
1253 u.notifications.append(assoc)
1254 Session.add(notification)
1254 Session.add(notification)
1255 return notification
1255 return notification
1256
1256
1257 @property
1257 @property
1258 def description(self):
1258 def description(self):
1259 from rhodecode.model.notification import NotificationModel
1259 from rhodecode.model.notification import NotificationModel
1260 return NotificationModel().make_description(self)
1260 return NotificationModel().make_description(self)
1261
1261
1262
1262
1263 class UserNotification(Base, BaseModel):
1263 class UserNotification(Base, BaseModel):
1264 __tablename__ = 'user_to_notification'
1264 __tablename__ = 'user_to_notification'
1265 __table_args__ = (
1265 __table_args__ = (
1266 UniqueConstraint('user_id', 'notification_id'),
1266 UniqueConstraint('user_id', 'notification_id'),
1267 {'extend_existing': True, 'mysql_engine':'InnoDB',
1267 {'extend_existing': True, 'mysql_engine':'InnoDB',
1268 'mysql_charset': 'utf8'}
1268 'mysql_charset': 'utf8'}
1269 )
1269 )
1270 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1270 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
1271 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1271 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
1272 read = Column('read', Boolean, default=False)
1272 read = Column('read', Boolean, default=False)
1273 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1273 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
1274
1274
1275 user = relationship('User', lazy="joined")
1275 user = relationship('User', lazy="joined")
1276 notification = relationship('Notification', lazy="joined",
1276 notification = relationship('Notification', lazy="joined",
1277 order_by=lambda: Notification.created_on.desc(),)
1277 order_by=lambda: Notification.created_on.desc(),)
1278
1278
1279 def mark_as_read(self):
1279 def mark_as_read(self):
1280 self.read = True
1280 self.read = True
1281 Session.add(self)
1281 Session.add(self)
1282
1282
1283
1283
1284 class DbMigrateVersion(Base, BaseModel):
1284 class DbMigrateVersion(Base, BaseModel):
1285 __tablename__ = 'db_migrate_version'
1285 __tablename__ = 'db_migrate_version'
1286 __table_args__ = (
1286 __table_args__ = (
1287 {'extend_existing': True, 'mysql_engine':'InnoDB',
1287 {'extend_existing': True, 'mysql_engine':'InnoDB',
1288 'mysql_charset': 'utf8'},
1288 'mysql_charset': 'utf8'},
1289 )
1289 )
1290 repository_id = Column('repository_id', String(250), primary_key=True)
1290 repository_id = Column('repository_id', String(250), primary_key=True)
1291 repository_path = Column('repository_path', Text)
1291 repository_path = Column('repository_path', Text)
1292 version = Column('version', Integer)
1292 version = Column('version', Integer)
1293
1293
1294 ## this is migration from 1_4_0, but now it's here to overcome a problem of
1294 ## this is migration from 1_4_0, but now it's here to overcome a problem of
1295 ## attaching a FK to this from 1_3_0 !
1295 ## attaching a FK to this from 1_3_0 !
1296
1296
1297
1297
1298 class PullRequest(Base, BaseModel):
1298 class PullRequest(Base, BaseModel):
1299 __tablename__ = 'pull_requests'
1299 __tablename__ = 'pull_requests'
1300 __table_args__ = (
1300 __table_args__ = (
1301 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1301 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1302 'mysql_charset': 'utf8'},
1302 'mysql_charset': 'utf8'},
1303 )
1303 )
1304
1304
1305 STATUS_NEW = u'new'
1305 STATUS_NEW = u'new'
1306 STATUS_OPEN = u'open'
1306 STATUS_OPEN = u'open'
1307 STATUS_CLOSED = u'closed'
1307 STATUS_CLOSED = u'closed'
1308
1308
1309 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1309 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1310 title = Column('title', Unicode(256), nullable=True)
1310 title = Column('title', Unicode(256), nullable=True)
1311 description = Column('description', UnicodeText(10240), nullable=True)
1311 description = Column('description', UnicodeText(10240), nullable=True)
1312 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1312 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1313 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1313 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1314 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1314 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1315 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1315 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1316 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1316 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1317 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1317 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1318 org_ref = Column('org_ref', Unicode(256), nullable=False)
1318 org_ref = Column('org_ref', Unicode(256), nullable=False)
1319 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1319 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1320 other_ref = Column('other_ref', Unicode(256), nullable=False) No newline at end of file
1320 other_ref = Column('other_ref', Unicode(256), nullable=False)
@@ -1,18 +1,18
1 """
1 """
2 Mercurial libs compatibility
2 Mercurial libs compatibility
3 """
3 """
4
4
5 from mercurial import archival, merge as hg_merge, patch, ui
5 from mercurial import archival, merge as hg_merge, patch, ui
6 from mercurial.commands import clone, nullid, pull
6 from mercurial.commands import clone, nullid, pull
7 from mercurial.context import memctx, memfilectx
7 from mercurial.context import memctx, memfilectx
8 from mercurial.error import RepoError, RepoLookupError, Abort
8 from mercurial.error import RepoError, RepoLookupError, Abort
9 from mercurial.hgweb.common import get_contact
9 from mercurial.hgweb.common import get_contact
10 from mercurial.localrepo import localrepository
10 from mercurial.localrepo import localrepository
11 from mercurial.match import match
11 from mercurial.match import match
12 from mercurial.mdiff import diffopts
12 from mercurial.mdiff import diffopts
13 from mercurial.node import hex
13 from mercurial.node import hex
14 from mercurial.encoding import tolocal
14 from mercurial.encoding import tolocal
15 from mercurial import discovery
15 from mercurial import discovery
16 from mercurial import localrepo
16 from mercurial import localrepo
17 from mercurial import scmutil
17 from mercurial import scmutil
18 from mercurial.discovery import findcommonoutgoing No newline at end of file
18 from mercurial.discovery import findcommonoutgoing
@@ -1,343 +1,343
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
97 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UsersGroupForm(formencode.Schema):
98 class _UsersGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUsersGroup(edit, old_data)
104 v.ValidUsersGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UsersGroupForm
115 return _UsersGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
119 class _ReposGroupForm(formencode.Schema):
119 class _ReposGroupForm(formencode.Schema):
120 allow_extra_fields = True
120 allow_extra_fields = True
121 filter_extra_fields = False
121 filter_extra_fields = False
122
122
123 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
123 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 v.SlugifyName())
124 v.SlugifyName())
125 group_description = v.UnicodeString(strip=True, min=1,
125 group_description = v.UnicodeString(strip=True, min=1,
126 not_empty=True)
126 not_empty=True)
127 group_parent_id = v.OneOf(available_groups, hideList=False,
127 group_parent_id = v.OneOf(available_groups, hideList=False,
128 testValueList=True,
128 testValueList=True,
129 if_missing=None, not_empty=False)
129 if_missing=None, not_empty=False)
130 enable_locking = v.StringBoolean(if_missing=False)
130 enable_locking = v.StringBoolean(if_missing=False)
131 chained_validators = [v.ValidReposGroup(edit, old_data),
131 chained_validators = [v.ValidReposGroup(edit, old_data),
132 v.ValidPerms('group')]
132 v.ValidPerms('group')]
133
133
134 return _ReposGroupForm
134 return _ReposGroupForm
135
135
136
136
137 def RegisterForm(edit=False, old_data={}):
137 def RegisterForm(edit=False, old_data={}):
138 class _RegisterForm(formencode.Schema):
138 class _RegisterForm(formencode.Schema):
139 allow_extra_fields = True
139 allow_extra_fields = True
140 filter_extra_fields = True
140 filter_extra_fields = True
141 username = All(
141 username = All(
142 v.ValidUsername(edit, old_data),
142 v.ValidUsername(edit, old_data),
143 v.UnicodeString(strip=True, min=1, not_empty=True)
143 v.UnicodeString(strip=True, min=1, not_empty=True)
144 )
144 )
145 password = All(
145 password = All(
146 v.ValidPassword(),
146 v.ValidPassword(),
147 v.UnicodeString(strip=False, min=6, not_empty=True)
147 v.UnicodeString(strip=False, min=6, not_empty=True)
148 )
148 )
149 password_confirmation = All(
149 password_confirmation = All(
150 v.ValidPassword(),
150 v.ValidPassword(),
151 v.UnicodeString(strip=False, min=6, not_empty=True)
151 v.UnicodeString(strip=False, min=6, not_empty=True)
152 )
152 )
153 active = v.StringBoolean(if_missing=False)
153 active = v.StringBoolean(if_missing=False)
154 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
154 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
155 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
156 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
156 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
157
157
158 chained_validators = [v.ValidPasswordsMatch()]
158 chained_validators = [v.ValidPasswordsMatch()]
159
159
160 return _RegisterForm
160 return _RegisterForm
161
161
162
162
163 def PasswordResetForm():
163 def PasswordResetForm():
164 class _PasswordResetForm(formencode.Schema):
164 class _PasswordResetForm(formencode.Schema):
165 allow_extra_fields = True
165 allow_extra_fields = True
166 filter_extra_fields = True
166 filter_extra_fields = True
167 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
167 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
168 return _PasswordResetForm
168 return _PasswordResetForm
169
169
170
170
171 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
171 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
172 repo_groups=[], landing_revs=[]):
172 repo_groups=[], landing_revs=[]):
173 class _RepoForm(formencode.Schema):
173 class _RepoForm(formencode.Schema):
174 allow_extra_fields = True
174 allow_extra_fields = True
175 filter_extra_fields = False
175 filter_extra_fields = False
176 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
176 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
177 v.SlugifyName())
177 v.SlugifyName())
178 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
178 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
179 repo_group = v.OneOf(repo_groups, hideList=True)
179 repo_group = v.OneOf(repo_groups, hideList=True)
180 repo_type = v.OneOf(supported_backends)
180 repo_type = v.OneOf(supported_backends)
181 description = v.UnicodeString(strip=True, min=1, not_empty=False)
181 description = v.UnicodeString(strip=True, min=1, not_empty=False)
182 private = v.StringBoolean(if_missing=False)
182 private = v.StringBoolean(if_missing=False)
183 enable_statistics = v.StringBoolean(if_missing=False)
183 enable_statistics = v.StringBoolean(if_missing=False)
184 enable_downloads = v.StringBoolean(if_missing=False)
184 enable_downloads = v.StringBoolean(if_missing=False)
185 enable_locking = v.StringBoolean(if_missing=False)
185 enable_locking = v.StringBoolean(if_missing=False)
186 landing_rev = v.OneOf(landing_revs, hideList=True)
186 landing_rev = v.OneOf(landing_revs, hideList=True)
187
187
188 if edit:
188 if edit:
189 #this is repo owner
189 #this is repo owner
190 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
190 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
191
191
192 chained_validators = [v.ValidCloneUri(),
192 chained_validators = [v.ValidCloneUri(),
193 v.ValidRepoName(edit, old_data),
193 v.ValidRepoName(edit, old_data),
194 v.ValidPerms()]
194 v.ValidPerms()]
195 return _RepoForm
195 return _RepoForm
196
196
197
197
198 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
198 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
199 repo_groups=[], landing_revs=[]):
199 repo_groups=[], landing_revs=[]):
200 class _RepoForkForm(formencode.Schema):
200 class _RepoForkForm(formencode.Schema):
201 allow_extra_fields = True
201 allow_extra_fields = True
202 filter_extra_fields = False
202 filter_extra_fields = False
203 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
203 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
204 v.SlugifyName())
204 v.SlugifyName())
205 repo_group = v.OneOf(repo_groups, hideList=True)
205 repo_group = v.OneOf(repo_groups, hideList=True)
206 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
206 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
207 description = v.UnicodeString(strip=True, min=1, not_empty=True)
207 description = v.UnicodeString(strip=True, min=1, not_empty=True)
208 private = v.StringBoolean(if_missing=False)
208 private = v.StringBoolean(if_missing=False)
209 copy_permissions = v.StringBoolean(if_missing=False)
209 copy_permissions = v.StringBoolean(if_missing=False)
210 update_after_clone = v.StringBoolean(if_missing=False)
210 update_after_clone = v.StringBoolean(if_missing=False)
211 fork_parent_id = v.UnicodeString()
211 fork_parent_id = v.UnicodeString()
212 chained_validators = [v.ValidForkName(edit, old_data)]
212 chained_validators = [v.ValidForkName(edit, old_data)]
213 landing_rev = v.OneOf(landing_revs, hideList=True)
213 landing_rev = v.OneOf(landing_revs, hideList=True)
214
214
215 return _RepoForkForm
215 return _RepoForkForm
216
216
217
217
218 def RepoSettingsForm(edit=False, old_data={},
218 def RepoSettingsForm(edit=False, old_data={},
219 supported_backends=BACKENDS.keys(), repo_groups=[],
219 supported_backends=BACKENDS.keys(), repo_groups=[],
220 landing_revs=[]):
220 landing_revs=[]):
221 class _RepoForm(formencode.Schema):
221 class _RepoForm(formencode.Schema):
222 allow_extra_fields = True
222 allow_extra_fields = True
223 filter_extra_fields = False
223 filter_extra_fields = False
224 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
224 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
225 v.SlugifyName())
225 v.SlugifyName())
226 description = v.UnicodeString(strip=True, min=1, not_empty=True)
226 description = v.UnicodeString(strip=True, min=1, not_empty=True)
227 repo_group = v.OneOf(repo_groups, hideList=True)
227 repo_group = v.OneOf(repo_groups, hideList=True)
228 private = v.StringBoolean(if_missing=False)
228 private = v.StringBoolean(if_missing=False)
229 landing_rev = v.OneOf(landing_revs, hideList=True)
229 landing_rev = v.OneOf(landing_revs, hideList=True)
230 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
230 chained_validators = [v.ValidRepoName(edit, old_data), v.ValidPerms(),
231 v.ValidSettings()]
231 v.ValidSettings()]
232 return _RepoForm
232 return _RepoForm
233
233
234
234
235 def ApplicationSettingsForm():
235 def ApplicationSettingsForm():
236 class _ApplicationSettingsForm(formencode.Schema):
236 class _ApplicationSettingsForm(formencode.Schema):
237 allow_extra_fields = True
237 allow_extra_fields = True
238 filter_extra_fields = False
238 filter_extra_fields = False
239 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
239 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
240 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
240 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
241 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
241 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
242
242
243 return _ApplicationSettingsForm
243 return _ApplicationSettingsForm
244
244
245
245
246 def ApplicationVisualisationForm():
246 def ApplicationVisualisationForm():
247 class _ApplicationVisualisationForm(formencode.Schema):
247 class _ApplicationVisualisationForm(formencode.Schema):
248 allow_extra_fields = True
248 allow_extra_fields = True
249 filter_extra_fields = False
249 filter_extra_fields = False
250 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
250 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
251 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
251 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
252 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
252 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
253
253
254 return _ApplicationVisualisationForm
254 return _ApplicationVisualisationForm
255
255
256
256
257 def ApplicationUiSettingsForm():
257 def ApplicationUiSettingsForm():
258 class _ApplicationUiSettingsForm(formencode.Schema):
258 class _ApplicationUiSettingsForm(formencode.Schema):
259 allow_extra_fields = True
259 allow_extra_fields = True
260 filter_extra_fields = False
260 filter_extra_fields = False
261 web_push_ssl = v.StringBoolean(if_missing=False)
261 web_push_ssl = v.StringBoolean(if_missing=False)
262 paths_root_path = All(
262 paths_root_path = All(
263 v.ValidPath(),
263 v.ValidPath(),
264 v.UnicodeString(strip=True, min=1, not_empty=True)
264 v.UnicodeString(strip=True, min=1, not_empty=True)
265 )
265 )
266 hooks_changegroup_update = v.StringBoolean(if_missing=False)
266 hooks_changegroup_update = v.StringBoolean(if_missing=False)
267 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
267 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
268 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
268 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
269 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
269 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
270
270
271 extensions_largefiles = v.StringBoolean(if_missing=False)
271 extensions_largefiles = v.StringBoolean(if_missing=False)
272 extensions_hgsubversion = v.StringBoolean(if_missing=False)
272 extensions_hgsubversion = v.StringBoolean(if_missing=False)
273 extensions_hggit = v.StringBoolean(if_missing=False)
273 extensions_hggit = v.StringBoolean(if_missing=False)
274
274
275 return _ApplicationUiSettingsForm
275 return _ApplicationUiSettingsForm
276
276
277
277
278 def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
278 def DefaultPermissionsForm(perms_choices, register_choices, create_choices,
279 fork_choices):
279 fork_choices):
280 class _DefaultPermissionsForm(formencode.Schema):
280 class _DefaultPermissionsForm(formencode.Schema):
281 allow_extra_fields = True
281 allow_extra_fields = True
282 filter_extra_fields = True
282 filter_extra_fields = True
283 overwrite_default = v.StringBoolean(if_missing=False)
283 overwrite_default = v.StringBoolean(if_missing=False)
284 anonymous = v.StringBoolean(if_missing=False)
284 anonymous = v.StringBoolean(if_missing=False)
285 default_perm = v.OneOf(perms_choices)
285 default_perm = v.OneOf(perms_choices)
286 default_register = v.OneOf(register_choices)
286 default_register = v.OneOf(register_choices)
287 default_create = v.OneOf(create_choices)
287 default_create = v.OneOf(create_choices)
288 default_fork = v.OneOf(fork_choices)
288 default_fork = v.OneOf(fork_choices)
289
289
290 return _DefaultPermissionsForm
290 return _DefaultPermissionsForm
291
291
292
292
293 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
293 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
294 tls_kind_choices):
294 tls_kind_choices):
295 class _LdapSettingsForm(formencode.Schema):
295 class _LdapSettingsForm(formencode.Schema):
296 allow_extra_fields = True
296 allow_extra_fields = True
297 filter_extra_fields = True
297 filter_extra_fields = True
298 #pre_validators = [LdapLibValidator]
298 #pre_validators = [LdapLibValidator]
299 ldap_active = v.StringBoolean(if_missing=False)
299 ldap_active = v.StringBoolean(if_missing=False)
300 ldap_host = v.UnicodeString(strip=True,)
300 ldap_host = v.UnicodeString(strip=True,)
301 ldap_port = v.Number(strip=True,)
301 ldap_port = v.Number(strip=True,)
302 ldap_tls_kind = v.OneOf(tls_kind_choices)
302 ldap_tls_kind = v.OneOf(tls_kind_choices)
303 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
303 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
304 ldap_dn_user = v.UnicodeString(strip=True,)
304 ldap_dn_user = v.UnicodeString(strip=True,)
305 ldap_dn_pass = v.UnicodeString(strip=True,)
305 ldap_dn_pass = v.UnicodeString(strip=True,)
306 ldap_base_dn = v.UnicodeString(strip=True,)
306 ldap_base_dn = v.UnicodeString(strip=True,)
307 ldap_filter = v.UnicodeString(strip=True,)
307 ldap_filter = v.UnicodeString(strip=True,)
308 ldap_search_scope = v.OneOf(search_scope_choices)
308 ldap_search_scope = v.OneOf(search_scope_choices)
309 ldap_attr_login = All(
309 ldap_attr_login = All(
310 v.AttrLoginValidator(),
310 v.AttrLoginValidator(),
311 v.UnicodeString(strip=True,)
311 v.UnicodeString(strip=True,)
312 )
312 )
313 ldap_attr_firstname = v.UnicodeString(strip=True,)
313 ldap_attr_firstname = v.UnicodeString(strip=True,)
314 ldap_attr_lastname = v.UnicodeString(strip=True,)
314 ldap_attr_lastname = v.UnicodeString(strip=True,)
315 ldap_attr_email = v.UnicodeString(strip=True,)
315 ldap_attr_email = v.UnicodeString(strip=True,)
316
316
317 return _LdapSettingsForm
317 return _LdapSettingsForm
318
318
319
319
320 def UserExtraEmailForm():
320 def UserExtraEmailForm():
321 class _UserExtraEmailForm(formencode.Schema):
321 class _UserExtraEmailForm(formencode.Schema):
322 email = All(v.UniqSystemEmail(), v.Email)
322 email = All(v.UniqSystemEmail(), v.Email)
323
323
324 return _UserExtraEmailForm
324 return _UserExtraEmailForm
325
325
326
326
327 def PullRequestForm():
327 def PullRequestForm():
328 class _PullRequestForm(formencode.Schema):
328 class _PullRequestForm(formencode.Schema):
329 allow_extra_fields = True
329 allow_extra_fields = True
330 filter_extra_fields = True
330 filter_extra_fields = True
331
331
332 user = v.UnicodeString(strip=True, required=True)
332 user = v.UnicodeString(strip=True, required=True)
333 org_repo = v.UnicodeString(strip=True, required=True)
333 org_repo = v.UnicodeString(strip=True, required=True)
334 org_ref = v.UnicodeString(strip=True, required=True)
334 org_ref = v.UnicodeString(strip=True, required=True)
335 other_repo = v.UnicodeString(strip=True, required=True)
335 other_repo = v.UnicodeString(strip=True, required=True)
336 other_ref = v.UnicodeString(strip=True, required=True)
336 other_ref = v.UnicodeString(strip=True, required=True)
337 revisions = All(v.NotReviewedRevisions()(), v.UniqueList(not_empty=True))
337 revisions = All(v.NotReviewedRevisions()(), v.UniqueList(not_empty=True))
338 review_members = v.UniqueList(not_empty=True)
338 review_members = v.UniqueList(not_empty=True)
339
339
340 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
340 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
341 pullrequest_desc = v.UnicodeString(strip=True, required=False)
341 pullrequest_desc = v.UnicodeString(strip=True, required=False)
342
342
343 return _PullRequestForm No newline at end of file
343 return _PullRequestForm
@@ -1,438 +1,437
1 import os
1 import os
2 import unittest
2 import unittest
3 from rhodecode.tests import *
3 from rhodecode.tests import *
4
4
5 from rhodecode.model.repos_group import ReposGroupModel
5 from rhodecode.model.repos_group import ReposGroupModel
6 from rhodecode.model.repo import RepoModel
6 from rhodecode.model.repo import RepoModel
7 from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
7 from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm
8 from rhodecode.model.user import UserModel
8 from rhodecode.model.user import UserModel
9
9
10 from rhodecode.model.meta import Session
10 from rhodecode.model.meta import Session
11 from rhodecode.model.users_group import UsersGroupModel
11 from rhodecode.model.users_group import UsersGroupModel
12 from rhodecode.lib.auth import AuthUser
12 from rhodecode.lib.auth import AuthUser
13
13
14
14
15 def _make_group(path, desc='desc', parent_id=None,
15 def _make_group(path, desc='desc', parent_id=None,
16 skip_if_exists=False):
16 skip_if_exists=False):
17
17
18 gr = RepoGroup.get_by_group_name(path)
18 gr = RepoGroup.get_by_group_name(path)
19 if gr and skip_if_exists:
19 if gr and skip_if_exists:
20 return gr
20 return gr
21
21
22 gr = ReposGroupModel().create(path, desc, parent_id)
22 gr = ReposGroupModel().create(path, desc, parent_id)
23 return gr
23 return gr
24
24
25
25
26 class TestPermissions(unittest.TestCase):
26 class TestPermissions(unittest.TestCase):
27 def __init__(self, methodName='runTest'):
27 def __init__(self, methodName='runTest'):
28 super(TestPermissions, self).__init__(methodName=methodName)
28 super(TestPermissions, self).__init__(methodName=methodName)
29
29
30 def setUp(self):
30 def setUp(self):
31 self.u1 = UserModel().create_or_update(
31 self.u1 = UserModel().create_or_update(
32 username=u'u1', password=u'qweqwe',
32 username=u'u1', password=u'qweqwe',
33 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
33 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
34 )
34 )
35 self.u2 = UserModel().create_or_update(
35 self.u2 = UserModel().create_or_update(
36 username=u'u2', password=u'qweqwe',
36 username=u'u2', password=u'qweqwe',
37 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
37 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
38 )
38 )
39 self.u3 = UserModel().create_or_update(
39 self.u3 = UserModel().create_or_update(
40 username=u'u3', password=u'qweqwe',
40 username=u'u3', password=u'qweqwe',
41 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
41 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
42 )
42 )
43 self.anon = User.get_by_username('default')
43 self.anon = User.get_by_username('default')
44 self.a1 = UserModel().create_or_update(
44 self.a1 = UserModel().create_or_update(
45 username=u'a1', password=u'qweqwe',
45 username=u'a1', password=u'qweqwe',
46 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
46 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
47 )
47 )
48 Session().commit()
48 Session().commit()
49
49
50 def tearDown(self):
50 def tearDown(self):
51 if hasattr(self, 'test_repo'):
51 if hasattr(self, 'test_repo'):
52 RepoModel().delete(repo=self.test_repo)
52 RepoModel().delete(repo=self.test_repo)
53 UserModel().delete(self.u1)
53 UserModel().delete(self.u1)
54 UserModel().delete(self.u2)
54 UserModel().delete(self.u2)
55 UserModel().delete(self.u3)
55 UserModel().delete(self.u3)
56 UserModel().delete(self.a1)
56 UserModel().delete(self.a1)
57 if hasattr(self, 'g1'):
57 if hasattr(self, 'g1'):
58 ReposGroupModel().delete(self.g1.group_id)
58 ReposGroupModel().delete(self.g1.group_id)
59 if hasattr(self, 'g2'):
59 if hasattr(self, 'g2'):
60 ReposGroupModel().delete(self.g2.group_id)
60 ReposGroupModel().delete(self.g2.group_id)
61
61
62 if hasattr(self, 'ug1'):
62 if hasattr(self, 'ug1'):
63 UsersGroupModel().delete(self.ug1, force=True)
63 UsersGroupModel().delete(self.ug1, force=True)
64
64
65 Session().commit()
65 Session().commit()
66
66
67 def test_default_perms_set(self):
67 def test_default_perms_set(self):
68 u1_auth = AuthUser(user_id=self.u1.user_id)
68 u1_auth = AuthUser(user_id=self.u1.user_id)
69 perms = {
69 perms = {
70 'repositories_groups': {},
70 'repositories_groups': {},
71 'global': set([u'hg.create.repository', u'repository.read',
71 'global': set([u'hg.create.repository', u'repository.read',
72 u'hg.register.manual_activate']),
72 u'hg.register.manual_activate']),
73 'repositories': {u'vcs_test_hg': u'repository.read'}
73 'repositories': {u'vcs_test_hg': u'repository.read'}
74 }
74 }
75 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
75 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
76 perms['repositories'][HG_REPO])
76 perms['repositories'][HG_REPO])
77 new_perm = 'repository.write'
77 new_perm = 'repository.write'
78 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
78 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
79 perm=new_perm)
79 perm=new_perm)
80 Session().commit()
80 Session().commit()
81
81
82 u1_auth = AuthUser(user_id=self.u1.user_id)
82 u1_auth = AuthUser(user_id=self.u1.user_id)
83 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
83 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
84 new_perm)
84 new_perm)
85
85
86 def test_default_admin_perms_set(self):
86 def test_default_admin_perms_set(self):
87 a1_auth = AuthUser(user_id=self.a1.user_id)
87 a1_auth = AuthUser(user_id=self.a1.user_id)
88 perms = {
88 perms = {
89 'repositories_groups': {},
89 'repositories_groups': {},
90 'global': set([u'hg.admin']),
90 'global': set([u'hg.admin']),
91 'repositories': {u'vcs_test_hg': u'repository.admin'}
91 'repositories': {u'vcs_test_hg': u'repository.admin'}
92 }
92 }
93 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
93 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
94 perms['repositories'][HG_REPO])
94 perms['repositories'][HG_REPO])
95 new_perm = 'repository.write'
95 new_perm = 'repository.write'
96 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
96 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
97 perm=new_perm)
97 perm=new_perm)
98 Session().commit()
98 Session().commit()
99 # cannot really downgrade admins permissions !? they still get's set as
99 # cannot really downgrade admins permissions !? they still get's set as
100 # admin !
100 # admin !
101 u1_auth = AuthUser(user_id=self.a1.user_id)
101 u1_auth = AuthUser(user_id=self.a1.user_id)
102 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
102 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
103 perms['repositories'][HG_REPO])
103 perms['repositories'][HG_REPO])
104
104
105 def test_default_group_perms(self):
105 def test_default_group_perms(self):
106 self.g1 = _make_group('test1', skip_if_exists=True)
106 self.g1 = _make_group('test1', skip_if_exists=True)
107 self.g2 = _make_group('test2', skip_if_exists=True)
107 self.g2 = _make_group('test2', skip_if_exists=True)
108 u1_auth = AuthUser(user_id=self.u1.user_id)
108 u1_auth = AuthUser(user_id=self.u1.user_id)
109 perms = {
109 perms = {
110 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
110 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
111 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
111 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
112 'repositories': {u'vcs_test_hg': u'repository.read'}
112 'repositories': {u'vcs_test_hg': u'repository.read'}
113 }
113 }
114 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
114 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
115 perms['repositories'][HG_REPO])
115 perms['repositories'][HG_REPO])
116 self.assertEqual(u1_auth.permissions['repositories_groups'],
116 self.assertEqual(u1_auth.permissions['repositories_groups'],
117 perms['repositories_groups'])
117 perms['repositories_groups'])
118
118
119 def test_default_admin_group_perms(self):
119 def test_default_admin_group_perms(self):
120 self.g1 = _make_group('test1', skip_if_exists=True)
120 self.g1 = _make_group('test1', skip_if_exists=True)
121 self.g2 = _make_group('test2', skip_if_exists=True)
121 self.g2 = _make_group('test2', skip_if_exists=True)
122 a1_auth = AuthUser(user_id=self.a1.user_id)
122 a1_auth = AuthUser(user_id=self.a1.user_id)
123 perms = {
123 perms = {
124 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
124 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
125 'global': set(['hg.admin']),
125 'global': set(['hg.admin']),
126 'repositories': {u'vcs_test_hg': 'repository.admin'}
126 'repositories': {u'vcs_test_hg': 'repository.admin'}
127 }
127 }
128
128
129 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
129 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
130 perms['repositories'][HG_REPO])
130 perms['repositories'][HG_REPO])
131 self.assertEqual(a1_auth.permissions['repositories_groups'],
131 self.assertEqual(a1_auth.permissions['repositories_groups'],
132 perms['repositories_groups'])
132 perms['repositories_groups'])
133
133
134 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
134 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
135 # make group
135 # make group
136 self.ug1 = UsersGroupModel().create('G1')
136 self.ug1 = UsersGroupModel().create('G1')
137 # add user to group
137 # add user to group
138
138
139 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
139 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
140
140
141 # set permission to lower
141 # set permission to lower
142 new_perm = 'repository.none'
142 new_perm = 'repository.none'
143 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
143 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
144 Session().commit()
144 Session().commit()
145 u1_auth = AuthUser(user_id=self.u1.user_id)
145 u1_auth = AuthUser(user_id=self.u1.user_id)
146 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
146 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
147 new_perm)
147 new_perm)
148
148
149 # grant perm for group this should not override permission from user
149 # grant perm for group this should not override permission from user
150 # since it has explicitly set
150 # since it has explicitly set
151 new_perm_gr = 'repository.write'
151 new_perm_gr = 'repository.write'
152 RepoModel().grant_users_group_permission(repo=HG_REPO,
152 RepoModel().grant_users_group_permission(repo=HG_REPO,
153 group_name=self.ug1,
153 group_name=self.ug1,
154 perm=new_perm_gr)
154 perm=new_perm_gr)
155 # check perms
155 # check perms
156 u1_auth = AuthUser(user_id=self.u1.user_id)
156 u1_auth = AuthUser(user_id=self.u1.user_id)
157 perms = {
157 perms = {
158 'repositories_groups': {},
158 'repositories_groups': {},
159 'global': set([u'hg.create.repository', u'repository.read',
159 'global': set([u'hg.create.repository', u'repository.read',
160 u'hg.register.manual_activate']),
160 u'hg.register.manual_activate']),
161 'repositories': {u'vcs_test_hg': u'repository.read'}
161 'repositories': {u'vcs_test_hg': u'repository.read'}
162 }
162 }
163 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
163 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
164 new_perm)
164 new_perm)
165 self.assertEqual(u1_auth.permissions['repositories_groups'],
165 self.assertEqual(u1_auth.permissions['repositories_groups'],
166 perms['repositories_groups'])
166 perms['repositories_groups'])
167
167
168 def test_propagated_permission_from_users_group(self):
168 def test_propagated_permission_from_users_group(self):
169 # make group
169 # make group
170 self.ug1 = UsersGroupModel().create('G1')
170 self.ug1 = UsersGroupModel().create('G1')
171 # add user to group
171 # add user to group
172
172
173 UsersGroupModel().add_user_to_group(self.ug1, self.u3)
173 UsersGroupModel().add_user_to_group(self.ug1, self.u3)
174
174
175 # grant perm for group this should override default permission from user
175 # grant perm for group this should override default permission from user
176 new_perm_gr = 'repository.write'
176 new_perm_gr = 'repository.write'
177 RepoModel().grant_users_group_permission(repo=HG_REPO,
177 RepoModel().grant_users_group_permission(repo=HG_REPO,
178 group_name=self.ug1,
178 group_name=self.ug1,
179 perm=new_perm_gr)
179 perm=new_perm_gr)
180 # check perms
180 # check perms
181 u3_auth = AuthUser(user_id=self.u3.user_id)
181 u3_auth = AuthUser(user_id=self.u3.user_id)
182 perms = {
182 perms = {
183 'repositories_groups': {},
183 'repositories_groups': {},
184 'global': set([u'hg.create.repository', u'repository.read',
184 'global': set([u'hg.create.repository', u'repository.read',
185 u'hg.register.manual_activate']),
185 u'hg.register.manual_activate']),
186 'repositories': {u'vcs_test_hg': u'repository.read'}
186 'repositories': {u'vcs_test_hg': u'repository.read'}
187 }
187 }
188 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
188 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
189 new_perm_gr)
189 new_perm_gr)
190 self.assertEqual(u3_auth.permissions['repositories_groups'],
190 self.assertEqual(u3_auth.permissions['repositories_groups'],
191 perms['repositories_groups'])
191 perms['repositories_groups'])
192
192
193 def test_propagated_permission_from_users_group_lower_weight(self):
193 def test_propagated_permission_from_users_group_lower_weight(self):
194 # make group
194 # make group
195 self.ug1 = UsersGroupModel().create('G1')
195 self.ug1 = UsersGroupModel().create('G1')
196 # add user to group
196 # add user to group
197 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
197 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
198
198
199 # set permission to lower
199 # set permission to lower
200 new_perm_h = 'repository.write'
200 new_perm_h = 'repository.write'
201 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
201 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
202 perm=new_perm_h)
202 perm=new_perm_h)
203 Session().commit()
203 Session().commit()
204 u1_auth = AuthUser(user_id=self.u1.user_id)
204 u1_auth = AuthUser(user_id=self.u1.user_id)
205 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
205 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
206 new_perm_h)
206 new_perm_h)
207
207
208 # grant perm for group this should NOT override permission from user
208 # grant perm for group this should NOT override permission from user
209 # since it's lower than granted
209 # since it's lower than granted
210 new_perm_l = 'repository.read'
210 new_perm_l = 'repository.read'
211 RepoModel().grant_users_group_permission(repo=HG_REPO,
211 RepoModel().grant_users_group_permission(repo=HG_REPO,
212 group_name=self.ug1,
212 group_name=self.ug1,
213 perm=new_perm_l)
213 perm=new_perm_l)
214 # check perms
214 # check perms
215 u1_auth = AuthUser(user_id=self.u1.user_id)
215 u1_auth = AuthUser(user_id=self.u1.user_id)
216 perms = {
216 perms = {
217 'repositories_groups': {},
217 'repositories_groups': {},
218 'global': set([u'hg.create.repository', u'repository.read',
218 'global': set([u'hg.create.repository', u'repository.read',
219 u'hg.register.manual_activate']),
219 u'hg.register.manual_activate']),
220 'repositories': {u'vcs_test_hg': u'repository.write'}
220 'repositories': {u'vcs_test_hg': u'repository.write'}
221 }
221 }
222 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
222 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
223 new_perm_h)
223 new_perm_h)
224 self.assertEqual(u1_auth.permissions['repositories_groups'],
224 self.assertEqual(u1_auth.permissions['repositories_groups'],
225 perms['repositories_groups'])
225 perms['repositories_groups'])
226
226
227 def test_repo_in_group_permissions(self):
227 def test_repo_in_group_permissions(self):
228 self.g1 = _make_group('group1', skip_if_exists=True)
228 self.g1 = _make_group('group1', skip_if_exists=True)
229 self.g2 = _make_group('group2', skip_if_exists=True)
229 self.g2 = _make_group('group2', skip_if_exists=True)
230 Session().commit()
230 Session().commit()
231 # both perms should be read !
231 # both perms should be read !
232 u1_auth = AuthUser(user_id=self.u1.user_id)
232 u1_auth = AuthUser(user_id=self.u1.user_id)
233 self.assertEqual(u1_auth.permissions['repositories_groups'],
233 self.assertEqual(u1_auth.permissions['repositories_groups'],
234 {u'group1': u'group.read', u'group2': u'group.read'})
234 {u'group1': u'group.read', u'group2': u'group.read'})
235
235
236 a1_auth = AuthUser(user_id=self.anon.user_id)
236 a1_auth = AuthUser(user_id=self.anon.user_id)
237 self.assertEqual(a1_auth.permissions['repositories_groups'],
237 self.assertEqual(a1_auth.permissions['repositories_groups'],
238 {u'group1': u'group.read', u'group2': u'group.read'})
238 {u'group1': u'group.read', u'group2': u'group.read'})
239
239
240 #Change perms to none for both groups
240 #Change perms to none for both groups
241 ReposGroupModel().grant_user_permission(repos_group=self.g1,
241 ReposGroupModel().grant_user_permission(repos_group=self.g1,
242 user=self.anon,
242 user=self.anon,
243 perm='group.none')
243 perm='group.none')
244 ReposGroupModel().grant_user_permission(repos_group=self.g2,
244 ReposGroupModel().grant_user_permission(repos_group=self.g2,
245 user=self.anon,
245 user=self.anon,
246 perm='group.none')
246 perm='group.none')
247
247
248 u1_auth = AuthUser(user_id=self.u1.user_id)
248 u1_auth = AuthUser(user_id=self.u1.user_id)
249 self.assertEqual(u1_auth.permissions['repositories_groups'],
249 self.assertEqual(u1_auth.permissions['repositories_groups'],
250 {u'group1': u'group.none', u'group2': u'group.none'})
250 {u'group1': u'group.none', u'group2': u'group.none'})
251
251
252 a1_auth = AuthUser(user_id=self.anon.user_id)
252 a1_auth = AuthUser(user_id=self.anon.user_id)
253 self.assertEqual(a1_auth.permissions['repositories_groups'],
253 self.assertEqual(a1_auth.permissions['repositories_groups'],
254 {u'group1': u'group.none', u'group2': u'group.none'})
254 {u'group1': u'group.none', u'group2': u'group.none'})
255
255
256 # add repo to group
256 # add repo to group
257 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
257 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
258 self.test_repo = RepoModel().create_repo(
258 self.test_repo = RepoModel().create_repo(
259 repo_name=name,
259 repo_name=name,
260 repo_type='hg',
260 repo_type='hg',
261 description='',
261 description='',
262 repos_group=self.g1,
262 repos_group=self.g1,
263 owner=self.u1,
263 owner=self.u1,
264 )
264 )
265 Session().commit()
265 Session().commit()
266
266
267 u1_auth = AuthUser(user_id=self.u1.user_id)
267 u1_auth = AuthUser(user_id=self.u1.user_id)
268 self.assertEqual(u1_auth.permissions['repositories_groups'],
268 self.assertEqual(u1_auth.permissions['repositories_groups'],
269 {u'group1': u'group.none', u'group2': u'group.none'})
269 {u'group1': u'group.none', u'group2': u'group.none'})
270
270
271 a1_auth = AuthUser(user_id=self.anon.user_id)
271 a1_auth = AuthUser(user_id=self.anon.user_id)
272 self.assertEqual(a1_auth.permissions['repositories_groups'],
272 self.assertEqual(a1_auth.permissions['repositories_groups'],
273 {u'group1': u'group.none', u'group2': u'group.none'})
273 {u'group1': u'group.none', u'group2': u'group.none'})
274
274
275 #grant permission for u2 !
275 #grant permission for u2 !
276 ReposGroupModel().grant_user_permission(repos_group=self.g1,
276 ReposGroupModel().grant_user_permission(repos_group=self.g1,
277 user=self.u2,
277 user=self.u2,
278 perm='group.read')
278 perm='group.read')
279 ReposGroupModel().grant_user_permission(repos_group=self.g2,
279 ReposGroupModel().grant_user_permission(repos_group=self.g2,
280 user=self.u2,
280 user=self.u2,
281 perm='group.read')
281 perm='group.read')
282 Session().commit()
282 Session().commit()
283 self.assertNotEqual(self.u1, self.u2)
283 self.assertNotEqual(self.u1, self.u2)
284 #u1 and anon should have not change perms while u2 should !
284 #u1 and anon should have not change perms while u2 should !
285 u1_auth = AuthUser(user_id=self.u1.user_id)
285 u1_auth = AuthUser(user_id=self.u1.user_id)
286 self.assertEqual(u1_auth.permissions['repositories_groups'],
286 self.assertEqual(u1_auth.permissions['repositories_groups'],
287 {u'group1': u'group.none', u'group2': u'group.none'})
287 {u'group1': u'group.none', u'group2': u'group.none'})
288
288
289 u2_auth = AuthUser(user_id=self.u2.user_id)
289 u2_auth = AuthUser(user_id=self.u2.user_id)
290 self.assertEqual(u2_auth.permissions['repositories_groups'],
290 self.assertEqual(u2_auth.permissions['repositories_groups'],
291 {u'group1': u'group.read', u'group2': u'group.read'})
291 {u'group1': u'group.read', u'group2': u'group.read'})
292
292
293 a1_auth = AuthUser(user_id=self.anon.user_id)
293 a1_auth = AuthUser(user_id=self.anon.user_id)
294 self.assertEqual(a1_auth.permissions['repositories_groups'],
294 self.assertEqual(a1_auth.permissions['repositories_groups'],
295 {u'group1': u'group.none', u'group2': u'group.none'})
295 {u'group1': u'group.none', u'group2': u'group.none'})
296
296
297 def test_repo_group_user_as_user_group_member(self):
297 def test_repo_group_user_as_user_group_member(self):
298 # create Group1
298 # create Group1
299 self.g1 = _make_group('group1', skip_if_exists=True)
299 self.g1 = _make_group('group1', skip_if_exists=True)
300 Session().commit()
300 Session().commit()
301 a1_auth = AuthUser(user_id=self.anon.user_id)
301 a1_auth = AuthUser(user_id=self.anon.user_id)
302
302
303 self.assertEqual(a1_auth.permissions['repositories_groups'],
303 self.assertEqual(a1_auth.permissions['repositories_groups'],
304 {u'group1': u'group.read'})
304 {u'group1': u'group.read'})
305
305
306 # set default permission to none
306 # set default permission to none
307 ReposGroupModel().grant_user_permission(repos_group=self.g1,
307 ReposGroupModel().grant_user_permission(repos_group=self.g1,
308 user=self.anon,
308 user=self.anon,
309 perm='group.none')
309 perm='group.none')
310 # make group
310 # make group
311 self.ug1 = UsersGroupModel().create('G1')
311 self.ug1 = UsersGroupModel().create('G1')
312 # add user to group
312 # add user to group
313 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
313 UsersGroupModel().add_user_to_group(self.ug1, self.u1)
314 Session().commit()
314 Session().commit()
315
315
316 # check if user is in the group
316 # check if user is in the group
317 membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
317 membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members]
318 self.assertEqual(membrs, [self.u1.user_id])
318 self.assertEqual(membrs, [self.u1.user_id])
319 # add some user to that group
319 # add some user to that group
320
320
321 # check his permissions
321 # check his permissions
322 a1_auth = AuthUser(user_id=self.anon.user_id)
322 a1_auth = AuthUser(user_id=self.anon.user_id)
323 self.assertEqual(a1_auth.permissions['repositories_groups'],
323 self.assertEqual(a1_auth.permissions['repositories_groups'],
324 {u'group1': u'group.none'})
324 {u'group1': u'group.none'})
325
325
326 u1_auth = AuthUser(user_id=self.u1.user_id)
326 u1_auth = AuthUser(user_id=self.u1.user_id)
327 self.assertEqual(u1_auth.permissions['repositories_groups'],
327 self.assertEqual(u1_auth.permissions['repositories_groups'],
328 {u'group1': u'group.none'})
328 {u'group1': u'group.none'})
329
329
330 # grant ug1 read permissions for
330 # grant ug1 read permissions for
331 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
331 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
332 group_name=self.ug1,
332 group_name=self.ug1,
333 perm='group.read')
333 perm='group.read')
334 Session().commit()
334 Session().commit()
335 # check if the
335 # check if the
336 obj = Session().query(UsersGroupRepoGroupToPerm)\
336 obj = Session().query(UsersGroupRepoGroupToPerm)\
337 .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
337 .filter(UsersGroupRepoGroupToPerm.group == self.g1)\
338 .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
338 .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\
339 .scalar()
339 .scalar()
340 self.assertEqual(obj.permission.permission_name, 'group.read')
340 self.assertEqual(obj.permission.permission_name, 'group.read')
341
341
342 a1_auth = AuthUser(user_id=self.anon.user_id)
342 a1_auth = AuthUser(user_id=self.anon.user_id)
343
343
344 self.assertEqual(a1_auth.permissions['repositories_groups'],
344 self.assertEqual(a1_auth.permissions['repositories_groups'],
345 {u'group1': u'group.none'})
345 {u'group1': u'group.none'})
346
346
347 u1_auth = AuthUser(user_id=self.u1.user_id)
347 u1_auth = AuthUser(user_id=self.u1.user_id)
348 self.assertEqual(u1_auth.permissions['repositories_groups'],
348 self.assertEqual(u1_auth.permissions['repositories_groups'],
349 {u'group1': u'group.read'})
349 {u'group1': u'group.read'})
350
350
351 def test_inherited_permissions_from_default_on_user_enabled(self):
351 def test_inherited_permissions_from_default_on_user_enabled(self):
352 user_model = UserModel()
352 user_model = UserModel()
353 # enable fork and create on default user
353 # enable fork and create on default user
354 usr = 'default'
354 usr = 'default'
355 user_model.revoke_perm(usr, 'hg.create.none')
355 user_model.revoke_perm(usr, 'hg.create.none')
356 user_model.grant_perm(usr, 'hg.create.repository')
356 user_model.grant_perm(usr, 'hg.create.repository')
357 user_model.revoke_perm(usr, 'hg.fork.none')
357 user_model.revoke_perm(usr, 'hg.fork.none')
358 user_model.grant_perm(usr, 'hg.fork.repository')
358 user_model.grant_perm(usr, 'hg.fork.repository')
359 # make sure inherit flag is turned on
359 # make sure inherit flag is turned on
360 self.u1.inherit_default_permissions = True
360 self.u1.inherit_default_permissions = True
361 Session().commit()
361 Session().commit()
362 u1_auth = AuthUser(user_id=self.u1.user_id)
362 u1_auth = AuthUser(user_id=self.u1.user_id)
363 # this user will have inherited permissions from default user
363 # this user will have inherited permissions from default user
364 self.assertEqual(u1_auth.permissions['global'],
364 self.assertEqual(u1_auth.permissions['global'],
365 set(['hg.create.repository', 'hg.fork.repository',
365 set(['hg.create.repository', 'hg.fork.repository',
366 'hg.register.manual_activate',
366 'hg.register.manual_activate',
367 'repository.read']))
367 'repository.read']))
368
368
369 def test_inherited_permissions_from_default_on_user_disabled(self):
369 def test_inherited_permissions_from_default_on_user_disabled(self):
370 user_model = UserModel()
370 user_model = UserModel()
371 # disable fork and create on default user
371 # disable fork and create on default user
372 usr = 'default'
372 usr = 'default'
373 user_model.revoke_perm(usr, 'hg.create.repository')
373 user_model.revoke_perm(usr, 'hg.create.repository')
374 user_model.grant_perm(usr, 'hg.create.none')
374 user_model.grant_perm(usr, 'hg.create.none')
375 user_model.revoke_perm(usr, 'hg.fork.repository')
375 user_model.revoke_perm(usr, 'hg.fork.repository')
376 user_model.grant_perm(usr, 'hg.fork.none')
376 user_model.grant_perm(usr, 'hg.fork.none')
377 # make sure inherit flag is turned on
377 # make sure inherit flag is turned on
378 self.u1.inherit_default_permissions = True
378 self.u1.inherit_default_permissions = True
379 Session().commit()
379 Session().commit()
380 u1_auth = AuthUser(user_id=self.u1.user_id)
380 u1_auth = AuthUser(user_id=self.u1.user_id)
381 # this user will have inherited permissions from default user
381 # this user will have inherited permissions from default user
382 self.assertEqual(u1_auth.permissions['global'],
382 self.assertEqual(u1_auth.permissions['global'],
383 set(['hg.create.none', 'hg.fork.none',
383 set(['hg.create.none', 'hg.fork.none',
384 'hg.register.manual_activate',
384 'hg.register.manual_activate',
385 'repository.read']))
385 'repository.read']))
386
386
387 def test_non_inherited_permissions_from_default_on_user_enabled(self):
387 def test_non_inherited_permissions_from_default_on_user_enabled(self):
388 user_model = UserModel()
388 user_model = UserModel()
389 # enable fork and create on default user
389 # enable fork and create on default user
390 usr = 'default'
390 usr = 'default'
391 user_model.revoke_perm(usr, 'hg.create.none')
391 user_model.revoke_perm(usr, 'hg.create.none')
392 user_model.grant_perm(usr, 'hg.create.repository')
392 user_model.grant_perm(usr, 'hg.create.repository')
393 user_model.revoke_perm(usr, 'hg.fork.none')
393 user_model.revoke_perm(usr, 'hg.fork.none')
394 user_model.grant_perm(usr, 'hg.fork.repository')
394 user_model.grant_perm(usr, 'hg.fork.repository')
395
395
396 #disable global perms on specific user
396 #disable global perms on specific user
397 user_model.revoke_perm(self.u1, 'hg.create.repository')
397 user_model.revoke_perm(self.u1, 'hg.create.repository')
398 user_model.grant_perm(self.u1, 'hg.create.none')
398 user_model.grant_perm(self.u1, 'hg.create.none')
399 user_model.revoke_perm(self.u1, 'hg.fork.repository')
399 user_model.revoke_perm(self.u1, 'hg.fork.repository')
400 user_model.grant_perm(self.u1, 'hg.fork.none')
400 user_model.grant_perm(self.u1, 'hg.fork.none')
401
401
402 # make sure inherit flag is turned off
402 # make sure inherit flag is turned off
403 self.u1.inherit_default_permissions = False
403 self.u1.inherit_default_permissions = False
404 Session().commit()
404 Session().commit()
405 u1_auth = AuthUser(user_id=self.u1.user_id)
405 u1_auth = AuthUser(user_id=self.u1.user_id)
406 # this user will have non inherited permissions from he's
406 # this user will have non inherited permissions from he's
407 # explicitly set permissions
407 # explicitly set permissions
408 self.assertEqual(u1_auth.permissions['global'],
408 self.assertEqual(u1_auth.permissions['global'],
409 set(['hg.create.none', 'hg.fork.none',
409 set(['hg.create.none', 'hg.fork.none',
410 'hg.register.manual_activate',
410 'hg.register.manual_activate',
411 'repository.read']))
411 'repository.read']))
412
412
413 def test_non_inherited_permissions_from_default_on_user_disabled(self):
413 def test_non_inherited_permissions_from_default_on_user_disabled(self):
414 user_model = UserModel()
414 user_model = UserModel()
415 # disable fork and create on default user
415 # disable fork and create on default user
416 usr = 'default'
416 usr = 'default'
417 user_model.revoke_perm(usr, 'hg.create.repository')
417 user_model.revoke_perm(usr, 'hg.create.repository')
418 user_model.grant_perm(usr, 'hg.create.none')
418 user_model.grant_perm(usr, 'hg.create.none')
419 user_model.revoke_perm(usr, 'hg.fork.repository')
419 user_model.revoke_perm(usr, 'hg.fork.repository')
420 user_model.grant_perm(usr, 'hg.fork.none')
420 user_model.grant_perm(usr, 'hg.fork.none')
421
421
422 #enable global perms on specific user
422 #enable global perms on specific user
423 user_model.revoke_perm(self.u1, 'hg.create.none')
423 user_model.revoke_perm(self.u1, 'hg.create.none')
424 user_model.grant_perm(self.u1, 'hg.create.repository')
424 user_model.grant_perm(self.u1, 'hg.create.repository')
425 user_model.revoke_perm(self.u1, 'hg.fork.none')
425 user_model.revoke_perm(self.u1, 'hg.fork.none')
426 user_model.grant_perm(self.u1, 'hg.fork.repository')
426 user_model.grant_perm(self.u1, 'hg.fork.repository')
427
427
428 # make sure inherit flag is turned off
428 # make sure inherit flag is turned off
429 self.u1.inherit_default_permissions = False
429 self.u1.inherit_default_permissions = False
430 Session().commit()
430 Session().commit()
431 u1_auth = AuthUser(user_id=self.u1.user_id)
431 u1_auth = AuthUser(user_id=self.u1.user_id)
432 # this user will have non inherited permissions from he's
432 # this user will have non inherited permissions from he's
433 # explicitly set permissions
433 # explicitly set permissions
434 self.assertEqual(u1_auth.permissions['global'],
434 self.assertEqual(u1_auth.permissions['global'],
435 set(['hg.create.repository', 'hg.fork.repository',
435 set(['hg.create.repository', 'hg.fork.repository',
436 'hg.register.manual_activate',
436 'hg.register.manual_activate',
437 'repository.read']))
437 'repository.read']))
438
General Comments 0
You need to be logged in to leave comments. Login now