##// END OF EJS Templates
fixed default permissions population during upgrades...
marcink -
r3733:af049a95 beta
parent child Browse files
Show More
@@ -1,726 +1,715 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.db_manage
3 rhodecode.lib.db_manage
4 ~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database creation, and setup module for RhodeCode. Used for creation
6 Database creation, and setup module for RhodeCode. Used for creation
7 of database as well as for migration operations
7 of database as well as for migration operations
8
8
9 :created_on: Apr 10, 2010
9 :created_on: Apr 10, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 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 import sys
28 import sys
29 import uuid
29 import uuid
30 import logging
30 import logging
31 from os.path import dirname as dn, join as jn
31 from os.path import dirname as dn, join as jn
32
32
33 from rhodecode import __dbversion__, __py_version__
33 from rhodecode import __dbversion__, __py_version__
34
34
35 from rhodecode.model.user import UserModel
35 from rhodecode.model.user import UserModel
36 from rhodecode.lib.utils import ask_ok
36 from rhodecode.lib.utils import ask_ok
37 from rhodecode.model import init_model
37 from rhodecode.model import init_model
38 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
38 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
39 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
39 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
40 UserRepoGroupToPerm
40 UserRepoGroupToPerm
41
41
42 from sqlalchemy.engine import create_engine
42 from sqlalchemy.engine import create_engine
43 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
44 #from rhodecode.model import meta
44 #from rhodecode.model import meta
45 from rhodecode.model.meta import Session, Base
45 from rhodecode.model.meta import Session, Base
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.permission import PermissionModel
47
48
48
49
49 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
50
51
51
52
52 def notify(msg):
53 def notify(msg):
53 """
54 """
54 Notification for migrations messages
55 Notification for migrations messages
55 """
56 """
56 ml = len(msg) + (4 * 2)
57 ml = len(msg) + (4 * 2)
57 print >> sys.stdout, ('*** %s ***\n%s' % (msg, '*' * ml)).upper()
58 print >> sys.stdout, ('*** %s ***\n%s' % (msg, '*' * ml)).upper()
58
59
59
60
60 class DbManage(object):
61 class DbManage(object):
61 def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
62 def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
62 self.dbname = dbconf.split('/')[-1]
63 self.dbname = dbconf.split('/')[-1]
63 self.tests = tests
64 self.tests = tests
64 self.root = root
65 self.root = root
65 self.dburi = dbconf
66 self.dburi = dbconf
66 self.log_sql = log_sql
67 self.log_sql = log_sql
67 self.db_exists = False
68 self.db_exists = False
68 self.cli_args = cli_args
69 self.cli_args = cli_args
69 self.init_db()
70 self.init_db()
70
71
71 force_ask = self.cli_args.get('force_ask')
72 force_ask = self.cli_args.get('force_ask')
72 if force_ask is not None:
73 if force_ask is not None:
73 global ask_ok
74 global ask_ok
74 ask_ok = lambda *args, **kwargs: force_ask
75 ask_ok = lambda *args, **kwargs: force_ask
75
76
76 def init_db(self):
77 def init_db(self):
77 engine = create_engine(self.dburi, echo=self.log_sql)
78 engine = create_engine(self.dburi, echo=self.log_sql)
78 init_model(engine)
79 init_model(engine)
79 self.sa = Session()
80 self.sa = Session()
80
81
81 def create_tables(self, override=False):
82 def create_tables(self, override=False):
82 """
83 """
83 Create a auth database
84 Create a auth database
84 """
85 """
85
86
86 log.info("Any existing database is going to be destroyed")
87 log.info("Any existing database is going to be destroyed")
87 if self.tests:
88 if self.tests:
88 destroy = True
89 destroy = True
89 else:
90 else:
90 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
91 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
91 if not destroy:
92 if not destroy:
92 sys.exit('Nothing tables created')
93 sys.exit('Nothing tables created')
93 if destroy:
94 if destroy:
94 Base.metadata.drop_all()
95 Base.metadata.drop_all()
95
96
96 checkfirst = not override
97 checkfirst = not override
97 Base.metadata.create_all(checkfirst=checkfirst)
98 Base.metadata.create_all(checkfirst=checkfirst)
98 log.info('Created tables for %s' % self.dbname)
99 log.info('Created tables for %s' % self.dbname)
99
100
100 def set_db_version(self):
101 def set_db_version(self):
101 ver = DbMigrateVersion()
102 ver = DbMigrateVersion()
102 ver.version = __dbversion__
103 ver.version = __dbversion__
103 ver.repository_id = 'rhodecode_db_migrations'
104 ver.repository_id = 'rhodecode_db_migrations'
104 ver.repository_path = 'versions'
105 ver.repository_path = 'versions'
105 self.sa.add(ver)
106 self.sa.add(ver)
106 log.info('db version set to: %s' % __dbversion__)
107 log.info('db version set to: %s' % __dbversion__)
107
108
108 def upgrade(self):
109 def upgrade(self):
109 """
110 """
110 Upgrades given database schema to given revision following
111 Upgrades given database schema to given revision following
111 all needed steps, to perform the upgrade
112 all needed steps, to perform the upgrade
112
113
113 """
114 """
114
115
115 from rhodecode.lib.dbmigrate.migrate.versioning import api
116 from rhodecode.lib.dbmigrate.migrate.versioning import api
116 from rhodecode.lib.dbmigrate.migrate.exceptions import \
117 from rhodecode.lib.dbmigrate.migrate.exceptions import \
117 DatabaseNotControlledError
118 DatabaseNotControlledError
118
119
119 if 'sqlite' in self.dburi:
120 if 'sqlite' in self.dburi:
120 print (
121 print (
121 '********************** WARNING **********************\n'
122 '********************** WARNING **********************\n'
122 'Make sure your version of sqlite is at least 3.7.X. \n'
123 'Make sure your version of sqlite is at least 3.7.X. \n'
123 'Earlier versions are known to fail on some migrations\n'
124 'Earlier versions are known to fail on some migrations\n'
124 '*****************************************************\n'
125 '*****************************************************\n'
125 )
126 )
126 upgrade = ask_ok('You are about to perform database upgrade, make '
127 upgrade = ask_ok('You are about to perform database upgrade, make '
127 'sure You backed up your database before. '
128 'sure You backed up your database before. '
128 'Continue ? [y/n]')
129 'Continue ? [y/n]')
129 if not upgrade:
130 if not upgrade:
130 sys.exit('No upgrade performed')
131 sys.exit('No upgrade performed')
131
132
132 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
133 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
133 'rhodecode/lib/dbmigrate')
134 'rhodecode/lib/dbmigrate')
134 db_uri = self.dburi
135 db_uri = self.dburi
135
136
136 try:
137 try:
137 curr_version = api.db_version(db_uri, repository_path)
138 curr_version = api.db_version(db_uri, repository_path)
138 msg = ('Found current database under version'
139 msg = ('Found current database under version'
139 ' control with version %s' % curr_version)
140 ' control with version %s' % curr_version)
140
141
141 except (RuntimeError, DatabaseNotControlledError):
142 except (RuntimeError, DatabaseNotControlledError):
142 curr_version = 1
143 curr_version = 1
143 msg = ('Current database is not under version control. Setting'
144 msg = ('Current database is not under version control. Setting'
144 ' as version %s' % curr_version)
145 ' as version %s' % curr_version)
145 api.version_control(db_uri, repository_path, curr_version)
146 api.version_control(db_uri, repository_path, curr_version)
146
147
147 notify(msg)
148 notify(msg)
148
149
149 if curr_version == __dbversion__:
150 if curr_version == __dbversion__:
150 sys.exit('This database is already at the newest version')
151 sys.exit('This database is already at the newest version')
151
152
152 #======================================================================
153 #======================================================================
153 # UPGRADE STEPS
154 # UPGRADE STEPS
154 #======================================================================
155 #======================================================================
155
156
156 class UpgradeSteps(object):
157 class UpgradeSteps(object):
157 """
158 """
158 Those steps follow schema versions so for example schema
159 Those steps follow schema versions so for example schema
159 for example schema with seq 002 == step_2 and so on.
160 for example schema with seq 002 == step_2 and so on.
160 """
161 """
161
162
162 def __init__(self, klass):
163 def __init__(self, klass):
163 self.klass = klass
164 self.klass = klass
164
165
165 def step_0(self):
166 def step_0(self):
166 # step 0 is the schema upgrade, and than follow proper upgrades
167 # step 0 is the schema upgrade, and than follow proper upgrades
167 notify('attempting to do database upgrade from '
168 notify('attempting to do database upgrade from '
168 'version %s to version %s' %(curr_version, __dbversion__))
169 'version %s to version %s' %(curr_version, __dbversion__))
169 api.upgrade(db_uri, repository_path, __dbversion__)
170 api.upgrade(db_uri, repository_path, __dbversion__)
170 notify('Schema upgrade completed')
171 notify('Schema upgrade completed')
171
172
172 def step_1(self):
173 def step_1(self):
173 pass
174 pass
174
175
175 def step_2(self):
176 def step_2(self):
176 notify('Patching repo paths for newer version of RhodeCode')
177 notify('Patching repo paths for newer version of RhodeCode')
177 self.klass.fix_repo_paths()
178 self.klass.fix_repo_paths()
178
179
179 notify('Patching default user of RhodeCode')
180 notify('Patching default user of RhodeCode')
180 self.klass.fix_default_user()
181 self.klass.fix_default_user()
181
182
182 log.info('Changing ui settings')
183 log.info('Changing ui settings')
183 self.klass.create_ui_settings()
184 self.klass.create_ui_settings()
184
185
185 def step_3(self):
186 def step_3(self):
186 notify('Adding additional settings into RhodeCode db')
187 notify('Adding additional settings into RhodeCode db')
187 self.klass.fix_settings()
188 self.klass.fix_settings()
188 notify('Adding ldap defaults')
189 notify('Adding ldap defaults')
189 self.klass.create_ldap_options(skip_existing=True)
190 self.klass.create_ldap_options(skip_existing=True)
190
191
191 def step_4(self):
192 def step_4(self):
192 notify('create permissions and fix groups')
193 notify('create permissions and fix groups')
193 self.klass.create_permissions()
194 self.klass.create_permissions()
194 self.klass.fixup_groups()
195 self.klass.fixup_groups()
195
196
196 def step_5(self):
197 def step_5(self):
197 pass
198 pass
198
199
199 def step_6(self):
200 def step_6(self):
200
201
201 notify('re-checking permissions')
202 notify('re-checking permissions')
202 self.klass.create_permissions()
203 self.klass.create_permissions()
203
204
204 notify('installing new UI options')
205 notify('installing new UI options')
205 sett4 = RhodeCodeSetting('show_public_icon', True)
206 sett4 = RhodeCodeSetting('show_public_icon', True)
206 Session().add(sett4)
207 Session().add(sett4)
207 sett5 = RhodeCodeSetting('show_private_icon', True)
208 sett5 = RhodeCodeSetting('show_private_icon', True)
208 Session().add(sett5)
209 Session().add(sett5)
209 sett6 = RhodeCodeSetting('stylify_metatags', False)
210 sett6 = RhodeCodeSetting('stylify_metatags', False)
210 Session().add(sett6)
211 Session().add(sett6)
211
212
212 notify('fixing old PULL hook')
213 notify('fixing old PULL hook')
213 _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
214 _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
214 if _pull:
215 if _pull:
215 _pull.ui_key = RhodeCodeUi.HOOK_PULL
216 _pull.ui_key = RhodeCodeUi.HOOK_PULL
216 Session().add(_pull)
217 Session().add(_pull)
217
218
218 notify('fixing old PUSH hook')
219 notify('fixing old PUSH hook')
219 _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
220 _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
220 if _push:
221 if _push:
221 _push.ui_key = RhodeCodeUi.HOOK_PUSH
222 _push.ui_key = RhodeCodeUi.HOOK_PUSH
222 Session().add(_push)
223 Session().add(_push)
223
224
224 notify('installing new pre-push hook')
225 notify('installing new pre-push hook')
225 hooks4 = RhodeCodeUi()
226 hooks4 = RhodeCodeUi()
226 hooks4.ui_section = 'hooks'
227 hooks4.ui_section = 'hooks'
227 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
228 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
228 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
229 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
229 Session().add(hooks4)
230 Session().add(hooks4)
230
231
231 notify('installing new pre-pull hook')
232 notify('installing new pre-pull hook')
232 hooks6 = RhodeCodeUi()
233 hooks6 = RhodeCodeUi()
233 hooks6.ui_section = 'hooks'
234 hooks6.ui_section = 'hooks'
234 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
235 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
235 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
236 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
236 Session().add(hooks6)
237 Session().add(hooks6)
237
238
238 notify('installing hgsubversion option')
239 notify('installing hgsubversion option')
239 # enable hgsubversion disabled by default
240 # enable hgsubversion disabled by default
240 hgsubversion = RhodeCodeUi()
241 hgsubversion = RhodeCodeUi()
241 hgsubversion.ui_section = 'extensions'
242 hgsubversion.ui_section = 'extensions'
242 hgsubversion.ui_key = 'hgsubversion'
243 hgsubversion.ui_key = 'hgsubversion'
243 hgsubversion.ui_value = ''
244 hgsubversion.ui_value = ''
244 hgsubversion.ui_active = False
245 hgsubversion.ui_active = False
245 Session().add(hgsubversion)
246 Session().add(hgsubversion)
246
247
247 notify('installing hg git option')
248 notify('installing hg git option')
248 # enable hggit disabled by default
249 # enable hggit disabled by default
249 hggit = RhodeCodeUi()
250 hggit = RhodeCodeUi()
250 hggit.ui_section = 'extensions'
251 hggit.ui_section = 'extensions'
251 hggit.ui_key = 'hggit'
252 hggit.ui_key = 'hggit'
252 hggit.ui_value = ''
253 hggit.ui_value = ''
253 hggit.ui_active = False
254 hggit.ui_active = False
254 Session().add(hggit)
255 Session().add(hggit)
255
256
256 notify('re-check default permissions')
257 notify('re-check default permissions')
257 default_user = User.get_by_username(User.DEFAULT_USER)
258 default_user = User.get_by_username(User.DEFAULT_USER)
258 perm = Permission.get_by_key('hg.fork.repository')
259 perm = Permission.get_by_key('hg.fork.repository')
259 reg_perm = UserToPerm()
260 reg_perm = UserToPerm()
260 reg_perm.user = default_user
261 reg_perm.user = default_user
261 reg_perm.permission = perm
262 reg_perm.permission = perm
262 Session().add(reg_perm)
263 Session().add(reg_perm)
263
264
264 def step_7(self):
265 def step_7(self):
265 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
266 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
266 Session().commit()
267 Session().commit()
267 if perm_fixes:
268 if perm_fixes:
268 notify('There was an inconsistent state of permissions '
269 notify('There was an inconsistent state of permissions '
269 'detected for default user. Permissions are now '
270 'detected for default user. Permissions are now '
270 'reset to the default value for default user. '
271 'reset to the default value for default user. '
271 'Please validate and check default permissions '
272 'Please validate and check default permissions '
272 'in admin panel')
273 'in admin panel')
273
274
274 def step_8(self):
275 def step_8(self):
275 self.klass.populate_default_permissions()
276 self.klass.populate_default_permissions()
276 self.klass.create_default_options(skip_existing=True)
277 self.klass.create_default_options(skip_existing=True)
277 Session().commit()
278 Session().commit()
278
279
279 def step_9(self):
280 def step_9(self):
280 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
281 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
281 Session().commit()
282 Session().commit()
282 if perm_fixes:
283 if perm_fixes:
283 notify('There was an inconsistent state of permissions '
284 notify('There was an inconsistent state of permissions '
284 'detected for default user. Permissions are now '
285 'detected for default user. Permissions are now '
285 'reset to the default value for default user. '
286 'reset to the default value for default user. '
286 'Please validate and check default permissions '
287 'Please validate and check default permissions '
287 'in admin panel')
288 'in admin panel')
288
289
289 def step_10(self):
290 def step_10(self):
290 pass
291 pass
291
292
292 def step_11(self):
293 def step_11(self):
293 self.klass.update_repo_info()
294 self.klass.update_repo_info()
294
295
295 def step_12(self):
296 def step_12(self):
296 self.klass.create_permissions()
297 self.klass.create_permissions()
297 self.klass.populate_default_permissions()
298 self.klass.populate_default_permissions()
298
299
299 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
300 upgrade_steps = [0] + range(curr_version + 1, __dbversion__ + 1)
300
301
301 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
302 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
302 _step = None
303 _step = None
303 for step in upgrade_steps:
304 for step in upgrade_steps:
304 notify('performing upgrade step %s' % step)
305 notify('performing upgrade step %s' % step)
305 getattr(UpgradeSteps(self), 'step_%s' % step)()
306 getattr(UpgradeSteps(self), 'step_%s' % step)()
306 self.sa.commit()
307 self.sa.commit()
307 _step = step
308 _step = step
308
309
309 notify('upgrade to version %s successful' % _step)
310 notify('upgrade to version %s successful' % _step)
310
311
311 def fix_repo_paths(self):
312 def fix_repo_paths(self):
312 """
313 """
313 Fixes a old rhodecode version path into new one without a '*'
314 Fixes a old rhodecode version path into new one without a '*'
314 """
315 """
315
316
316 paths = self.sa.query(RhodeCodeUi)\
317 paths = self.sa.query(RhodeCodeUi)\
317 .filter(RhodeCodeUi.ui_key == '/')\
318 .filter(RhodeCodeUi.ui_key == '/')\
318 .scalar()
319 .scalar()
319
320
320 paths.ui_value = paths.ui_value.replace('*', '')
321 paths.ui_value = paths.ui_value.replace('*', '')
321
322
322 try:
323 try:
323 self.sa.add(paths)
324 self.sa.add(paths)
324 self.sa.commit()
325 self.sa.commit()
325 except Exception:
326 except Exception:
326 self.sa.rollback()
327 self.sa.rollback()
327 raise
328 raise
328
329
329 def fix_default_user(self):
330 def fix_default_user(self):
330 """
331 """
331 Fixes a old default user with some 'nicer' default values,
332 Fixes a old default user with some 'nicer' default values,
332 used mostly for anonymous access
333 used mostly for anonymous access
333 """
334 """
334 def_user = self.sa.query(User)\
335 def_user = self.sa.query(User)\
335 .filter(User.username == 'default')\
336 .filter(User.username == 'default')\
336 .one()
337 .one()
337
338
338 def_user.name = 'Anonymous'
339 def_user.name = 'Anonymous'
339 def_user.lastname = 'User'
340 def_user.lastname = 'User'
340 def_user.email = 'anonymous@rhodecode.org'
341 def_user.email = 'anonymous@rhodecode.org'
341
342
342 try:
343 try:
343 self.sa.add(def_user)
344 self.sa.add(def_user)
344 self.sa.commit()
345 self.sa.commit()
345 except Exception:
346 except Exception:
346 self.sa.rollback()
347 self.sa.rollback()
347 raise
348 raise
348
349
349 def fix_settings(self):
350 def fix_settings(self):
350 """
351 """
351 Fixes rhodecode settings adds ga_code key for google analytics
352 Fixes rhodecode settings adds ga_code key for google analytics
352 """
353 """
353
354
354 hgsettings3 = RhodeCodeSetting('ga_code', '')
355 hgsettings3 = RhodeCodeSetting('ga_code', '')
355
356
356 try:
357 try:
357 self.sa.add(hgsettings3)
358 self.sa.add(hgsettings3)
358 self.sa.commit()
359 self.sa.commit()
359 except Exception:
360 except Exception:
360 self.sa.rollback()
361 self.sa.rollback()
361 raise
362 raise
362
363
363 def admin_prompt(self, second=False):
364 def admin_prompt(self, second=False):
364 if not self.tests:
365 if not self.tests:
365 import getpass
366 import getpass
366
367
367 # defaults
368 # defaults
368 defaults = self.cli_args
369 defaults = self.cli_args
369 username = defaults.get('username')
370 username = defaults.get('username')
370 password = defaults.get('password')
371 password = defaults.get('password')
371 email = defaults.get('email')
372 email = defaults.get('email')
372
373
373 def get_password():
374 def get_password():
374 password = getpass.getpass('Specify admin password '
375 password = getpass.getpass('Specify admin password '
375 '(min 6 chars):')
376 '(min 6 chars):')
376 confirm = getpass.getpass('Confirm password:')
377 confirm = getpass.getpass('Confirm password:')
377
378
378 if password != confirm:
379 if password != confirm:
379 log.error('passwords mismatch')
380 log.error('passwords mismatch')
380 return False
381 return False
381 if len(password) < 6:
382 if len(password) < 6:
382 log.error('password is to short use at least 6 characters')
383 log.error('password is to short use at least 6 characters')
383 return False
384 return False
384
385
385 return password
386 return password
386 if username is None:
387 if username is None:
387 username = raw_input('Specify admin username:')
388 username = raw_input('Specify admin username:')
388 if password is None:
389 if password is None:
389 password = get_password()
390 password = get_password()
390 if not password:
391 if not password:
391 #second try
392 #second try
392 password = get_password()
393 password = get_password()
393 if not password:
394 if not password:
394 sys.exit()
395 sys.exit()
395 if email is None:
396 if email is None:
396 email = raw_input('Specify admin email:')
397 email = raw_input('Specify admin email:')
397 self.create_user(username, password, email, True)
398 self.create_user(username, password, email, True)
398 else:
399 else:
399 log.info('creating admin and regular test users')
400 log.info('creating admin and regular test users')
400 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
401 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
401 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
402 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
402 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
403 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
403 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
404 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
404 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
405 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
405
406
406 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
407 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
407 TEST_USER_ADMIN_EMAIL, True)
408 TEST_USER_ADMIN_EMAIL, True)
408
409
409 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
410 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
410 TEST_USER_REGULAR_EMAIL, False)
411 TEST_USER_REGULAR_EMAIL, False)
411
412
412 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
413 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
413 TEST_USER_REGULAR2_EMAIL, False)
414 TEST_USER_REGULAR2_EMAIL, False)
414
415
415 def create_ui_settings(self):
416 def create_ui_settings(self):
416 """
417 """
417 Creates ui settings, fills out hooks
418 Creates ui settings, fills out hooks
418 and disables dotencode
419 and disables dotencode
419 """
420 """
420
421
421 #HOOKS
422 #HOOKS
422 hooks1_key = RhodeCodeUi.HOOK_UPDATE
423 hooks1_key = RhodeCodeUi.HOOK_UPDATE
423 hooks1_ = self.sa.query(RhodeCodeUi)\
424 hooks1_ = self.sa.query(RhodeCodeUi)\
424 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
425 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
425
426
426 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
427 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
427 hooks1.ui_section = 'hooks'
428 hooks1.ui_section = 'hooks'
428 hooks1.ui_key = hooks1_key
429 hooks1.ui_key = hooks1_key
429 hooks1.ui_value = 'hg update >&2'
430 hooks1.ui_value = 'hg update >&2'
430 hooks1.ui_active = False
431 hooks1.ui_active = False
431 self.sa.add(hooks1)
432 self.sa.add(hooks1)
432
433
433 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
434 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
434 hooks2_ = self.sa.query(RhodeCodeUi)\
435 hooks2_ = self.sa.query(RhodeCodeUi)\
435 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
436 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
436 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
437 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
437 hooks2.ui_section = 'hooks'
438 hooks2.ui_section = 'hooks'
438 hooks2.ui_key = hooks2_key
439 hooks2.ui_key = hooks2_key
439 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
440 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
440 self.sa.add(hooks2)
441 self.sa.add(hooks2)
441
442
442 hooks3 = RhodeCodeUi()
443 hooks3 = RhodeCodeUi()
443 hooks3.ui_section = 'hooks'
444 hooks3.ui_section = 'hooks'
444 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
445 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
445 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
446 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
446 self.sa.add(hooks3)
447 self.sa.add(hooks3)
447
448
448 hooks4 = RhodeCodeUi()
449 hooks4 = RhodeCodeUi()
449 hooks4.ui_section = 'hooks'
450 hooks4.ui_section = 'hooks'
450 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
451 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
451 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
452 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
452 self.sa.add(hooks4)
453 self.sa.add(hooks4)
453
454
454 hooks5 = RhodeCodeUi()
455 hooks5 = RhodeCodeUi()
455 hooks5.ui_section = 'hooks'
456 hooks5.ui_section = 'hooks'
456 hooks5.ui_key = RhodeCodeUi.HOOK_PULL
457 hooks5.ui_key = RhodeCodeUi.HOOK_PULL
457 hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
458 hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
458 self.sa.add(hooks5)
459 self.sa.add(hooks5)
459
460
460 hooks6 = RhodeCodeUi()
461 hooks6 = RhodeCodeUi()
461 hooks6.ui_section = 'hooks'
462 hooks6.ui_section = 'hooks'
462 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
463 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
463 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
464 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
464 self.sa.add(hooks6)
465 self.sa.add(hooks6)
465
466
466 # enable largefiles
467 # enable largefiles
467 largefiles = RhodeCodeUi()
468 largefiles = RhodeCodeUi()
468 largefiles.ui_section = 'extensions'
469 largefiles.ui_section = 'extensions'
469 largefiles.ui_key = 'largefiles'
470 largefiles.ui_key = 'largefiles'
470 largefiles.ui_value = ''
471 largefiles.ui_value = ''
471 self.sa.add(largefiles)
472 self.sa.add(largefiles)
472
473
473 # enable hgsubversion disabled by default
474 # enable hgsubversion disabled by default
474 hgsubversion = RhodeCodeUi()
475 hgsubversion = RhodeCodeUi()
475 hgsubversion.ui_section = 'extensions'
476 hgsubversion.ui_section = 'extensions'
476 hgsubversion.ui_key = 'hgsubversion'
477 hgsubversion.ui_key = 'hgsubversion'
477 hgsubversion.ui_value = ''
478 hgsubversion.ui_value = ''
478 hgsubversion.ui_active = False
479 hgsubversion.ui_active = False
479 self.sa.add(hgsubversion)
480 self.sa.add(hgsubversion)
480
481
481 # enable hggit disabled by default
482 # enable hggit disabled by default
482 hggit = RhodeCodeUi()
483 hggit = RhodeCodeUi()
483 hggit.ui_section = 'extensions'
484 hggit.ui_section = 'extensions'
484 hggit.ui_key = 'hggit'
485 hggit.ui_key = 'hggit'
485 hggit.ui_value = ''
486 hggit.ui_value = ''
486 hggit.ui_active = False
487 hggit.ui_active = False
487 self.sa.add(hggit)
488 self.sa.add(hggit)
488
489
489 def create_ldap_options(self, skip_existing=False):
490 def create_ldap_options(self, skip_existing=False):
490 """Creates ldap settings"""
491 """Creates ldap settings"""
491
492
492 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
493 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
493 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
494 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
494 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
495 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
495 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
496 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
496 ('ldap_filter', ''), ('ldap_search_scope', ''),
497 ('ldap_filter', ''), ('ldap_search_scope', ''),
497 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
498 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
498 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
499 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
499
500
500 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
501 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
501 log.debug('Skipping option %s' % k)
502 log.debug('Skipping option %s' % k)
502 continue
503 continue
503 setting = RhodeCodeSetting(k, v)
504 setting = RhodeCodeSetting(k, v)
504 self.sa.add(setting)
505 self.sa.add(setting)
505
506
506 def create_default_options(self, skip_existing=False):
507 def create_default_options(self, skip_existing=False):
507 """Creates default settings"""
508 """Creates default settings"""
508
509
509 for k, v in [
510 for k, v in [
510 ('default_repo_enable_locking', False),
511 ('default_repo_enable_locking', False),
511 ('default_repo_enable_downloads', False),
512 ('default_repo_enable_downloads', False),
512 ('default_repo_enable_statistics', False),
513 ('default_repo_enable_statistics', False),
513 ('default_repo_private', False),
514 ('default_repo_private', False),
514 ('default_repo_type', 'hg')]:
515 ('default_repo_type', 'hg')]:
515
516
516 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
517 if skip_existing and RhodeCodeSetting.get_by_name(k) != None:
517 log.debug('Skipping option %s' % k)
518 log.debug('Skipping option %s' % k)
518 continue
519 continue
519 setting = RhodeCodeSetting(k, v)
520 setting = RhodeCodeSetting(k, v)
520 self.sa.add(setting)
521 self.sa.add(setting)
521
522
522 def fixup_groups(self):
523 def fixup_groups(self):
523 def_usr = User.get_by_username('default')
524 def_usr = User.get_by_username('default')
524 for g in RepoGroup.query().all():
525 for g in RepoGroup.query().all():
525 g.group_name = g.get_new_name(g.name)
526 g.group_name = g.get_new_name(g.name)
526 self.sa.add(g)
527 self.sa.add(g)
527 # get default perm
528 # get default perm
528 default = UserRepoGroupToPerm.query()\
529 default = UserRepoGroupToPerm.query()\
529 .filter(UserRepoGroupToPerm.group == g)\
530 .filter(UserRepoGroupToPerm.group == g)\
530 .filter(UserRepoGroupToPerm.user == def_usr)\
531 .filter(UserRepoGroupToPerm.user == def_usr)\
531 .scalar()
532 .scalar()
532
533
533 if default is None:
534 if default is None:
534 log.debug('missing default permission for group %s adding' % g)
535 log.debug('missing default permission for group %s adding' % g)
535 perm_obj = ReposGroupModel()._create_default_perms(g)
536 perm_obj = ReposGroupModel()._create_default_perms(g)
536 self.sa.add(perm_obj)
537 self.sa.add(perm_obj)
537
538
538 def reset_permissions(self, username):
539 def reset_permissions(self, username):
539 """
540 """
540 Resets permissions to default state, usefull when old systems had
541 Resets permissions to default state, usefull when old systems had
541 bad permissions, we must clean them up
542 bad permissions, we must clean them up
542
543
543 :param username:
544 :param username:
544 :type username:
545 :type username:
545 """
546 """
546 default_user = User.get_by_username(username)
547 default_user = User.get_by_username(username)
547 if not default_user:
548 if not default_user:
548 return
549 return
549
550
550 u2p = UserToPerm.query()\
551 u2p = UserToPerm.query()\
551 .filter(UserToPerm.user == default_user).all()
552 .filter(UserToPerm.user == default_user).all()
552 fixed = False
553 fixed = False
553 if len(u2p) != len(User.DEFAULT_PERMISSIONS):
554 if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
554 for p in u2p:
555 for p in u2p:
555 Session().delete(p)
556 Session().delete(p)
556 fixed = True
557 fixed = True
557 self.populate_default_permissions()
558 self.populate_default_permissions()
558 return fixed
559 return fixed
559
560
560 def update_repo_info(self):
561 def update_repo_info(self):
561 RepoModel.update_repoinfo()
562 RepoModel.update_repoinfo()
562
563
563 def config_prompt(self, test_repo_path='', retries=3):
564 def config_prompt(self, test_repo_path='', retries=3):
564 defaults = self.cli_args
565 defaults = self.cli_args
565 _path = defaults.get('repos_location')
566 _path = defaults.get('repos_location')
566 if retries == 3:
567 if retries == 3:
567 log.info('Setting up repositories config')
568 log.info('Setting up repositories config')
568
569
569 if _path is not None:
570 if _path is not None:
570 path = _path
571 path = _path
571 elif not self.tests and not test_repo_path:
572 elif not self.tests and not test_repo_path:
572 path = raw_input(
573 path = raw_input(
573 'Enter a valid absolute path to store repositories. '
574 'Enter a valid absolute path to store repositories. '
574 'All repositories in that path will be added automatically:'
575 'All repositories in that path will be added automatically:'
575 )
576 )
576 else:
577 else:
577 path = test_repo_path
578 path = test_repo_path
578 path_ok = True
579 path_ok = True
579
580
580 # check proper dir
581 # check proper dir
581 if not os.path.isdir(path):
582 if not os.path.isdir(path):
582 path_ok = False
583 path_ok = False
583 log.error('Given path %s is not a valid directory' % path)
584 log.error('Given path %s is not a valid directory' % path)
584
585
585 elif not os.path.isabs(path):
586 elif not os.path.isabs(path):
586 path_ok = False
587 path_ok = False
587 log.error('Given path %s is not an absolute path' % path)
588 log.error('Given path %s is not an absolute path' % path)
588
589
589 # check write access
590 # check write access
590 elif not os.access(path, os.W_OK) and path_ok:
591 elif not os.access(path, os.W_OK) and path_ok:
591 path_ok = False
592 path_ok = False
592 log.error('No write permission to given path %s' % path)
593 log.error('No write permission to given path %s' % path)
593
594
594 if retries == 0:
595 if retries == 0:
595 sys.exit('max retries reached')
596 sys.exit('max retries reached')
596 if not path_ok:
597 if not path_ok:
597 retries -= 1
598 retries -= 1
598 return self.config_prompt(test_repo_path, retries)
599 return self.config_prompt(test_repo_path, retries)
599
600
600 real_path = os.path.normpath(os.path.realpath(path))
601 real_path = os.path.normpath(os.path.realpath(path))
601
602
602 if real_path != os.path.normpath(path):
603 if real_path != os.path.normpath(path):
603 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
604 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
604 'given path as %s ? [y/n]') % (real_path)):
605 'given path as %s ? [y/n]') % (real_path)):
605 log.error('Canceled by user')
606 log.error('Canceled by user')
606 sys.exit(-1)
607 sys.exit(-1)
607
608
608 return real_path
609 return real_path
609
610
610 def create_settings(self, path):
611 def create_settings(self, path):
611
612
612 self.create_ui_settings()
613 self.create_ui_settings()
613
614
614 #HG UI OPTIONS
615 #HG UI OPTIONS
615 web1 = RhodeCodeUi()
616 web1 = RhodeCodeUi()
616 web1.ui_section = 'web'
617 web1.ui_section = 'web'
617 web1.ui_key = 'push_ssl'
618 web1.ui_key = 'push_ssl'
618 web1.ui_value = 'false'
619 web1.ui_value = 'false'
619
620
620 web2 = RhodeCodeUi()
621 web2 = RhodeCodeUi()
621 web2.ui_section = 'web'
622 web2.ui_section = 'web'
622 web2.ui_key = 'allow_archive'
623 web2.ui_key = 'allow_archive'
623 web2.ui_value = 'gz zip bz2'
624 web2.ui_value = 'gz zip bz2'
624
625
625 web3 = RhodeCodeUi()
626 web3 = RhodeCodeUi()
626 web3.ui_section = 'web'
627 web3.ui_section = 'web'
627 web3.ui_key = 'allow_push'
628 web3.ui_key = 'allow_push'
628 web3.ui_value = '*'
629 web3.ui_value = '*'
629
630
630 web4 = RhodeCodeUi()
631 web4 = RhodeCodeUi()
631 web4.ui_section = 'web'
632 web4.ui_section = 'web'
632 web4.ui_key = 'baseurl'
633 web4.ui_key = 'baseurl'
633 web4.ui_value = '/'
634 web4.ui_value = '/'
634
635
635 paths = RhodeCodeUi()
636 paths = RhodeCodeUi()
636 paths.ui_section = 'paths'
637 paths.ui_section = 'paths'
637 paths.ui_key = '/'
638 paths.ui_key = '/'
638 paths.ui_value = path
639 paths.ui_value = path
639
640
640 phases = RhodeCodeUi()
641 phases = RhodeCodeUi()
641 phases.ui_section = 'phases'
642 phases.ui_section = 'phases'
642 phases.ui_key = 'publish'
643 phases.ui_key = 'publish'
643 phases.ui_value = False
644 phases.ui_value = False
644
645
645 sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
646 sett1 = RhodeCodeSetting('realm', 'RhodeCode authentication')
646 sett2 = RhodeCodeSetting('title', 'RhodeCode')
647 sett2 = RhodeCodeSetting('title', 'RhodeCode')
647 sett3 = RhodeCodeSetting('ga_code', '')
648 sett3 = RhodeCodeSetting('ga_code', '')
648
649
649 sett4 = RhodeCodeSetting('show_public_icon', True)
650 sett4 = RhodeCodeSetting('show_public_icon', True)
650 sett5 = RhodeCodeSetting('show_private_icon', True)
651 sett5 = RhodeCodeSetting('show_private_icon', True)
651 sett6 = RhodeCodeSetting('stylify_metatags', False)
652 sett6 = RhodeCodeSetting('stylify_metatags', False)
652
653
653 self.sa.add(web1)
654 self.sa.add(web1)
654 self.sa.add(web2)
655 self.sa.add(web2)
655 self.sa.add(web3)
656 self.sa.add(web3)
656 self.sa.add(web4)
657 self.sa.add(web4)
657 self.sa.add(paths)
658 self.sa.add(paths)
658 self.sa.add(sett1)
659 self.sa.add(sett1)
659 self.sa.add(sett2)
660 self.sa.add(sett2)
660 self.sa.add(sett3)
661 self.sa.add(sett3)
661 self.sa.add(sett4)
662 self.sa.add(sett4)
662 self.sa.add(sett5)
663 self.sa.add(sett5)
663 self.sa.add(sett6)
664 self.sa.add(sett6)
664
665
665 self.create_ldap_options()
666 self.create_ldap_options()
666 self.create_default_options()
667 self.create_default_options()
667
668
668 log.info('created ui config')
669 log.info('created ui config')
669
670
670 def create_user(self, username, password, email='', admin=False):
671 def create_user(self, username, password, email='', admin=False):
671 log.info('creating user %s' % username)
672 log.info('creating user %s' % username)
672 UserModel().create_or_update(username, password, email,
673 UserModel().create_or_update(username, password, email,
673 firstname='RhodeCode', lastname='Admin',
674 firstname='RhodeCode', lastname='Admin',
674 active=True, admin=admin)
675 active=True, admin=admin)
675
676
676 def create_default_user(self):
677 def create_default_user(self):
677 log.info('creating default user')
678 log.info('creating default user')
678 # create default user for handling default permissions.
679 # create default user for handling default permissions.
679 UserModel().create_or_update(username='default',
680 UserModel().create_or_update(username='default',
680 password=str(uuid.uuid1())[:8],
681 password=str(uuid.uuid1())[:8],
681 email='anonymous@rhodecode.org',
682 email='anonymous@rhodecode.org',
682 firstname='Anonymous', lastname='User')
683 firstname='Anonymous', lastname='User')
683
684
684 def create_permissions(self):
685 def create_permissions(self):
686 """
687 Creates all permissions defined in the system
688 """
685 # module.(access|create|change|delete)_[name]
689 # module.(access|create|change|delete)_[name]
686 # module.(none|read|write|admin)
690 # module.(none|read|write|admin)
687
691
688 for p in Permission.PERMS:
692 for p in Permission.PERMS:
689 if not Permission.get_by_key(p[0]):
693 if not Permission.get_by_key(p[0]):
690 new_perm = Permission()
694 new_perm = Permission()
691 new_perm.permission_name = p[0]
695 new_perm.permission_name = p[0]
692 new_perm.permission_longname = p[0]
696 new_perm.permission_longname = p[0]
693 self.sa.add(new_perm)
697 self.sa.add(new_perm)
694
698
695 def populate_default_permissions(self):
699 def populate_default_permissions(self):
700 """
701 Populate default permissions. It will create only the default
702 permissions that are missing, and not alter already defined ones
703 """
696 log.info('creating default user permissions')
704 log.info('creating default user permissions')
697
705 PermissionModel(self.sa).create_default_permissions(user=User.DEFAULT_USER)
698 default_user = User.get_by_username('default')
699
700 for def_perm in User.DEFAULT_PERMISSIONS:
701
702 perm = self.sa.query(Permission)\
703 .filter(Permission.permission_name == def_perm)\
704 .scalar()
705 if not perm:
706 raise Exception(
707 'CRITICAL: permission %s not found inside database !!'
708 % def_perm
709 )
710 if not UserToPerm.query()\
711 .filter(UserToPerm.permission == perm)\
712 .filter(UserToPerm.user == default_user).scalar():
713 reg_perm = UserToPerm()
714 reg_perm.user = default_user
715 reg_perm.permission = perm
716 self.sa.add(reg_perm)
717
706
718 @staticmethod
707 @staticmethod
719 def check_waitress():
708 def check_waitress():
720 """
709 """
721 Function executed at the end of setup
710 Function executed at the end of setup
722 """
711 """
723 if not __py_version__ >= (2, 6):
712 if not __py_version__ >= (2, 6):
724 notify('Python2.5 detected, please switch '
713 notify('Python2.5 detected, please switch '
725 'egg:waitress#main -> egg:Paste#http '
714 'egg:waitress#main -> egg:Paste#http '
726 'in your .ini file')
715 'in your .ini file')
@@ -1,2139 +1,2156 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.db
3 rhodecode.model.db
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 Database Models for RhodeCode
6 Database Models for RhodeCode
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 import hashlib
30 import hashlib
31 import time
31 import time
32 from collections import defaultdict
32 from collections import defaultdict
33
33
34 from sqlalchemy import *
34 from sqlalchemy import *
35 from sqlalchemy.ext.hybrid import hybrid_property
35 from sqlalchemy.ext.hybrid import hybrid_property
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
36 from sqlalchemy.orm import relationship, joinedload, class_mapper, validates
37 from sqlalchemy.exc import DatabaseError
37 from sqlalchemy.exc import DatabaseError
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39 from webob.exc import HTTPNotFound
39 from webob.exc import HTTPNotFound
40
40
41 from pylons.i18n.translation import lazy_ugettext as _
41 from pylons.i18n.translation import lazy_ugettext as _
42
42
43 from rhodecode.lib.vcs import get_backend
43 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs.utils.helpers import get_scm
44 from rhodecode.lib.vcs.utils.helpers import get_scm
45 from rhodecode.lib.vcs.exceptions import VCSError
45 from rhodecode.lib.vcs.exceptions import VCSError
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
47 from rhodecode.lib.vcs.backends.base import EmptyChangeset
48
48
49 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
49 from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
50 safe_unicode, remove_suffix, remove_prefix, time_to_datetime, _set_extras
50 safe_unicode, remove_suffix, remove_prefix, time_to_datetime, _set_extras
51 from rhodecode.lib.compat import json
51 from rhodecode.lib.compat import json
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model.meta import Base, Session
54 from rhodecode.model.meta import Base, Session
55
55
56 URL_SEP = '/'
56 URL_SEP = '/'
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59 #==============================================================================
59 #==============================================================================
60 # BASE CLASSES
60 # BASE CLASSES
61 #==============================================================================
61 #==============================================================================
62
62
63 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
63 _hash_key = lambda k: hashlib.md5(safe_str(k)).hexdigest()
64
64
65
65
66 class BaseModel(object):
66 class BaseModel(object):
67 """
67 """
68 Base Model for all classess
68 Base Model for all classess
69 """
69 """
70
70
71 @classmethod
71 @classmethod
72 def _get_keys(cls):
72 def _get_keys(cls):
73 """return column names for this model """
73 """return column names for this model """
74 return class_mapper(cls).c.keys()
74 return class_mapper(cls).c.keys()
75
75
76 def get_dict(self):
76 def get_dict(self):
77 """
77 """
78 return dict with keys and values corresponding
78 return dict with keys and values corresponding
79 to this model data """
79 to this model data """
80
80
81 d = {}
81 d = {}
82 for k in self._get_keys():
82 for k in self._get_keys():
83 d[k] = getattr(self, k)
83 d[k] = getattr(self, k)
84
84
85 # also use __json__() if present to get additional fields
85 # also use __json__() if present to get additional fields
86 _json_attr = getattr(self, '__json__', None)
86 _json_attr = getattr(self, '__json__', None)
87 if _json_attr:
87 if _json_attr:
88 # update with attributes from __json__
88 # update with attributes from __json__
89 if callable(_json_attr):
89 if callable(_json_attr):
90 _json_attr = _json_attr()
90 _json_attr = _json_attr()
91 for k, val in _json_attr.iteritems():
91 for k, val in _json_attr.iteritems():
92 d[k] = val
92 d[k] = val
93 return d
93 return d
94
94
95 def get_appstruct(self):
95 def get_appstruct(self):
96 """return list with keys and values tupples corresponding
96 """return list with keys and values tupples corresponding
97 to this model data """
97 to this model data """
98
98
99 l = []
99 l = []
100 for k in self._get_keys():
100 for k in self._get_keys():
101 l.append((k, getattr(self, k),))
101 l.append((k, getattr(self, k),))
102 return l
102 return l
103
103
104 def populate_obj(self, populate_dict):
104 def populate_obj(self, populate_dict):
105 """populate model with data from given populate_dict"""
105 """populate model with data from given populate_dict"""
106
106
107 for k in self._get_keys():
107 for k in self._get_keys():
108 if k in populate_dict:
108 if k in populate_dict:
109 setattr(self, k, populate_dict[k])
109 setattr(self, k, populate_dict[k])
110
110
111 @classmethod
111 @classmethod
112 def query(cls):
112 def query(cls):
113 return Session().query(cls)
113 return Session().query(cls)
114
114
115 @classmethod
115 @classmethod
116 def get(cls, id_):
116 def get(cls, id_):
117 if id_:
117 if id_:
118 return cls.query().get(id_)
118 return cls.query().get(id_)
119
119
120 @classmethod
120 @classmethod
121 def get_or_404(cls, id_):
121 def get_or_404(cls, id_):
122 try:
122 try:
123 id_ = int(id_)
123 id_ = int(id_)
124 except (TypeError, ValueError):
124 except (TypeError, ValueError):
125 raise HTTPNotFound
125 raise HTTPNotFound
126
126
127 res = cls.query().get(id_)
127 res = cls.query().get(id_)
128 if not res:
128 if not res:
129 raise HTTPNotFound
129 raise HTTPNotFound
130 return res
130 return res
131
131
132 @classmethod
132 @classmethod
133 def getAll(cls):
133 def getAll(cls):
134 # deprecated and left for backward compatibility
134 # deprecated and left for backward compatibility
135 return cls.get_all()
135 return cls.get_all()
136
136
137 @classmethod
137 @classmethod
138 def get_all(cls):
138 def get_all(cls):
139 return cls.query().all()
139 return cls.query().all()
140
140
141 @classmethod
141 @classmethod
142 def delete(cls, id_):
142 def delete(cls, id_):
143 obj = cls.query().get(id_)
143 obj = cls.query().get(id_)
144 Session().delete(obj)
144 Session().delete(obj)
145
145
146 def __repr__(self):
146 def __repr__(self):
147 if hasattr(self, '__unicode__'):
147 if hasattr(self, '__unicode__'):
148 # python repr needs to return str
148 # python repr needs to return str
149 return safe_str(self.__unicode__())
149 return safe_str(self.__unicode__())
150 return '<DB:%s>' % (self.__class__.__name__)
150 return '<DB:%s>' % (self.__class__.__name__)
151
151
152
152
153 class RhodeCodeSetting(Base, BaseModel):
153 class RhodeCodeSetting(Base, BaseModel):
154 __tablename__ = 'rhodecode_settings'
154 __tablename__ = 'rhodecode_settings'
155 __table_args__ = (
155 __table_args__ = (
156 UniqueConstraint('app_settings_name'),
156 UniqueConstraint('app_settings_name'),
157 {'extend_existing': True, 'mysql_engine': 'InnoDB',
157 {'extend_existing': True, 'mysql_engine': 'InnoDB',
158 'mysql_charset': 'utf8'}
158 'mysql_charset': 'utf8'}
159 )
159 )
160 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
160 app_settings_id = Column("app_settings_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
161 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
161 app_settings_name = Column("app_settings_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
162 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
162 _app_settings_value = Column("app_settings_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
163
163
164 def __init__(self, k='', v=''):
164 def __init__(self, k='', v=''):
165 self.app_settings_name = k
165 self.app_settings_name = k
166 self.app_settings_value = v
166 self.app_settings_value = v
167
167
168 @validates('_app_settings_value')
168 @validates('_app_settings_value')
169 def validate_settings_value(self, key, val):
169 def validate_settings_value(self, key, val):
170 assert type(val) == unicode
170 assert type(val) == unicode
171 return val
171 return val
172
172
173 @hybrid_property
173 @hybrid_property
174 def app_settings_value(self):
174 def app_settings_value(self):
175 v = self._app_settings_value
175 v = self._app_settings_value
176 if self.app_settings_name in ["ldap_active",
176 if self.app_settings_name in ["ldap_active",
177 "default_repo_enable_statistics",
177 "default_repo_enable_statistics",
178 "default_repo_enable_locking",
178 "default_repo_enable_locking",
179 "default_repo_private",
179 "default_repo_private",
180 "default_repo_enable_downloads"]:
180 "default_repo_enable_downloads"]:
181 v = str2bool(v)
181 v = str2bool(v)
182 return v
182 return v
183
183
184 @app_settings_value.setter
184 @app_settings_value.setter
185 def app_settings_value(self, val):
185 def app_settings_value(self, val):
186 """
186 """
187 Setter that will always make sure we use unicode in app_settings_value
187 Setter that will always make sure we use unicode in app_settings_value
188
188
189 :param val:
189 :param val:
190 """
190 """
191 self._app_settings_value = safe_unicode(val)
191 self._app_settings_value = safe_unicode(val)
192
192
193 def __unicode__(self):
193 def __unicode__(self):
194 return u"<%s('%s:%s')>" % (
194 return u"<%s('%s:%s')>" % (
195 self.__class__.__name__,
195 self.__class__.__name__,
196 self.app_settings_name, self.app_settings_value
196 self.app_settings_name, self.app_settings_value
197 )
197 )
198
198
199 @classmethod
199 @classmethod
200 def get_by_name(cls, key):
200 def get_by_name(cls, key):
201 return cls.query()\
201 return cls.query()\
202 .filter(cls.app_settings_name == key).scalar()
202 .filter(cls.app_settings_name == key).scalar()
203
203
204 @classmethod
204 @classmethod
205 def get_by_name_or_create(cls, key):
205 def get_by_name_or_create(cls, key):
206 res = cls.get_by_name(key)
206 res = cls.get_by_name(key)
207 if not res:
207 if not res:
208 res = cls(key)
208 res = cls(key)
209 return res
209 return res
210
210
211 @classmethod
211 @classmethod
212 def get_app_settings(cls, cache=False):
212 def get_app_settings(cls, cache=False):
213
213
214 ret = cls.query()
214 ret = cls.query()
215
215
216 if cache:
216 if cache:
217 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
217 ret = ret.options(FromCache("sql_cache_short", "get_hg_settings"))
218
218
219 if not ret:
219 if not ret:
220 raise Exception('Could not get application settings !')
220 raise Exception('Could not get application settings !')
221 settings = {}
221 settings = {}
222 for each in ret:
222 for each in ret:
223 settings['rhodecode_' + each.app_settings_name] = \
223 settings['rhodecode_' + each.app_settings_name] = \
224 each.app_settings_value
224 each.app_settings_value
225
225
226 return settings
226 return settings
227
227
228 @classmethod
228 @classmethod
229 def get_ldap_settings(cls, cache=False):
229 def get_ldap_settings(cls, cache=False):
230 ret = cls.query()\
230 ret = cls.query()\
231 .filter(cls.app_settings_name.startswith('ldap_')).all()
231 .filter(cls.app_settings_name.startswith('ldap_')).all()
232 fd = {}
232 fd = {}
233 for row in ret:
233 for row in ret:
234 fd.update({row.app_settings_name: row.app_settings_value})
234 fd.update({row.app_settings_name: row.app_settings_value})
235
235
236 return fd
236 return fd
237
237
238 @classmethod
238 @classmethod
239 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
239 def get_default_repo_settings(cls, cache=False, strip_prefix=False):
240 ret = cls.query()\
240 ret = cls.query()\
241 .filter(cls.app_settings_name.startswith('default_')).all()
241 .filter(cls.app_settings_name.startswith('default_')).all()
242 fd = {}
242 fd = {}
243 for row in ret:
243 for row in ret:
244 key = row.app_settings_name
244 key = row.app_settings_name
245 if strip_prefix:
245 if strip_prefix:
246 key = remove_prefix(key, prefix='default_')
246 key = remove_prefix(key, prefix='default_')
247 fd.update({key: row.app_settings_value})
247 fd.update({key: row.app_settings_value})
248
248
249 return fd
249 return fd
250
250
251
251
252 class RhodeCodeUi(Base, BaseModel):
252 class RhodeCodeUi(Base, BaseModel):
253 __tablename__ = 'rhodecode_ui'
253 __tablename__ = 'rhodecode_ui'
254 __table_args__ = (
254 __table_args__ = (
255 UniqueConstraint('ui_key'),
255 UniqueConstraint('ui_key'),
256 {'extend_existing': True, 'mysql_engine': 'InnoDB',
256 {'extend_existing': True, 'mysql_engine': 'InnoDB',
257 'mysql_charset': 'utf8'}
257 'mysql_charset': 'utf8'}
258 )
258 )
259
259
260 HOOK_UPDATE = 'changegroup.update'
260 HOOK_UPDATE = 'changegroup.update'
261 HOOK_REPO_SIZE = 'changegroup.repo_size'
261 HOOK_REPO_SIZE = 'changegroup.repo_size'
262 HOOK_PUSH = 'changegroup.push_logger'
262 HOOK_PUSH = 'changegroup.push_logger'
263 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
263 HOOK_PRE_PUSH = 'prechangegroup.pre_push'
264 HOOK_PULL = 'outgoing.pull_logger'
264 HOOK_PULL = 'outgoing.pull_logger'
265 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
265 HOOK_PRE_PULL = 'preoutgoing.pre_pull'
266
266
267 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
267 ui_id = Column("ui_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
268 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
268 ui_section = Column("ui_section", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
269 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
269 ui_key = Column("ui_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
270 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
270 ui_value = Column("ui_value", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
271 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
271 ui_active = Column("ui_active", Boolean(), nullable=True, unique=None, default=True)
272
272
273 @classmethod
273 @classmethod
274 def get_by_key(cls, key):
274 def get_by_key(cls, key):
275 return cls.query().filter(cls.ui_key == key).scalar()
275 return cls.query().filter(cls.ui_key == key).scalar()
276
276
277 @classmethod
277 @classmethod
278 def get_builtin_hooks(cls):
278 def get_builtin_hooks(cls):
279 q = cls.query()
279 q = cls.query()
280 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
280 q = q.filter(cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
281 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
281 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
282 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
282 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
283 return q.all()
283 return q.all()
284
284
285 @classmethod
285 @classmethod
286 def get_custom_hooks(cls):
286 def get_custom_hooks(cls):
287 q = cls.query()
287 q = cls.query()
288 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
288 q = q.filter(~cls.ui_key.in_([cls.HOOK_UPDATE, cls.HOOK_REPO_SIZE,
289 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
289 cls.HOOK_PUSH, cls.HOOK_PRE_PUSH,
290 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
290 cls.HOOK_PULL, cls.HOOK_PRE_PULL]))
291 q = q.filter(cls.ui_section == 'hooks')
291 q = q.filter(cls.ui_section == 'hooks')
292 return q.all()
292 return q.all()
293
293
294 @classmethod
294 @classmethod
295 def get_repos_location(cls):
295 def get_repos_location(cls):
296 return cls.get_by_key('/').ui_value
296 return cls.get_by_key('/').ui_value
297
297
298 @classmethod
298 @classmethod
299 def create_or_update_hook(cls, key, val):
299 def create_or_update_hook(cls, key, val):
300 new_ui = cls.get_by_key(key) or cls()
300 new_ui = cls.get_by_key(key) or cls()
301 new_ui.ui_section = 'hooks'
301 new_ui.ui_section = 'hooks'
302 new_ui.ui_active = True
302 new_ui.ui_active = True
303 new_ui.ui_key = key
303 new_ui.ui_key = key
304 new_ui.ui_value = val
304 new_ui.ui_value = val
305
305
306 Session().add(new_ui)
306 Session().add(new_ui)
307
307
308 def __repr__(self):
308 def __repr__(self):
309 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
309 return '<DB:%s[%s:%s]>' % (self.__class__.__name__, self.ui_key,
310 self.ui_value)
310 self.ui_value)
311
311
312
312
313 class User(Base, BaseModel):
313 class User(Base, BaseModel):
314 __tablename__ = 'users'
314 __tablename__ = 'users'
315 __table_args__ = (
315 __table_args__ = (
316 UniqueConstraint('username'), UniqueConstraint('email'),
316 UniqueConstraint('username'), UniqueConstraint('email'),
317 Index('u_username_idx', 'username'),
317 Index('u_username_idx', 'username'),
318 Index('u_email_idx', 'email'),
318 Index('u_email_idx', 'email'),
319 {'extend_existing': True, 'mysql_engine': 'InnoDB',
319 {'extend_existing': True, 'mysql_engine': 'InnoDB',
320 'mysql_charset': 'utf8'}
320 'mysql_charset': 'utf8'}
321 )
321 )
322 DEFAULT_USER = 'default'
322 DEFAULT_USER = 'default'
323 DEFAULT_PERMISSIONS = [
323
324 'hg.register.manual_activate', 'hg.create.repository',
325 'hg.fork.repository', 'repository.read', 'group.read'
326 ]
327 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
324 user_id = Column("user_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
328 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
325 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
326 password = Column("password", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
327 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
331 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
328 admin = Column("admin", Boolean(), nullable=True, unique=None, default=False)
332 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
329 name = Column("firstname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
333 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
330 lastname = Column("lastname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
334 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
331 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
335 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
332 last_login = Column("last_login", DateTime(timezone=False), nullable=True, unique=None, default=None)
336 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
333 ldap_dn = Column("ldap_dn", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
337 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
334 api_key = Column("api_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
338 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
335 inherit_default_permissions = Column("inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
339
336
340 user_log = relationship('UserLog')
337 user_log = relationship('UserLog')
341 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
338 user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
342
339
343 repositories = relationship('Repository')
340 repositories = relationship('Repository')
344 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
341 user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
345 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
342 followings = relationship('UserFollowing', primaryjoin='UserFollowing.user_id==User.user_id', cascade='all')
346
343
347 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
344 repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
348 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
345 repo_group_to_perm = relationship('UserRepoGroupToPerm', primaryjoin='UserRepoGroupToPerm.user_id==User.user_id', cascade='all')
349
346
350 group_member = relationship('UserGroupMember', cascade='all')
347 group_member = relationship('UserGroupMember', cascade='all')
351
348
352 notifications = relationship('UserNotification', cascade='all')
349 notifications = relationship('UserNotification', cascade='all')
353 # notifications assigned to this user
350 # notifications assigned to this user
354 user_created_notifications = relationship('Notification', cascade='all')
351 user_created_notifications = relationship('Notification', cascade='all')
355 # comments created by this user
352 # comments created by this user
356 user_comments = relationship('ChangesetComment', cascade='all')
353 user_comments = relationship('ChangesetComment', cascade='all')
357 #extra emails for this user
354 #extra emails for this user
358 user_emails = relationship('UserEmailMap', cascade='all')
355 user_emails = relationship('UserEmailMap', cascade='all')
359
356
360 @hybrid_property
357 @hybrid_property
361 def email(self):
358 def email(self):
362 return self._email
359 return self._email
363
360
364 @email.setter
361 @email.setter
365 def email(self, val):
362 def email(self, val):
366 self._email = val.lower() if val else None
363 self._email = val.lower() if val else None
367
364
368 @property
365 @property
369 def firstname(self):
366 def firstname(self):
370 # alias for future
367 # alias for future
371 return self.name
368 return self.name
372
369
373 @property
370 @property
374 def emails(self):
371 def emails(self):
375 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
372 other = UserEmailMap.query().filter(UserEmailMap.user==self).all()
376 return [self.email] + [x.email for x in other]
373 return [self.email] + [x.email for x in other]
377
374
378 @property
375 @property
379 def ip_addresses(self):
376 def ip_addresses(self):
380 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
377 ret = UserIpMap.query().filter(UserIpMap.user == self).all()
381 return [x.ip_addr for x in ret]
378 return [x.ip_addr for x in ret]
382
379
383 @property
380 @property
384 def username_and_name(self):
381 def username_and_name(self):
385 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
382 return '%s (%s %s)' % (self.username, self.firstname, self.lastname)
386
383
387 @property
384 @property
388 def full_name(self):
385 def full_name(self):
389 return '%s %s' % (self.firstname, self.lastname)
386 return '%s %s' % (self.firstname, self.lastname)
390
387
391 @property
388 @property
392 def full_name_or_username(self):
389 def full_name_or_username(self):
393 return ('%s %s' % (self.firstname, self.lastname)
390 return ('%s %s' % (self.firstname, self.lastname)
394 if (self.firstname and self.lastname) else self.username)
391 if (self.firstname and self.lastname) else self.username)
395
392
396 @property
393 @property
397 def full_contact(self):
394 def full_contact(self):
398 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
395 return '%s %s <%s>' % (self.firstname, self.lastname, self.email)
399
396
400 @property
397 @property
401 def short_contact(self):
398 def short_contact(self):
402 return '%s %s' % (self.firstname, self.lastname)
399 return '%s %s' % (self.firstname, self.lastname)
403
400
404 @property
401 @property
405 def is_admin(self):
402 def is_admin(self):
406 return self.admin
403 return self.admin
407
404
408 @property
405 @property
409 def AuthUser(self):
406 def AuthUser(self):
410 """
407 """
411 Returns instance of AuthUser for this user
408 Returns instance of AuthUser for this user
412 """
409 """
413 from rhodecode.lib.auth import AuthUser
410 from rhodecode.lib.auth import AuthUser
414 return AuthUser(user_id=self.user_id, api_key=self.api_key,
411 return AuthUser(user_id=self.user_id, api_key=self.api_key,
415 username=self.username)
412 username=self.username)
416
413
417 def __unicode__(self):
414 def __unicode__(self):
418 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
415 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
419 self.user_id, self.username)
416 self.user_id, self.username)
420
417
421 @classmethod
418 @classmethod
422 def get_by_username(cls, username, case_insensitive=False, cache=False):
419 def get_by_username(cls, username, case_insensitive=False, cache=False):
423 if case_insensitive:
420 if case_insensitive:
424 q = cls.query().filter(cls.username.ilike(username))
421 q = cls.query().filter(cls.username.ilike(username))
425 else:
422 else:
426 q = cls.query().filter(cls.username == username)
423 q = cls.query().filter(cls.username == username)
427
424
428 if cache:
425 if cache:
429 q = q.options(FromCache(
426 q = q.options(FromCache(
430 "sql_cache_short",
427 "sql_cache_short",
431 "get_user_%s" % _hash_key(username)
428 "get_user_%s" % _hash_key(username)
432 )
429 )
433 )
430 )
434 return q.scalar()
431 return q.scalar()
435
432
436 @classmethod
433 @classmethod
437 def get_by_api_key(cls, api_key, cache=False):
434 def get_by_api_key(cls, api_key, cache=False):
438 q = cls.query().filter(cls.api_key == api_key)
435 q = cls.query().filter(cls.api_key == api_key)
439
436
440 if cache:
437 if cache:
441 q = q.options(FromCache("sql_cache_short",
438 q = q.options(FromCache("sql_cache_short",
442 "get_api_key_%s" % api_key))
439 "get_api_key_%s" % api_key))
443 return q.scalar()
440 return q.scalar()
444
441
445 @classmethod
442 @classmethod
446 def get_by_email(cls, email, case_insensitive=False, cache=False):
443 def get_by_email(cls, email, case_insensitive=False, cache=False):
447 if case_insensitive:
444 if case_insensitive:
448 q = cls.query().filter(cls.email.ilike(email))
445 q = cls.query().filter(cls.email.ilike(email))
449 else:
446 else:
450 q = cls.query().filter(cls.email == email)
447 q = cls.query().filter(cls.email == email)
451
448
452 if cache:
449 if cache:
453 q = q.options(FromCache("sql_cache_short",
450 q = q.options(FromCache("sql_cache_short",
454 "get_email_key_%s" % email))
451 "get_email_key_%s" % email))
455
452
456 ret = q.scalar()
453 ret = q.scalar()
457 if ret is None:
454 if ret is None:
458 q = UserEmailMap.query()
455 q = UserEmailMap.query()
459 # try fetching in alternate email map
456 # try fetching in alternate email map
460 if case_insensitive:
457 if case_insensitive:
461 q = q.filter(UserEmailMap.email.ilike(email))
458 q = q.filter(UserEmailMap.email.ilike(email))
462 else:
459 else:
463 q = q.filter(UserEmailMap.email == email)
460 q = q.filter(UserEmailMap.email == email)
464 q = q.options(joinedload(UserEmailMap.user))
461 q = q.options(joinedload(UserEmailMap.user))
465 if cache:
462 if cache:
466 q = q.options(FromCache("sql_cache_short",
463 q = q.options(FromCache("sql_cache_short",
467 "get_email_map_key_%s" % email))
464 "get_email_map_key_%s" % email))
468 ret = getattr(q.scalar(), 'user', None)
465 ret = getattr(q.scalar(), 'user', None)
469
466
470 return ret
467 return ret
471
468
472 @classmethod
469 @classmethod
473 def get_from_cs_author(cls, author):
470 def get_from_cs_author(cls, author):
474 """
471 """
475 Tries to get User objects out of commit author string
472 Tries to get User objects out of commit author string
476
473
477 :param author:
474 :param author:
478 """
475 """
479 from rhodecode.lib.helpers import email, author_name
476 from rhodecode.lib.helpers import email, author_name
480 # Valid email in the attribute passed, see if they're in the system
477 # Valid email in the attribute passed, see if they're in the system
481 _email = email(author)
478 _email = email(author)
482 if _email:
479 if _email:
483 user = cls.get_by_email(_email, case_insensitive=True)
480 user = cls.get_by_email(_email, case_insensitive=True)
484 if user:
481 if user:
485 return user
482 return user
486 # Maybe we can match by username?
483 # Maybe we can match by username?
487 _author = author_name(author)
484 _author = author_name(author)
488 user = cls.get_by_username(_author, case_insensitive=True)
485 user = cls.get_by_username(_author, case_insensitive=True)
489 if user:
486 if user:
490 return user
487 return user
491
488
492 def update_lastlogin(self):
489 def update_lastlogin(self):
493 """Update user lastlogin"""
490 """Update user lastlogin"""
494 self.last_login = datetime.datetime.now()
491 self.last_login = datetime.datetime.now()
495 Session().add(self)
492 Session().add(self)
496 log.debug('updated user %s lastlogin' % self.username)
493 log.debug('updated user %s lastlogin' % self.username)
497
494
498 @classmethod
495 @classmethod
499 def get_first_admin(cls):
496 def get_first_admin(cls):
500 user = User.query().filter(User.admin == True).first()
497 user = User.query().filter(User.admin == True).first()
501 if user is None:
498 if user is None:
502 raise Exception('Missing administrative account!')
499 raise Exception('Missing administrative account!')
503 return user
500 return user
504
501
502 @classmethod
503 def get_default_user(cls, cache=False):
504 user = User.get_by_username(User.DEFAULT_USER, cache=cache)
505 if user is None:
506 raise Exception('Missing default account!')
507 return user
508
505 def get_api_data(self):
509 def get_api_data(self):
506 """
510 """
507 Common function for generating user related data for API
511 Common function for generating user related data for API
508 """
512 """
509 user = self
513 user = self
510 data = dict(
514 data = dict(
511 user_id=user.user_id,
515 user_id=user.user_id,
512 username=user.username,
516 username=user.username,
513 firstname=user.name,
517 firstname=user.name,
514 lastname=user.lastname,
518 lastname=user.lastname,
515 email=user.email,
519 email=user.email,
516 emails=user.emails,
520 emails=user.emails,
517 api_key=user.api_key,
521 api_key=user.api_key,
518 active=user.active,
522 active=user.active,
519 admin=user.admin,
523 admin=user.admin,
520 ldap_dn=user.ldap_dn,
524 ldap_dn=user.ldap_dn,
521 last_login=user.last_login,
525 last_login=user.last_login,
522 ip_addresses=user.ip_addresses
526 ip_addresses=user.ip_addresses
523 )
527 )
524 return data
528 return data
525
529
526 def __json__(self):
530 def __json__(self):
527 data = dict(
531 data = dict(
528 full_name=self.full_name,
532 full_name=self.full_name,
529 full_name_or_username=self.full_name_or_username,
533 full_name_or_username=self.full_name_or_username,
530 short_contact=self.short_contact,
534 short_contact=self.short_contact,
531 full_contact=self.full_contact
535 full_contact=self.full_contact
532 )
536 )
533 data.update(self.get_api_data())
537 data.update(self.get_api_data())
534 return data
538 return data
535
539
536
540
537 class UserEmailMap(Base, BaseModel):
541 class UserEmailMap(Base, BaseModel):
538 __tablename__ = 'user_email_map'
542 __tablename__ = 'user_email_map'
539 __table_args__ = (
543 __table_args__ = (
540 Index('uem_email_idx', 'email'),
544 Index('uem_email_idx', 'email'),
541 UniqueConstraint('email'),
545 UniqueConstraint('email'),
542 {'extend_existing': True, 'mysql_engine': 'InnoDB',
546 {'extend_existing': True, 'mysql_engine': 'InnoDB',
543 'mysql_charset': 'utf8'}
547 'mysql_charset': 'utf8'}
544 )
548 )
545 __mapper_args__ = {}
549 __mapper_args__ = {}
546
550
547 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
551 email_id = Column("email_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
548 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
552 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
549 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
553 _email = Column("email", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
550 user = relationship('User', lazy='joined')
554 user = relationship('User', lazy='joined')
551
555
552 @validates('_email')
556 @validates('_email')
553 def validate_email(self, key, email):
557 def validate_email(self, key, email):
554 # check if this email is not main one
558 # check if this email is not main one
555 main_email = Session().query(User).filter(User.email == email).scalar()
559 main_email = Session().query(User).filter(User.email == email).scalar()
556 if main_email is not None:
560 if main_email is not None:
557 raise AttributeError('email %s is present is user table' % email)
561 raise AttributeError('email %s is present is user table' % email)
558 return email
562 return email
559
563
560 @hybrid_property
564 @hybrid_property
561 def email(self):
565 def email(self):
562 return self._email
566 return self._email
563
567
564 @email.setter
568 @email.setter
565 def email(self, val):
569 def email(self, val):
566 self._email = val.lower() if val else None
570 self._email = val.lower() if val else None
567
571
568
572
569 class UserIpMap(Base, BaseModel):
573 class UserIpMap(Base, BaseModel):
570 __tablename__ = 'user_ip_map'
574 __tablename__ = 'user_ip_map'
571 __table_args__ = (
575 __table_args__ = (
572 UniqueConstraint('user_id', 'ip_addr'),
576 UniqueConstraint('user_id', 'ip_addr'),
573 {'extend_existing': True, 'mysql_engine': 'InnoDB',
577 {'extend_existing': True, 'mysql_engine': 'InnoDB',
574 'mysql_charset': 'utf8'}
578 'mysql_charset': 'utf8'}
575 )
579 )
576 __mapper_args__ = {}
580 __mapper_args__ = {}
577
581
578 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
582 ip_id = Column("ip_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
579 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
583 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
580 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
584 ip_addr = Column("ip_addr", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
581 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
585 active = Column("active", Boolean(), nullable=True, unique=None, default=True)
582 user = relationship('User', lazy='joined')
586 user = relationship('User', lazy='joined')
583
587
584 @classmethod
588 @classmethod
585 def _get_ip_range(cls, ip_addr):
589 def _get_ip_range(cls, ip_addr):
586 from rhodecode.lib import ipaddr
590 from rhodecode.lib import ipaddr
587 net = ipaddr.IPNetwork(address=ip_addr)
591 net = ipaddr.IPNetwork(address=ip_addr)
588 return [str(net.network), str(net.broadcast)]
592 return [str(net.network), str(net.broadcast)]
589
593
590 def __json__(self):
594 def __json__(self):
591 return dict(
595 return dict(
592 ip_addr=self.ip_addr,
596 ip_addr=self.ip_addr,
593 ip_range=self._get_ip_range(self.ip_addr)
597 ip_range=self._get_ip_range(self.ip_addr)
594 )
598 )
595
599
596
600
597 class UserLog(Base, BaseModel):
601 class UserLog(Base, BaseModel):
598 __tablename__ = 'user_logs'
602 __tablename__ = 'user_logs'
599 __table_args__ = (
603 __table_args__ = (
600 {'extend_existing': True, 'mysql_engine': 'InnoDB',
604 {'extend_existing': True, 'mysql_engine': 'InnoDB',
601 'mysql_charset': 'utf8'},
605 'mysql_charset': 'utf8'},
602 )
606 )
603 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
607 user_log_id = Column("user_log_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
604 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
608 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
605 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
609 username = Column("username", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
606 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
610 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True)
607 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
611 repository_name = Column("repository_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
608 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
612 user_ip = Column("user_ip", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
609 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
613 action = Column("action", UnicodeText(1200000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
610 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
614 action_date = Column("action_date", DateTime(timezone=False), nullable=True, unique=None, default=None)
611
615
612 @property
616 @property
613 def action_as_day(self):
617 def action_as_day(self):
614 return datetime.date(*self.action_date.timetuple()[:3])
618 return datetime.date(*self.action_date.timetuple()[:3])
615
619
616 user = relationship('User')
620 user = relationship('User')
617 repository = relationship('Repository', cascade='')
621 repository = relationship('Repository', cascade='')
618
622
619
623
620 class UserGroup(Base, BaseModel):
624 class UserGroup(Base, BaseModel):
621 __tablename__ = 'users_groups'
625 __tablename__ = 'users_groups'
622 __table_args__ = (
626 __table_args__ = (
623 {'extend_existing': True, 'mysql_engine': 'InnoDB',
627 {'extend_existing': True, 'mysql_engine': 'InnoDB',
624 'mysql_charset': 'utf8'},
628 'mysql_charset': 'utf8'},
625 )
629 )
626
630
627 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
631 users_group_id = Column("users_group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
628 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
632 users_group_name = Column("users_group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
629 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
633 users_group_active = Column("users_group_active", Boolean(), nullable=True, unique=None, default=None)
630 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
634 inherit_default_permissions = Column("users_group_inherit_default_permissions", Boolean(), nullable=False, unique=None, default=True)
631 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
635 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
632
636
633 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
637 members = relationship('UserGroupMember', cascade="all, delete, delete-orphan", lazy="joined")
634 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
638 users_group_to_perm = relationship('UserGroupToPerm', cascade='all')
635 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
639 users_group_repo_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
636 user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all')
640 user_user_group_to_perm = relationship('UserUserGroupToPerm ', cascade='all')
637 user = relationship('User')
641 user = relationship('User')
638
642
639 def __unicode__(self):
643 def __unicode__(self):
640 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
644 return u"<%s('id:%s:%s')>" % (self.__class__.__name__,
641 self.users_group_id,
645 self.users_group_id,
642 self.users_group_name)
646 self.users_group_name)
643
647
644 @classmethod
648 @classmethod
645 def get_by_group_name(cls, group_name, cache=False,
649 def get_by_group_name(cls, group_name, cache=False,
646 case_insensitive=False):
650 case_insensitive=False):
647 if case_insensitive:
651 if case_insensitive:
648 q = cls.query().filter(cls.users_group_name.ilike(group_name))
652 q = cls.query().filter(cls.users_group_name.ilike(group_name))
649 else:
653 else:
650 q = cls.query().filter(cls.users_group_name == group_name)
654 q = cls.query().filter(cls.users_group_name == group_name)
651 if cache:
655 if cache:
652 q = q.options(FromCache(
656 q = q.options(FromCache(
653 "sql_cache_short",
657 "sql_cache_short",
654 "get_user_%s" % _hash_key(group_name)
658 "get_user_%s" % _hash_key(group_name)
655 )
659 )
656 )
660 )
657 return q.scalar()
661 return q.scalar()
658
662
659 @classmethod
663 @classmethod
660 def get(cls, users_group_id, cache=False):
664 def get(cls, users_group_id, cache=False):
661 users_group = cls.query()
665 users_group = cls.query()
662 if cache:
666 if cache:
663 users_group = users_group.options(FromCache("sql_cache_short",
667 users_group = users_group.options(FromCache("sql_cache_short",
664 "get_users_group_%s" % users_group_id))
668 "get_users_group_%s" % users_group_id))
665 return users_group.get(users_group_id)
669 return users_group.get(users_group_id)
666
670
667 def get_api_data(self):
671 def get_api_data(self):
668 users_group = self
672 users_group = self
669
673
670 data = dict(
674 data = dict(
671 users_group_id=users_group.users_group_id,
675 users_group_id=users_group.users_group_id,
672 group_name=users_group.users_group_name,
676 group_name=users_group.users_group_name,
673 active=users_group.users_group_active,
677 active=users_group.users_group_active,
674 )
678 )
675
679
676 return data
680 return data
677
681
678
682
679 class UserGroupMember(Base, BaseModel):
683 class UserGroupMember(Base, BaseModel):
680 __tablename__ = 'users_groups_members'
684 __tablename__ = 'users_groups_members'
681 __table_args__ = (
685 __table_args__ = (
682 {'extend_existing': True, 'mysql_engine': 'InnoDB',
686 {'extend_existing': True, 'mysql_engine': 'InnoDB',
683 'mysql_charset': 'utf8'},
687 'mysql_charset': 'utf8'},
684 )
688 )
685
689
686 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
690 users_group_member_id = Column("users_group_member_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
687 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
691 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
688 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
692 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
689
693
690 user = relationship('User', lazy='joined')
694 user = relationship('User', lazy='joined')
691 users_group = relationship('UserGroup')
695 users_group = relationship('UserGroup')
692
696
693 def __init__(self, gr_id='', u_id=''):
697 def __init__(self, gr_id='', u_id=''):
694 self.users_group_id = gr_id
698 self.users_group_id = gr_id
695 self.user_id = u_id
699 self.user_id = u_id
696
700
697
701
698 class RepositoryField(Base, BaseModel):
702 class RepositoryField(Base, BaseModel):
699 __tablename__ = 'repositories_fields'
703 __tablename__ = 'repositories_fields'
700 __table_args__ = (
704 __table_args__ = (
701 UniqueConstraint('repository_id', 'field_key'), # no-multi field
705 UniqueConstraint('repository_id', 'field_key'), # no-multi field
702 {'extend_existing': True, 'mysql_engine': 'InnoDB',
706 {'extend_existing': True, 'mysql_engine': 'InnoDB',
703 'mysql_charset': 'utf8'},
707 'mysql_charset': 'utf8'},
704 )
708 )
705 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
709 PREFIX = 'ex_' # prefix used in form to not conflict with already existing fields
706
710
707 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
711 repo_field_id = Column("repo_field_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
708 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
712 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
709 field_key = Column("field_key", String(250, convert_unicode=False, assert_unicode=None))
713 field_key = Column("field_key", String(250, convert_unicode=False, assert_unicode=None))
710 field_label = Column("field_label", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
714 field_label = Column("field_label", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
711 field_value = Column("field_value", String(10000, convert_unicode=False, assert_unicode=None), nullable=False)
715 field_value = Column("field_value", String(10000, convert_unicode=False, assert_unicode=None), nullable=False)
712 field_desc = Column("field_desc", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
716 field_desc = Column("field_desc", String(1024, convert_unicode=False, assert_unicode=None), nullable=False)
713 field_type = Column("field_type", String(256), nullable=False, unique=None)
717 field_type = Column("field_type", String(256), nullable=False, unique=None)
714 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
718 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
715
719
716 repository = relationship('Repository')
720 repository = relationship('Repository')
717
721
718 @property
722 @property
719 def field_key_prefixed(self):
723 def field_key_prefixed(self):
720 return 'ex_%s' % self.field_key
724 return 'ex_%s' % self.field_key
721
725
722 @classmethod
726 @classmethod
723 def un_prefix_key(cls, key):
727 def un_prefix_key(cls, key):
724 if key.startswith(cls.PREFIX):
728 if key.startswith(cls.PREFIX):
725 return key[len(cls.PREFIX):]
729 return key[len(cls.PREFIX):]
726 return key
730 return key
727
731
728 @classmethod
732 @classmethod
729 def get_by_key_name(cls, key, repo):
733 def get_by_key_name(cls, key, repo):
730 row = cls.query()\
734 row = cls.query()\
731 .filter(cls.repository == repo)\
735 .filter(cls.repository == repo)\
732 .filter(cls.field_key == key).scalar()
736 .filter(cls.field_key == key).scalar()
733 return row
737 return row
734
738
735
739
736 class Repository(Base, BaseModel):
740 class Repository(Base, BaseModel):
737 __tablename__ = 'repositories'
741 __tablename__ = 'repositories'
738 __table_args__ = (
742 __table_args__ = (
739 UniqueConstraint('repo_name'),
743 UniqueConstraint('repo_name'),
740 Index('r_repo_name_idx', 'repo_name'),
744 Index('r_repo_name_idx', 'repo_name'),
741 {'extend_existing': True, 'mysql_engine': 'InnoDB',
745 {'extend_existing': True, 'mysql_engine': 'InnoDB',
742 'mysql_charset': 'utf8'},
746 'mysql_charset': 'utf8'},
743 )
747 )
744
748
745 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
749 repo_id = Column("repo_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
746 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
750 repo_name = Column("repo_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
747 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
751 clone_uri = Column("clone_uri", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
748 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
752 repo_type = Column("repo_type", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
749 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
753 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
750 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
754 private = Column("private", Boolean(), nullable=True, unique=None, default=None)
751 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
755 enable_statistics = Column("statistics", Boolean(), nullable=True, unique=None, default=True)
752 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
756 enable_downloads = Column("downloads", Boolean(), nullable=True, unique=None, default=True)
753 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
757 description = Column("description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
754 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
758 created_on = Column('created_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
755 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
759 updated_on = Column('updated_on', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
756 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
760 landing_rev = Column("landing_revision", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=False, default=None)
757 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
761 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
758 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
762 _locked = Column("locked", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=False, default=None)
759 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
763 _changeset_cache = Column("changeset_cache", LargeBinary(), nullable=True) #JSON data
760
764
761 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
765 fork_id = Column("fork_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=False, default=None)
762 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
766 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=False, default=None)
763
767
764 user = relationship('User')
768 user = relationship('User')
765 fork = relationship('Repository', remote_side=repo_id)
769 fork = relationship('Repository', remote_side=repo_id)
766 group = relationship('RepoGroup')
770 group = relationship('RepoGroup')
767 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
771 repo_to_perm = relationship('UserRepoToPerm', cascade='all', order_by='UserRepoToPerm.repo_to_perm_id')
768 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
772 users_group_to_perm = relationship('UserGroupRepoToPerm', cascade='all')
769 stats = relationship('Statistics', cascade='all', uselist=False)
773 stats = relationship('Statistics', cascade='all', uselist=False)
770
774
771 followers = relationship('UserFollowing',
775 followers = relationship('UserFollowing',
772 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
776 primaryjoin='UserFollowing.follows_repo_id==Repository.repo_id',
773 cascade='all')
777 cascade='all')
774 extra_fields = relationship('RepositoryField',
778 extra_fields = relationship('RepositoryField',
775 cascade="all, delete, delete-orphan")
779 cascade="all, delete, delete-orphan")
776
780
777 logs = relationship('UserLog')
781 logs = relationship('UserLog')
778 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
782 comments = relationship('ChangesetComment', cascade="all, delete, delete-orphan")
779
783
780 pull_requests_org = relationship('PullRequest',
784 pull_requests_org = relationship('PullRequest',
781 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
785 primaryjoin='PullRequest.org_repo_id==Repository.repo_id',
782 cascade="all, delete, delete-orphan")
786 cascade="all, delete, delete-orphan")
783
787
784 pull_requests_other = relationship('PullRequest',
788 pull_requests_other = relationship('PullRequest',
785 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
789 primaryjoin='PullRequest.other_repo_id==Repository.repo_id',
786 cascade="all, delete, delete-orphan")
790 cascade="all, delete, delete-orphan")
787
791
788 def __unicode__(self):
792 def __unicode__(self):
789 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
793 return u"<%s('%s:%s')>" % (self.__class__.__name__, self.repo_id,
790 self.repo_name)
794 self.repo_name)
791
795
792 @hybrid_property
796 @hybrid_property
793 def locked(self):
797 def locked(self):
794 # always should return [user_id, timelocked]
798 # always should return [user_id, timelocked]
795 if self._locked:
799 if self._locked:
796 _lock_info = self._locked.split(':')
800 _lock_info = self._locked.split(':')
797 return int(_lock_info[0]), _lock_info[1]
801 return int(_lock_info[0]), _lock_info[1]
798 return [None, None]
802 return [None, None]
799
803
800 @locked.setter
804 @locked.setter
801 def locked(self, val):
805 def locked(self, val):
802 if val and isinstance(val, (list, tuple)):
806 if val and isinstance(val, (list, tuple)):
803 self._locked = ':'.join(map(str, val))
807 self._locked = ':'.join(map(str, val))
804 else:
808 else:
805 self._locked = None
809 self._locked = None
806
810
807 @hybrid_property
811 @hybrid_property
808 def changeset_cache(self):
812 def changeset_cache(self):
809 from rhodecode.lib.vcs.backends.base import EmptyChangeset
813 from rhodecode.lib.vcs.backends.base import EmptyChangeset
810 dummy = EmptyChangeset().__json__()
814 dummy = EmptyChangeset().__json__()
811 if not self._changeset_cache:
815 if not self._changeset_cache:
812 return dummy
816 return dummy
813 try:
817 try:
814 return json.loads(self._changeset_cache)
818 return json.loads(self._changeset_cache)
815 except TypeError:
819 except TypeError:
816 return dummy
820 return dummy
817
821
818 @changeset_cache.setter
822 @changeset_cache.setter
819 def changeset_cache(self, val):
823 def changeset_cache(self, val):
820 try:
824 try:
821 self._changeset_cache = json.dumps(val)
825 self._changeset_cache = json.dumps(val)
822 except Exception:
826 except Exception:
823 log.error(traceback.format_exc())
827 log.error(traceback.format_exc())
824
828
825 @classmethod
829 @classmethod
826 def url_sep(cls):
830 def url_sep(cls):
827 return URL_SEP
831 return URL_SEP
828
832
829 @classmethod
833 @classmethod
830 def normalize_repo_name(cls, repo_name):
834 def normalize_repo_name(cls, repo_name):
831 """
835 """
832 Normalizes os specific repo_name to the format internally stored inside
836 Normalizes os specific repo_name to the format internally stored inside
833 dabatabase using URL_SEP
837 dabatabase using URL_SEP
834
838
835 :param cls:
839 :param cls:
836 :param repo_name:
840 :param repo_name:
837 """
841 """
838 return cls.url_sep().join(repo_name.split(os.sep))
842 return cls.url_sep().join(repo_name.split(os.sep))
839
843
840 @classmethod
844 @classmethod
841 def get_by_repo_name(cls, repo_name):
845 def get_by_repo_name(cls, repo_name):
842 q = Session().query(cls).filter(cls.repo_name == repo_name)
846 q = Session().query(cls).filter(cls.repo_name == repo_name)
843 q = q.options(joinedload(Repository.fork))\
847 q = q.options(joinedload(Repository.fork))\
844 .options(joinedload(Repository.user))\
848 .options(joinedload(Repository.user))\
845 .options(joinedload(Repository.group))
849 .options(joinedload(Repository.group))
846 return q.scalar()
850 return q.scalar()
847
851
848 @classmethod
852 @classmethod
849 def get_by_full_path(cls, repo_full_path):
853 def get_by_full_path(cls, repo_full_path):
850 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
854 repo_name = repo_full_path.split(cls.base_path(), 1)[-1]
851 repo_name = cls.normalize_repo_name(repo_name)
855 repo_name = cls.normalize_repo_name(repo_name)
852 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
856 return cls.get_by_repo_name(repo_name.strip(URL_SEP))
853
857
854 @classmethod
858 @classmethod
855 def get_repo_forks(cls, repo_id):
859 def get_repo_forks(cls, repo_id):
856 return cls.query().filter(Repository.fork_id == repo_id)
860 return cls.query().filter(Repository.fork_id == repo_id)
857
861
858 @classmethod
862 @classmethod
859 def base_path(cls):
863 def base_path(cls):
860 """
864 """
861 Returns base path when all repos are stored
865 Returns base path when all repos are stored
862
866
863 :param cls:
867 :param cls:
864 """
868 """
865 q = Session().query(RhodeCodeUi)\
869 q = Session().query(RhodeCodeUi)\
866 .filter(RhodeCodeUi.ui_key == cls.url_sep())
870 .filter(RhodeCodeUi.ui_key == cls.url_sep())
867 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
871 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
868 return q.one().ui_value
872 return q.one().ui_value
869
873
870 @property
874 @property
871 def forks(self):
875 def forks(self):
872 """
876 """
873 Return forks of this repo
877 Return forks of this repo
874 """
878 """
875 return Repository.get_repo_forks(self.repo_id)
879 return Repository.get_repo_forks(self.repo_id)
876
880
877 @property
881 @property
878 def parent(self):
882 def parent(self):
879 """
883 """
880 Returns fork parent
884 Returns fork parent
881 """
885 """
882 return self.fork
886 return self.fork
883
887
884 @property
888 @property
885 def just_name(self):
889 def just_name(self):
886 return self.repo_name.split(Repository.url_sep())[-1]
890 return self.repo_name.split(Repository.url_sep())[-1]
887
891
888 @property
892 @property
889 def groups_with_parents(self):
893 def groups_with_parents(self):
890 groups = []
894 groups = []
891 if self.group is None:
895 if self.group is None:
892 return groups
896 return groups
893
897
894 cur_gr = self.group
898 cur_gr = self.group
895 groups.insert(0, cur_gr)
899 groups.insert(0, cur_gr)
896 while 1:
900 while 1:
897 gr = getattr(cur_gr, 'parent_group', None)
901 gr = getattr(cur_gr, 'parent_group', None)
898 cur_gr = cur_gr.parent_group
902 cur_gr = cur_gr.parent_group
899 if gr is None:
903 if gr is None:
900 break
904 break
901 groups.insert(0, gr)
905 groups.insert(0, gr)
902
906
903 return groups
907 return groups
904
908
905 @property
909 @property
906 def groups_and_repo(self):
910 def groups_and_repo(self):
907 return self.groups_with_parents, self.just_name, self.repo_name
911 return self.groups_with_parents, self.just_name, self.repo_name
908
912
909 @LazyProperty
913 @LazyProperty
910 def repo_path(self):
914 def repo_path(self):
911 """
915 """
912 Returns base full path for that repository means where it actually
916 Returns base full path for that repository means where it actually
913 exists on a filesystem
917 exists on a filesystem
914 """
918 """
915 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
919 q = Session().query(RhodeCodeUi).filter(RhodeCodeUi.ui_key ==
916 Repository.url_sep())
920 Repository.url_sep())
917 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
921 q = q.options(FromCache("sql_cache_short", "repository_repo_path"))
918 return q.one().ui_value
922 return q.one().ui_value
919
923
920 @property
924 @property
921 def repo_full_path(self):
925 def repo_full_path(self):
922 p = [self.repo_path]
926 p = [self.repo_path]
923 # we need to split the name by / since this is how we store the
927 # we need to split the name by / since this is how we store the
924 # names in the database, but that eventually needs to be converted
928 # names in the database, but that eventually needs to be converted
925 # into a valid system path
929 # into a valid system path
926 p += self.repo_name.split(Repository.url_sep())
930 p += self.repo_name.split(Repository.url_sep())
927 return os.path.join(*map(safe_unicode, p))
931 return os.path.join(*map(safe_unicode, p))
928
932
929 @property
933 @property
930 def cache_keys(self):
934 def cache_keys(self):
931 """
935 """
932 Returns associated cache keys for that repo
936 Returns associated cache keys for that repo
933 """
937 """
934 return CacheInvalidation.query()\
938 return CacheInvalidation.query()\
935 .filter(CacheInvalidation.cache_args == self.repo_name)\
939 .filter(CacheInvalidation.cache_args == self.repo_name)\
936 .order_by(CacheInvalidation.cache_key)\
940 .order_by(CacheInvalidation.cache_key)\
937 .all()
941 .all()
938
942
939 def get_new_name(self, repo_name):
943 def get_new_name(self, repo_name):
940 """
944 """
941 returns new full repository name based on assigned group and new new
945 returns new full repository name based on assigned group and new new
942
946
943 :param group_name:
947 :param group_name:
944 """
948 """
945 path_prefix = self.group.full_path_splitted if self.group else []
949 path_prefix = self.group.full_path_splitted if self.group else []
946 return Repository.url_sep().join(path_prefix + [repo_name])
950 return Repository.url_sep().join(path_prefix + [repo_name])
947
951
948 @property
952 @property
949 def _ui(self):
953 def _ui(self):
950 """
954 """
951 Creates an db based ui object for this repository
955 Creates an db based ui object for this repository
952 """
956 """
953 from rhodecode.lib.utils import make_ui
957 from rhodecode.lib.utils import make_ui
954 return make_ui('db', clear_session=False)
958 return make_ui('db', clear_session=False)
955
959
956 @classmethod
960 @classmethod
957 def is_valid(cls, repo_name):
961 def is_valid(cls, repo_name):
958 """
962 """
959 returns True if given repo name is a valid filesystem repository
963 returns True if given repo name is a valid filesystem repository
960
964
961 :param cls:
965 :param cls:
962 :param repo_name:
966 :param repo_name:
963 """
967 """
964 from rhodecode.lib.utils import is_valid_repo
968 from rhodecode.lib.utils import is_valid_repo
965
969
966 return is_valid_repo(repo_name, cls.base_path())
970 return is_valid_repo(repo_name, cls.base_path())
967
971
968 def get_api_data(self):
972 def get_api_data(self):
969 """
973 """
970 Common function for generating repo api data
974 Common function for generating repo api data
971
975
972 """
976 """
973 repo = self
977 repo = self
974 data = dict(
978 data = dict(
975 repo_id=repo.repo_id,
979 repo_id=repo.repo_id,
976 repo_name=repo.repo_name,
980 repo_name=repo.repo_name,
977 repo_type=repo.repo_type,
981 repo_type=repo.repo_type,
978 clone_uri=repo.clone_uri,
982 clone_uri=repo.clone_uri,
979 private=repo.private,
983 private=repo.private,
980 created_on=repo.created_on,
984 created_on=repo.created_on,
981 description=repo.description,
985 description=repo.description,
982 landing_rev=repo.landing_rev,
986 landing_rev=repo.landing_rev,
983 owner=repo.user.username,
987 owner=repo.user.username,
984 fork_of=repo.fork.repo_name if repo.fork else None,
988 fork_of=repo.fork.repo_name if repo.fork else None,
985 enable_statistics=repo.enable_statistics,
989 enable_statistics=repo.enable_statistics,
986 enable_locking=repo.enable_locking,
990 enable_locking=repo.enable_locking,
987 enable_downloads=repo.enable_downloads,
991 enable_downloads=repo.enable_downloads,
988 last_changeset=repo.changeset_cache,
992 last_changeset=repo.changeset_cache,
989 locked_by=User.get(self.locked[0]).get_api_data() \
993 locked_by=User.get(self.locked[0]).get_api_data() \
990 if self.locked[0] else None,
994 if self.locked[0] else None,
991 locked_date=time_to_datetime(self.locked[1]) \
995 locked_date=time_to_datetime(self.locked[1]) \
992 if self.locked[1] else None
996 if self.locked[1] else None
993 )
997 )
994 rc_config = RhodeCodeSetting.get_app_settings()
998 rc_config = RhodeCodeSetting.get_app_settings()
995 repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
999 repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
996 if repository_fields:
1000 if repository_fields:
997 for f in self.extra_fields:
1001 for f in self.extra_fields:
998 data[f.field_key_prefixed] = f.field_value
1002 data[f.field_key_prefixed] = f.field_value
999
1003
1000 return data
1004 return data
1001
1005
1002 @classmethod
1006 @classmethod
1003 def lock(cls, repo, user_id):
1007 def lock(cls, repo, user_id):
1004 repo.locked = [user_id, time.time()]
1008 repo.locked = [user_id, time.time()]
1005 Session().add(repo)
1009 Session().add(repo)
1006 Session().commit()
1010 Session().commit()
1007
1011
1008 @classmethod
1012 @classmethod
1009 def unlock(cls, repo):
1013 def unlock(cls, repo):
1010 repo.locked = None
1014 repo.locked = None
1011 Session().add(repo)
1015 Session().add(repo)
1012 Session().commit()
1016 Session().commit()
1013
1017
1014 @classmethod
1018 @classmethod
1015 def getlock(cls, repo):
1019 def getlock(cls, repo):
1016 return repo.locked
1020 return repo.locked
1017
1021
1018 @property
1022 @property
1019 def last_db_change(self):
1023 def last_db_change(self):
1020 return self.updated_on
1024 return self.updated_on
1021
1025
1022 def clone_url(self, **override):
1026 def clone_url(self, **override):
1023 from pylons import url
1027 from pylons import url
1024 from urlparse import urlparse
1028 from urlparse import urlparse
1025 import urllib
1029 import urllib
1026 parsed_url = urlparse(url('home', qualified=True))
1030 parsed_url = urlparse(url('home', qualified=True))
1027 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
1031 default_clone_uri = '%(scheme)s://%(user)s%(pass)s%(netloc)s%(prefix)s%(path)s'
1028 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
1032 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
1029 args = {
1033 args = {
1030 'user': '',
1034 'user': '',
1031 'pass': '',
1035 'pass': '',
1032 'scheme': parsed_url.scheme,
1036 'scheme': parsed_url.scheme,
1033 'netloc': parsed_url.netloc,
1037 'netloc': parsed_url.netloc,
1034 'prefix': decoded_path,
1038 'prefix': decoded_path,
1035 'path': self.repo_name
1039 'path': self.repo_name
1036 }
1040 }
1037
1041
1038 args.update(override)
1042 args.update(override)
1039 return default_clone_uri % args
1043 return default_clone_uri % args
1040
1044
1041 #==========================================================================
1045 #==========================================================================
1042 # SCM PROPERTIES
1046 # SCM PROPERTIES
1043 #==========================================================================
1047 #==========================================================================
1044
1048
1045 def get_changeset(self, rev=None):
1049 def get_changeset(self, rev=None):
1046 return get_changeset_safe(self.scm_instance, rev)
1050 return get_changeset_safe(self.scm_instance, rev)
1047
1051
1048 def get_landing_changeset(self):
1052 def get_landing_changeset(self):
1049 """
1053 """
1050 Returns landing changeset, or if that doesn't exist returns the tip
1054 Returns landing changeset, or if that doesn't exist returns the tip
1051 """
1055 """
1052 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
1056 cs = self.get_changeset(self.landing_rev) or self.get_changeset()
1053 return cs
1057 return cs
1054
1058
1055 def update_changeset_cache(self, cs_cache=None):
1059 def update_changeset_cache(self, cs_cache=None):
1056 """
1060 """
1057 Update cache of last changeset for repository, keys should be::
1061 Update cache of last changeset for repository, keys should be::
1058
1062
1059 short_id
1063 short_id
1060 raw_id
1064 raw_id
1061 revision
1065 revision
1062 message
1066 message
1063 date
1067 date
1064 author
1068 author
1065
1069
1066 :param cs_cache:
1070 :param cs_cache:
1067 """
1071 """
1068 from rhodecode.lib.vcs.backends.base import BaseChangeset
1072 from rhodecode.lib.vcs.backends.base import BaseChangeset
1069 if cs_cache is None:
1073 if cs_cache is None:
1070 cs_cache = EmptyChangeset()
1074 cs_cache = EmptyChangeset()
1071 # use no-cache version here
1075 # use no-cache version here
1072 scm_repo = self.scm_instance_no_cache()
1076 scm_repo = self.scm_instance_no_cache()
1073 if scm_repo:
1077 if scm_repo:
1074 cs_cache = scm_repo.get_changeset()
1078 cs_cache = scm_repo.get_changeset()
1075
1079
1076 if isinstance(cs_cache, BaseChangeset):
1080 if isinstance(cs_cache, BaseChangeset):
1077 cs_cache = cs_cache.__json__()
1081 cs_cache = cs_cache.__json__()
1078
1082
1079 if (cs_cache != self.changeset_cache or not self.changeset_cache):
1083 if (cs_cache != self.changeset_cache or not self.changeset_cache):
1080 _default = datetime.datetime.fromtimestamp(0)
1084 _default = datetime.datetime.fromtimestamp(0)
1081 last_change = cs_cache.get('date') or _default
1085 last_change = cs_cache.get('date') or _default
1082 log.debug('updated repo %s with new cs cache %s'
1086 log.debug('updated repo %s with new cs cache %s'
1083 % (self.repo_name, cs_cache))
1087 % (self.repo_name, cs_cache))
1084 self.updated_on = last_change
1088 self.updated_on = last_change
1085 self.changeset_cache = cs_cache
1089 self.changeset_cache = cs_cache
1086 Session().add(self)
1090 Session().add(self)
1087 Session().commit()
1091 Session().commit()
1088 else:
1092 else:
1089 log.debug('Skipping repo:%s already with latest changes'
1093 log.debug('Skipping repo:%s already with latest changes'
1090 % self.repo_name)
1094 % self.repo_name)
1091
1095
1092 @property
1096 @property
1093 def tip(self):
1097 def tip(self):
1094 return self.get_changeset('tip')
1098 return self.get_changeset('tip')
1095
1099
1096 @property
1100 @property
1097 def author(self):
1101 def author(self):
1098 return self.tip.author
1102 return self.tip.author
1099
1103
1100 @property
1104 @property
1101 def last_change(self):
1105 def last_change(self):
1102 return self.scm_instance.last_change
1106 return self.scm_instance.last_change
1103
1107
1104 def get_comments(self, revisions=None):
1108 def get_comments(self, revisions=None):
1105 """
1109 """
1106 Returns comments for this repository grouped by revisions
1110 Returns comments for this repository grouped by revisions
1107
1111
1108 :param revisions: filter query by revisions only
1112 :param revisions: filter query by revisions only
1109 """
1113 """
1110 cmts = ChangesetComment.query()\
1114 cmts = ChangesetComment.query()\
1111 .filter(ChangesetComment.repo == self)
1115 .filter(ChangesetComment.repo == self)
1112 if revisions:
1116 if revisions:
1113 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1117 cmts = cmts.filter(ChangesetComment.revision.in_(revisions))
1114 grouped = defaultdict(list)
1118 grouped = defaultdict(list)
1115 for cmt in cmts.all():
1119 for cmt in cmts.all():
1116 grouped[cmt.revision].append(cmt)
1120 grouped[cmt.revision].append(cmt)
1117 return grouped
1121 return grouped
1118
1122
1119 def statuses(self, revisions=None):
1123 def statuses(self, revisions=None):
1120 """
1124 """
1121 Returns statuses for this repository
1125 Returns statuses for this repository
1122
1126
1123 :param revisions: list of revisions to get statuses for
1127 :param revisions: list of revisions to get statuses for
1124 :type revisions: list
1128 :type revisions: list
1125 """
1129 """
1126
1130
1127 statuses = ChangesetStatus.query()\
1131 statuses = ChangesetStatus.query()\
1128 .filter(ChangesetStatus.repo == self)\
1132 .filter(ChangesetStatus.repo == self)\
1129 .filter(ChangesetStatus.version == 0)
1133 .filter(ChangesetStatus.version == 0)
1130 if revisions:
1134 if revisions:
1131 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1135 statuses = statuses.filter(ChangesetStatus.revision.in_(revisions))
1132 grouped = {}
1136 grouped = {}
1133
1137
1134 #maybe we have open new pullrequest without a status ?
1138 #maybe we have open new pullrequest without a status ?
1135 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1139 stat = ChangesetStatus.STATUS_UNDER_REVIEW
1136 status_lbl = ChangesetStatus.get_status_lbl(stat)
1140 status_lbl = ChangesetStatus.get_status_lbl(stat)
1137 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1141 for pr in PullRequest.query().filter(PullRequest.org_repo == self).all():
1138 for rev in pr.revisions:
1142 for rev in pr.revisions:
1139 pr_id = pr.pull_request_id
1143 pr_id = pr.pull_request_id
1140 pr_repo = pr.other_repo.repo_name
1144 pr_repo = pr.other_repo.repo_name
1141 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1145 grouped[rev] = [stat, status_lbl, pr_id, pr_repo]
1142
1146
1143 for stat in statuses.all():
1147 for stat in statuses.all():
1144 pr_id = pr_repo = None
1148 pr_id = pr_repo = None
1145 if stat.pull_request:
1149 if stat.pull_request:
1146 pr_id = stat.pull_request.pull_request_id
1150 pr_id = stat.pull_request.pull_request_id
1147 pr_repo = stat.pull_request.other_repo.repo_name
1151 pr_repo = stat.pull_request.other_repo.repo_name
1148 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1152 grouped[stat.revision] = [str(stat.status), stat.status_lbl,
1149 pr_id, pr_repo]
1153 pr_id, pr_repo]
1150 return grouped
1154 return grouped
1151
1155
1152 def _repo_size(self):
1156 def _repo_size(self):
1153 from rhodecode.lib import helpers as h
1157 from rhodecode.lib import helpers as h
1154 log.debug('calculating repository size...')
1158 log.debug('calculating repository size...')
1155 return h.format_byte_size(self.scm_instance.size)
1159 return h.format_byte_size(self.scm_instance.size)
1156
1160
1157 #==========================================================================
1161 #==========================================================================
1158 # SCM CACHE INSTANCE
1162 # SCM CACHE INSTANCE
1159 #==========================================================================
1163 #==========================================================================
1160
1164
1161 @property
1165 @property
1162 def invalidate(self):
1166 def invalidate(self):
1163 return CacheInvalidation.invalidate(self.repo_name)
1167 return CacheInvalidation.invalidate(self.repo_name)
1164
1168
1165 def set_invalidate(self):
1169 def set_invalidate(self):
1166 """
1170 """
1167 Mark caches of this repo as invalid.
1171 Mark caches of this repo as invalid.
1168 """
1172 """
1169 CacheInvalidation.set_invalidate(self.repo_name)
1173 CacheInvalidation.set_invalidate(self.repo_name)
1170
1174
1171 def scm_instance_no_cache(self):
1175 def scm_instance_no_cache(self):
1172 return self.__get_instance()
1176 return self.__get_instance()
1173
1177
1174 @property
1178 @property
1175 def scm_instance(self):
1179 def scm_instance(self):
1176 import rhodecode
1180 import rhodecode
1177 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1181 full_cache = str2bool(rhodecode.CONFIG.get('vcs_full_cache'))
1178 if full_cache:
1182 if full_cache:
1179 return self.scm_instance_cached()
1183 return self.scm_instance_cached()
1180 return self.__get_instance()
1184 return self.__get_instance()
1181
1185
1182 def scm_instance_cached(self, cache_map=None):
1186 def scm_instance_cached(self, cache_map=None):
1183 @cache_region('long_term')
1187 @cache_region('long_term')
1184 def _c(repo_name):
1188 def _c(repo_name):
1185 return self.__get_instance()
1189 return self.__get_instance()
1186 rn = self.repo_name
1190 rn = self.repo_name
1187
1191
1188 if cache_map:
1192 if cache_map:
1189 # get using prefilled cache_map
1193 # get using prefilled cache_map
1190 invalidate_repo = cache_map[self.repo_name]
1194 invalidate_repo = cache_map[self.repo_name]
1191 if invalidate_repo:
1195 if invalidate_repo:
1192 invalidate_repo = (None if invalidate_repo.cache_active
1196 invalidate_repo = (None if invalidate_repo.cache_active
1193 else invalidate_repo)
1197 else invalidate_repo)
1194 else:
1198 else:
1195 # get from invalidate
1199 # get from invalidate
1196 invalidate_repo = self.invalidate
1200 invalidate_repo = self.invalidate
1197
1201
1198 if invalidate_repo is not None:
1202 if invalidate_repo is not None:
1199 region_invalidate(_c, None, rn)
1203 region_invalidate(_c, None, rn)
1200 log.debug('Cache for %s invalidated, getting new object' % (rn))
1204 log.debug('Cache for %s invalidated, getting new object' % (rn))
1201 # update our cache
1205 # update our cache
1202 CacheInvalidation.set_valid(invalidate_repo.cache_key)
1206 CacheInvalidation.set_valid(invalidate_repo.cache_key)
1203 else:
1207 else:
1204 log.debug('Getting obj for %s from cache' % (rn))
1208 log.debug('Getting obj for %s from cache' % (rn))
1205 return _c(rn)
1209 return _c(rn)
1206
1210
1207 def __get_instance(self):
1211 def __get_instance(self):
1208 repo_full_path = self.repo_full_path
1212 repo_full_path = self.repo_full_path
1209 try:
1213 try:
1210 alias = get_scm(repo_full_path)[0]
1214 alias = get_scm(repo_full_path)[0]
1211 log.debug('Creating instance of %s repository from %s'
1215 log.debug('Creating instance of %s repository from %s'
1212 % (alias, repo_full_path))
1216 % (alias, repo_full_path))
1213 backend = get_backend(alias)
1217 backend = get_backend(alias)
1214 except VCSError:
1218 except VCSError:
1215 log.error(traceback.format_exc())
1219 log.error(traceback.format_exc())
1216 log.error('Perhaps this repository is in db and not in '
1220 log.error('Perhaps this repository is in db and not in '
1217 'filesystem run rescan repositories with '
1221 'filesystem run rescan repositories with '
1218 '"destroy old data " option from admin panel')
1222 '"destroy old data " option from admin panel')
1219 return
1223 return
1220
1224
1221 if alias == 'hg':
1225 if alias == 'hg':
1222
1226
1223 repo = backend(safe_str(repo_full_path), create=False,
1227 repo = backend(safe_str(repo_full_path), create=False,
1224 baseui=self._ui)
1228 baseui=self._ui)
1225 # skip hidden web repository
1229 # skip hidden web repository
1226 if repo._get_hidden():
1230 if repo._get_hidden():
1227 return
1231 return
1228 else:
1232 else:
1229 repo = backend(repo_full_path, create=False)
1233 repo = backend(repo_full_path, create=False)
1230
1234
1231 return repo
1235 return repo
1232
1236
1233
1237
1234 class RepoGroup(Base, BaseModel):
1238 class RepoGroup(Base, BaseModel):
1235 __tablename__ = 'groups'
1239 __tablename__ = 'groups'
1236 __table_args__ = (
1240 __table_args__ = (
1237 UniqueConstraint('group_name', 'group_parent_id'),
1241 UniqueConstraint('group_name', 'group_parent_id'),
1238 CheckConstraint('group_id != group_parent_id'),
1242 CheckConstraint('group_id != group_parent_id'),
1239 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1243 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1240 'mysql_charset': 'utf8'},
1244 'mysql_charset': 'utf8'},
1241 )
1245 )
1242 __mapper_args__ = {'order_by': 'group_name'}
1246 __mapper_args__ = {'order_by': 'group_name'}
1243
1247
1244 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1248 group_id = Column("group_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1245 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1249 group_name = Column("group_name", String(255, convert_unicode=False, assert_unicode=None), nullable=False, unique=True, default=None)
1246 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1250 group_parent_id = Column("group_parent_id", Integer(), ForeignKey('groups.group_id'), nullable=True, unique=None, default=None)
1247 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1251 group_description = Column("group_description", String(10000, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1248 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1252 enable_locking = Column("enable_locking", Boolean(), nullable=False, unique=None, default=False)
1249 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1253 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=False, default=None)
1250
1254
1251 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1255 repo_group_to_perm = relationship('UserRepoGroupToPerm', cascade='all', order_by='UserRepoGroupToPerm.group_to_perm_id')
1252 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1256 users_group_to_perm = relationship('UserGroupRepoGroupToPerm', cascade='all')
1253 parent_group = relationship('RepoGroup', remote_side=group_id)
1257 parent_group = relationship('RepoGroup', remote_side=group_id)
1254 user = relationship('User')
1258 user = relationship('User')
1255
1259
1256 def __init__(self, group_name='', parent_group=None):
1260 def __init__(self, group_name='', parent_group=None):
1257 self.group_name = group_name
1261 self.group_name = group_name
1258 self.parent_group = parent_group
1262 self.parent_group = parent_group
1259
1263
1260 def __unicode__(self):
1264 def __unicode__(self):
1261 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
1265 return u"<%s('id:%s:%s')>" % (self.__class__.__name__, self.group_id,
1262 self.group_name)
1266 self.group_name)
1263
1267
1264 @classmethod
1268 @classmethod
1265 def groups_choices(cls, groups=None, show_empty_group=True):
1269 def groups_choices(cls, groups=None, show_empty_group=True):
1266 from webhelpers.html import literal as _literal
1270 from webhelpers.html import literal as _literal
1267 if not groups:
1271 if not groups:
1268 groups = cls.query().all()
1272 groups = cls.query().all()
1269
1273
1270 repo_groups = []
1274 repo_groups = []
1271 if show_empty_group:
1275 if show_empty_group:
1272 repo_groups = [('-1', '-- %s --' % _('top level'))]
1276 repo_groups = [('-1', '-- %s --' % _('top level'))]
1273 sep = ' &raquo; '
1277 sep = ' &raquo; '
1274 _name = lambda k: _literal(sep.join(k))
1278 _name = lambda k: _literal(sep.join(k))
1275
1279
1276 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1280 repo_groups.extend([(x.group_id, _name(x.full_path_splitted))
1277 for x in groups])
1281 for x in groups])
1278
1282
1279 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1283 repo_groups = sorted(repo_groups, key=lambda t: t[1].split(sep)[0])
1280 return repo_groups
1284 return repo_groups
1281
1285
1282 @classmethod
1286 @classmethod
1283 def url_sep(cls):
1287 def url_sep(cls):
1284 return URL_SEP
1288 return URL_SEP
1285
1289
1286 @classmethod
1290 @classmethod
1287 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1291 def get_by_group_name(cls, group_name, cache=False, case_insensitive=False):
1288 if case_insensitive:
1292 if case_insensitive:
1289 gr = cls.query()\
1293 gr = cls.query()\
1290 .filter(cls.group_name.ilike(group_name))
1294 .filter(cls.group_name.ilike(group_name))
1291 else:
1295 else:
1292 gr = cls.query()\
1296 gr = cls.query()\
1293 .filter(cls.group_name == group_name)
1297 .filter(cls.group_name == group_name)
1294 if cache:
1298 if cache:
1295 gr = gr.options(FromCache(
1299 gr = gr.options(FromCache(
1296 "sql_cache_short",
1300 "sql_cache_short",
1297 "get_group_%s" % _hash_key(group_name)
1301 "get_group_%s" % _hash_key(group_name)
1298 )
1302 )
1299 )
1303 )
1300 return gr.scalar()
1304 return gr.scalar()
1301
1305
1302 @property
1306 @property
1303 def parents(self):
1307 def parents(self):
1304 parents_recursion_limit = 5
1308 parents_recursion_limit = 5
1305 groups = []
1309 groups = []
1306 if self.parent_group is None:
1310 if self.parent_group is None:
1307 return groups
1311 return groups
1308 cur_gr = self.parent_group
1312 cur_gr = self.parent_group
1309 groups.insert(0, cur_gr)
1313 groups.insert(0, cur_gr)
1310 cnt = 0
1314 cnt = 0
1311 while 1:
1315 while 1:
1312 cnt += 1
1316 cnt += 1
1313 gr = getattr(cur_gr, 'parent_group', None)
1317 gr = getattr(cur_gr, 'parent_group', None)
1314 cur_gr = cur_gr.parent_group
1318 cur_gr = cur_gr.parent_group
1315 if gr is None:
1319 if gr is None:
1316 break
1320 break
1317 if cnt == parents_recursion_limit:
1321 if cnt == parents_recursion_limit:
1318 # this will prevent accidental infinit loops
1322 # this will prevent accidental infinit loops
1319 log.error('group nested more than %s' %
1323 log.error('group nested more than %s' %
1320 parents_recursion_limit)
1324 parents_recursion_limit)
1321 break
1325 break
1322
1326
1323 groups.insert(0, gr)
1327 groups.insert(0, gr)
1324 return groups
1328 return groups
1325
1329
1326 @property
1330 @property
1327 def children(self):
1331 def children(self):
1328 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1332 return RepoGroup.query().filter(RepoGroup.parent_group == self)
1329
1333
1330 @property
1334 @property
1331 def name(self):
1335 def name(self):
1332 return self.group_name.split(RepoGroup.url_sep())[-1]
1336 return self.group_name.split(RepoGroup.url_sep())[-1]
1333
1337
1334 @property
1338 @property
1335 def full_path(self):
1339 def full_path(self):
1336 return self.group_name
1340 return self.group_name
1337
1341
1338 @property
1342 @property
1339 def full_path_splitted(self):
1343 def full_path_splitted(self):
1340 return self.group_name.split(RepoGroup.url_sep())
1344 return self.group_name.split(RepoGroup.url_sep())
1341
1345
1342 @property
1346 @property
1343 def repositories(self):
1347 def repositories(self):
1344 return Repository.query()\
1348 return Repository.query()\
1345 .filter(Repository.group == self)\
1349 .filter(Repository.group == self)\
1346 .order_by(Repository.repo_name)
1350 .order_by(Repository.repo_name)
1347
1351
1348 @property
1352 @property
1349 def repositories_recursive_count(self):
1353 def repositories_recursive_count(self):
1350 cnt = self.repositories.count()
1354 cnt = self.repositories.count()
1351
1355
1352 def children_count(group):
1356 def children_count(group):
1353 cnt = 0
1357 cnt = 0
1354 for child in group.children:
1358 for child in group.children:
1355 cnt += child.repositories.count()
1359 cnt += child.repositories.count()
1356 cnt += children_count(child)
1360 cnt += children_count(child)
1357 return cnt
1361 return cnt
1358
1362
1359 return cnt + children_count(self)
1363 return cnt + children_count(self)
1360
1364
1361 def _recursive_objects(self, include_repos=True):
1365 def _recursive_objects(self, include_repos=True):
1362 all_ = []
1366 all_ = []
1363
1367
1364 def _get_members(root_gr):
1368 def _get_members(root_gr):
1365 if include_repos:
1369 if include_repos:
1366 for r in root_gr.repositories:
1370 for r in root_gr.repositories:
1367 all_.append(r)
1371 all_.append(r)
1368 childs = root_gr.children.all()
1372 childs = root_gr.children.all()
1369 if childs:
1373 if childs:
1370 for gr in childs:
1374 for gr in childs:
1371 all_.append(gr)
1375 all_.append(gr)
1372 _get_members(gr)
1376 _get_members(gr)
1373
1377
1374 _get_members(self)
1378 _get_members(self)
1375 return [self] + all_
1379 return [self] + all_
1376
1380
1377 def recursive_groups_and_repos(self):
1381 def recursive_groups_and_repos(self):
1378 """
1382 """
1379 Recursive return all groups, with repositories in those groups
1383 Recursive return all groups, with repositories in those groups
1380 """
1384 """
1381 return self._recursive_objects()
1385 return self._recursive_objects()
1382
1386
1383 def recursive_groups(self):
1387 def recursive_groups(self):
1384 """
1388 """
1385 Returns all children groups for this group including children of children
1389 Returns all children groups for this group including children of children
1386 """
1390 """
1387 return self._recursive_objects(include_repos=False)
1391 return self._recursive_objects(include_repos=False)
1388
1392
1389 def get_new_name(self, group_name):
1393 def get_new_name(self, group_name):
1390 """
1394 """
1391 returns new full group name based on parent and new name
1395 returns new full group name based on parent and new name
1392
1396
1393 :param group_name:
1397 :param group_name:
1394 """
1398 """
1395 path_prefix = (self.parent_group.full_path_splitted if
1399 path_prefix = (self.parent_group.full_path_splitted if
1396 self.parent_group else [])
1400 self.parent_group else [])
1397 return RepoGroup.url_sep().join(path_prefix + [group_name])
1401 return RepoGroup.url_sep().join(path_prefix + [group_name])
1398
1402
1399
1403
1400 class Permission(Base, BaseModel):
1404 class Permission(Base, BaseModel):
1401 __tablename__ = 'permissions'
1405 __tablename__ = 'permissions'
1402 __table_args__ = (
1406 __table_args__ = (
1403 Index('p_perm_name_idx', 'permission_name'),
1407 Index('p_perm_name_idx', 'permission_name'),
1404 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1408 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1405 'mysql_charset': 'utf8'},
1409 'mysql_charset': 'utf8'},
1406 )
1410 )
1407 PERMS = [
1411 PERMS = [
1412 ('hg.admin', _('RhodeCode Administrator')),
1413
1408 ('repository.none', _('Repository no access')),
1414 ('repository.none', _('Repository no access')),
1409 ('repository.read', _('Repository read access')),
1415 ('repository.read', _('Repository read access')),
1410 ('repository.write', _('Repository write access')),
1416 ('repository.write', _('Repository write access')),
1411 ('repository.admin', _('Repository admin access')),
1417 ('repository.admin', _('Repository admin access')),
1412
1418
1413 ('group.none', _('Repository group no access')),
1419 ('group.none', _('Repository group no access')),
1414 ('group.read', _('Repository group read access')),
1420 ('group.read', _('Repository group read access')),
1415 ('group.write', _('Repository group write access')),
1421 ('group.write', _('Repository group write access')),
1416 ('group.admin', _('Repository group admin access')),
1422 ('group.admin', _('Repository group admin access')),
1417
1423
1418 ('usergroup.none', _('User group no access')),
1424 ('usergroup.none', _('User group no access')),
1419 ('usergroup.read', _('User group read access')),
1425 ('usergroup.read', _('User group read access')),
1420 ('usergroup.write', _('User group write access')),
1426 ('usergroup.write', _('User group write access')),
1421 ('usergroup.admin', _('User group admin access')),
1427 ('usergroup.admin', _('User group admin access')),
1422
1428
1423 ('hg.admin', _('RhodeCode Administrator')),
1424 ('hg.create.none', _('Repository creation disabled')),
1429 ('hg.create.none', _('Repository creation disabled')),
1425 ('hg.create.repository', _('Repository creation enabled')),
1430 ('hg.create.repository', _('Repository creation enabled')),
1431
1426 ('hg.fork.none', _('Repository forking disabled')),
1432 ('hg.fork.none', _('Repository forking disabled')),
1427 ('hg.fork.repository', _('Repository forking enabled')),
1433 ('hg.fork.repository', _('Repository forking enabled')),
1434
1428 ('hg.register.none', _('Register disabled')),
1435 ('hg.register.none', _('Register disabled')),
1429 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1436 ('hg.register.manual_activate', _('Register new user with RhodeCode '
1430 'with manual activation')),
1437 'with manual activation')),
1431
1438
1432 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1439 ('hg.register.auto_activate', _('Register new user with RhodeCode '
1433 'with auto activation')),
1440 'with auto activation')),
1434 ]
1441 ]
1435
1442
1443 #definition of system default permissions for DEFAULT user
1444 DEFAULT_USER_PERMISSIONS = [
1445 'repository.read',
1446 'group.read',
1447 'usergroup.read',
1448 'hg.create.repository',
1449 'hg.fork.repository',
1450 'hg.register.manual_activate',
1451 ]
1452
1436 # defines which permissions are more important higher the more important
1453 # defines which permissions are more important higher the more important
1437 PERM_WEIGHTS = {
1454 PERM_WEIGHTS = {
1438 'repository.none': 0,
1455 'repository.none': 0,
1439 'repository.read': 1,
1456 'repository.read': 1,
1440 'repository.write': 3,
1457 'repository.write': 3,
1441 'repository.admin': 4,
1458 'repository.admin': 4,
1442
1459
1443 'group.none': 0,
1460 'group.none': 0,
1444 'group.read': 1,
1461 'group.read': 1,
1445 'group.write': 3,
1462 'group.write': 3,
1446 'group.admin': 4,
1463 'group.admin': 4,
1447
1464
1448 'usergroup.none': 0,
1465 'usergroup.none': 0,
1449 'usergroup.read': 1,
1466 'usergroup.read': 1,
1450 'usergroup.write': 3,
1467 'usergroup.write': 3,
1451 'usergroup.admin': 4,
1468 'usergroup.admin': 4,
1452
1469
1453 'hg.fork.none': 0,
1470 'hg.fork.none': 0,
1454 'hg.fork.repository': 1,
1471 'hg.fork.repository': 1,
1455 'hg.create.none': 0,
1472 'hg.create.none': 0,
1456 'hg.create.repository': 1
1473 'hg.create.repository': 1
1457 }
1474 }
1458
1475
1459 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1476 permission_id = Column("permission_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1460 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1477 permission_name = Column("permission_name", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1461 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1478 permission_longname = Column("permission_longname", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1462
1479
1463 def __unicode__(self):
1480 def __unicode__(self):
1464 return u"<%s('%s:%s')>" % (
1481 return u"<%s('%s:%s')>" % (
1465 self.__class__.__name__, self.permission_id, self.permission_name
1482 self.__class__.__name__, self.permission_id, self.permission_name
1466 )
1483 )
1467
1484
1468 @classmethod
1485 @classmethod
1469 def get_by_key(cls, key):
1486 def get_by_key(cls, key):
1470 return cls.query().filter(cls.permission_name == key).scalar()
1487 return cls.query().filter(cls.permission_name == key).scalar()
1471
1488
1472 @classmethod
1489 @classmethod
1473 def get_default_perms(cls, default_user_id):
1490 def get_default_perms(cls, default_user_id):
1474 q = Session().query(UserRepoToPerm, Repository, cls)\
1491 q = Session().query(UserRepoToPerm, Repository, cls)\
1475 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1492 .join((Repository, UserRepoToPerm.repository_id == Repository.repo_id))\
1476 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1493 .join((cls, UserRepoToPerm.permission_id == cls.permission_id))\
1477 .filter(UserRepoToPerm.user_id == default_user_id)
1494 .filter(UserRepoToPerm.user_id == default_user_id)
1478
1495
1479 return q.all()
1496 return q.all()
1480
1497
1481 @classmethod
1498 @classmethod
1482 def get_default_group_perms(cls, default_user_id):
1499 def get_default_group_perms(cls, default_user_id):
1483 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1500 q = Session().query(UserRepoGroupToPerm, RepoGroup, cls)\
1484 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1501 .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\
1485 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1502 .join((cls, UserRepoGroupToPerm.permission_id == cls.permission_id))\
1486 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1503 .filter(UserRepoGroupToPerm.user_id == default_user_id)
1487
1504
1488 return q.all()
1505 return q.all()
1489
1506
1490 @classmethod
1507 @classmethod
1491 def get_default_user_group_perms(cls, default_user_id):
1508 def get_default_user_group_perms(cls, default_user_id):
1492 q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
1509 q = Session().query(UserUserGroupToPerm, UserGroup, cls)\
1493 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
1510 .join((UserGroup, UserUserGroupToPerm.user_group_id == UserGroup.users_group_id))\
1494 .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
1511 .join((cls, UserUserGroupToPerm.permission_id == cls.permission_id))\
1495 .filter(UserUserGroupToPerm.user_id == default_user_id)
1512 .filter(UserUserGroupToPerm.user_id == default_user_id)
1496
1513
1497 return q.all()
1514 return q.all()
1498
1515
1499
1516
1500 class UserRepoToPerm(Base, BaseModel):
1517 class UserRepoToPerm(Base, BaseModel):
1501 __tablename__ = 'repo_to_perm'
1518 __tablename__ = 'repo_to_perm'
1502 __table_args__ = (
1519 __table_args__ = (
1503 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1520 UniqueConstraint('user_id', 'repository_id', 'permission_id'),
1504 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1521 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1505 'mysql_charset': 'utf8'}
1522 'mysql_charset': 'utf8'}
1506 )
1523 )
1507 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1524 repo_to_perm_id = Column("repo_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1508 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1525 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1509 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1526 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1510 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1527 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1511
1528
1512 user = relationship('User')
1529 user = relationship('User')
1513 repository = relationship('Repository')
1530 repository = relationship('Repository')
1514 permission = relationship('Permission')
1531 permission = relationship('Permission')
1515
1532
1516 @classmethod
1533 @classmethod
1517 def create(cls, user, repository, permission):
1534 def create(cls, user, repository, permission):
1518 n = cls()
1535 n = cls()
1519 n.user = user
1536 n.user = user
1520 n.repository = repository
1537 n.repository = repository
1521 n.permission = permission
1538 n.permission = permission
1522 Session().add(n)
1539 Session().add(n)
1523 return n
1540 return n
1524
1541
1525 def __unicode__(self):
1542 def __unicode__(self):
1526 return u'<%s => %s >' % (self.user, self.repository)
1543 return u'<%s => %s >' % (self.user, self.repository)
1527
1544
1528
1545
1529 class UserUserGroupToPerm(Base, BaseModel):
1546 class UserUserGroupToPerm(Base, BaseModel):
1530 __tablename__ = 'user_user_group_to_perm'
1547 __tablename__ = 'user_user_group_to_perm'
1531 __table_args__ = (
1548 __table_args__ = (
1532 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1549 UniqueConstraint('user_id', 'user_group_id', 'permission_id'),
1533 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1550 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1534 'mysql_charset': 'utf8'}
1551 'mysql_charset': 'utf8'}
1535 )
1552 )
1536 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1553 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1537 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1554 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1538 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1555 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1539 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1556 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1540
1557
1541 user = relationship('User')
1558 user = relationship('User')
1542 user_group = relationship('UserGroup')
1559 user_group = relationship('UserGroup')
1543 permission = relationship('Permission')
1560 permission = relationship('Permission')
1544
1561
1545 @classmethod
1562 @classmethod
1546 def create(cls, user, user_group, permission):
1563 def create(cls, user, user_group, permission):
1547 n = cls()
1564 n = cls()
1548 n.user = user
1565 n.user = user
1549 n.user_group = user_group
1566 n.user_group = user_group
1550 n.permission = permission
1567 n.permission = permission
1551 Session().add(n)
1568 Session().add(n)
1552 return n
1569 return n
1553
1570
1554 def __unicode__(self):
1571 def __unicode__(self):
1555 return u'<%s => %s >' % (self.user, self.user_group)
1572 return u'<%s => %s >' % (self.user, self.user_group)
1556
1573
1557
1574
1558 class UserToPerm(Base, BaseModel):
1575 class UserToPerm(Base, BaseModel):
1559 __tablename__ = 'user_to_perm'
1576 __tablename__ = 'user_to_perm'
1560 __table_args__ = (
1577 __table_args__ = (
1561 UniqueConstraint('user_id', 'permission_id'),
1578 UniqueConstraint('user_id', 'permission_id'),
1562 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1579 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1563 'mysql_charset': 'utf8'}
1580 'mysql_charset': 'utf8'}
1564 )
1581 )
1565 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1582 user_to_perm_id = Column("user_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1566 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1583 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1567 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1584 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1568
1585
1569 user = relationship('User')
1586 user = relationship('User')
1570 permission = relationship('Permission', lazy='joined')
1587 permission = relationship('Permission', lazy='joined')
1571
1588
1572 def __unicode__(self):
1589 def __unicode__(self):
1573 return u'<%s => %s >' % (self.user, self.permission)
1590 return u'<%s => %s >' % (self.user, self.permission)
1574
1591
1575
1592
1576 class UserGroupRepoToPerm(Base, BaseModel):
1593 class UserGroupRepoToPerm(Base, BaseModel):
1577 __tablename__ = 'users_group_repo_to_perm'
1594 __tablename__ = 'users_group_repo_to_perm'
1578 __table_args__ = (
1595 __table_args__ = (
1579 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1596 UniqueConstraint('repository_id', 'users_group_id', 'permission_id'),
1580 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1597 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1581 'mysql_charset': 'utf8'}
1598 'mysql_charset': 'utf8'}
1582 )
1599 )
1583 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1600 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1584 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1601 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1585 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1602 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1586 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1603 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=None, default=None)
1587
1604
1588 users_group = relationship('UserGroup')
1605 users_group = relationship('UserGroup')
1589 permission = relationship('Permission')
1606 permission = relationship('Permission')
1590 repository = relationship('Repository')
1607 repository = relationship('Repository')
1591
1608
1592 @classmethod
1609 @classmethod
1593 def create(cls, users_group, repository, permission):
1610 def create(cls, users_group, repository, permission):
1594 n = cls()
1611 n = cls()
1595 n.users_group = users_group
1612 n.users_group = users_group
1596 n.repository = repository
1613 n.repository = repository
1597 n.permission = permission
1614 n.permission = permission
1598 Session().add(n)
1615 Session().add(n)
1599 return n
1616 return n
1600
1617
1601 def __unicode__(self):
1618 def __unicode__(self):
1602 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1619 return u'<userGroup:%s => %s >' % (self.users_group, self.repository)
1603
1620
1604
1621
1605 #TODO; not sure if this will be ever used
1622 #TODO; not sure if this will be ever used
1606 class UserGroupUserGroupToPerm(Base, BaseModel):
1623 class UserGroupUserGroupToPerm(Base, BaseModel):
1607 __tablename__ = 'user_group_user_group_to_perm'
1624 __tablename__ = 'user_group_user_group_to_perm'
1608 __table_args__ = (
1625 __table_args__ = (
1609 UniqueConstraint('user_group_id', 'user_group_id', 'permission_id'),
1626 UniqueConstraint('user_group_id', 'user_group_id', 'permission_id'),
1610 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1627 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1611 'mysql_charset': 'utf8'}
1628 'mysql_charset': 'utf8'}
1612 )
1629 )
1613 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1630 user_user_group_to_perm_id = Column("user_user_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1614 target_user_group_id = Column("target_users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1631 target_user_group_id = Column("target_users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1615 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1632 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1616 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1633 user_group_id = Column("user_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1617
1634
1618 target_user_group = relationship('UserGroup', remote_side=target_user_group_id, primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1635 target_user_group = relationship('UserGroup', remote_side=target_user_group_id, primaryjoin='UserGroupUserGroupToPerm.target_user_group_id==UserGroup.users_group_id')
1619 user_group = relationship('UserGroup', remote_side=user_group_id, primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1636 user_group = relationship('UserGroup', remote_side=user_group_id, primaryjoin='UserGroupUserGroupToPerm.user_group_id==UserGroup.users_group_id')
1620 permission = relationship('Permission')
1637 permission = relationship('Permission')
1621
1638
1622 @classmethod
1639 @classmethod
1623 def create(cls, target_user_group, user_group, permission):
1640 def create(cls, target_user_group, user_group, permission):
1624 n = cls()
1641 n = cls()
1625 n.target_user_group = target_user_group
1642 n.target_user_group = target_user_group
1626 n.user_group = user_group
1643 n.user_group = user_group
1627 n.permission = permission
1644 n.permission = permission
1628 Session().add(n)
1645 Session().add(n)
1629 return n
1646 return n
1630
1647
1631 def __unicode__(self):
1648 def __unicode__(self):
1632 return u'<UserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1649 return u'<UserGroup:%s => %s >' % (self.target_user_group, self.user_group)
1633
1650
1634
1651
1635 class UserGroupToPerm(Base, BaseModel):
1652 class UserGroupToPerm(Base, BaseModel):
1636 __tablename__ = 'users_group_to_perm'
1653 __tablename__ = 'users_group_to_perm'
1637 __table_args__ = (
1654 __table_args__ = (
1638 UniqueConstraint('users_group_id', 'permission_id',),
1655 UniqueConstraint('users_group_id', 'permission_id',),
1639 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1656 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1640 'mysql_charset': 'utf8'}
1657 'mysql_charset': 'utf8'}
1641 )
1658 )
1642 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1659 users_group_to_perm_id = Column("users_group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1643 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1660 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1644 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1661 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1645
1662
1646 users_group = relationship('UserGroup')
1663 users_group = relationship('UserGroup')
1647 permission = relationship('Permission')
1664 permission = relationship('Permission')
1648
1665
1649
1666
1650 class UserRepoGroupToPerm(Base, BaseModel):
1667 class UserRepoGroupToPerm(Base, BaseModel):
1651 __tablename__ = 'user_repo_group_to_perm'
1668 __tablename__ = 'user_repo_group_to_perm'
1652 __table_args__ = (
1669 __table_args__ = (
1653 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1670 UniqueConstraint('user_id', 'group_id', 'permission_id'),
1654 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1671 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1655 'mysql_charset': 'utf8'}
1672 'mysql_charset': 'utf8'}
1656 )
1673 )
1657
1674
1658 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1675 group_to_perm_id = Column("group_to_perm_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1659 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1676 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1660 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1677 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1661 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1678 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1662
1679
1663 user = relationship('User')
1680 user = relationship('User')
1664 group = relationship('RepoGroup')
1681 group = relationship('RepoGroup')
1665 permission = relationship('Permission')
1682 permission = relationship('Permission')
1666
1683
1667
1684
1668 class UserGroupRepoGroupToPerm(Base, BaseModel):
1685 class UserGroupRepoGroupToPerm(Base, BaseModel):
1669 __tablename__ = 'users_group_repo_group_to_perm'
1686 __tablename__ = 'users_group_repo_group_to_perm'
1670 __table_args__ = (
1687 __table_args__ = (
1671 UniqueConstraint('users_group_id', 'group_id'),
1688 UniqueConstraint('users_group_id', 'group_id'),
1672 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1689 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1673 'mysql_charset': 'utf8'}
1690 'mysql_charset': 'utf8'}
1674 )
1691 )
1675
1692
1676 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)
1693 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)
1677 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1694 users_group_id = Column("users_group_id", Integer(), ForeignKey('users_groups.users_group_id'), nullable=False, unique=None, default=None)
1678 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1695 group_id = Column("group_id", Integer(), ForeignKey('groups.group_id'), nullable=False, unique=None, default=None)
1679 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1696 permission_id = Column("permission_id", Integer(), ForeignKey('permissions.permission_id'), nullable=False, unique=None, default=None)
1680
1697
1681 users_group = relationship('UserGroup')
1698 users_group = relationship('UserGroup')
1682 permission = relationship('Permission')
1699 permission = relationship('Permission')
1683 group = relationship('RepoGroup')
1700 group = relationship('RepoGroup')
1684
1701
1685
1702
1686 class Statistics(Base, BaseModel):
1703 class Statistics(Base, BaseModel):
1687 __tablename__ = 'statistics'
1704 __tablename__ = 'statistics'
1688 __table_args__ = (
1705 __table_args__ = (
1689 UniqueConstraint('repository_id'),
1706 UniqueConstraint('repository_id'),
1690 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1707 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1691 'mysql_charset': 'utf8'}
1708 'mysql_charset': 'utf8'}
1692 )
1709 )
1693 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1710 stat_id = Column("stat_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1694 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1711 repository_id = Column("repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=False, unique=True, default=None)
1695 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1712 stat_on_revision = Column("stat_on_revision", Integer(), nullable=False)
1696 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1713 commit_activity = Column("commit_activity", LargeBinary(1000000), nullable=False)#JSON data
1697 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1714 commit_activity_combined = Column("commit_activity_combined", LargeBinary(), nullable=False)#JSON data
1698 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1715 languages = Column("languages", LargeBinary(1000000), nullable=False)#JSON data
1699
1716
1700 repository = relationship('Repository', single_parent=True)
1717 repository = relationship('Repository', single_parent=True)
1701
1718
1702
1719
1703 class UserFollowing(Base, BaseModel):
1720 class UserFollowing(Base, BaseModel):
1704 __tablename__ = 'user_followings'
1721 __tablename__ = 'user_followings'
1705 __table_args__ = (
1722 __table_args__ = (
1706 UniqueConstraint('user_id', 'follows_repository_id'),
1723 UniqueConstraint('user_id', 'follows_repository_id'),
1707 UniqueConstraint('user_id', 'follows_user_id'),
1724 UniqueConstraint('user_id', 'follows_user_id'),
1708 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1725 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1709 'mysql_charset': 'utf8'}
1726 'mysql_charset': 'utf8'}
1710 )
1727 )
1711
1728
1712 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1729 user_following_id = Column("user_following_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1713 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1730 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
1714 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1731 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
1715 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1732 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
1716 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1733 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
1717
1734
1718 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1735 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
1719
1736
1720 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1737 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
1721 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1738 follows_repository = relationship('Repository', order_by='Repository.repo_name')
1722
1739
1723 @classmethod
1740 @classmethod
1724 def get_repo_followers(cls, repo_id):
1741 def get_repo_followers(cls, repo_id):
1725 return cls.query().filter(cls.follows_repo_id == repo_id)
1742 return cls.query().filter(cls.follows_repo_id == repo_id)
1726
1743
1727
1744
1728 class CacheInvalidation(Base, BaseModel):
1745 class CacheInvalidation(Base, BaseModel):
1729 __tablename__ = 'cache_invalidation'
1746 __tablename__ = 'cache_invalidation'
1730 __table_args__ = (
1747 __table_args__ = (
1731 UniqueConstraint('cache_key'),
1748 UniqueConstraint('cache_key'),
1732 Index('key_idx', 'cache_key'),
1749 Index('key_idx', 'cache_key'),
1733 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1750 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1734 'mysql_charset': 'utf8'},
1751 'mysql_charset': 'utf8'},
1735 )
1752 )
1736 # cache_id, not used
1753 # cache_id, not used
1737 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1754 cache_id = Column("cache_id", Integer(), nullable=False, unique=True, default=None, primary_key=True)
1738 # cache_key as created by _get_cache_key
1755 # cache_key as created by _get_cache_key
1739 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1756 cache_key = Column("cache_key", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1740 # cache_args is a repo_name
1757 # cache_args is a repo_name
1741 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1758 cache_args = Column("cache_args", String(255, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
1742 # instance sets cache_active True when it is caching,
1759 # instance sets cache_active True when it is caching,
1743 # other instances set cache_active to False to indicate that this cache is invalid
1760 # other instances set cache_active to False to indicate that this cache is invalid
1744 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1761 cache_active = Column("cache_active", Boolean(), nullable=True, unique=None, default=False)
1745
1762
1746 def __init__(self, cache_key, repo_name=''):
1763 def __init__(self, cache_key, repo_name=''):
1747 self.cache_key = cache_key
1764 self.cache_key = cache_key
1748 self.cache_args = repo_name
1765 self.cache_args = repo_name
1749 self.cache_active = False
1766 self.cache_active = False
1750
1767
1751 def __unicode__(self):
1768 def __unicode__(self):
1752 return u"<%s('%s:%s[%s]')>" % (self.__class__.__name__,
1769 return u"<%s('%s:%s[%s]')>" % (self.__class__.__name__,
1753 self.cache_id, self.cache_key, self.cache_active)
1770 self.cache_id, self.cache_key, self.cache_active)
1754
1771
1755 def _cache_key_partition(self):
1772 def _cache_key_partition(self):
1756 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
1773 prefix, repo_name, suffix = self.cache_key.partition(self.cache_args)
1757 return prefix, repo_name, suffix
1774 return prefix, repo_name, suffix
1758
1775
1759 def get_prefix(self):
1776 def get_prefix(self):
1760 """
1777 """
1761 get prefix that might have been used in _get_cache_key to
1778 get prefix that might have been used in _get_cache_key to
1762 generate self.cache_key. Only used for informational purposes
1779 generate self.cache_key. Only used for informational purposes
1763 in repo_edit.html.
1780 in repo_edit.html.
1764 """
1781 """
1765 # prefix, repo_name, suffix
1782 # prefix, repo_name, suffix
1766 return self._cache_key_partition()[0]
1783 return self._cache_key_partition()[0]
1767
1784
1768 def get_suffix(self):
1785 def get_suffix(self):
1769 """
1786 """
1770 get suffix that might have been used in _get_cache_key to
1787 get suffix that might have been used in _get_cache_key to
1771 generate self.cache_key. Only used for informational purposes
1788 generate self.cache_key. Only used for informational purposes
1772 in repo_edit.html.
1789 in repo_edit.html.
1773 """
1790 """
1774 # prefix, repo_name, suffix
1791 # prefix, repo_name, suffix
1775 return self._cache_key_partition()[2]
1792 return self._cache_key_partition()[2]
1776
1793
1777 @classmethod
1794 @classmethod
1778 def _get_cache_key(cls, key):
1795 def _get_cache_key(cls, key):
1779 """
1796 """
1780 Wrapper for generating a unique cache key for this instance and "key".
1797 Wrapper for generating a unique cache key for this instance and "key".
1781 key must / will start with a repo_name which will be stored in .cache_args .
1798 key must / will start with a repo_name which will be stored in .cache_args .
1782 """
1799 """
1783 import rhodecode
1800 import rhodecode
1784 prefix = rhodecode.CONFIG.get('instance_id', '')
1801 prefix = rhodecode.CONFIG.get('instance_id', '')
1785 return "%s%s" % (prefix, key)
1802 return "%s%s" % (prefix, key)
1786
1803
1787 @classmethod
1804 @classmethod
1788 def invalidate(cls, key):
1805 def invalidate(cls, key):
1789 """
1806 """
1790 Returns Invalidation object if the local cache with the given key is invalid,
1807 Returns Invalidation object if the local cache with the given key is invalid,
1791 None otherwise.
1808 None otherwise.
1792 """
1809 """
1793 repo_name = key
1810 repo_name = key
1794 repo_name = remove_suffix(repo_name, '_README')
1811 repo_name = remove_suffix(repo_name, '_README')
1795 repo_name = remove_suffix(repo_name, '_RSS')
1812 repo_name = remove_suffix(repo_name, '_RSS')
1796 repo_name = remove_suffix(repo_name, '_ATOM')
1813 repo_name = remove_suffix(repo_name, '_ATOM')
1797
1814
1798 cache_key = cls._get_cache_key(key)
1815 cache_key = cls._get_cache_key(key)
1799 inv_obj = Session().query(cls).filter(cls.cache_key == cache_key).scalar()
1816 inv_obj = Session().query(cls).filter(cls.cache_key == cache_key).scalar()
1800 if not inv_obj:
1817 if not inv_obj:
1801 try:
1818 try:
1802 inv_obj = CacheInvalidation(cache_key, repo_name)
1819 inv_obj = CacheInvalidation(cache_key, repo_name)
1803 Session().add(inv_obj)
1820 Session().add(inv_obj)
1804 Session().commit()
1821 Session().commit()
1805 except Exception:
1822 except Exception:
1806 log.error(traceback.format_exc())
1823 log.error(traceback.format_exc())
1807 Session().rollback()
1824 Session().rollback()
1808 return
1825 return
1809
1826
1810 if not inv_obj.cache_active:
1827 if not inv_obj.cache_active:
1811 # `cache_active = False` means that this cache
1828 # `cache_active = False` means that this cache
1812 # no longer is valid
1829 # no longer is valid
1813 return inv_obj
1830 return inv_obj
1814
1831
1815 @classmethod
1832 @classmethod
1816 def set_invalidate(cls, repo_name):
1833 def set_invalidate(cls, repo_name):
1817 """
1834 """
1818 Mark all caches of a repo as invalid in the database.
1835 Mark all caches of a repo as invalid in the database.
1819 """
1836 """
1820 invalidated_keys = []
1837 invalidated_keys = []
1821 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1838 inv_objs = Session().query(cls).filter(cls.cache_args == repo_name).all()
1822
1839
1823 try:
1840 try:
1824 for inv_obj in inv_objs:
1841 for inv_obj in inv_objs:
1825 log.debug('marking %s key for invalidation based on repo_name=%s'
1842 log.debug('marking %s key for invalidation based on repo_name=%s'
1826 % (inv_obj, safe_str(repo_name)))
1843 % (inv_obj, safe_str(repo_name)))
1827 inv_obj.cache_active = False
1844 inv_obj.cache_active = False
1828 invalidated_keys.append(inv_obj.cache_key)
1845 invalidated_keys.append(inv_obj.cache_key)
1829 Session().add(inv_obj)
1846 Session().add(inv_obj)
1830 Session().commit()
1847 Session().commit()
1831 except Exception:
1848 except Exception:
1832 log.error(traceback.format_exc())
1849 log.error(traceback.format_exc())
1833 Session().rollback()
1850 Session().rollback()
1834 return invalidated_keys
1851 return invalidated_keys
1835
1852
1836 @classmethod
1853 @classmethod
1837 def set_valid(cls, cache_key):
1854 def set_valid(cls, cache_key):
1838 """
1855 """
1839 Mark this cache key as active and currently cached
1856 Mark this cache key as active and currently cached
1840 """
1857 """
1841 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
1858 inv_obj = cls.query().filter(cls.cache_key == cache_key).scalar()
1842 inv_obj.cache_active = True
1859 inv_obj.cache_active = True
1843 Session().add(inv_obj)
1860 Session().add(inv_obj)
1844 Session().commit()
1861 Session().commit()
1845
1862
1846 @classmethod
1863 @classmethod
1847 def get_cache_map(cls):
1864 def get_cache_map(cls):
1848
1865
1849 class cachemapdict(dict):
1866 class cachemapdict(dict):
1850
1867
1851 def __init__(self, *args, **kwargs):
1868 def __init__(self, *args, **kwargs):
1852 self.fixkey = kwargs.pop('fixkey', False)
1869 self.fixkey = kwargs.pop('fixkey', False)
1853 super(cachemapdict, self).__init__(*args, **kwargs)
1870 super(cachemapdict, self).__init__(*args, **kwargs)
1854
1871
1855 def __getattr__(self, name):
1872 def __getattr__(self, name):
1856 cache_key = name
1873 cache_key = name
1857 if self.fixkey:
1874 if self.fixkey:
1858 cache_key = cls._get_cache_key(name)
1875 cache_key = cls._get_cache_key(name)
1859 if cache_key in self.__dict__:
1876 if cache_key in self.__dict__:
1860 return self.__dict__[cache_key]
1877 return self.__dict__[cache_key]
1861 else:
1878 else:
1862 return self[cache_key]
1879 return self[cache_key]
1863
1880
1864 def __getitem__(self, name):
1881 def __getitem__(self, name):
1865 cache_key = name
1882 cache_key = name
1866 if self.fixkey:
1883 if self.fixkey:
1867 cache_key = cls._get_cache_key(name)
1884 cache_key = cls._get_cache_key(name)
1868 try:
1885 try:
1869 return super(cachemapdict, self).__getitem__(cache_key)
1886 return super(cachemapdict, self).__getitem__(cache_key)
1870 except KeyError:
1887 except KeyError:
1871 return None
1888 return None
1872
1889
1873 cache_map = cachemapdict(fixkey=True)
1890 cache_map = cachemapdict(fixkey=True)
1874 for obj in cls.query().all():
1891 for obj in cls.query().all():
1875 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1892 cache_map[obj.cache_key] = cachemapdict(obj.get_dict())
1876 return cache_map
1893 return cache_map
1877
1894
1878
1895
1879 class ChangesetComment(Base, BaseModel):
1896 class ChangesetComment(Base, BaseModel):
1880 __tablename__ = 'changeset_comments'
1897 __tablename__ = 'changeset_comments'
1881 __table_args__ = (
1898 __table_args__ = (
1882 Index('cc_revision_idx', 'revision'),
1899 Index('cc_revision_idx', 'revision'),
1883 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1900 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1884 'mysql_charset': 'utf8'},
1901 'mysql_charset': 'utf8'},
1885 )
1902 )
1886 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1903 comment_id = Column('comment_id', Integer(), nullable=False, primary_key=True)
1887 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1904 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1888 revision = Column('revision', String(40), nullable=True)
1905 revision = Column('revision', String(40), nullable=True)
1889 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1906 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1890 line_no = Column('line_no', Unicode(10), nullable=True)
1907 line_no = Column('line_no', Unicode(10), nullable=True)
1891 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1908 hl_lines = Column('hl_lines', Unicode(512), nullable=True)
1892 f_path = Column('f_path', Unicode(1000), nullable=True)
1909 f_path = Column('f_path', Unicode(1000), nullable=True)
1893 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1910 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
1894 text = Column('text', UnicodeText(25000), nullable=False)
1911 text = Column('text', UnicodeText(25000), nullable=False)
1895 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1912 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1896 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1913 modified_at = Column('modified_at', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1897
1914
1898 author = relationship('User', lazy='joined')
1915 author = relationship('User', lazy='joined')
1899 repo = relationship('Repository')
1916 repo = relationship('Repository')
1900 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1917 status_change = relationship('ChangesetStatus', cascade="all, delete, delete-orphan")
1901 pull_request = relationship('PullRequest', lazy='joined')
1918 pull_request = relationship('PullRequest', lazy='joined')
1902
1919
1903 @classmethod
1920 @classmethod
1904 def get_users(cls, revision=None, pull_request_id=None):
1921 def get_users(cls, revision=None, pull_request_id=None):
1905 """
1922 """
1906 Returns user associated with this ChangesetComment. ie those
1923 Returns user associated with this ChangesetComment. ie those
1907 who actually commented
1924 who actually commented
1908
1925
1909 :param cls:
1926 :param cls:
1910 :param revision:
1927 :param revision:
1911 """
1928 """
1912 q = Session().query(User)\
1929 q = Session().query(User)\
1913 .join(ChangesetComment.author)
1930 .join(ChangesetComment.author)
1914 if revision:
1931 if revision:
1915 q = q.filter(cls.revision == revision)
1932 q = q.filter(cls.revision == revision)
1916 elif pull_request_id:
1933 elif pull_request_id:
1917 q = q.filter(cls.pull_request_id == pull_request_id)
1934 q = q.filter(cls.pull_request_id == pull_request_id)
1918 return q.all()
1935 return q.all()
1919
1936
1920
1937
1921 class ChangesetStatus(Base, BaseModel):
1938 class ChangesetStatus(Base, BaseModel):
1922 __tablename__ = 'changeset_statuses'
1939 __tablename__ = 'changeset_statuses'
1923 __table_args__ = (
1940 __table_args__ = (
1924 Index('cs_revision_idx', 'revision'),
1941 Index('cs_revision_idx', 'revision'),
1925 Index('cs_version_idx', 'version'),
1942 Index('cs_version_idx', 'version'),
1926 UniqueConstraint('repo_id', 'revision', 'version'),
1943 UniqueConstraint('repo_id', 'revision', 'version'),
1927 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1944 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1928 'mysql_charset': 'utf8'}
1945 'mysql_charset': 'utf8'}
1929 )
1946 )
1930 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1947 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1931 STATUS_APPROVED = 'approved'
1948 STATUS_APPROVED = 'approved'
1932 STATUS_REJECTED = 'rejected'
1949 STATUS_REJECTED = 'rejected'
1933 STATUS_UNDER_REVIEW = 'under_review'
1950 STATUS_UNDER_REVIEW = 'under_review'
1934
1951
1935 STATUSES = [
1952 STATUSES = [
1936 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1953 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1937 (STATUS_APPROVED, _("Approved")),
1954 (STATUS_APPROVED, _("Approved")),
1938 (STATUS_REJECTED, _("Rejected")),
1955 (STATUS_REJECTED, _("Rejected")),
1939 (STATUS_UNDER_REVIEW, _("Under Review")),
1956 (STATUS_UNDER_REVIEW, _("Under Review")),
1940 ]
1957 ]
1941
1958
1942 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1959 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1943 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1960 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1944 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1961 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1945 revision = Column('revision', String(40), nullable=False)
1962 revision = Column('revision', String(40), nullable=False)
1946 status = Column('status', String(128), nullable=False, default=DEFAULT)
1963 status = Column('status', String(128), nullable=False, default=DEFAULT)
1947 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1964 changeset_comment_id = Column('changeset_comment_id', Integer(), ForeignKey('changeset_comments.comment_id'))
1948 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1965 modified_at = Column('modified_at', DateTime(), nullable=False, default=datetime.datetime.now)
1949 version = Column('version', Integer(), nullable=False, default=0)
1966 version = Column('version', Integer(), nullable=False, default=0)
1950 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1967 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=True)
1951
1968
1952 author = relationship('User', lazy='joined')
1969 author = relationship('User', lazy='joined')
1953 repo = relationship('Repository')
1970 repo = relationship('Repository')
1954 comment = relationship('ChangesetComment', lazy='joined')
1971 comment = relationship('ChangesetComment', lazy='joined')
1955 pull_request = relationship('PullRequest', lazy='joined')
1972 pull_request = relationship('PullRequest', lazy='joined')
1956
1973
1957 def __unicode__(self):
1974 def __unicode__(self):
1958 return u"<%s('%s:%s')>" % (
1975 return u"<%s('%s:%s')>" % (
1959 self.__class__.__name__,
1976 self.__class__.__name__,
1960 self.status, self.author
1977 self.status, self.author
1961 )
1978 )
1962
1979
1963 @classmethod
1980 @classmethod
1964 def get_status_lbl(cls, value):
1981 def get_status_lbl(cls, value):
1965 return dict(cls.STATUSES).get(value)
1982 return dict(cls.STATUSES).get(value)
1966
1983
1967 @property
1984 @property
1968 def status_lbl(self):
1985 def status_lbl(self):
1969 return ChangesetStatus.get_status_lbl(self.status)
1986 return ChangesetStatus.get_status_lbl(self.status)
1970
1987
1971
1988
1972 class PullRequest(Base, BaseModel):
1989 class PullRequest(Base, BaseModel):
1973 __tablename__ = 'pull_requests'
1990 __tablename__ = 'pull_requests'
1974 __table_args__ = (
1991 __table_args__ = (
1975 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1992 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1976 'mysql_charset': 'utf8'},
1993 'mysql_charset': 'utf8'},
1977 )
1994 )
1978
1995
1979 STATUS_NEW = u'new'
1996 STATUS_NEW = u'new'
1980 STATUS_OPEN = u'open'
1997 STATUS_OPEN = u'open'
1981 STATUS_CLOSED = u'closed'
1998 STATUS_CLOSED = u'closed'
1982
1999
1983 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
2000 pull_request_id = Column('pull_request_id', Integer(), nullable=False, primary_key=True)
1984 title = Column('title', Unicode(256), nullable=True)
2001 title = Column('title', Unicode(256), nullable=True)
1985 description = Column('description', UnicodeText(10240), nullable=True)
2002 description = Column('description', UnicodeText(10240), nullable=True)
1986 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
2003 status = Column('status', Unicode(256), nullable=False, default=STATUS_NEW)
1987 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2004 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1988 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2005 updated_on = Column('updated_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
1989 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
2006 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None)
1990 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
2007 _revisions = Column('revisions', UnicodeText(20500)) # 500 revisions max
1991 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
2008 org_repo_id = Column('org_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1992 org_ref = Column('org_ref', Unicode(256), nullable=False)
2009 org_ref = Column('org_ref', Unicode(256), nullable=False)
1993 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
2010 other_repo_id = Column('other_repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
1994 other_ref = Column('other_ref', Unicode(256), nullable=False)
2011 other_ref = Column('other_ref', Unicode(256), nullable=False)
1995
2012
1996 @hybrid_property
2013 @hybrid_property
1997 def revisions(self):
2014 def revisions(self):
1998 return self._revisions.split(':')
2015 return self._revisions.split(':')
1999
2016
2000 @revisions.setter
2017 @revisions.setter
2001 def revisions(self, val):
2018 def revisions(self, val):
2002 self._revisions = ':'.join(val)
2019 self._revisions = ':'.join(val)
2003
2020
2004 @property
2021 @property
2005 def org_ref_parts(self):
2022 def org_ref_parts(self):
2006 return self.org_ref.split(':')
2023 return self.org_ref.split(':')
2007
2024
2008 @property
2025 @property
2009 def other_ref_parts(self):
2026 def other_ref_parts(self):
2010 return self.other_ref.split(':')
2027 return self.other_ref.split(':')
2011
2028
2012 author = relationship('User', lazy='joined')
2029 author = relationship('User', lazy='joined')
2013 reviewers = relationship('PullRequestReviewers',
2030 reviewers = relationship('PullRequestReviewers',
2014 cascade="all, delete, delete-orphan")
2031 cascade="all, delete, delete-orphan")
2015 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
2032 org_repo = relationship('Repository', primaryjoin='PullRequest.org_repo_id==Repository.repo_id')
2016 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
2033 other_repo = relationship('Repository', primaryjoin='PullRequest.other_repo_id==Repository.repo_id')
2017 statuses = relationship('ChangesetStatus')
2034 statuses = relationship('ChangesetStatus')
2018 comments = relationship('ChangesetComment',
2035 comments = relationship('ChangesetComment',
2019 cascade="all, delete, delete-orphan")
2036 cascade="all, delete, delete-orphan")
2020
2037
2021 def is_closed(self):
2038 def is_closed(self):
2022 return self.status == self.STATUS_CLOSED
2039 return self.status == self.STATUS_CLOSED
2023
2040
2024 @property
2041 @property
2025 def last_review_status(self):
2042 def last_review_status(self):
2026 return self.statuses[-1].status if self.statuses else ''
2043 return self.statuses[-1].status if self.statuses else ''
2027
2044
2028 def __json__(self):
2045 def __json__(self):
2029 return dict(
2046 return dict(
2030 revisions=self.revisions
2047 revisions=self.revisions
2031 )
2048 )
2032
2049
2033
2050
2034 class PullRequestReviewers(Base, BaseModel):
2051 class PullRequestReviewers(Base, BaseModel):
2035 __tablename__ = 'pull_request_reviewers'
2052 __tablename__ = 'pull_request_reviewers'
2036 __table_args__ = (
2053 __table_args__ = (
2037 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2054 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2038 'mysql_charset': 'utf8'},
2055 'mysql_charset': 'utf8'},
2039 )
2056 )
2040
2057
2041 def __init__(self, user=None, pull_request=None):
2058 def __init__(self, user=None, pull_request=None):
2042 self.user = user
2059 self.user = user
2043 self.pull_request = pull_request
2060 self.pull_request = pull_request
2044
2061
2045 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
2062 pull_requests_reviewers_id = Column('pull_requests_reviewers_id', Integer(), nullable=False, primary_key=True)
2046 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
2063 pull_request_id = Column("pull_request_id", Integer(), ForeignKey('pull_requests.pull_request_id'), nullable=False)
2047 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
2064 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=True)
2048
2065
2049 user = relationship('User')
2066 user = relationship('User')
2050 pull_request = relationship('PullRequest')
2067 pull_request = relationship('PullRequest')
2051
2068
2052
2069
2053 class Notification(Base, BaseModel):
2070 class Notification(Base, BaseModel):
2054 __tablename__ = 'notifications'
2071 __tablename__ = 'notifications'
2055 __table_args__ = (
2072 __table_args__ = (
2056 Index('notification_type_idx', 'type'),
2073 Index('notification_type_idx', 'type'),
2057 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2074 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2058 'mysql_charset': 'utf8'},
2075 'mysql_charset': 'utf8'},
2059 )
2076 )
2060
2077
2061 TYPE_CHANGESET_COMMENT = u'cs_comment'
2078 TYPE_CHANGESET_COMMENT = u'cs_comment'
2062 TYPE_MESSAGE = u'message'
2079 TYPE_MESSAGE = u'message'
2063 TYPE_MENTION = u'mention'
2080 TYPE_MENTION = u'mention'
2064 TYPE_REGISTRATION = u'registration'
2081 TYPE_REGISTRATION = u'registration'
2065 TYPE_PULL_REQUEST = u'pull_request'
2082 TYPE_PULL_REQUEST = u'pull_request'
2066 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
2083 TYPE_PULL_REQUEST_COMMENT = u'pull_request_comment'
2067
2084
2068 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
2085 notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
2069 subject = Column('subject', Unicode(512), nullable=True)
2086 subject = Column('subject', Unicode(512), nullable=True)
2070 body = Column('body', UnicodeText(50000), nullable=True)
2087 body = Column('body', UnicodeText(50000), nullable=True)
2071 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
2088 created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
2072 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2089 created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
2073 type_ = Column('type', Unicode(256))
2090 type_ = Column('type', Unicode(256))
2074
2091
2075 created_by_user = relationship('User')
2092 created_by_user = relationship('User')
2076 notifications_to_users = relationship('UserNotification', lazy='joined',
2093 notifications_to_users = relationship('UserNotification', lazy='joined',
2077 cascade="all, delete, delete-orphan")
2094 cascade="all, delete, delete-orphan")
2078
2095
2079 @property
2096 @property
2080 def recipients(self):
2097 def recipients(self):
2081 return [x.user for x in UserNotification.query()\
2098 return [x.user for x in UserNotification.query()\
2082 .filter(UserNotification.notification == self)\
2099 .filter(UserNotification.notification == self)\
2083 .order_by(UserNotification.user_id.asc()).all()]
2100 .order_by(UserNotification.user_id.asc()).all()]
2084
2101
2085 @classmethod
2102 @classmethod
2086 def create(cls, created_by, subject, body, recipients, type_=None):
2103 def create(cls, created_by, subject, body, recipients, type_=None):
2087 if type_ is None:
2104 if type_ is None:
2088 type_ = Notification.TYPE_MESSAGE
2105 type_ = Notification.TYPE_MESSAGE
2089
2106
2090 notification = cls()
2107 notification = cls()
2091 notification.created_by_user = created_by
2108 notification.created_by_user = created_by
2092 notification.subject = subject
2109 notification.subject = subject
2093 notification.body = body
2110 notification.body = body
2094 notification.type_ = type_
2111 notification.type_ = type_
2095 notification.created_on = datetime.datetime.now()
2112 notification.created_on = datetime.datetime.now()
2096
2113
2097 for u in recipients:
2114 for u in recipients:
2098 assoc = UserNotification()
2115 assoc = UserNotification()
2099 assoc.notification = notification
2116 assoc.notification = notification
2100 u.notifications.append(assoc)
2117 u.notifications.append(assoc)
2101 Session().add(notification)
2118 Session().add(notification)
2102 return notification
2119 return notification
2103
2120
2104 @property
2121 @property
2105 def description(self):
2122 def description(self):
2106 from rhodecode.model.notification import NotificationModel
2123 from rhodecode.model.notification import NotificationModel
2107 return NotificationModel().make_description(self)
2124 return NotificationModel().make_description(self)
2108
2125
2109
2126
2110 class UserNotification(Base, BaseModel):
2127 class UserNotification(Base, BaseModel):
2111 __tablename__ = 'user_to_notification'
2128 __tablename__ = 'user_to_notification'
2112 __table_args__ = (
2129 __table_args__ = (
2113 UniqueConstraint('user_id', 'notification_id'),
2130 UniqueConstraint('user_id', 'notification_id'),
2114 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2131 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2115 'mysql_charset': 'utf8'}
2132 'mysql_charset': 'utf8'}
2116 )
2133 )
2117 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
2134 user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), primary_key=True)
2118 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
2135 notification_id = Column("notification_id", Integer(), ForeignKey('notifications.notification_id'), primary_key=True)
2119 read = Column('read', Boolean, default=False)
2136 read = Column('read', Boolean, default=False)
2120 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
2137 sent_on = Column('sent_on', DateTime(timezone=False), nullable=True, unique=None)
2121
2138
2122 user = relationship('User', lazy="joined")
2139 user = relationship('User', lazy="joined")
2123 notification = relationship('Notification', lazy="joined",
2140 notification = relationship('Notification', lazy="joined",
2124 order_by=lambda: Notification.created_on.desc(),)
2141 order_by=lambda: Notification.created_on.desc(),)
2125
2142
2126 def mark_as_read(self):
2143 def mark_as_read(self):
2127 self.read = True
2144 self.read = True
2128 Session().add(self)
2145 Session().add(self)
2129
2146
2130
2147
2131 class DbMigrateVersion(Base, BaseModel):
2148 class DbMigrateVersion(Base, BaseModel):
2132 __tablename__ = 'db_migrate_version'
2149 __tablename__ = 'db_migrate_version'
2133 __table_args__ = (
2150 __table_args__ = (
2134 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2151 {'extend_existing': True, 'mysql_engine': 'InnoDB',
2135 'mysql_charset': 'utf8'},
2152 'mysql_charset': 'utf8'},
2136 )
2153 )
2137 repository_id = Column('repository_id', String(250), primary_key=True)
2154 repository_id = Column('repository_id', String(250), primary_key=True)
2138 repository_path = Column('repository_path', Text)
2155 repository_path = Column('repository_path', Text)
2139 version = Column('version', Integer)
2156 version = Column('version', Integer)
@@ -1,101 +1,137 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.permission
3 rhodecode.model.permission
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 permissions model for RhodeCode
6 permissions model for RhodeCode
7
7
8 :created_on: Aug 20, 2010
8 :created_on: Aug 20, 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 logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from sqlalchemy.exc import DatabaseError
29 from sqlalchemy.exc import DatabaseError
30
30
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
32 from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
33 UserRepoGroupToPerm
33 UserRepoGroupToPerm
34 from rhodecode.lib.utils2 import str2bool
34 from rhodecode.lib.utils2 import str2bool
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class PermissionModel(BaseModel):
39 class PermissionModel(BaseModel):
40 """
40 """
41 Permissions model for RhodeCode
41 Permissions model for RhodeCode
42 """
42 """
43
43
44 cls = Permission
44 cls = Permission
45
45
46 def create_default_permissions(self, user):
47 """
48 Creates only missing default permissions for user
49
50 :param user:
51 """
52 user = self._get_user(user)
53
54 def _make_perm(perm):
55 new_perm = UserToPerm()
56 new_perm.user = user
57 new_perm.permission = Permission.get_by_key(perm)
58 return new_perm
59
60 def _get_group(perm_name):
61 return '.'.join(perm_name.split('.')[:1])
62
63 perms = UserToPerm.query().filter(UserToPerm.user == user).all()
64 defined_perms_groups = map(_get_group,
65 (x.permission.permission_name for x in perms))
66 log.debug('GOT ALREADY DEFINED:%s' % perms)
67 DEFAULT_PERMS = Permission.DEFAULT_USER_PERMISSIONS
68
69 # for every default permission that needs to be created, we check if
70 # it's group is already defined, if it's not we create default perm
71 for perm_name in DEFAULT_PERMS:
72 gr = _get_group(perm_name)
73 if gr not in defined_perms_groups:
74 log.debug('GR:%s not found, creating permission %s'
75 % (gr, perm_name))
76 new_perm = _make_perm(perm_name)
77 self.sa.add(new_perm)
78
46 def update(self, form_result):
79 def update(self, form_result):
47 perm_user = User.get_by_username(username=form_result['perm_user_name'])
80 perm_user = User.get_by_username(username=form_result['perm_user_name'])
48 u2p = self.sa.query(UserToPerm).filter(UserToPerm.user == perm_user).all()
49
81
50 try:
82 try:
83 # stage 1 set anonymous access
84 if perm_user.username == 'default':
85 perm_user.active = str2bool(form_result['anonymous'])
86 self.sa.add(perm_user)
87
88 # stage 2 reset defaults and set them from form data
51 def _make_new(usr, perm_name):
89 def _make_new(usr, perm_name):
52 new = UserToPerm()
90 new = UserToPerm()
53 new.user = usr
91 new.user = usr
54 new.permission = Permission.get_by_key(perm_name)
92 new.permission = Permission.get_by_key(perm_name)
55 return new
93 return new
56 # clear current entries, to make this function idempotent
94 # clear current entries, to make this function idempotent
57 # it will fix even if we define more permissions or permissions
95 # it will fix even if we define more permissions or permissions
58 # are somehow missing
96 # are somehow missing
97 u2p = self.sa.query(UserToPerm)\
98 .filter(UserToPerm.user == perm_user)\
99 .all()
59 for p in u2p:
100 for p in u2p:
60 self.sa.delete(p)
101 self.sa.delete(p)
61 #create fresh set of permissions
102 #create fresh set of permissions
62 for def_perm_key in ['default_repo_perm', 'default_group_perm',
103 for def_perm_key in ['default_repo_perm', 'default_group_perm',
63 'default_register', 'default_create',
104 'default_register', 'default_create',
64 'default_fork']:
105 'default_fork']:
65 p = _make_new(perm_user, form_result[def_perm_key])
106 p = _make_new(perm_user, form_result[def_perm_key])
66 self.sa.add(p)
107 self.sa.add(p)
67
108
68 #stage 2 update all default permissions for repos if checked
109 #stage 3 update all default permissions for repos if checked
69 if form_result['overwrite_default_repo'] == True:
110 if form_result['overwrite_default_repo'] == True:
70 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
111 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
71 _def = Permission.get_by_key('repository.' + _def_name)
112 _def = Permission.get_by_key('repository.' + _def_name)
72 # repos
113 # repos
73 for r2p in self.sa.query(UserRepoToPerm)\
114 for r2p in self.sa.query(UserRepoToPerm)\
74 .filter(UserRepoToPerm.user == perm_user)\
115 .filter(UserRepoToPerm.user == perm_user)\
75 .all():
116 .all():
76
117
77 #don't reset PRIVATE repositories
118 #don't reset PRIVATE repositories
78 if not r2p.repository.private:
119 if not r2p.repository.private:
79 r2p.permission = _def
120 r2p.permission = _def
80 self.sa.add(r2p)
121 self.sa.add(r2p)
81
122
82 if form_result['overwrite_default_group'] == True:
123 if form_result['overwrite_default_group'] == True:
83 _def_name = form_result['default_group_perm'].split('group.')[-1]
124 _def_name = form_result['default_group_perm'].split('group.')[-1]
84 # groups
125 # groups
85 _def = Permission.get_by_key('group.' + _def_name)
126 _def = Permission.get_by_key('group.' + _def_name)
86 for g2p in self.sa.query(UserRepoGroupToPerm)\
127 for g2p in self.sa.query(UserRepoGroupToPerm)\
87 .filter(UserRepoGroupToPerm.user == perm_user)\
128 .filter(UserRepoGroupToPerm.user == perm_user)\
88 .all():
129 .all():
89 g2p.permission = _def
130 g2p.permission = _def
90 self.sa.add(g2p)
131 self.sa.add(g2p)
91
132
92 # stage 3 set anonymous access
93 if perm_user.username == 'default':
94 perm_user.active = str2bool(form_result['anonymous'])
95 self.sa.add(perm_user)
96
97 self.sa.commit()
133 self.sa.commit()
98 except (DatabaseError,):
134 except (DatabaseError,):
99 log.error(traceback.format_exc())
135 log.error(traceback.format_exc())
100 self.sa.rollback()
136 self.sa.rollback()
101 raise
137 raise
@@ -1,460 +1,525 b''
1 import os
1 import os
2 import unittest
2 import unittest
3 from rhodecode.tests import *
3 from rhodecode.tests import *
4 from rhodecode.tests.fixture import Fixture
4 from rhodecode.tests.fixture import Fixture
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, UserGroupRepoGroupToPerm
7 from rhodecode.model.db import RepoGroup, User, UserGroupRepoGroupToPerm,\
8 Permission, UserToPerm
8 from rhodecode.model.user import UserModel
9 from rhodecode.model.user import UserModel
9
10
10 from rhodecode.model.meta import Session
11 from rhodecode.model.meta import Session
11 from rhodecode.model.users_group import UserGroupModel
12 from rhodecode.model.users_group import UserGroupModel
12 from rhodecode.lib.auth import AuthUser
13 from rhodecode.lib.auth import AuthUser
14 from rhodecode.model.permission import PermissionModel
13
15
14
16
15 fixture = Fixture()
17 fixture = Fixture()
16
18
17
19
18 class TestPermissions(unittest.TestCase):
20 class TestPermissions(unittest.TestCase):
19 def __init__(self, methodName='runTest'):
21 def __init__(self, methodName='runTest'):
20 super(TestPermissions, self).__init__(methodName=methodName)
22 super(TestPermissions, self).__init__(methodName=methodName)
21
23
22 def setUp(self):
24 def setUp(self):
23 self.u1 = UserModel().create_or_update(
25 self.u1 = UserModel().create_or_update(
24 username=u'u1', password=u'qweqwe',
26 username=u'u1', password=u'qweqwe',
25 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
27 email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1'
26 )
28 )
27 self.u2 = UserModel().create_or_update(
29 self.u2 = UserModel().create_or_update(
28 username=u'u2', password=u'qweqwe',
30 username=u'u2', password=u'qweqwe',
29 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
31 email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2'
30 )
32 )
31 self.u3 = UserModel().create_or_update(
33 self.u3 = UserModel().create_or_update(
32 username=u'u3', password=u'qweqwe',
34 username=u'u3', password=u'qweqwe',
33 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
35 email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3'
34 )
36 )
35 self.anon = User.get_by_username('default')
37 self.anon = User.get_by_username('default')
36 self.a1 = UserModel().create_or_update(
38 self.a1 = UserModel().create_or_update(
37 username=u'a1', password=u'qweqwe',
39 username=u'a1', password=u'qweqwe',
38 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
40 email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True
39 )
41 )
40 Session().commit()
42 Session().commit()
41
43
42 def tearDown(self):
44 def tearDown(self):
43 if hasattr(self, 'test_repo'):
45 if hasattr(self, 'test_repo'):
44 RepoModel().delete(repo=self.test_repo)
46 RepoModel().delete(repo=self.test_repo)
45
47
46 UserModel().delete(self.u1)
48 UserModel().delete(self.u1)
47 UserModel().delete(self.u2)
49 UserModel().delete(self.u2)
48 UserModel().delete(self.u3)
50 UserModel().delete(self.u3)
49 UserModel().delete(self.a1)
51 UserModel().delete(self.a1)
50 if hasattr(self, 'g1'):
52 if hasattr(self, 'g1'):
51 ReposGroupModel().delete(self.g1.group_id)
53 ReposGroupModel().delete(self.g1.group_id)
52 if hasattr(self, 'g2'):
54 if hasattr(self, 'g2'):
53 ReposGroupModel().delete(self.g2.group_id)
55 ReposGroupModel().delete(self.g2.group_id)
54
56
55 if hasattr(self, 'ug1'):
57 if hasattr(self, 'ug1'):
56 UserGroupModel().delete(self.ug1, force=True)
58 UserGroupModel().delete(self.ug1, force=True)
57
59
58 Session().commit()
60 Session().commit()
59
61
60 def test_default_perms_set(self):
62 def test_default_perms_set(self):
61 u1_auth = AuthUser(user_id=self.u1.user_id)
63 u1_auth = AuthUser(user_id=self.u1.user_id)
62 perms = {
64 perms = {
63 'repositories_groups': {},
65 'repositories_groups': {},
64 'global': set([u'hg.create.repository', u'repository.read',
66 'global': set([u'hg.create.repository', u'repository.read',
65 u'hg.register.manual_activate']),
67 u'hg.register.manual_activate']),
66 'repositories': {u'vcs_test_hg': u'repository.read'}
68 'repositories': {u'vcs_test_hg': u'repository.read'}
67 }
69 }
68 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
70 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
69 perms['repositories'][HG_REPO])
71 perms['repositories'][HG_REPO])
70 new_perm = 'repository.write'
72 new_perm = 'repository.write'
71 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
73 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
72 perm=new_perm)
74 perm=new_perm)
73 Session().commit()
75 Session().commit()
74
76
75 u1_auth = AuthUser(user_id=self.u1.user_id)
77 u1_auth = AuthUser(user_id=self.u1.user_id)
76 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
78 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
77 new_perm)
79 new_perm)
78
80
79 def test_default_admin_perms_set(self):
81 def test_default_admin_perms_set(self):
80 a1_auth = AuthUser(user_id=self.a1.user_id)
82 a1_auth = AuthUser(user_id=self.a1.user_id)
81 perms = {
83 perms = {
82 'repositories_groups': {},
84 'repositories_groups': {},
83 'global': set([u'hg.admin']),
85 'global': set([u'hg.admin']),
84 'repositories': {u'vcs_test_hg': u'repository.admin'}
86 'repositories': {u'vcs_test_hg': u'repository.admin'}
85 }
87 }
86 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
88 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
87 perms['repositories'][HG_REPO])
89 perms['repositories'][HG_REPO])
88 new_perm = 'repository.write'
90 new_perm = 'repository.write'
89 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
91 RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1,
90 perm=new_perm)
92 perm=new_perm)
91 Session().commit()
93 Session().commit()
92 # cannot really downgrade admins permissions !? they still get's set as
94 # cannot really downgrade admins permissions !? they still get's set as
93 # admin !
95 # admin !
94 u1_auth = AuthUser(user_id=self.a1.user_id)
96 u1_auth = AuthUser(user_id=self.a1.user_id)
95 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
97 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
96 perms['repositories'][HG_REPO])
98 perms['repositories'][HG_REPO])
97
99
98 def test_default_group_perms(self):
100 def test_default_group_perms(self):
99 self.g1 = fixture.create_group('test1', skip_if_exists=True)
101 self.g1 = fixture.create_group('test1', skip_if_exists=True)
100 self.g2 = fixture.create_group('test2', skip_if_exists=True)
102 self.g2 = fixture.create_group('test2', skip_if_exists=True)
101 u1_auth = AuthUser(user_id=self.u1.user_id)
103 u1_auth = AuthUser(user_id=self.u1.user_id)
102 perms = {
104 perms = {
103 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
105 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'},
104 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']),
106 'global': set(Permission.DEFAULT_USER_PERMISSIONS),
105 'repositories': {u'vcs_test_hg': u'repository.read'}
107 'repositories': {u'vcs_test_hg': u'repository.read'}
106 }
108 }
107 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
109 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
108 perms['repositories'][HG_REPO])
110 perms['repositories'][HG_REPO])
109 self.assertEqual(u1_auth.permissions['repositories_groups'],
111 self.assertEqual(u1_auth.permissions['repositories_groups'],
110 perms['repositories_groups'])
112 perms['repositories_groups'])
113 self.assertEqual(u1_auth.permissions['global'],
114 perms['global'])
111
115
112 def test_default_admin_group_perms(self):
116 def test_default_admin_group_perms(self):
113 self.g1 = fixture.create_group('test1', skip_if_exists=True)
117 self.g1 = fixture.create_group('test1', skip_if_exists=True)
114 self.g2 = fixture.create_group('test2', skip_if_exists=True)
118 self.g2 = fixture.create_group('test2', skip_if_exists=True)
115 a1_auth = AuthUser(user_id=self.a1.user_id)
119 a1_auth = AuthUser(user_id=self.a1.user_id)
116 perms = {
120 perms = {
117 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
121 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'},
118 'global': set(['hg.admin']),
122 'global': set(['hg.admin']),
119 'repositories': {u'vcs_test_hg': 'repository.admin'}
123 'repositories': {u'vcs_test_hg': 'repository.admin'}
120 }
124 }
121
125
122 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
126 self.assertEqual(a1_auth.permissions['repositories'][HG_REPO],
123 perms['repositories'][HG_REPO])
127 perms['repositories'][HG_REPO])
124 self.assertEqual(a1_auth.permissions['repositories_groups'],
128 self.assertEqual(a1_auth.permissions['repositories_groups'],
125 perms['repositories_groups'])
129 perms['repositories_groups'])
126
130
127 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
131 def test_propagated_permission_from_users_group_by_explicit_perms_exist(self):
128 # make group
132 # make group
129 self.ug1 = fixture.create_user_group('G1')
133 self.ug1 = fixture.create_user_group('G1')
130 UserGroupModel().add_user_to_group(self.ug1, self.u1)
134 UserGroupModel().add_user_to_group(self.ug1, self.u1)
131
135
132 # set permission to lower
136 # set permission to lower
133 new_perm = 'repository.none'
137 new_perm = 'repository.none'
134 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
138 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm)
135 Session().commit()
139 Session().commit()
136 u1_auth = AuthUser(user_id=self.u1.user_id)
140 u1_auth = AuthUser(user_id=self.u1.user_id)
137 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
141 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
138 new_perm)
142 new_perm)
139
143
140 # grant perm for group this should not override permission from user
144 # grant perm for group this should not override permission from user
141 # since it has explicitly set
145 # since it has explicitly set
142 new_perm_gr = 'repository.write'
146 new_perm_gr = 'repository.write'
143 RepoModel().grant_users_group_permission(repo=HG_REPO,
147 RepoModel().grant_users_group_permission(repo=HG_REPO,
144 group_name=self.ug1,
148 group_name=self.ug1,
145 perm=new_perm_gr)
149 perm=new_perm_gr)
146 # check perms
150 # check perms
147 u1_auth = AuthUser(user_id=self.u1.user_id)
151 u1_auth = AuthUser(user_id=self.u1.user_id)
148 perms = {
152 perms = {
149 'repositories_groups': {},
153 'repositories_groups': {},
150 'global': set([u'hg.create.repository', u'repository.read',
154 'global': set([u'hg.create.repository', u'repository.read',
151 u'hg.register.manual_activate']),
155 u'hg.register.manual_activate']),
152 'repositories': {u'vcs_test_hg': u'repository.read'}
156 'repositories': {u'vcs_test_hg': u'repository.read'}
153 }
157 }
154 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
158 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
155 new_perm)
159 new_perm)
156 self.assertEqual(u1_auth.permissions['repositories_groups'],
160 self.assertEqual(u1_auth.permissions['repositories_groups'],
157 perms['repositories_groups'])
161 perms['repositories_groups'])
158
162
159 def test_propagated_permission_from_users_group(self):
163 def test_propagated_permission_from_users_group(self):
160 # make group
164 # make group
161 self.ug1 = fixture.create_user_group('G1')
165 self.ug1 = fixture.create_user_group('G1')
162 UserGroupModel().add_user_to_group(self.ug1, self.u3)
166 UserGroupModel().add_user_to_group(self.ug1, self.u3)
163
167
164 # grant perm for group this should override default permission from user
168 # grant perm for group this should override default permission from user
165 new_perm_gr = 'repository.write'
169 new_perm_gr = 'repository.write'
166 RepoModel().grant_users_group_permission(repo=HG_REPO,
170 RepoModel().grant_users_group_permission(repo=HG_REPO,
167 group_name=self.ug1,
171 group_name=self.ug1,
168 perm=new_perm_gr)
172 perm=new_perm_gr)
169 # check perms
173 # check perms
170 u3_auth = AuthUser(user_id=self.u3.user_id)
174 u3_auth = AuthUser(user_id=self.u3.user_id)
171 perms = {
175 perms = {
172 'repositories_groups': {},
176 'repositories_groups': {},
173 'global': set([u'hg.create.repository', u'repository.read',
177 'global': set([u'hg.create.repository', u'repository.read',
174 u'hg.register.manual_activate']),
178 u'hg.register.manual_activate']),
175 'repositories': {u'vcs_test_hg': u'repository.read'}
179 'repositories': {u'vcs_test_hg': u'repository.read'}
176 }
180 }
177 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
181 self.assertEqual(u3_auth.permissions['repositories'][HG_REPO],
178 new_perm_gr)
182 new_perm_gr)
179 self.assertEqual(u3_auth.permissions['repositories_groups'],
183 self.assertEqual(u3_auth.permissions['repositories_groups'],
180 perms['repositories_groups'])
184 perms['repositories_groups'])
181
185
182 def test_propagated_permission_from_users_group_lower_weight(self):
186 def test_propagated_permission_from_users_group_lower_weight(self):
183 # make group
187 # make group
184 self.ug1 = fixture.create_user_group('G1')
188 self.ug1 = fixture.create_user_group('G1')
185 # add user to group
189 # add user to group
186 UserGroupModel().add_user_to_group(self.ug1, self.u1)
190 UserGroupModel().add_user_to_group(self.ug1, self.u1)
187
191
188 # set permission to lower
192 # set permission to lower
189 new_perm_h = 'repository.write'
193 new_perm_h = 'repository.write'
190 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
194 RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1,
191 perm=new_perm_h)
195 perm=new_perm_h)
192 Session().commit()
196 Session().commit()
193 u1_auth = AuthUser(user_id=self.u1.user_id)
197 u1_auth = AuthUser(user_id=self.u1.user_id)
194 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
198 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
195 new_perm_h)
199 new_perm_h)
196
200
197 # grant perm for group this should NOT override permission from user
201 # grant perm for group this should NOT override permission from user
198 # since it's lower than granted
202 # since it's lower than granted
199 new_perm_l = 'repository.read'
203 new_perm_l = 'repository.read'
200 RepoModel().grant_users_group_permission(repo=HG_REPO,
204 RepoModel().grant_users_group_permission(repo=HG_REPO,
201 group_name=self.ug1,
205 group_name=self.ug1,
202 perm=new_perm_l)
206 perm=new_perm_l)
203 # check perms
207 # check perms
204 u1_auth = AuthUser(user_id=self.u1.user_id)
208 u1_auth = AuthUser(user_id=self.u1.user_id)
205 perms = {
209 perms = {
206 'repositories_groups': {},
210 'repositories_groups': {},
207 'global': set([u'hg.create.repository', u'repository.read',
211 'global': set([u'hg.create.repository', u'repository.read',
208 u'hg.register.manual_activate']),
212 u'hg.register.manual_activate']),
209 'repositories': {u'vcs_test_hg': u'repository.write'}
213 'repositories': {u'vcs_test_hg': u'repository.write'}
210 }
214 }
211 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
215 self.assertEqual(u1_auth.permissions['repositories'][HG_REPO],
212 new_perm_h)
216 new_perm_h)
213 self.assertEqual(u1_auth.permissions['repositories_groups'],
217 self.assertEqual(u1_auth.permissions['repositories_groups'],
214 perms['repositories_groups'])
218 perms['repositories_groups'])
215
219
216 def test_repo_in_group_permissions(self):
220 def test_repo_in_group_permissions(self):
217 self.g1 = fixture.create_group('group1', skip_if_exists=True)
221 self.g1 = fixture.create_group('group1', skip_if_exists=True)
218 self.g2 = fixture.create_group('group2', skip_if_exists=True)
222 self.g2 = fixture.create_group('group2', skip_if_exists=True)
219 # both perms should be read !
223 # both perms should be read !
220 u1_auth = AuthUser(user_id=self.u1.user_id)
224 u1_auth = AuthUser(user_id=self.u1.user_id)
221 self.assertEqual(u1_auth.permissions['repositories_groups'],
225 self.assertEqual(u1_auth.permissions['repositories_groups'],
222 {u'group1': u'group.read', u'group2': u'group.read'})
226 {u'group1': u'group.read', u'group2': u'group.read'})
223
227
224 a1_auth = AuthUser(user_id=self.anon.user_id)
228 a1_auth = AuthUser(user_id=self.anon.user_id)
225 self.assertEqual(a1_auth.permissions['repositories_groups'],
229 self.assertEqual(a1_auth.permissions['repositories_groups'],
226 {u'group1': u'group.read', u'group2': u'group.read'})
230 {u'group1': u'group.read', u'group2': u'group.read'})
227
231
228 #Change perms to none for both groups
232 #Change perms to none for both groups
229 ReposGroupModel().grant_user_permission(repos_group=self.g1,
233 ReposGroupModel().grant_user_permission(repos_group=self.g1,
230 user=self.anon,
234 user=self.anon,
231 perm='group.none')
235 perm='group.none')
232 ReposGroupModel().grant_user_permission(repos_group=self.g2,
236 ReposGroupModel().grant_user_permission(repos_group=self.g2,
233 user=self.anon,
237 user=self.anon,
234 perm='group.none')
238 perm='group.none')
235
239
236 u1_auth = AuthUser(user_id=self.u1.user_id)
240 u1_auth = AuthUser(user_id=self.u1.user_id)
237 self.assertEqual(u1_auth.permissions['repositories_groups'],
241 self.assertEqual(u1_auth.permissions['repositories_groups'],
238 {u'group1': u'group.none', u'group2': u'group.none'})
242 {u'group1': u'group.none', u'group2': u'group.none'})
239
243
240 a1_auth = AuthUser(user_id=self.anon.user_id)
244 a1_auth = AuthUser(user_id=self.anon.user_id)
241 self.assertEqual(a1_auth.permissions['repositories_groups'],
245 self.assertEqual(a1_auth.permissions['repositories_groups'],
242 {u'group1': u'group.none', u'group2': u'group.none'})
246 {u'group1': u'group.none', u'group2': u'group.none'})
243
247
244 # add repo to group
248 # add repo to group
245 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
249 name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm'])
246 self.test_repo = fixture.create_repo(name=name,
250 self.test_repo = fixture.create_repo(name=name,
247 repo_type='hg',
251 repo_type='hg',
248 repos_group=self.g1,
252 repos_group=self.g1,
249 cur_user=self.u1,)
253 cur_user=self.u1,)
250
254
251 u1_auth = AuthUser(user_id=self.u1.user_id)
255 u1_auth = AuthUser(user_id=self.u1.user_id)
252 self.assertEqual(u1_auth.permissions['repositories_groups'],
256 self.assertEqual(u1_auth.permissions['repositories_groups'],
253 {u'group1': u'group.none', u'group2': u'group.none'})
257 {u'group1': u'group.none', u'group2': u'group.none'})
254
258
255 a1_auth = AuthUser(user_id=self.anon.user_id)
259 a1_auth = AuthUser(user_id=self.anon.user_id)
256 self.assertEqual(a1_auth.permissions['repositories_groups'],
260 self.assertEqual(a1_auth.permissions['repositories_groups'],
257 {u'group1': u'group.none', u'group2': u'group.none'})
261 {u'group1': u'group.none', u'group2': u'group.none'})
258
262
259 #grant permission for u2 !
263 #grant permission for u2 !
260 ReposGroupModel().grant_user_permission(repos_group=self.g1,
264 ReposGroupModel().grant_user_permission(repos_group=self.g1,
261 user=self.u2,
265 user=self.u2,
262 perm='group.read')
266 perm='group.read')
263 ReposGroupModel().grant_user_permission(repos_group=self.g2,
267 ReposGroupModel().grant_user_permission(repos_group=self.g2,
264 user=self.u2,
268 user=self.u2,
265 perm='group.read')
269 perm='group.read')
266 Session().commit()
270 Session().commit()
267 self.assertNotEqual(self.u1, self.u2)
271 self.assertNotEqual(self.u1, self.u2)
268 #u1 and anon should have not change perms while u2 should !
272 #u1 and anon should have not change perms while u2 should !
269 u1_auth = AuthUser(user_id=self.u1.user_id)
273 u1_auth = AuthUser(user_id=self.u1.user_id)
270 self.assertEqual(u1_auth.permissions['repositories_groups'],
274 self.assertEqual(u1_auth.permissions['repositories_groups'],
271 {u'group1': u'group.none', u'group2': u'group.none'})
275 {u'group1': u'group.none', u'group2': u'group.none'})
272
276
273 u2_auth = AuthUser(user_id=self.u2.user_id)
277 u2_auth = AuthUser(user_id=self.u2.user_id)
274 self.assertEqual(u2_auth.permissions['repositories_groups'],
278 self.assertEqual(u2_auth.permissions['repositories_groups'],
275 {u'group1': u'group.read', u'group2': u'group.read'})
279 {u'group1': u'group.read', u'group2': u'group.read'})
276
280
277 a1_auth = AuthUser(user_id=self.anon.user_id)
281 a1_auth = AuthUser(user_id=self.anon.user_id)
278 self.assertEqual(a1_auth.permissions['repositories_groups'],
282 self.assertEqual(a1_auth.permissions['repositories_groups'],
279 {u'group1': u'group.none', u'group2': u'group.none'})
283 {u'group1': u'group.none', u'group2': u'group.none'})
280
284
281 def test_repo_group_user_as_user_group_member(self):
285 def test_repo_group_user_as_user_group_member(self):
282 # create Group1
286 # create Group1
283 self.g1 = fixture.create_group('group1', skip_if_exists=True)
287 self.g1 = fixture.create_group('group1', skip_if_exists=True)
284 a1_auth = AuthUser(user_id=self.anon.user_id)
288 a1_auth = AuthUser(user_id=self.anon.user_id)
285
289
286 self.assertEqual(a1_auth.permissions['repositories_groups'],
290 self.assertEqual(a1_auth.permissions['repositories_groups'],
287 {u'group1': u'group.read'})
291 {u'group1': u'group.read'})
288
292
289 # set default permission to none
293 # set default permission to none
290 ReposGroupModel().grant_user_permission(repos_group=self.g1,
294 ReposGroupModel().grant_user_permission(repos_group=self.g1,
291 user=self.anon,
295 user=self.anon,
292 perm='group.none')
296 perm='group.none')
293 # make group
297 # make group
294 self.ug1 = fixture.create_user_group('G1')
298 self.ug1 = fixture.create_user_group('G1')
295 # add user to group
299 # add user to group
296 UserGroupModel().add_user_to_group(self.ug1, self.u1)
300 UserGroupModel().add_user_to_group(self.ug1, self.u1)
297 Session().commit()
301 Session().commit()
298
302
299 # check if user is in the group
303 # check if user is in the group
300 membrs = [x.user_id for x in UserGroupModel().get(self.ug1.users_group_id).members]
304 membrs = [x.user_id for x in UserGroupModel().get(self.ug1.users_group_id).members]
301 self.assertEqual(membrs, [self.u1.user_id])
305 self.assertEqual(membrs, [self.u1.user_id])
302 # add some user to that group
306 # add some user to that group
303
307
304 # check his permissions
308 # check his permissions
305 a1_auth = AuthUser(user_id=self.anon.user_id)
309 a1_auth = AuthUser(user_id=self.anon.user_id)
306 self.assertEqual(a1_auth.permissions['repositories_groups'],
310 self.assertEqual(a1_auth.permissions['repositories_groups'],
307 {u'group1': u'group.none'})
311 {u'group1': u'group.none'})
308
312
309 u1_auth = AuthUser(user_id=self.u1.user_id)
313 u1_auth = AuthUser(user_id=self.u1.user_id)
310 self.assertEqual(u1_auth.permissions['repositories_groups'],
314 self.assertEqual(u1_auth.permissions['repositories_groups'],
311 {u'group1': u'group.none'})
315 {u'group1': u'group.none'})
312
316
313 # grant ug1 read permissions for
317 # grant ug1 read permissions for
314 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
318 ReposGroupModel().grant_users_group_permission(repos_group=self.g1,
315 group_name=self.ug1,
319 group_name=self.ug1,
316 perm='group.read')
320 perm='group.read')
317 Session().commit()
321 Session().commit()
318 # check if the
322 # check if the
319 obj = Session().query(UserGroupRepoGroupToPerm)\
323 obj = Session().query(UserGroupRepoGroupToPerm)\
320 .filter(UserGroupRepoGroupToPerm.group == self.g1)\
324 .filter(UserGroupRepoGroupToPerm.group == self.g1)\
321 .filter(UserGroupRepoGroupToPerm.users_group == self.ug1)\
325 .filter(UserGroupRepoGroupToPerm.users_group == self.ug1)\
322 .scalar()
326 .scalar()
323 self.assertEqual(obj.permission.permission_name, 'group.read')
327 self.assertEqual(obj.permission.permission_name, 'group.read')
324
328
325 a1_auth = AuthUser(user_id=self.anon.user_id)
329 a1_auth = AuthUser(user_id=self.anon.user_id)
326
330
327 self.assertEqual(a1_auth.permissions['repositories_groups'],
331 self.assertEqual(a1_auth.permissions['repositories_groups'],
328 {u'group1': u'group.none'})
332 {u'group1': u'group.none'})
329
333
330 u1_auth = AuthUser(user_id=self.u1.user_id)
334 u1_auth = AuthUser(user_id=self.u1.user_id)
331 self.assertEqual(u1_auth.permissions['repositories_groups'],
335 self.assertEqual(u1_auth.permissions['repositories_groups'],
332 {u'group1': u'group.read'})
336 {u'group1': u'group.read'})
333
337
334 def test_inherited_permissions_from_default_on_user_enabled(self):
338 def test_inherited_permissions_from_default_on_user_enabled(self):
335 user_model = UserModel()
339 user_model = UserModel()
336 # enable fork and create on default user
340 # enable fork and create on default user
337 usr = 'default'
341 usr = 'default'
338 user_model.revoke_perm(usr, 'hg.create.none')
342 user_model.revoke_perm(usr, 'hg.create.none')
339 user_model.grant_perm(usr, 'hg.create.repository')
343 user_model.grant_perm(usr, 'hg.create.repository')
340 user_model.revoke_perm(usr, 'hg.fork.none')
344 user_model.revoke_perm(usr, 'hg.fork.none')
341 user_model.grant_perm(usr, 'hg.fork.repository')
345 user_model.grant_perm(usr, 'hg.fork.repository')
342 # make sure inherit flag is turned on
346 # make sure inherit flag is turned on
343 self.u1.inherit_default_permissions = True
347 self.u1.inherit_default_permissions = True
344 Session().commit()
348 Session().commit()
345 u1_auth = AuthUser(user_id=self.u1.user_id)
349 u1_auth = AuthUser(user_id=self.u1.user_id)
346 # this user will have inherited permissions from default user
350 # this user will have inherited permissions from default user
347 self.assertEqual(u1_auth.permissions['global'],
351 self.assertEqual(u1_auth.permissions['global'],
348 set(['hg.create.repository', 'hg.fork.repository',
352 set(['hg.create.repository', 'hg.fork.repository',
349 'hg.register.manual_activate',
353 'hg.register.manual_activate',
350 'repository.read', 'group.read']))
354 'repository.read', 'group.read',
355 'usergroup.read']))
351
356
352 def test_inherited_permissions_from_default_on_user_disabled(self):
357 def test_inherited_permissions_from_default_on_user_disabled(self):
353 user_model = UserModel()
358 user_model = UserModel()
354 # disable fork and create on default user
359 # disable fork and create on default user
355 usr = 'default'
360 usr = 'default'
356 user_model.revoke_perm(usr, 'hg.create.repository')
361 user_model.revoke_perm(usr, 'hg.create.repository')
357 user_model.grant_perm(usr, 'hg.create.none')
362 user_model.grant_perm(usr, 'hg.create.none')
358 user_model.revoke_perm(usr, 'hg.fork.repository')
363 user_model.revoke_perm(usr, 'hg.fork.repository')
359 user_model.grant_perm(usr, 'hg.fork.none')
364 user_model.grant_perm(usr, 'hg.fork.none')
360 # make sure inherit flag is turned on
365 # make sure inherit flag is turned on
361 self.u1.inherit_default_permissions = True
366 self.u1.inherit_default_permissions = True
362 Session().commit()
367 Session().commit()
363 u1_auth = AuthUser(user_id=self.u1.user_id)
368 u1_auth = AuthUser(user_id=self.u1.user_id)
364 # this user will have inherited permissions from default user
369 # this user will have inherited permissions from default user
365 self.assertEqual(u1_auth.permissions['global'],
370 self.assertEqual(u1_auth.permissions['global'],
366 set(['hg.create.none', 'hg.fork.none',
371 set(['hg.create.none', 'hg.fork.none',
367 'hg.register.manual_activate',
372 'hg.register.manual_activate',
368 'repository.read', 'group.read']))
373 'repository.read', 'group.read',
374 'usergroup.read']))
369
375
370 def test_non_inherited_permissions_from_default_on_user_enabled(self):
376 def test_non_inherited_permissions_from_default_on_user_enabled(self):
371 user_model = UserModel()
377 user_model = UserModel()
372 # enable fork and create on default user
378 # enable fork and create on default user
373 usr = 'default'
379 usr = 'default'
374 user_model.revoke_perm(usr, 'hg.create.none')
380 user_model.revoke_perm(usr, 'hg.create.none')
375 user_model.grant_perm(usr, 'hg.create.repository')
381 user_model.grant_perm(usr, 'hg.create.repository')
376 user_model.revoke_perm(usr, 'hg.fork.none')
382 user_model.revoke_perm(usr, 'hg.fork.none')
377 user_model.grant_perm(usr, 'hg.fork.repository')
383 user_model.grant_perm(usr, 'hg.fork.repository')
378
384
379 #disable global perms on specific user
385 #disable global perms on specific user
380 user_model.revoke_perm(self.u1, 'hg.create.repository')
386 user_model.revoke_perm(self.u1, 'hg.create.repository')
381 user_model.grant_perm(self.u1, 'hg.create.none')
387 user_model.grant_perm(self.u1, 'hg.create.none')
382 user_model.revoke_perm(self.u1, 'hg.fork.repository')
388 user_model.revoke_perm(self.u1, 'hg.fork.repository')
383 user_model.grant_perm(self.u1, 'hg.fork.none')
389 user_model.grant_perm(self.u1, 'hg.fork.none')
384
390
385 # make sure inherit flag is turned off
391 # make sure inherit flag is turned off
386 self.u1.inherit_default_permissions = False
392 self.u1.inherit_default_permissions = False
387 Session().commit()
393 Session().commit()
388 u1_auth = AuthUser(user_id=self.u1.user_id)
394 u1_auth = AuthUser(user_id=self.u1.user_id)
389 # this user will have non inherited permissions from he's
395 # this user will have non inherited permissions from he's
390 # explicitly set permissions
396 # explicitly set permissions
391 self.assertEqual(u1_auth.permissions['global'],
397 self.assertEqual(u1_auth.permissions['global'],
392 set(['hg.create.none', 'hg.fork.none',
398 set(['hg.create.none', 'hg.fork.none',
393 'hg.register.manual_activate',
399 'hg.register.manual_activate',
394 'repository.read', 'group.read']))
400 'repository.read', 'group.read',
401 'usergroup.read']))
395
402
396 def test_non_inherited_permissions_from_default_on_user_disabled(self):
403 def test_non_inherited_permissions_from_default_on_user_disabled(self):
397 user_model = UserModel()
404 user_model = UserModel()
398 # disable fork and create on default user
405 # disable fork and create on default user
399 usr = 'default'
406 usr = 'default'
400 user_model.revoke_perm(usr, 'hg.create.repository')
407 user_model.revoke_perm(usr, 'hg.create.repository')
401 user_model.grant_perm(usr, 'hg.create.none')
408 user_model.grant_perm(usr, 'hg.create.none')
402 user_model.revoke_perm(usr, 'hg.fork.repository')
409 user_model.revoke_perm(usr, 'hg.fork.repository')
403 user_model.grant_perm(usr, 'hg.fork.none')
410 user_model.grant_perm(usr, 'hg.fork.none')
404
411
405 #enable global perms on specific user
412 #enable global perms on specific user
406 user_model.revoke_perm(self.u1, 'hg.create.none')
413 user_model.revoke_perm(self.u1, 'hg.create.none')
407 user_model.grant_perm(self.u1, 'hg.create.repository')
414 user_model.grant_perm(self.u1, 'hg.create.repository')
408 user_model.revoke_perm(self.u1, 'hg.fork.none')
415 user_model.revoke_perm(self.u1, 'hg.fork.none')
409 user_model.grant_perm(self.u1, 'hg.fork.repository')
416 user_model.grant_perm(self.u1, 'hg.fork.repository')
410
417
411 # make sure inherit flag is turned off
418 # make sure inherit flag is turned off
412 self.u1.inherit_default_permissions = False
419 self.u1.inherit_default_permissions = False
413 Session().commit()
420 Session().commit()
414 u1_auth = AuthUser(user_id=self.u1.user_id)
421 u1_auth = AuthUser(user_id=self.u1.user_id)
415 # this user will have non inherited permissions from he's
422 # this user will have non inherited permissions from he's
416 # explicitly set permissions
423 # explicitly set permissions
417 self.assertEqual(u1_auth.permissions['global'],
424 self.assertEqual(u1_auth.permissions['global'],
418 set(['hg.create.repository', 'hg.fork.repository',
425 set(['hg.create.repository', 'hg.fork.repository',
419 'hg.register.manual_activate',
426 'hg.register.manual_activate',
420 'repository.read', 'group.read']))
427 'repository.read', 'group.read',
428 'usergroup.read']))
421
429
422 def test_owner_permissions_doesnot_get_overwritten_by_group(self):
430 def test_owner_permissions_doesnot_get_overwritten_by_group(self):
423 #create repo as USER,
431 #create repo as USER,
424 self.test_repo = fixture.create_repo(name='myownrepo',
432 self.test_repo = fixture.create_repo(name='myownrepo',
425 repo_type='hg',
433 repo_type='hg',
426 cur_user=self.u1)
434 cur_user=self.u1)
427
435
428 #he has permissions of admin as owner
436 #he has permissions of admin as owner
429 u1_auth = AuthUser(user_id=self.u1.user_id)
437 u1_auth = AuthUser(user_id=self.u1.user_id)
430 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
438 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
431 'repository.admin')
439 'repository.admin')
432 #set his permission as user group, he should still be admin
440 #set his permission as user group, he should still be admin
433 self.ug1 = fixture.create_user_group('G1')
441 self.ug1 = fixture.create_user_group('G1')
434 UserGroupModel().add_user_to_group(self.ug1, self.u1)
442 UserGroupModel().add_user_to_group(self.ug1, self.u1)
435 RepoModel().grant_users_group_permission(self.test_repo,
443 RepoModel().grant_users_group_permission(self.test_repo,
436 group_name=self.ug1,
444 group_name=self.ug1,
437 perm='repository.none')
445 perm='repository.none')
438
446
439 Session().commit()
447 Session().commit()
440 u1_auth = AuthUser(user_id=self.u1.user_id)
448 u1_auth = AuthUser(user_id=self.u1.user_id)
441 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
449 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
442 'repository.admin')
450 'repository.admin')
443
451
444 def test_owner_permissions_doesnot_get_overwritten_by_others(self):
452 def test_owner_permissions_doesnot_get_overwritten_by_others(self):
445 #create repo as USER,
453 #create repo as USER,
446 self.test_repo = fixture.create_repo(name='myownrepo',
454 self.test_repo = fixture.create_repo(name='myownrepo',
447 repo_type='hg',
455 repo_type='hg',
448 cur_user=self.u1)
456 cur_user=self.u1)
449
457
450 #he has permissions of admin as owner
458 #he has permissions of admin as owner
451 u1_auth = AuthUser(user_id=self.u1.user_id)
459 u1_auth = AuthUser(user_id=self.u1.user_id)
452 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
460 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
453 'repository.admin')
461 'repository.admin')
454 #set his permission as user, he should still be admin
462 #set his permission as user, he should still be admin
455 RepoModel().grant_user_permission(self.test_repo, user=self.u1,
463 RepoModel().grant_user_permission(self.test_repo, user=self.u1,
456 perm='repository.none')
464 perm='repository.none')
457 Session().commit()
465 Session().commit()
458 u1_auth = AuthUser(user_id=self.u1.user_id)
466 u1_auth = AuthUser(user_id=self.u1.user_id)
459 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
467 self.assertEqual(u1_auth.permissions['repositories']['myownrepo'],
460 'repository.admin')
468 'repository.admin')
469
470 def _test_def_perm_equal(self, user, change_factor=0):
471 perms = UserToPerm.query()\
472 .filter(UserToPerm.user == user)\
473 .all()
474 self.assertEqual(len(perms),
475 len(Permission.DEFAULT_USER_PERMISSIONS,)+change_factor,
476 msg=perms)
477
478 def test_set_default_permissions(self):
479 PermissionModel().create_default_permissions(user=self.u1)
480 self._test_def_perm_equal(user=self.u1)
481
482 def test_set_default_permissions_after_one_is_missing(self):
483 PermissionModel().create_default_permissions(user=self.u1)
484 self._test_def_perm_equal(user=self.u1)
485 #now we delete one, it should be re-created after another call
486 perms = UserToPerm.query()\
487 .filter(UserToPerm.user == self.u1)\
488 .all()
489 Session().delete(perms[0])
490 Session().commit()
491
492 self._test_def_perm_equal(user=self.u1, change_factor=-1)
493
494 #create missing one !
495 PermissionModel().create_default_permissions(user=self.u1)
496 self._test_def_perm_equal(user=self.u1)
497
498 @parameterized.expand([
499 ('repository.read', 'repository.none'),
500 ('group.read', 'group.none'),
501 ('usergroup.read', 'usergroup.none'),
502 ('hg.create.repository', 'hg.create.none'),
503 ('hg.fork.repository', 'hg.fork.none'),
504 ('hg.register.manual_activate', 'hg.register.auto_activate',)
505 ])
506 def test_set_default_permissions_after_modification(self, perm, modify_to):
507 PermissionModel().create_default_permissions(user=self.u1)
508 self._test_def_perm_equal(user=self.u1)
509
510 old = Permission.get_by_key(perm)
511 new = Permission.get_by_key(modify_to)
512 self.assertNotEqual(old, None)
513 self.assertNotEqual(new, None)
514
515 #now modify permissions
516 p = UserToPerm.query()\
517 .filter(UserToPerm.user == self.u1)\
518 .filter(UserToPerm.permission == old)\
519 .one()
520 p.permission = new
521 Session().add(p)
522 Session().commit()
523
524 PermissionModel().create_default_permissions(user=self.u1)
525 self._test_def_perm_equal(user=self.u1)
General Comments 0
You need to be logged in to leave comments. Login now