##// END OF EJS Templates
caches: removed unused cache option from repo by id fetch.
marcink -
r2889:1b472a1b default
parent child Browse files
Show More
@@ -1,1050 +1,1047 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2018 RhodeCode GmbH
3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import re
22 import re
23 import shutil
23 import shutil
24 import time
24 import time
25 import logging
25 import logging
26 import traceback
26 import traceback
27 import datetime
27 import datetime
28
28
29 from pyramid.threadlocal import get_current_request
29 from pyramid.threadlocal import get_current_request
30 from zope.cachedescriptors.property import Lazy as LazyProperty
30 from zope.cachedescriptors.property import Lazy as LazyProperty
31
31
32 from rhodecode import events
32 from rhodecode import events
33 from rhodecode.lib.auth import HasUserGroupPermissionAny
33 from rhodecode.lib.auth import HasUserGroupPermissionAny
34 from rhodecode.lib.caching_query import FromCache
34 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.lib.exceptions import AttachedForksError
35 from rhodecode.lib.exceptions import AttachedForksError
36 from rhodecode.lib.hooks_base import log_delete_repository
36 from rhodecode.lib.hooks_base import log_delete_repository
37 from rhodecode.lib.user_log_filter import user_log_filter
37 from rhodecode.lib.user_log_filter import user_log_filter
38 from rhodecode.lib.utils import make_db_config
38 from rhodecode.lib.utils import make_db_config
39 from rhodecode.lib.utils2 import (
39 from rhodecode.lib.utils2 import (
40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
40 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
41 get_current_rhodecode_user, safe_int, datetime_to_time,
41 get_current_rhodecode_user, safe_int, datetime_to_time,
42 action_logger_generic)
42 action_logger_generic)
43 from rhodecode.lib.vcs.backends import get_backend
43 from rhodecode.lib.vcs.backends import get_backend
44 from rhodecode.model import BaseModel
44 from rhodecode.model import BaseModel
45 from rhodecode.model.db import (
45 from rhodecode.model.db import (
46 _hash_key, joinedload, or_, Repository, UserRepoToPerm, UserGroupRepoToPerm,
46 _hash_key, joinedload, or_, Repository, UserRepoToPerm, UserGroupRepoToPerm,
47 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
47 UserRepoGroupToPerm, UserGroupRepoGroupToPerm, User, Permission,
48 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
48 Statistics, UserGroup, RepoGroup, RepositoryField, UserLog)
49
49
50 from rhodecode.model.settings import VcsSettingsModel
50 from rhodecode.model.settings import VcsSettingsModel
51
51
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 class RepoModel(BaseModel):
56 class RepoModel(BaseModel):
57
57
58 cls = Repository
58 cls = Repository
59
59
60 def _get_user_group(self, users_group):
60 def _get_user_group(self, users_group):
61 return self._get_instance(UserGroup, users_group,
61 return self._get_instance(UserGroup, users_group,
62 callback=UserGroup.get_by_group_name)
62 callback=UserGroup.get_by_group_name)
63
63
64 def _get_repo_group(self, repo_group):
64 def _get_repo_group(self, repo_group):
65 return self._get_instance(RepoGroup, repo_group,
65 return self._get_instance(RepoGroup, repo_group,
66 callback=RepoGroup.get_by_group_name)
66 callback=RepoGroup.get_by_group_name)
67
67
68 def _create_default_perms(self, repository, private):
68 def _create_default_perms(self, repository, private):
69 # create default permission
69 # create default permission
70 default = 'repository.read'
70 default = 'repository.read'
71 def_user = User.get_default_user()
71 def_user = User.get_default_user()
72 for p in def_user.user_perms:
72 for p in def_user.user_perms:
73 if p.permission.permission_name.startswith('repository.'):
73 if p.permission.permission_name.startswith('repository.'):
74 default = p.permission.permission_name
74 default = p.permission.permission_name
75 break
75 break
76
76
77 default_perm = 'repository.none' if private else default
77 default_perm = 'repository.none' if private else default
78
78
79 repo_to_perm = UserRepoToPerm()
79 repo_to_perm = UserRepoToPerm()
80 repo_to_perm.permission = Permission.get_by_key(default_perm)
80 repo_to_perm.permission = Permission.get_by_key(default_perm)
81
81
82 repo_to_perm.repository = repository
82 repo_to_perm.repository = repository
83 repo_to_perm.user_id = def_user.user_id
83 repo_to_perm.user_id = def_user.user_id
84
84
85 return repo_to_perm
85 return repo_to_perm
86
86
87 @LazyProperty
87 @LazyProperty
88 def repos_path(self):
88 def repos_path(self):
89 """
89 """
90 Gets the repositories root path from database
90 Gets the repositories root path from database
91 """
91 """
92 settings_model = VcsSettingsModel(sa=self.sa)
92 settings_model = VcsSettingsModel(sa=self.sa)
93 return settings_model.get_repos_location()
93 return settings_model.get_repos_location()
94
94
95 def get(self, repo_id, cache=False):
95 def get(self, repo_id):
96 repo = self.sa.query(Repository) \
96 repo = self.sa.query(Repository) \
97 .filter(Repository.repo_id == repo_id)
97 .filter(Repository.repo_id == repo_id)
98
98
99 if cache:
100 repo = repo.options(
101 FromCache("sql_cache_short", "get_repo_%s" % repo_id))
102 return repo.scalar()
99 return repo.scalar()
103
100
104 def get_repo(self, repository):
101 def get_repo(self, repository):
105 return self._get_repo(repository)
102 return self._get_repo(repository)
106
103
107 def get_by_repo_name(self, repo_name, cache=False):
104 def get_by_repo_name(self, repo_name, cache=False):
108 repo = self.sa.query(Repository) \
105 repo = self.sa.query(Repository) \
109 .filter(Repository.repo_name == repo_name)
106 .filter(Repository.repo_name == repo_name)
110
107
111 if cache:
108 if cache:
112 name_key = _hash_key(repo_name)
109 name_key = _hash_key(repo_name)
113 repo = repo.options(
110 repo = repo.options(
114 FromCache("sql_cache_short", "get_repo_%s" % name_key))
111 FromCache("sql_cache_short", "get_repo_%s" % name_key))
115 return repo.scalar()
112 return repo.scalar()
116
113
117 def _extract_id_from_repo_name(self, repo_name):
114 def _extract_id_from_repo_name(self, repo_name):
118 if repo_name.startswith('/'):
115 if repo_name.startswith('/'):
119 repo_name = repo_name.lstrip('/')
116 repo_name = repo_name.lstrip('/')
120 by_id_match = re.match(r'^_(\d{1,})', repo_name)
117 by_id_match = re.match(r'^_(\d{1,})', repo_name)
121 if by_id_match:
118 if by_id_match:
122 return by_id_match.groups()[0]
119 return by_id_match.groups()[0]
123
120
124 def get_repo_by_id(self, repo_name):
121 def get_repo_by_id(self, repo_name):
125 """
122 """
126 Extracts repo_name by id from special urls.
123 Extracts repo_name by id from special urls.
127 Example url is _11/repo_name
124 Example url is _11/repo_name
128
125
129 :param repo_name:
126 :param repo_name:
130 :return: repo object if matched else None
127 :return: repo object if matched else None
131 """
128 """
132
129
133 try:
130 try:
134 _repo_id = self._extract_id_from_repo_name(repo_name)
131 _repo_id = self._extract_id_from_repo_name(repo_name)
135 if _repo_id:
132 if _repo_id:
136 return self.get(_repo_id)
133 return self.get(_repo_id)
137 except Exception:
134 except Exception:
138 log.exception('Failed to extract repo_name from URL')
135 log.exception('Failed to extract repo_name from URL')
139
136
140 return None
137 return None
141
138
142 def get_repos_for_root(self, root, traverse=False):
139 def get_repos_for_root(self, root, traverse=False):
143 if traverse:
140 if traverse:
144 like_expression = u'{}%'.format(safe_unicode(root))
141 like_expression = u'{}%'.format(safe_unicode(root))
145 repos = Repository.query().filter(
142 repos = Repository.query().filter(
146 Repository.repo_name.like(like_expression)).all()
143 Repository.repo_name.like(like_expression)).all()
147 else:
144 else:
148 if root and not isinstance(root, RepoGroup):
145 if root and not isinstance(root, RepoGroup):
149 raise ValueError(
146 raise ValueError(
150 'Root must be an instance '
147 'Root must be an instance '
151 'of RepoGroup, got:{} instead'.format(type(root)))
148 'of RepoGroup, got:{} instead'.format(type(root)))
152 repos = Repository.query().filter(Repository.group == root).all()
149 repos = Repository.query().filter(Repository.group == root).all()
153 return repos
150 return repos
154
151
155 def get_url(self, repo, request=None, permalink=False):
152 def get_url(self, repo, request=None, permalink=False):
156 if not request:
153 if not request:
157 request = get_current_request()
154 request = get_current_request()
158
155
159 if not request:
156 if not request:
160 return
157 return
161
158
162 if permalink:
159 if permalink:
163 return request.route_url(
160 return request.route_url(
164 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
161 'repo_summary', repo_name='_{}'.format(safe_str(repo.repo_id)))
165 else:
162 else:
166 return request.route_url(
163 return request.route_url(
167 'repo_summary', repo_name=safe_str(repo.repo_name))
164 'repo_summary', repo_name=safe_str(repo.repo_name))
168
165
169 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
166 def get_commit_url(self, repo, commit_id, request=None, permalink=False):
170 if not request:
167 if not request:
171 request = get_current_request()
168 request = get_current_request()
172
169
173 if not request:
170 if not request:
174 return
171 return
175
172
176 if permalink:
173 if permalink:
177 return request.route_url(
174 return request.route_url(
178 'repo_commit', repo_name=safe_str(repo.repo_id),
175 'repo_commit', repo_name=safe_str(repo.repo_id),
179 commit_id=commit_id)
176 commit_id=commit_id)
180
177
181 else:
178 else:
182 return request.route_url(
179 return request.route_url(
183 'repo_commit', repo_name=safe_str(repo.repo_name),
180 'repo_commit', repo_name=safe_str(repo.repo_name),
184 commit_id=commit_id)
181 commit_id=commit_id)
185
182
186 def get_repo_log(self, repo, filter_term):
183 def get_repo_log(self, repo, filter_term):
187 repo_log = UserLog.query()\
184 repo_log = UserLog.query()\
188 .filter(or_(UserLog.repository_id == repo.repo_id,
185 .filter(or_(UserLog.repository_id == repo.repo_id,
189 UserLog.repository_name == repo.repo_name))\
186 UserLog.repository_name == repo.repo_name))\
190 .options(joinedload(UserLog.user))\
187 .options(joinedload(UserLog.user))\
191 .options(joinedload(UserLog.repository))\
188 .options(joinedload(UserLog.repository))\
192 .order_by(UserLog.action_date.desc())
189 .order_by(UserLog.action_date.desc())
193
190
194 repo_log = user_log_filter(repo_log, filter_term)
191 repo_log = user_log_filter(repo_log, filter_term)
195 return repo_log
192 return repo_log
196
193
197 @classmethod
194 @classmethod
198 def update_repoinfo(cls, repositories=None):
195 def update_repoinfo(cls, repositories=None):
199 if not repositories:
196 if not repositories:
200 repositories = Repository.getAll()
197 repositories = Repository.getAll()
201 for repo in repositories:
198 for repo in repositories:
202 repo.update_commit_cache()
199 repo.update_commit_cache()
203
200
204 def get_repos_as_dict(self, repo_list=None, admin=False,
201 def get_repos_as_dict(self, repo_list=None, admin=False,
205 super_user_actions=False):
202 super_user_actions=False):
206 _render = get_current_request().get_partial_renderer(
203 _render = get_current_request().get_partial_renderer(
207 'rhodecode:templates/data_table/_dt_elements.mako')
204 'rhodecode:templates/data_table/_dt_elements.mako')
208 c = _render.get_call_context()
205 c = _render.get_call_context()
209
206
210 def quick_menu(repo_name):
207 def quick_menu(repo_name):
211 return _render('quick_menu', repo_name)
208 return _render('quick_menu', repo_name)
212
209
213 def repo_lnk(name, rtype, rstate, private, fork_of):
210 def repo_lnk(name, rtype, rstate, private, fork_of):
214 return _render('repo_name', name, rtype, rstate, private, fork_of,
211 return _render('repo_name', name, rtype, rstate, private, fork_of,
215 short_name=not admin, admin=False)
212 short_name=not admin, admin=False)
216
213
217 def last_change(last_change):
214 def last_change(last_change):
218 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
215 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
219 last_change = last_change + datetime.timedelta(seconds=
216 last_change = last_change + datetime.timedelta(seconds=
220 (datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
217 (datetime.datetime.now() - datetime.datetime.utcnow()).seconds)
221 return _render("last_change", last_change)
218 return _render("last_change", last_change)
222
219
223 def rss_lnk(repo_name):
220 def rss_lnk(repo_name):
224 return _render("rss", repo_name)
221 return _render("rss", repo_name)
225
222
226 def atom_lnk(repo_name):
223 def atom_lnk(repo_name):
227 return _render("atom", repo_name)
224 return _render("atom", repo_name)
228
225
229 def last_rev(repo_name, cs_cache):
226 def last_rev(repo_name, cs_cache):
230 return _render('revision', repo_name, cs_cache.get('revision'),
227 return _render('revision', repo_name, cs_cache.get('revision'),
231 cs_cache.get('raw_id'), cs_cache.get('author'),
228 cs_cache.get('raw_id'), cs_cache.get('author'),
232 cs_cache.get('message'), cs_cache.get('date'))
229 cs_cache.get('message'), cs_cache.get('date'))
233
230
234 def desc(desc):
231 def desc(desc):
235 return _render('repo_desc', desc, c.visual.stylify_metatags)
232 return _render('repo_desc', desc, c.visual.stylify_metatags)
236
233
237 def state(repo_state):
234 def state(repo_state):
238 return _render("repo_state", repo_state)
235 return _render("repo_state", repo_state)
239
236
240 def repo_actions(repo_name):
237 def repo_actions(repo_name):
241 return _render('repo_actions', repo_name, super_user_actions)
238 return _render('repo_actions', repo_name, super_user_actions)
242
239
243 def user_profile(username):
240 def user_profile(username):
244 return _render('user_profile', username)
241 return _render('user_profile', username)
245
242
246 repos_data = []
243 repos_data = []
247 for repo in repo_list:
244 for repo in repo_list:
248 cs_cache = repo.changeset_cache
245 cs_cache = repo.changeset_cache
249 row = {
246 row = {
250 "menu": quick_menu(repo.repo_name),
247 "menu": quick_menu(repo.repo_name),
251
248
252 "name": repo_lnk(repo.repo_name, repo.repo_type,
249 "name": repo_lnk(repo.repo_name, repo.repo_type,
253 repo.repo_state, repo.private, repo.fork),
250 repo.repo_state, repo.private, repo.fork),
254 "name_raw": repo.repo_name.lower(),
251 "name_raw": repo.repo_name.lower(),
255
252
256 "last_change": last_change(repo.last_db_change),
253 "last_change": last_change(repo.last_db_change),
257 "last_change_raw": datetime_to_time(repo.last_db_change),
254 "last_change_raw": datetime_to_time(repo.last_db_change),
258
255
259 "last_changeset": last_rev(repo.repo_name, cs_cache),
256 "last_changeset": last_rev(repo.repo_name, cs_cache),
260 "last_changeset_raw": cs_cache.get('revision'),
257 "last_changeset_raw": cs_cache.get('revision'),
261
258
262 "desc": desc(repo.description_safe),
259 "desc": desc(repo.description_safe),
263 "owner": user_profile(repo.user.username),
260 "owner": user_profile(repo.user.username),
264
261
265 "state": state(repo.repo_state),
262 "state": state(repo.repo_state),
266 "rss": rss_lnk(repo.repo_name),
263 "rss": rss_lnk(repo.repo_name),
267
264
268 "atom": atom_lnk(repo.repo_name),
265 "atom": atom_lnk(repo.repo_name),
269 }
266 }
270 if admin:
267 if admin:
271 row.update({
268 row.update({
272 "action": repo_actions(repo.repo_name),
269 "action": repo_actions(repo.repo_name),
273 })
270 })
274 repos_data.append(row)
271 repos_data.append(row)
275
272
276 return repos_data
273 return repos_data
277
274
278 def _get_defaults(self, repo_name):
275 def _get_defaults(self, repo_name):
279 """
276 """
280 Gets information about repository, and returns a dict for
277 Gets information about repository, and returns a dict for
281 usage in forms
278 usage in forms
282
279
283 :param repo_name:
280 :param repo_name:
284 """
281 """
285
282
286 repo_info = Repository.get_by_repo_name(repo_name)
283 repo_info = Repository.get_by_repo_name(repo_name)
287
284
288 if repo_info is None:
285 if repo_info is None:
289 return None
286 return None
290
287
291 defaults = repo_info.get_dict()
288 defaults = repo_info.get_dict()
292 defaults['repo_name'] = repo_info.just_name
289 defaults['repo_name'] = repo_info.just_name
293
290
294 groups = repo_info.groups_with_parents
291 groups = repo_info.groups_with_parents
295 parent_group = groups[-1] if groups else None
292 parent_group = groups[-1] if groups else None
296
293
297 # we use -1 as this is how in HTML, we mark an empty group
294 # we use -1 as this is how in HTML, we mark an empty group
298 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
295 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
299
296
300 keys_to_process = (
297 keys_to_process = (
301 {'k': 'repo_type', 'strip': False},
298 {'k': 'repo_type', 'strip': False},
302 {'k': 'repo_enable_downloads', 'strip': True},
299 {'k': 'repo_enable_downloads', 'strip': True},
303 {'k': 'repo_description', 'strip': True},
300 {'k': 'repo_description', 'strip': True},
304 {'k': 'repo_enable_locking', 'strip': True},
301 {'k': 'repo_enable_locking', 'strip': True},
305 {'k': 'repo_landing_rev', 'strip': True},
302 {'k': 'repo_landing_rev', 'strip': True},
306 {'k': 'clone_uri', 'strip': False},
303 {'k': 'clone_uri', 'strip': False},
307 {'k': 'push_uri', 'strip': False},
304 {'k': 'push_uri', 'strip': False},
308 {'k': 'repo_private', 'strip': True},
305 {'k': 'repo_private', 'strip': True},
309 {'k': 'repo_enable_statistics', 'strip': True}
306 {'k': 'repo_enable_statistics', 'strip': True}
310 )
307 )
311
308
312 for item in keys_to_process:
309 for item in keys_to_process:
313 attr = item['k']
310 attr = item['k']
314 if item['strip']:
311 if item['strip']:
315 attr = remove_prefix(item['k'], 'repo_')
312 attr = remove_prefix(item['k'], 'repo_')
316
313
317 val = defaults[attr]
314 val = defaults[attr]
318 if item['k'] == 'repo_landing_rev':
315 if item['k'] == 'repo_landing_rev':
319 val = ':'.join(defaults[attr])
316 val = ':'.join(defaults[attr])
320 defaults[item['k']] = val
317 defaults[item['k']] = val
321 if item['k'] == 'clone_uri':
318 if item['k'] == 'clone_uri':
322 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
319 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
323 if item['k'] == 'push_uri':
320 if item['k'] == 'push_uri':
324 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
321 defaults['push_uri_hidden'] = repo_info.push_uri_hidden
325
322
326 # fill owner
323 # fill owner
327 if repo_info.user:
324 if repo_info.user:
328 defaults.update({'user': repo_info.user.username})
325 defaults.update({'user': repo_info.user.username})
329 else:
326 else:
330 replacement_user = User.get_first_super_admin().username
327 replacement_user = User.get_first_super_admin().username
331 defaults.update({'user': replacement_user})
328 defaults.update({'user': replacement_user})
332
329
333 return defaults
330 return defaults
334
331
335 def update(self, repo, **kwargs):
332 def update(self, repo, **kwargs):
336 try:
333 try:
337 cur_repo = self._get_repo(repo)
334 cur_repo = self._get_repo(repo)
338 source_repo_name = cur_repo.repo_name
335 source_repo_name = cur_repo.repo_name
339 if 'user' in kwargs:
336 if 'user' in kwargs:
340 cur_repo.user = User.get_by_username(kwargs['user'])
337 cur_repo.user = User.get_by_username(kwargs['user'])
341
338
342 if 'repo_group' in kwargs:
339 if 'repo_group' in kwargs:
343 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
340 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
344 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
341 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
345
342
346 update_keys = [
343 update_keys = [
347 (1, 'repo_description'),
344 (1, 'repo_description'),
348 (1, 'repo_landing_rev'),
345 (1, 'repo_landing_rev'),
349 (1, 'repo_private'),
346 (1, 'repo_private'),
350 (1, 'repo_enable_downloads'),
347 (1, 'repo_enable_downloads'),
351 (1, 'repo_enable_locking'),
348 (1, 'repo_enable_locking'),
352 (1, 'repo_enable_statistics'),
349 (1, 'repo_enable_statistics'),
353 (0, 'clone_uri'),
350 (0, 'clone_uri'),
354 (0, 'push_uri'),
351 (0, 'push_uri'),
355 (0, 'fork_id')
352 (0, 'fork_id')
356 ]
353 ]
357 for strip, k in update_keys:
354 for strip, k in update_keys:
358 if k in kwargs:
355 if k in kwargs:
359 val = kwargs[k]
356 val = kwargs[k]
360 if strip:
357 if strip:
361 k = remove_prefix(k, 'repo_')
358 k = remove_prefix(k, 'repo_')
362
359
363 setattr(cur_repo, k, val)
360 setattr(cur_repo, k, val)
364
361
365 new_name = cur_repo.get_new_name(kwargs['repo_name'])
362 new_name = cur_repo.get_new_name(kwargs['repo_name'])
366 cur_repo.repo_name = new_name
363 cur_repo.repo_name = new_name
367
364
368 # if private flag is set, reset default permission to NONE
365 # if private flag is set, reset default permission to NONE
369 if kwargs.get('repo_private'):
366 if kwargs.get('repo_private'):
370 EMPTY_PERM = 'repository.none'
367 EMPTY_PERM = 'repository.none'
371 RepoModel().grant_user_permission(
368 RepoModel().grant_user_permission(
372 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
369 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
373 )
370 )
374
371
375 # handle extra fields
372 # handle extra fields
376 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
373 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
377 kwargs):
374 kwargs):
378 k = RepositoryField.un_prefix_key(field)
375 k = RepositoryField.un_prefix_key(field)
379 ex_field = RepositoryField.get_by_key_name(
376 ex_field = RepositoryField.get_by_key_name(
380 key=k, repo=cur_repo)
377 key=k, repo=cur_repo)
381 if ex_field:
378 if ex_field:
382 ex_field.field_value = kwargs[field]
379 ex_field.field_value = kwargs[field]
383 self.sa.add(ex_field)
380 self.sa.add(ex_field)
384 cur_repo.updated_on = datetime.datetime.now()
381 cur_repo.updated_on = datetime.datetime.now()
385 self.sa.add(cur_repo)
382 self.sa.add(cur_repo)
386
383
387 if source_repo_name != new_name:
384 if source_repo_name != new_name:
388 # rename repository
385 # rename repository
389 self._rename_filesystem_repo(
386 self._rename_filesystem_repo(
390 old=source_repo_name, new=new_name)
387 old=source_repo_name, new=new_name)
391
388
392 return cur_repo
389 return cur_repo
393 except Exception:
390 except Exception:
394 log.error(traceback.format_exc())
391 log.error(traceback.format_exc())
395 raise
392 raise
396
393
397 def _create_repo(self, repo_name, repo_type, description, owner,
394 def _create_repo(self, repo_name, repo_type, description, owner,
398 private=False, clone_uri=None, repo_group=None,
395 private=False, clone_uri=None, repo_group=None,
399 landing_rev='rev:tip', fork_of=None,
396 landing_rev='rev:tip', fork_of=None,
400 copy_fork_permissions=False, enable_statistics=False,
397 copy_fork_permissions=False, enable_statistics=False,
401 enable_locking=False, enable_downloads=False,
398 enable_locking=False, enable_downloads=False,
402 copy_group_permissions=False,
399 copy_group_permissions=False,
403 state=Repository.STATE_PENDING):
400 state=Repository.STATE_PENDING):
404 """
401 """
405 Create repository inside database with PENDING state, this should be
402 Create repository inside database with PENDING state, this should be
406 only executed by create() repo. With exception of importing existing
403 only executed by create() repo. With exception of importing existing
407 repos
404 repos
408 """
405 """
409 from rhodecode.model.scm import ScmModel
406 from rhodecode.model.scm import ScmModel
410
407
411 owner = self._get_user(owner)
408 owner = self._get_user(owner)
412 fork_of = self._get_repo(fork_of)
409 fork_of = self._get_repo(fork_of)
413 repo_group = self._get_repo_group(safe_int(repo_group))
410 repo_group = self._get_repo_group(safe_int(repo_group))
414
411
415 try:
412 try:
416 repo_name = safe_unicode(repo_name)
413 repo_name = safe_unicode(repo_name)
417 description = safe_unicode(description)
414 description = safe_unicode(description)
418 # repo name is just a name of repository
415 # repo name is just a name of repository
419 # while repo_name_full is a full qualified name that is combined
416 # while repo_name_full is a full qualified name that is combined
420 # with name and path of group
417 # with name and path of group
421 repo_name_full = repo_name
418 repo_name_full = repo_name
422 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
419 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
423
420
424 new_repo = Repository()
421 new_repo = Repository()
425 new_repo.repo_state = state
422 new_repo.repo_state = state
426 new_repo.enable_statistics = False
423 new_repo.enable_statistics = False
427 new_repo.repo_name = repo_name_full
424 new_repo.repo_name = repo_name_full
428 new_repo.repo_type = repo_type
425 new_repo.repo_type = repo_type
429 new_repo.user = owner
426 new_repo.user = owner
430 new_repo.group = repo_group
427 new_repo.group = repo_group
431 new_repo.description = description or repo_name
428 new_repo.description = description or repo_name
432 new_repo.private = private
429 new_repo.private = private
433 new_repo.clone_uri = clone_uri
430 new_repo.clone_uri = clone_uri
434 new_repo.landing_rev = landing_rev
431 new_repo.landing_rev = landing_rev
435
432
436 new_repo.enable_statistics = enable_statistics
433 new_repo.enable_statistics = enable_statistics
437 new_repo.enable_locking = enable_locking
434 new_repo.enable_locking = enable_locking
438 new_repo.enable_downloads = enable_downloads
435 new_repo.enable_downloads = enable_downloads
439
436
440 if repo_group:
437 if repo_group:
441 new_repo.enable_locking = repo_group.enable_locking
438 new_repo.enable_locking = repo_group.enable_locking
442
439
443 if fork_of:
440 if fork_of:
444 parent_repo = fork_of
441 parent_repo = fork_of
445 new_repo.fork = parent_repo
442 new_repo.fork = parent_repo
446
443
447 events.trigger(events.RepoPreCreateEvent(new_repo))
444 events.trigger(events.RepoPreCreateEvent(new_repo))
448
445
449 self.sa.add(new_repo)
446 self.sa.add(new_repo)
450
447
451 EMPTY_PERM = 'repository.none'
448 EMPTY_PERM = 'repository.none'
452 if fork_of and copy_fork_permissions:
449 if fork_of and copy_fork_permissions:
453 repo = fork_of
450 repo = fork_of
454 user_perms = UserRepoToPerm.query() \
451 user_perms = UserRepoToPerm.query() \
455 .filter(UserRepoToPerm.repository == repo).all()
452 .filter(UserRepoToPerm.repository == repo).all()
456 group_perms = UserGroupRepoToPerm.query() \
453 group_perms = UserGroupRepoToPerm.query() \
457 .filter(UserGroupRepoToPerm.repository == repo).all()
454 .filter(UserGroupRepoToPerm.repository == repo).all()
458
455
459 for perm in user_perms:
456 for perm in user_perms:
460 UserRepoToPerm.create(
457 UserRepoToPerm.create(
461 perm.user, new_repo, perm.permission)
458 perm.user, new_repo, perm.permission)
462
459
463 for perm in group_perms:
460 for perm in group_perms:
464 UserGroupRepoToPerm.create(
461 UserGroupRepoToPerm.create(
465 perm.users_group, new_repo, perm.permission)
462 perm.users_group, new_repo, perm.permission)
466 # in case we copy permissions and also set this repo to private
463 # in case we copy permissions and also set this repo to private
467 # override the default user permission to make it a private
464 # override the default user permission to make it a private
468 # repo
465 # repo
469 if private:
466 if private:
470 RepoModel(self.sa).grant_user_permission(
467 RepoModel(self.sa).grant_user_permission(
471 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
468 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
472
469
473 elif repo_group and copy_group_permissions:
470 elif repo_group and copy_group_permissions:
474 user_perms = UserRepoGroupToPerm.query() \
471 user_perms = UserRepoGroupToPerm.query() \
475 .filter(UserRepoGroupToPerm.group == repo_group).all()
472 .filter(UserRepoGroupToPerm.group == repo_group).all()
476
473
477 group_perms = UserGroupRepoGroupToPerm.query() \
474 group_perms = UserGroupRepoGroupToPerm.query() \
478 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
475 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
479
476
480 for perm in user_perms:
477 for perm in user_perms:
481 perm_name = perm.permission.permission_name.replace(
478 perm_name = perm.permission.permission_name.replace(
482 'group.', 'repository.')
479 'group.', 'repository.')
483 perm_obj = Permission.get_by_key(perm_name)
480 perm_obj = Permission.get_by_key(perm_name)
484 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
481 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
485
482
486 for perm in group_perms:
483 for perm in group_perms:
487 perm_name = perm.permission.permission_name.replace(
484 perm_name = perm.permission.permission_name.replace(
488 'group.', 'repository.')
485 'group.', 'repository.')
489 perm_obj = Permission.get_by_key(perm_name)
486 perm_obj = Permission.get_by_key(perm_name)
490 UserGroupRepoToPerm.create(
487 UserGroupRepoToPerm.create(
491 perm.users_group, new_repo, perm_obj)
488 perm.users_group, new_repo, perm_obj)
492
489
493 if private:
490 if private:
494 RepoModel(self.sa).grant_user_permission(
491 RepoModel(self.sa).grant_user_permission(
495 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
492 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
496
493
497 else:
494 else:
498 perm_obj = self._create_default_perms(new_repo, private)
495 perm_obj = self._create_default_perms(new_repo, private)
499 self.sa.add(perm_obj)
496 self.sa.add(perm_obj)
500
497
501 # now automatically start following this repository as owner
498 # now automatically start following this repository as owner
502 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
499 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
503 owner.user_id)
500 owner.user_id)
504
501
505 # we need to flush here, in order to check if database won't
502 # we need to flush here, in order to check if database won't
506 # throw any exceptions, create filesystem dirs at the very end
503 # throw any exceptions, create filesystem dirs at the very end
507 self.sa.flush()
504 self.sa.flush()
508 events.trigger(events.RepoCreateEvent(new_repo))
505 events.trigger(events.RepoCreateEvent(new_repo))
509 return new_repo
506 return new_repo
510
507
511 except Exception:
508 except Exception:
512 log.error(traceback.format_exc())
509 log.error(traceback.format_exc())
513 raise
510 raise
514
511
515 def create(self, form_data, cur_user):
512 def create(self, form_data, cur_user):
516 """
513 """
517 Create repository using celery tasks
514 Create repository using celery tasks
518
515
519 :param form_data:
516 :param form_data:
520 :param cur_user:
517 :param cur_user:
521 """
518 """
522 from rhodecode.lib.celerylib import tasks, run_task
519 from rhodecode.lib.celerylib import tasks, run_task
523 return run_task(tasks.create_repo, form_data, cur_user)
520 return run_task(tasks.create_repo, form_data, cur_user)
524
521
525 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
522 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
526 perm_deletions=None, check_perms=True,
523 perm_deletions=None, check_perms=True,
527 cur_user=None):
524 cur_user=None):
528 if not perm_additions:
525 if not perm_additions:
529 perm_additions = []
526 perm_additions = []
530 if not perm_updates:
527 if not perm_updates:
531 perm_updates = []
528 perm_updates = []
532 if not perm_deletions:
529 if not perm_deletions:
533 perm_deletions = []
530 perm_deletions = []
534
531
535 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
532 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
536
533
537 changes = {
534 changes = {
538 'added': [],
535 'added': [],
539 'updated': [],
536 'updated': [],
540 'deleted': []
537 'deleted': []
541 }
538 }
542 # update permissions
539 # update permissions
543 for member_id, perm, member_type in perm_updates:
540 for member_id, perm, member_type in perm_updates:
544 member_id = int(member_id)
541 member_id = int(member_id)
545 if member_type == 'user':
542 if member_type == 'user':
546 member_name = User.get(member_id).username
543 member_name = User.get(member_id).username
547 # this updates also current one if found
544 # this updates also current one if found
548 self.grant_user_permission(
545 self.grant_user_permission(
549 repo=repo, user=member_id, perm=perm)
546 repo=repo, user=member_id, perm=perm)
550 elif member_type == 'user_group':
547 elif member_type == 'user_group':
551 # check if we have permissions to alter this usergroup
548 # check if we have permissions to alter this usergroup
552 member_name = UserGroup.get(member_id).users_group_name
549 member_name = UserGroup.get(member_id).users_group_name
553 if not check_perms or HasUserGroupPermissionAny(
550 if not check_perms or HasUserGroupPermissionAny(
554 *req_perms)(member_name, user=cur_user):
551 *req_perms)(member_name, user=cur_user):
555 self.grant_user_group_permission(
552 self.grant_user_group_permission(
556 repo=repo, group_name=member_id, perm=perm)
553 repo=repo, group_name=member_id, perm=perm)
557 else:
554 else:
558 raise ValueError("member_type must be 'user' or 'user_group' "
555 raise ValueError("member_type must be 'user' or 'user_group' "
559 "got {} instead".format(member_type))
556 "got {} instead".format(member_type))
560 changes['updated'].append({'type': member_type, 'id': member_id,
557 changes['updated'].append({'type': member_type, 'id': member_id,
561 'name': member_name, 'new_perm': perm})
558 'name': member_name, 'new_perm': perm})
562
559
563 # set new permissions
560 # set new permissions
564 for member_id, perm, member_type in perm_additions:
561 for member_id, perm, member_type in perm_additions:
565 member_id = int(member_id)
562 member_id = int(member_id)
566 if member_type == 'user':
563 if member_type == 'user':
567 member_name = User.get(member_id).username
564 member_name = User.get(member_id).username
568 self.grant_user_permission(
565 self.grant_user_permission(
569 repo=repo, user=member_id, perm=perm)
566 repo=repo, user=member_id, perm=perm)
570 elif member_type == 'user_group':
567 elif member_type == 'user_group':
571 # check if we have permissions to alter this usergroup
568 # check if we have permissions to alter this usergroup
572 member_name = UserGroup.get(member_id).users_group_name
569 member_name = UserGroup.get(member_id).users_group_name
573 if not check_perms or HasUserGroupPermissionAny(
570 if not check_perms or HasUserGroupPermissionAny(
574 *req_perms)(member_name, user=cur_user):
571 *req_perms)(member_name, user=cur_user):
575 self.grant_user_group_permission(
572 self.grant_user_group_permission(
576 repo=repo, group_name=member_id, perm=perm)
573 repo=repo, group_name=member_id, perm=perm)
577 else:
574 else:
578 raise ValueError("member_type must be 'user' or 'user_group' "
575 raise ValueError("member_type must be 'user' or 'user_group' "
579 "got {} instead".format(member_type))
576 "got {} instead".format(member_type))
580
577
581 changes['added'].append({'type': member_type, 'id': member_id,
578 changes['added'].append({'type': member_type, 'id': member_id,
582 'name': member_name, 'new_perm': perm})
579 'name': member_name, 'new_perm': perm})
583 # delete permissions
580 # delete permissions
584 for member_id, perm, member_type in perm_deletions:
581 for member_id, perm, member_type in perm_deletions:
585 member_id = int(member_id)
582 member_id = int(member_id)
586 if member_type == 'user':
583 if member_type == 'user':
587 member_name = User.get(member_id).username
584 member_name = User.get(member_id).username
588 self.revoke_user_permission(repo=repo, user=member_id)
585 self.revoke_user_permission(repo=repo, user=member_id)
589 elif member_type == 'user_group':
586 elif member_type == 'user_group':
590 # check if we have permissions to alter this usergroup
587 # check if we have permissions to alter this usergroup
591 member_name = UserGroup.get(member_id).users_group_name
588 member_name = UserGroup.get(member_id).users_group_name
592 if not check_perms or HasUserGroupPermissionAny(
589 if not check_perms or HasUserGroupPermissionAny(
593 *req_perms)(member_name, user=cur_user):
590 *req_perms)(member_name, user=cur_user):
594 self.revoke_user_group_permission(
591 self.revoke_user_group_permission(
595 repo=repo, group_name=member_id)
592 repo=repo, group_name=member_id)
596 else:
593 else:
597 raise ValueError("member_type must be 'user' or 'user_group' "
594 raise ValueError("member_type must be 'user' or 'user_group' "
598 "got {} instead".format(member_type))
595 "got {} instead".format(member_type))
599
596
600 changes['deleted'].append({'type': member_type, 'id': member_id,
597 changes['deleted'].append({'type': member_type, 'id': member_id,
601 'name': member_name, 'new_perm': perm})
598 'name': member_name, 'new_perm': perm})
602 return changes
599 return changes
603
600
604 def create_fork(self, form_data, cur_user):
601 def create_fork(self, form_data, cur_user):
605 """
602 """
606 Simple wrapper into executing celery task for fork creation
603 Simple wrapper into executing celery task for fork creation
607
604
608 :param form_data:
605 :param form_data:
609 :param cur_user:
606 :param cur_user:
610 """
607 """
611 from rhodecode.lib.celerylib import tasks, run_task
608 from rhodecode.lib.celerylib import tasks, run_task
612 return run_task(tasks.create_repo_fork, form_data, cur_user)
609 return run_task(tasks.create_repo_fork, form_data, cur_user)
613
610
614 def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
611 def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
615 """
612 """
616 Delete given repository, forks parameter defines what do do with
613 Delete given repository, forks parameter defines what do do with
617 attached forks. Throws AttachedForksError if deleted repo has attached
614 attached forks. Throws AttachedForksError if deleted repo has attached
618 forks
615 forks
619
616
620 :param repo:
617 :param repo:
621 :param forks: str 'delete' or 'detach'
618 :param forks: str 'delete' or 'detach'
622 :param fs_remove: remove(archive) repo from filesystem
619 :param fs_remove: remove(archive) repo from filesystem
623 """
620 """
624 if not cur_user:
621 if not cur_user:
625 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
622 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
626 repo = self._get_repo(repo)
623 repo = self._get_repo(repo)
627 if repo:
624 if repo:
628 if forks == 'detach':
625 if forks == 'detach':
629 for r in repo.forks:
626 for r in repo.forks:
630 r.fork = None
627 r.fork = None
631 self.sa.add(r)
628 self.sa.add(r)
632 elif forks == 'delete':
629 elif forks == 'delete':
633 for r in repo.forks:
630 for r in repo.forks:
634 self.delete(r, forks='delete')
631 self.delete(r, forks='delete')
635 elif [f for f in repo.forks]:
632 elif [f for f in repo.forks]:
636 raise AttachedForksError()
633 raise AttachedForksError()
637
634
638 old_repo_dict = repo.get_dict()
635 old_repo_dict = repo.get_dict()
639 events.trigger(events.RepoPreDeleteEvent(repo))
636 events.trigger(events.RepoPreDeleteEvent(repo))
640 try:
637 try:
641 self.sa.delete(repo)
638 self.sa.delete(repo)
642 if fs_remove:
639 if fs_remove:
643 self._delete_filesystem_repo(repo)
640 self._delete_filesystem_repo(repo)
644 else:
641 else:
645 log.debug('skipping removal from filesystem')
642 log.debug('skipping removal from filesystem')
646 old_repo_dict.update({
643 old_repo_dict.update({
647 'deleted_by': cur_user,
644 'deleted_by': cur_user,
648 'deleted_on': time.time(),
645 'deleted_on': time.time(),
649 })
646 })
650 log_delete_repository(**old_repo_dict)
647 log_delete_repository(**old_repo_dict)
651 events.trigger(events.RepoDeleteEvent(repo))
648 events.trigger(events.RepoDeleteEvent(repo))
652 except Exception:
649 except Exception:
653 log.error(traceback.format_exc())
650 log.error(traceback.format_exc())
654 raise
651 raise
655
652
656 def grant_user_permission(self, repo, user, perm):
653 def grant_user_permission(self, repo, user, perm):
657 """
654 """
658 Grant permission for user on given repository, or update existing one
655 Grant permission for user on given repository, or update existing one
659 if found
656 if found
660
657
661 :param repo: Instance of Repository, repository_id, or repository name
658 :param repo: Instance of Repository, repository_id, or repository name
662 :param user: Instance of User, user_id or username
659 :param user: Instance of User, user_id or username
663 :param perm: Instance of Permission, or permission_name
660 :param perm: Instance of Permission, or permission_name
664 """
661 """
665 user = self._get_user(user)
662 user = self._get_user(user)
666 repo = self._get_repo(repo)
663 repo = self._get_repo(repo)
667 permission = self._get_perm(perm)
664 permission = self._get_perm(perm)
668
665
669 # check if we have that permission already
666 # check if we have that permission already
670 obj = self.sa.query(UserRepoToPerm) \
667 obj = self.sa.query(UserRepoToPerm) \
671 .filter(UserRepoToPerm.user == user) \
668 .filter(UserRepoToPerm.user == user) \
672 .filter(UserRepoToPerm.repository == repo) \
669 .filter(UserRepoToPerm.repository == repo) \
673 .scalar()
670 .scalar()
674 if obj is None:
671 if obj is None:
675 # create new !
672 # create new !
676 obj = UserRepoToPerm()
673 obj = UserRepoToPerm()
677 obj.repository = repo
674 obj.repository = repo
678 obj.user = user
675 obj.user = user
679 obj.permission = permission
676 obj.permission = permission
680 self.sa.add(obj)
677 self.sa.add(obj)
681 log.debug('Granted perm %s to %s on %s', perm, user, repo)
678 log.debug('Granted perm %s to %s on %s', perm, user, repo)
682 action_logger_generic(
679 action_logger_generic(
683 'granted permission: {} to user: {} on repo: {}'.format(
680 'granted permission: {} to user: {} on repo: {}'.format(
684 perm, user, repo), namespace='security.repo')
681 perm, user, repo), namespace='security.repo')
685 return obj
682 return obj
686
683
687 def revoke_user_permission(self, repo, user):
684 def revoke_user_permission(self, repo, user):
688 """
685 """
689 Revoke permission for user on given repository
686 Revoke permission for user on given repository
690
687
691 :param repo: Instance of Repository, repository_id, or repository name
688 :param repo: Instance of Repository, repository_id, or repository name
692 :param user: Instance of User, user_id or username
689 :param user: Instance of User, user_id or username
693 """
690 """
694
691
695 user = self._get_user(user)
692 user = self._get_user(user)
696 repo = self._get_repo(repo)
693 repo = self._get_repo(repo)
697
694
698 obj = self.sa.query(UserRepoToPerm) \
695 obj = self.sa.query(UserRepoToPerm) \
699 .filter(UserRepoToPerm.repository == repo) \
696 .filter(UserRepoToPerm.repository == repo) \
700 .filter(UserRepoToPerm.user == user) \
697 .filter(UserRepoToPerm.user == user) \
701 .scalar()
698 .scalar()
702 if obj:
699 if obj:
703 self.sa.delete(obj)
700 self.sa.delete(obj)
704 log.debug('Revoked perm on %s on %s', repo, user)
701 log.debug('Revoked perm on %s on %s', repo, user)
705 action_logger_generic(
702 action_logger_generic(
706 'revoked permission from user: {} on repo: {}'.format(
703 'revoked permission from user: {} on repo: {}'.format(
707 user, repo), namespace='security.repo')
704 user, repo), namespace='security.repo')
708
705
709 def grant_user_group_permission(self, repo, group_name, perm):
706 def grant_user_group_permission(self, repo, group_name, perm):
710 """
707 """
711 Grant permission for user group on given repository, or update
708 Grant permission for user group on given repository, or update
712 existing one if found
709 existing one if found
713
710
714 :param repo: Instance of Repository, repository_id, or repository name
711 :param repo: Instance of Repository, repository_id, or repository name
715 :param group_name: Instance of UserGroup, users_group_id,
712 :param group_name: Instance of UserGroup, users_group_id,
716 or user group name
713 or user group name
717 :param perm: Instance of Permission, or permission_name
714 :param perm: Instance of Permission, or permission_name
718 """
715 """
719 repo = self._get_repo(repo)
716 repo = self._get_repo(repo)
720 group_name = self._get_user_group(group_name)
717 group_name = self._get_user_group(group_name)
721 permission = self._get_perm(perm)
718 permission = self._get_perm(perm)
722
719
723 # check if we have that permission already
720 # check if we have that permission already
724 obj = self.sa.query(UserGroupRepoToPerm) \
721 obj = self.sa.query(UserGroupRepoToPerm) \
725 .filter(UserGroupRepoToPerm.users_group == group_name) \
722 .filter(UserGroupRepoToPerm.users_group == group_name) \
726 .filter(UserGroupRepoToPerm.repository == repo) \
723 .filter(UserGroupRepoToPerm.repository == repo) \
727 .scalar()
724 .scalar()
728
725
729 if obj is None:
726 if obj is None:
730 # create new
727 # create new
731 obj = UserGroupRepoToPerm()
728 obj = UserGroupRepoToPerm()
732
729
733 obj.repository = repo
730 obj.repository = repo
734 obj.users_group = group_name
731 obj.users_group = group_name
735 obj.permission = permission
732 obj.permission = permission
736 self.sa.add(obj)
733 self.sa.add(obj)
737 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
734 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
738 action_logger_generic(
735 action_logger_generic(
739 'granted permission: {} to usergroup: {} on repo: {}'.format(
736 'granted permission: {} to usergroup: {} on repo: {}'.format(
740 perm, group_name, repo), namespace='security.repo')
737 perm, group_name, repo), namespace='security.repo')
741
738
742 return obj
739 return obj
743
740
744 def revoke_user_group_permission(self, repo, group_name):
741 def revoke_user_group_permission(self, repo, group_name):
745 """
742 """
746 Revoke permission for user group on given repository
743 Revoke permission for user group on given repository
747
744
748 :param repo: Instance of Repository, repository_id, or repository name
745 :param repo: Instance of Repository, repository_id, or repository name
749 :param group_name: Instance of UserGroup, users_group_id,
746 :param group_name: Instance of UserGroup, users_group_id,
750 or user group name
747 or user group name
751 """
748 """
752 repo = self._get_repo(repo)
749 repo = self._get_repo(repo)
753 group_name = self._get_user_group(group_name)
750 group_name = self._get_user_group(group_name)
754
751
755 obj = self.sa.query(UserGroupRepoToPerm) \
752 obj = self.sa.query(UserGroupRepoToPerm) \
756 .filter(UserGroupRepoToPerm.repository == repo) \
753 .filter(UserGroupRepoToPerm.repository == repo) \
757 .filter(UserGroupRepoToPerm.users_group == group_name) \
754 .filter(UserGroupRepoToPerm.users_group == group_name) \
758 .scalar()
755 .scalar()
759 if obj:
756 if obj:
760 self.sa.delete(obj)
757 self.sa.delete(obj)
761 log.debug('Revoked perm to %s on %s', repo, group_name)
758 log.debug('Revoked perm to %s on %s', repo, group_name)
762 action_logger_generic(
759 action_logger_generic(
763 'revoked permission from usergroup: {} on repo: {}'.format(
760 'revoked permission from usergroup: {} on repo: {}'.format(
764 group_name, repo), namespace='security.repo')
761 group_name, repo), namespace='security.repo')
765
762
766 def delete_stats(self, repo_name):
763 def delete_stats(self, repo_name):
767 """
764 """
768 removes stats for given repo
765 removes stats for given repo
769
766
770 :param repo_name:
767 :param repo_name:
771 """
768 """
772 repo = self._get_repo(repo_name)
769 repo = self._get_repo(repo_name)
773 try:
770 try:
774 obj = self.sa.query(Statistics) \
771 obj = self.sa.query(Statistics) \
775 .filter(Statistics.repository == repo).scalar()
772 .filter(Statistics.repository == repo).scalar()
776 if obj:
773 if obj:
777 self.sa.delete(obj)
774 self.sa.delete(obj)
778 except Exception:
775 except Exception:
779 log.error(traceback.format_exc())
776 log.error(traceback.format_exc())
780 raise
777 raise
781
778
782 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
779 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
783 field_type='str', field_desc=''):
780 field_type='str', field_desc=''):
784
781
785 repo = self._get_repo(repo_name)
782 repo = self._get_repo(repo_name)
786
783
787 new_field = RepositoryField()
784 new_field = RepositoryField()
788 new_field.repository = repo
785 new_field.repository = repo
789 new_field.field_key = field_key
786 new_field.field_key = field_key
790 new_field.field_type = field_type # python type
787 new_field.field_type = field_type # python type
791 new_field.field_value = field_value
788 new_field.field_value = field_value
792 new_field.field_desc = field_desc
789 new_field.field_desc = field_desc
793 new_field.field_label = field_label
790 new_field.field_label = field_label
794 self.sa.add(new_field)
791 self.sa.add(new_field)
795 return new_field
792 return new_field
796
793
797 def delete_repo_field(self, repo_name, field_key):
794 def delete_repo_field(self, repo_name, field_key):
798 repo = self._get_repo(repo_name)
795 repo = self._get_repo(repo_name)
799 field = RepositoryField.get_by_key_name(field_key, repo)
796 field = RepositoryField.get_by_key_name(field_key, repo)
800 if field:
797 if field:
801 self.sa.delete(field)
798 self.sa.delete(field)
802
799
803 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
800 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
804 clone_uri=None, repo_store_location=None,
801 clone_uri=None, repo_store_location=None,
805 use_global_config=False):
802 use_global_config=False):
806 """
803 """
807 makes repository on filesystem. It's group aware means it'll create
804 makes repository on filesystem. It's group aware means it'll create
808 a repository within a group, and alter the paths accordingly of
805 a repository within a group, and alter the paths accordingly of
809 group location
806 group location
810
807
811 :param repo_name:
808 :param repo_name:
812 :param alias:
809 :param alias:
813 :param parent:
810 :param parent:
814 :param clone_uri:
811 :param clone_uri:
815 :param repo_store_location:
812 :param repo_store_location:
816 """
813 """
817 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
814 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
818 from rhodecode.model.scm import ScmModel
815 from rhodecode.model.scm import ScmModel
819
816
820 if Repository.NAME_SEP in repo_name:
817 if Repository.NAME_SEP in repo_name:
821 raise ValueError(
818 raise ValueError(
822 'repo_name must not contain groups got `%s`' % repo_name)
819 'repo_name must not contain groups got `%s`' % repo_name)
823
820
824 if isinstance(repo_group, RepoGroup):
821 if isinstance(repo_group, RepoGroup):
825 new_parent_path = os.sep.join(repo_group.full_path_splitted)
822 new_parent_path = os.sep.join(repo_group.full_path_splitted)
826 else:
823 else:
827 new_parent_path = repo_group or ''
824 new_parent_path = repo_group or ''
828
825
829 if repo_store_location:
826 if repo_store_location:
830 _paths = [repo_store_location]
827 _paths = [repo_store_location]
831 else:
828 else:
832 _paths = [self.repos_path, new_parent_path, repo_name]
829 _paths = [self.repos_path, new_parent_path, repo_name]
833 # we need to make it str for mercurial
830 # we need to make it str for mercurial
834 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
831 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
835
832
836 # check if this path is not a repository
833 # check if this path is not a repository
837 if is_valid_repo(repo_path, self.repos_path):
834 if is_valid_repo(repo_path, self.repos_path):
838 raise Exception('This path %s is a valid repository' % repo_path)
835 raise Exception('This path %s is a valid repository' % repo_path)
839
836
840 # check if this path is a group
837 # check if this path is a group
841 if is_valid_repo_group(repo_path, self.repos_path):
838 if is_valid_repo_group(repo_path, self.repos_path):
842 raise Exception('This path %s is a valid group' % repo_path)
839 raise Exception('This path %s is a valid group' % repo_path)
843
840
844 log.info('creating repo %s in %s from url: `%s`',
841 log.info('creating repo %s in %s from url: `%s`',
845 repo_name, safe_unicode(repo_path),
842 repo_name, safe_unicode(repo_path),
846 obfuscate_url_pw(clone_uri))
843 obfuscate_url_pw(clone_uri))
847
844
848 backend = get_backend(repo_type)
845 backend = get_backend(repo_type)
849
846
850 config_repo = None if use_global_config else repo_name
847 config_repo = None if use_global_config else repo_name
851 if config_repo and new_parent_path:
848 if config_repo and new_parent_path:
852 config_repo = Repository.NAME_SEP.join(
849 config_repo = Repository.NAME_SEP.join(
853 (new_parent_path, config_repo))
850 (new_parent_path, config_repo))
854 config = make_db_config(clear_session=False, repo=config_repo)
851 config = make_db_config(clear_session=False, repo=config_repo)
855 config.set('extensions', 'largefiles', '')
852 config.set('extensions', 'largefiles', '')
856
853
857 # patch and reset hooks section of UI config to not run any
854 # patch and reset hooks section of UI config to not run any
858 # hooks on creating remote repo
855 # hooks on creating remote repo
859 config.clear_section('hooks')
856 config.clear_section('hooks')
860
857
861 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
858 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
862 if repo_type == 'git':
859 if repo_type == 'git':
863 repo = backend(
860 repo = backend(
864 repo_path, config=config, create=True, src_url=clone_uri,
861 repo_path, config=config, create=True, src_url=clone_uri,
865 bare=True)
862 bare=True)
866 else:
863 else:
867 repo = backend(
864 repo = backend(
868 repo_path, config=config, create=True, src_url=clone_uri)
865 repo_path, config=config, create=True, src_url=clone_uri)
869
866
870 repo.install_hooks()
867 repo.install_hooks()
871
868
872 log.debug('Created repo %s with %s backend',
869 log.debug('Created repo %s with %s backend',
873 safe_unicode(repo_name), safe_unicode(repo_type))
870 safe_unicode(repo_name), safe_unicode(repo_type))
874 return repo
871 return repo
875
872
876 def _rename_filesystem_repo(self, old, new):
873 def _rename_filesystem_repo(self, old, new):
877 """
874 """
878 renames repository on filesystem
875 renames repository on filesystem
879
876
880 :param old: old name
877 :param old: old name
881 :param new: new name
878 :param new: new name
882 """
879 """
883 log.info('renaming repo from %s to %s', old, new)
880 log.info('renaming repo from %s to %s', old, new)
884
881
885 old_path = os.path.join(self.repos_path, old)
882 old_path = os.path.join(self.repos_path, old)
886 new_path = os.path.join(self.repos_path, new)
883 new_path = os.path.join(self.repos_path, new)
887 if os.path.isdir(new_path):
884 if os.path.isdir(new_path):
888 raise Exception(
885 raise Exception(
889 'Was trying to rename to already existing dir %s' % new_path
886 'Was trying to rename to already existing dir %s' % new_path
890 )
887 )
891 shutil.move(old_path, new_path)
888 shutil.move(old_path, new_path)
892
889
893 def _delete_filesystem_repo(self, repo):
890 def _delete_filesystem_repo(self, repo):
894 """
891 """
895 removes repo from filesystem, the removal is acctually made by
892 removes repo from filesystem, the removal is acctually made by
896 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
893 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
897 repository is no longer valid for rhodecode, can be undeleted later on
894 repository is no longer valid for rhodecode, can be undeleted later on
898 by reverting the renames on this repository
895 by reverting the renames on this repository
899
896
900 :param repo: repo object
897 :param repo: repo object
901 """
898 """
902 rm_path = os.path.join(self.repos_path, repo.repo_name)
899 rm_path = os.path.join(self.repos_path, repo.repo_name)
903 repo_group = repo.group
900 repo_group = repo.group
904 log.info("Removing repository %s", rm_path)
901 log.info("Removing repository %s", rm_path)
905 # disable hg/git internal that it doesn't get detected as repo
902 # disable hg/git internal that it doesn't get detected as repo
906 alias = repo.repo_type
903 alias = repo.repo_type
907
904
908 config = make_db_config(clear_session=False)
905 config = make_db_config(clear_session=False)
909 config.set('extensions', 'largefiles', '')
906 config.set('extensions', 'largefiles', '')
910 bare = getattr(repo.scm_instance(config=config), 'bare', False)
907 bare = getattr(repo.scm_instance(config=config), 'bare', False)
911
908
912 # skip this for bare git repos
909 # skip this for bare git repos
913 if not bare:
910 if not bare:
914 # disable VCS repo
911 # disable VCS repo
915 vcs_path = os.path.join(rm_path, '.%s' % alias)
912 vcs_path = os.path.join(rm_path, '.%s' % alias)
916 if os.path.exists(vcs_path):
913 if os.path.exists(vcs_path):
917 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
914 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
918
915
919 _now = datetime.datetime.now()
916 _now = datetime.datetime.now()
920 _ms = str(_now.microsecond).rjust(6, '0')
917 _ms = str(_now.microsecond).rjust(6, '0')
921 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
918 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
922 repo.just_name)
919 repo.just_name)
923 if repo_group:
920 if repo_group:
924 # if repository is in group, prefix the removal path with the group
921 # if repository is in group, prefix the removal path with the group
925 args = repo_group.full_path_splitted + [_d]
922 args = repo_group.full_path_splitted + [_d]
926 _d = os.path.join(*args)
923 _d = os.path.join(*args)
927
924
928 if os.path.isdir(rm_path):
925 if os.path.isdir(rm_path):
929 shutil.move(rm_path, os.path.join(self.repos_path, _d))
926 shutil.move(rm_path, os.path.join(self.repos_path, _d))
930
927
931 # finally cleanup diff-cache if it exists
928 # finally cleanup diff-cache if it exists
932 cached_diffs_dir = repo.cached_diffs_dir
929 cached_diffs_dir = repo.cached_diffs_dir
933 if os.path.isdir(cached_diffs_dir):
930 if os.path.isdir(cached_diffs_dir):
934 shutil.rmtree(cached_diffs_dir)
931 shutil.rmtree(cached_diffs_dir)
935
932
936
933
937 class ReadmeFinder:
934 class ReadmeFinder:
938 """
935 """
939 Utility which knows how to find a readme for a specific commit.
936 Utility which knows how to find a readme for a specific commit.
940
937
941 The main idea is that this is a configurable algorithm. When creating an
938 The main idea is that this is a configurable algorithm. When creating an
942 instance you can define parameters, currently only the `default_renderer`.
939 instance you can define parameters, currently only the `default_renderer`.
943 Based on this configuration the method :meth:`search` behaves slightly
940 Based on this configuration the method :meth:`search` behaves slightly
944 different.
941 different.
945 """
942 """
946
943
947 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
944 readme_re = re.compile(r'^readme(\.[^\.]+)?$', re.IGNORECASE)
948 path_re = re.compile(r'^docs?', re.IGNORECASE)
945 path_re = re.compile(r'^docs?', re.IGNORECASE)
949
946
950 default_priorities = {
947 default_priorities = {
951 None: 0,
948 None: 0,
952 '.text': 2,
949 '.text': 2,
953 '.txt': 3,
950 '.txt': 3,
954 '.rst': 1,
951 '.rst': 1,
955 '.rest': 2,
952 '.rest': 2,
956 '.md': 1,
953 '.md': 1,
957 '.mkdn': 2,
954 '.mkdn': 2,
958 '.mdown': 3,
955 '.mdown': 3,
959 '.markdown': 4,
956 '.markdown': 4,
960 }
957 }
961
958
962 path_priority = {
959 path_priority = {
963 'doc': 0,
960 'doc': 0,
964 'docs': 1,
961 'docs': 1,
965 }
962 }
966
963
967 FALLBACK_PRIORITY = 99
964 FALLBACK_PRIORITY = 99
968
965
969 RENDERER_TO_EXTENSION = {
966 RENDERER_TO_EXTENSION = {
970 'rst': ['.rst', '.rest'],
967 'rst': ['.rst', '.rest'],
971 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
968 'markdown': ['.md', 'mkdn', '.mdown', '.markdown'],
972 }
969 }
973
970
974 def __init__(self, default_renderer=None):
971 def __init__(self, default_renderer=None):
975 self._default_renderer = default_renderer
972 self._default_renderer = default_renderer
976 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
973 self._renderer_extensions = self.RENDERER_TO_EXTENSION.get(
977 default_renderer, [])
974 default_renderer, [])
978
975
979 def search(self, commit, path='/'):
976 def search(self, commit, path='/'):
980 """
977 """
981 Find a readme in the given `commit`.
978 Find a readme in the given `commit`.
982 """
979 """
983 nodes = commit.get_nodes(path)
980 nodes = commit.get_nodes(path)
984 matches = self._match_readmes(nodes)
981 matches = self._match_readmes(nodes)
985 matches = self._sort_according_to_priority(matches)
982 matches = self._sort_according_to_priority(matches)
986 if matches:
983 if matches:
987 return matches[0].node
984 return matches[0].node
988
985
989 paths = self._match_paths(nodes)
986 paths = self._match_paths(nodes)
990 paths = self._sort_paths_according_to_priority(paths)
987 paths = self._sort_paths_according_to_priority(paths)
991 for path in paths:
988 for path in paths:
992 match = self.search(commit, path=path)
989 match = self.search(commit, path=path)
993 if match:
990 if match:
994 return match
991 return match
995
992
996 return None
993 return None
997
994
998 def _match_readmes(self, nodes):
995 def _match_readmes(self, nodes):
999 for node in nodes:
996 for node in nodes:
1000 if not node.is_file():
997 if not node.is_file():
1001 continue
998 continue
1002 path = node.path.rsplit('/', 1)[-1]
999 path = node.path.rsplit('/', 1)[-1]
1003 match = self.readme_re.match(path)
1000 match = self.readme_re.match(path)
1004 if match:
1001 if match:
1005 extension = match.group(1)
1002 extension = match.group(1)
1006 yield ReadmeMatch(node, match, self._priority(extension))
1003 yield ReadmeMatch(node, match, self._priority(extension))
1007
1004
1008 def _match_paths(self, nodes):
1005 def _match_paths(self, nodes):
1009 for node in nodes:
1006 for node in nodes:
1010 if not node.is_dir():
1007 if not node.is_dir():
1011 continue
1008 continue
1012 match = self.path_re.match(node.path)
1009 match = self.path_re.match(node.path)
1013 if match:
1010 if match:
1014 yield node.path
1011 yield node.path
1015
1012
1016 def _priority(self, extension):
1013 def _priority(self, extension):
1017 renderer_priority = (
1014 renderer_priority = (
1018 0 if extension in self._renderer_extensions else 1)
1015 0 if extension in self._renderer_extensions else 1)
1019 extension_priority = self.default_priorities.get(
1016 extension_priority = self.default_priorities.get(
1020 extension, self.FALLBACK_PRIORITY)
1017 extension, self.FALLBACK_PRIORITY)
1021 return (renderer_priority, extension_priority)
1018 return (renderer_priority, extension_priority)
1022
1019
1023 def _sort_according_to_priority(self, matches):
1020 def _sort_according_to_priority(self, matches):
1024
1021
1025 def priority_and_path(match):
1022 def priority_and_path(match):
1026 return (match.priority, match.path)
1023 return (match.priority, match.path)
1027
1024
1028 return sorted(matches, key=priority_and_path)
1025 return sorted(matches, key=priority_and_path)
1029
1026
1030 def _sort_paths_according_to_priority(self, paths):
1027 def _sort_paths_according_to_priority(self, paths):
1031
1028
1032 def priority_and_path(path):
1029 def priority_and_path(path):
1033 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1030 return (self.path_priority.get(path, self.FALLBACK_PRIORITY), path)
1034
1031
1035 return sorted(paths, key=priority_and_path)
1032 return sorted(paths, key=priority_and_path)
1036
1033
1037
1034
1038 class ReadmeMatch:
1035 class ReadmeMatch:
1039
1036
1040 def __init__(self, node, match, priority):
1037 def __init__(self, node, match, priority):
1041 self.node = node
1038 self.node = node
1042 self._match = match
1039 self._match = match
1043 self.priority = priority
1040 self.priority = priority
1044
1041
1045 @property
1042 @property
1046 def path(self):
1043 def path(self):
1047 return self.node.path
1044 return self.node.path
1048
1045
1049 def __repr__(self):
1046 def __repr__(self):
1050 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
1047 return '<ReadmeMatch {} priority={}'.format(self.path, self.priority)
General Comments 0
You need to be logged in to leave comments. Login now