##// END OF EJS Templates
summary: Move logic to find a readme out...
johbo -
r768:95f8a91c default
parent child Browse files
Show More
@@ -1,304 +1,301 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
21 """
22 Summary controller for RhodeCode Enterprise
22 Summary controller for RhodeCode Enterprise
23 """
23 """
24
24
25 import logging
25 import logging
26 from string import lower
26 from string import lower
27
27
28 from pylons import tmpl_context as c, request
28 from pylons import tmpl_context as c, request
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 from beaker.cache import cache_region, region_invalidate
30 from beaker.cache import cache_region, region_invalidate
31
31
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
32 from rhodecode.config.conf import (LANGUAGES_EXTENSIONS_MAP)
33 from rhodecode.controllers import utils
33 from rhodecode.controllers import utils
34 from rhodecode.controllers.changelog import _load_changelog_summary
34 from rhodecode.controllers.changelog import _load_changelog_summary
35 from rhodecode.lib import caches, helpers as h
35 from rhodecode.lib import caches, helpers as h
36 from rhodecode.lib.utils import jsonify
36 from rhodecode.lib.utils import jsonify
37 from rhodecode.lib.utils2 import safe_str
37 from rhodecode.lib.utils2 import safe_str
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, XHRRequired)
39 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous, XHRRequired)
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.markup_renderer import MarkupRenderer
41 from rhodecode.lib.markup_renderer import MarkupRenderer
42 from rhodecode.lib.ext_json import json
42 from rhodecode.lib.ext_json import json
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
43 from rhodecode.lib.vcs.backends.base import EmptyCommit
44 from rhodecode.lib.vcs.exceptions import (
44 from rhodecode.lib.vcs.exceptions import (
45 CommitError, EmptyRepositoryError, NodeDoesNotExistError)
45 CommitError, EmptyRepositoryError, NodeDoesNotExistError)
46 from rhodecode.model.db import Statistics, CacheKey, User
46 from rhodecode.model.db import Statistics, CacheKey, User
47 from rhodecode.model.repo import ReadmeFinder
48
47
49
48 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
49
51
50
52
51 class SummaryController(BaseRepoController):
53 class SummaryController(BaseRepoController):
52
54
53 def __before__(self):
55 def __before__(self):
54 super(SummaryController, self).__before__()
56 super(SummaryController, self).__before__()
55
57
56 def __get_readme_data(self, db_repo):
58 def __get_readme_data(self, db_repo):
57 repo_name = db_repo.repo_name
59 repo_name = db_repo.repo_name
58 log.debug('Looking for README file')
60 log.debug('Looking for README file')
59 default_renderer = c.visual.default_renderer
61 default_renderer = c.visual.default_renderer
60
62
61 @cache_region('long_term')
63 @cache_region('long_term')
62 def _generate_readme(cache_key):
64 def _generate_readme(cache_key):
63 readme_data = None
65 readme_data = None
64 readme_file = None
66 readme_file = None
65 try:
67 try:
66 # gets the landing revision or tip if fails
68 # Find the landing commit
67 commit = db_repo.get_landing_commit()
69 commit = db_repo.get_landing_commit()
68 if isinstance(commit, EmptyCommit):
70 if isinstance(commit, EmptyCommit):
69 raise EmptyRepositoryError()
71 raise EmptyRepositoryError()
72
73 readme_file = ReadmeFinder(default_renderer).search(commit)
74
75 # Render the readme if one was found
76 if readme_file:
70 renderer = MarkupRenderer()
77 renderer = MarkupRenderer()
71 for f in renderer.pick_readme_order(default_renderer):
78 node = commit.get_node(readme_file)
72 try:
73 node = commit.get_node(f)
74 except NodeDoesNotExistError:
75 continue
76
77 if not node.is_file():
78 continue
79
80 readme_file = f
81 log.debug('Found README file `%s` rendering...',
79 log.debug('Found README file `%s` rendering...',
82 readme_file)
80 readme_file)
83 readme_data = renderer.render(node.content,
81 readme_data = renderer.render(
84 filename=f)
82 node.content, filename=readme_file)
85 break
86 except CommitError:
83 except CommitError:
87 log.exception(
84 log.exception(
88 "Problem getting commit when trying to render the README.")
85 "Problem getting commit when trying to render the README.")
89 except EmptyRepositoryError:
86 except EmptyRepositoryError:
90 log.debug("Repository is empty, no README to render.")
87 log.debug("Repository is empty, no README to render.")
91 except Exception:
88 except Exception:
92 log.exception("Exception while trying to render the README")
89 log.exception("Exception while trying to render the README")
93
90
94 return readme_data, readme_file
91 return readme_data, readme_file
95
92
96 invalidator_context = CacheKey.repo_context_cache(
93 invalidator_context = CacheKey.repo_context_cache(
97 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
94 _generate_readme, repo_name, CacheKey.CACHE_TYPE_README)
98
95
99 with invalidator_context as context:
96 with invalidator_context as context:
100 context.invalidate()
97 context.invalidate()
101 computed = context.compute()
98 computed = context.compute()
102
99
103 return computed
100 return computed
104
101
105 @LoginRequired()
102 @LoginRequired()
106 @HasRepoPermissionAnyDecorator(
103 @HasRepoPermissionAnyDecorator(
107 'repository.read', 'repository.write', 'repository.admin')
104 'repository.read', 'repository.write', 'repository.admin')
108 def index(self, repo_name):
105 def index(self, repo_name):
109
106
110 # Prepare the clone URL
107 # Prepare the clone URL
111
108
112 username = ''
109 username = ''
113 if c.rhodecode_user.username != User.DEFAULT_USER:
110 if c.rhodecode_user.username != User.DEFAULT_USER:
114 username = safe_str(c.rhodecode_user.username)
111 username = safe_str(c.rhodecode_user.username)
115
112
116 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
113 _def_clone_uri = _def_clone_uri_by_id = c.clone_uri_tmpl
117 if '{repo}' in _def_clone_uri:
114 if '{repo}' in _def_clone_uri:
118 _def_clone_uri_by_id = _def_clone_uri.replace(
115 _def_clone_uri_by_id = _def_clone_uri.replace(
119 '{repo}', '_{repoid}')
116 '{repo}', '_{repoid}')
120 elif '{repoid}' in _def_clone_uri:
117 elif '{repoid}' in _def_clone_uri:
121 _def_clone_uri_by_id = _def_clone_uri.replace(
118 _def_clone_uri_by_id = _def_clone_uri.replace(
122 '_{repoid}', '{repo}')
119 '_{repoid}', '{repo}')
123
120
124 c.clone_repo_url = c.rhodecode_db_repo.clone_url(
121 c.clone_repo_url = c.rhodecode_db_repo.clone_url(
125 user=username, uri_tmpl=_def_clone_uri)
122 user=username, uri_tmpl=_def_clone_uri)
126 c.clone_repo_url_id = c.rhodecode_db_repo.clone_url(
123 c.clone_repo_url_id = c.rhodecode_db_repo.clone_url(
127 user=username, uri_tmpl=_def_clone_uri_by_id)
124 user=username, uri_tmpl=_def_clone_uri_by_id)
128
125
129 # If enabled, get statistics data
126 # If enabled, get statistics data
130
127
131 c.show_stats = bool(c.rhodecode_db_repo.enable_statistics)
128 c.show_stats = bool(c.rhodecode_db_repo.enable_statistics)
132
129
133 stats = self.sa.query(Statistics)\
130 stats = self.sa.query(Statistics)\
134 .filter(Statistics.repository == c.rhodecode_db_repo)\
131 .filter(Statistics.repository == c.rhodecode_db_repo)\
135 .scalar()
132 .scalar()
136
133
137 c.stats_percentage = 0
134 c.stats_percentage = 0
138
135
139 if stats and stats.languages:
136 if stats and stats.languages:
140 c.no_data = False is c.rhodecode_db_repo.enable_statistics
137 c.no_data = False is c.rhodecode_db_repo.enable_statistics
141 lang_stats_d = json.loads(stats.languages)
138 lang_stats_d = json.loads(stats.languages)
142
139
143 # Sort first by decreasing count and second by the file extension,
140 # Sort first by decreasing count and second by the file extension,
144 # so we have a consistent output.
141 # so we have a consistent output.
145 lang_stats_items = sorted(lang_stats_d.iteritems(),
142 lang_stats_items = sorted(lang_stats_d.iteritems(),
146 key=lambda k: (-k[1], k[0]))[:10]
143 key=lambda k: (-k[1], k[0]))[:10]
147 lang_stats = [(x, {"count": y,
144 lang_stats = [(x, {"count": y,
148 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
145 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
149 for x, y in lang_stats_items]
146 for x, y in lang_stats_items]
150
147
151 c.trending_languages = json.dumps(lang_stats)
148 c.trending_languages = json.dumps(lang_stats)
152 else:
149 else:
153 c.no_data = True
150 c.no_data = True
154 c.trending_languages = json.dumps({})
151 c.trending_languages = json.dumps({})
155
152
156 c.enable_downloads = c.rhodecode_db_repo.enable_downloads
153 c.enable_downloads = c.rhodecode_db_repo.enable_downloads
157 c.repository_followers = self.scm_model.get_followers(
154 c.repository_followers = self.scm_model.get_followers(
158 c.rhodecode_db_repo)
155 c.rhodecode_db_repo)
159 c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo)
156 c.repository_forks = self.scm_model.get_forks(c.rhodecode_db_repo)
160 c.repository_is_user_following = self.scm_model.is_following_repo(
157 c.repository_is_user_following = self.scm_model.is_following_repo(
161 c.repo_name, c.rhodecode_user.user_id)
158 c.repo_name, c.rhodecode_user.user_id)
162
159
163 if c.repository_requirements_missing:
160 if c.repository_requirements_missing:
164 return render('summary/missing_requirements.html')
161 return render('summary/missing_requirements.html')
165
162
166 c.readme_data, c.readme_file = \
163 c.readme_data, c.readme_file = \
167 self.__get_readme_data(c.rhodecode_db_repo)
164 self.__get_readme_data(c.rhodecode_db_repo)
168
165
169 _load_changelog_summary()
166 _load_changelog_summary()
170
167
171 if request.is_xhr:
168 if request.is_xhr:
172 return render('changelog/changelog_summary_data.html')
169 return render('changelog/changelog_summary_data.html')
173
170
174 return render('summary/summary.html')
171 return render('summary/summary.html')
175
172
176 @LoginRequired()
173 @LoginRequired()
177 @XHRRequired()
174 @XHRRequired()
178 @HasRepoPermissionAnyDecorator(
175 @HasRepoPermissionAnyDecorator(
179 'repository.read', 'repository.write', 'repository.admin')
176 'repository.read', 'repository.write', 'repository.admin')
180 @jsonify
177 @jsonify
181 def repo_stats(self, repo_name, commit_id):
178 def repo_stats(self, repo_name, commit_id):
182 _namespace = caches.get_repo_namespace_key(
179 _namespace = caches.get_repo_namespace_key(
183 caches.SUMMARY_STATS, repo_name)
180 caches.SUMMARY_STATS, repo_name)
184 show_stats = bool(c.rhodecode_db_repo.enable_statistics)
181 show_stats = bool(c.rhodecode_db_repo.enable_statistics)
185 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
182 cache_manager = caches.get_cache_manager('repo_cache_long', _namespace)
186 _cache_key = caches.compute_key_from_params(
183 _cache_key = caches.compute_key_from_params(
187 repo_name, commit_id, show_stats)
184 repo_name, commit_id, show_stats)
188
185
189 def compute_stats():
186 def compute_stats():
190 code_stats = {}
187 code_stats = {}
191 size = 0
188 size = 0
192 try:
189 try:
193 scm_instance = c.rhodecode_db_repo.scm_instance()
190 scm_instance = c.rhodecode_db_repo.scm_instance()
194 commit = scm_instance.get_commit(commit_id)
191 commit = scm_instance.get_commit(commit_id)
195
192
196 for node in commit.get_filenodes_generator():
193 for node in commit.get_filenodes_generator():
197 size += node.size
194 size += node.size
198 if not show_stats:
195 if not show_stats:
199 continue
196 continue
200 ext = lower(node.extension)
197 ext = lower(node.extension)
201 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
198 ext_info = LANGUAGES_EXTENSIONS_MAP.get(ext)
202 if ext_info:
199 if ext_info:
203 if ext in code_stats:
200 if ext in code_stats:
204 code_stats[ext]['count'] += 1
201 code_stats[ext]['count'] += 1
205 else:
202 else:
206 code_stats[ext] = {"count": 1, "desc": ext_info}
203 code_stats[ext] = {"count": 1, "desc": ext_info}
207 except EmptyRepositoryError:
204 except EmptyRepositoryError:
208 pass
205 pass
209 return {'size': h.format_byte_size_binary(size),
206 return {'size': h.format_byte_size_binary(size),
210 'code_stats': code_stats}
207 'code_stats': code_stats}
211
208
212 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
209 stats = cache_manager.get(_cache_key, createfunc=compute_stats)
213 return stats
210 return stats
214
211
215 def _switcher_reference_data(self, repo_name, references, is_svn):
212 def _switcher_reference_data(self, repo_name, references, is_svn):
216 """Prepare reference data for given `references`"""
213 """Prepare reference data for given `references`"""
217 items = []
214 items = []
218 for name, commit_id in references.items():
215 for name, commit_id in references.items():
219 use_commit_id = '/' in name or is_svn
216 use_commit_id = '/' in name or is_svn
220 items.append({
217 items.append({
221 'name': name,
218 'name': name,
222 'commit_id': commit_id,
219 'commit_id': commit_id,
223 'files_url': h.url(
220 'files_url': h.url(
224 'files_home',
221 'files_home',
225 repo_name=repo_name,
222 repo_name=repo_name,
226 f_path=name if is_svn else '',
223 f_path=name if is_svn else '',
227 revision=commit_id if use_commit_id else name,
224 revision=commit_id if use_commit_id else name,
228 at=name)
225 at=name)
229 })
226 })
230 return items
227 return items
231
228
232 @LoginRequired()
229 @LoginRequired()
233 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
230 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
234 'repository.admin')
231 'repository.admin')
235 @jsonify
232 @jsonify
236 def repo_refs_data(self, repo_name):
233 def repo_refs_data(self, repo_name):
237 repo = c.rhodecode_repo
234 repo = c.rhodecode_repo
238 refs_to_create = [
235 refs_to_create = [
239 (_("Branch"), repo.branches, 'branch'),
236 (_("Branch"), repo.branches, 'branch'),
240 (_("Tag"), repo.tags, 'tag'),
237 (_("Tag"), repo.tags, 'tag'),
241 (_("Bookmark"), repo.bookmarks, 'book'),
238 (_("Bookmark"), repo.bookmarks, 'book'),
242 ]
239 ]
243 res = self._create_reference_data(repo, repo_name, refs_to_create)
240 res = self._create_reference_data(repo, repo_name, refs_to_create)
244 data = {
241 data = {
245 'more': False,
242 'more': False,
246 'results': res
243 'results': res
247 }
244 }
248 return data
245 return data
249
246
250 @jsonify
247 @jsonify
251 def repo_refs_changelog_data(self, repo_name):
248 def repo_refs_changelog_data(self, repo_name):
252 repo = c.rhodecode_repo
249 repo = c.rhodecode_repo
253
250
254 refs_to_create = [
251 refs_to_create = [
255 (_("Branches"), repo.branches, 'branch'),
252 (_("Branches"), repo.branches, 'branch'),
256 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
253 (_("Closed branches"), repo.branches_closed, 'branch_closed'),
257 # TODO: enable when vcs can handle bookmarks filters
254 # TODO: enable when vcs can handle bookmarks filters
258 # (_("Bookmarks"), repo.bookmarks, "book"),
255 # (_("Bookmarks"), repo.bookmarks, "book"),
259 ]
256 ]
260 res = self._create_reference_data(repo, repo_name, refs_to_create)
257 res = self._create_reference_data(repo, repo_name, refs_to_create)
261 data = {
258 data = {
262 'more': False,
259 'more': False,
263 'results': res
260 'results': res
264 }
261 }
265 return data
262 return data
266
263
267 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
264 def _create_reference_data(self, repo, full_repo_name, refs_to_create):
268 format_ref_id = utils.get_format_ref_id(repo)
265 format_ref_id = utils.get_format_ref_id(repo)
269
266
270 result = []
267 result = []
271 for title, refs, ref_type in refs_to_create:
268 for title, refs, ref_type in refs_to_create:
272 if refs:
269 if refs:
273 result.append({
270 result.append({
274 'text': title,
271 'text': title,
275 'children': self._create_reference_items(
272 'children': self._create_reference_items(
276 repo, full_repo_name, refs, ref_type, format_ref_id),
273 repo, full_repo_name, refs, ref_type, format_ref_id),
277 })
274 })
278 return result
275 return result
279
276
280 def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
277 def _create_reference_items(self, repo, full_repo_name, refs, ref_type,
281 format_ref_id):
278 format_ref_id):
282 result = []
279 result = []
283 is_svn = h.is_svn(repo)
280 is_svn = h.is_svn(repo)
284 for ref_name, raw_id in refs.iteritems():
281 for ref_name, raw_id in refs.iteritems():
285 files_url = self._create_files_url(
282 files_url = self._create_files_url(
286 repo, full_repo_name, ref_name, raw_id, is_svn)
283 repo, full_repo_name, ref_name, raw_id, is_svn)
287 result.append({
284 result.append({
288 'text': ref_name,
285 'text': ref_name,
289 'id': format_ref_id(ref_name, raw_id),
286 'id': format_ref_id(ref_name, raw_id),
290 'raw_id': raw_id,
287 'raw_id': raw_id,
291 'type': ref_type,
288 'type': ref_type,
292 'files_url': files_url,
289 'files_url': files_url,
293 })
290 })
294 return result
291 return result
295
292
296 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id,
293 def _create_files_url(self, repo, full_repo_name, ref_name, raw_id,
297 is_svn):
294 is_svn):
298 use_commit_id = '/' in ref_name or is_svn
295 use_commit_id = '/' in ref_name or is_svn
299 return h.url(
296 return h.url(
300 'files_home',
297 'files_home',
301 repo_name=full_repo_name,
298 repo_name=full_repo_name,
302 f_path=ref_name if is_svn else '',
299 f_path=ref_name if is_svn else '',
303 revision=raw_id if use_commit_id else ref_name,
300 revision=raw_id if use_commit_id else ref_name,
304 at=ref_name)
301 at=ref_name)
@@ -1,935 +1,968 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
21 """
22 Repository model for rhodecode
22 Repository model for rhodecode
23 """
23 """
24
24
25 import logging
25 import logging
26 import os
26 import os
27 import re
27 import re
28 import shutil
28 import shutil
29 import time
29 import time
30 import traceback
30 import traceback
31 from datetime import datetime
31 from datetime import datetime
32
32
33 from sqlalchemy.sql import func
33 from sqlalchemy.sql import func
34 from sqlalchemy.sql.expression import true, or_
34 from sqlalchemy.sql.expression import true, or_
35 from zope.cachedescriptors.property import Lazy as LazyProperty
35 from zope.cachedescriptors.property import Lazy as LazyProperty
36
36
37 from rhodecode import events
37 from rhodecode import events
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import HasUserGroupPermissionAny
39 from rhodecode.lib.auth import HasUserGroupPermissionAny
40 from rhodecode.lib.caching_query import FromCache
40 from rhodecode.lib.caching_query import FromCache
41 from rhodecode.lib.exceptions import AttachedForksError
41 from rhodecode.lib.exceptions import AttachedForksError
42 from rhodecode.lib.hooks_base import log_delete_repository
42 from rhodecode.lib.hooks_base import log_delete_repository
43 from rhodecode.lib.markup_renderer import MarkupRenderer
43 from rhodecode.lib.utils import make_db_config
44 from rhodecode.lib.utils import make_db_config
44 from rhodecode.lib.utils2 import (
45 from rhodecode.lib.utils2 import (
45 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
46 safe_str, safe_unicode, remove_prefix, obfuscate_url_pw,
46 get_current_rhodecode_user, safe_int, datetime_to_time, action_logger_generic)
47 get_current_rhodecode_user, safe_int, datetime_to_time, action_logger_generic)
47 from rhodecode.lib.vcs.backends import get_backend
48 from rhodecode.lib.vcs.backends import get_backend
49 from rhodecode.lib.vcs.exceptions import NodeDoesNotExistError
48 from rhodecode.model import BaseModel
50 from rhodecode.model import BaseModel
49 from rhodecode.model.db import (
51 from rhodecode.model.db import (
50 Repository, UserRepoToPerm, UserGroupRepoToPerm, UserRepoGroupToPerm,
52 Repository, UserRepoToPerm, UserGroupRepoToPerm, UserRepoGroupToPerm,
51 UserGroupRepoGroupToPerm, User, Permission, Statistics, UserGroup,
53 UserGroupRepoGroupToPerm, User, Permission, Statistics, UserGroup,
52 RepoGroup, RepositoryField)
54 RepoGroup, RepositoryField)
53 from rhodecode.model.scm import UserGroupList
55 from rhodecode.model.scm import UserGroupList
54 from rhodecode.model.settings import VcsSettingsModel
56 from rhodecode.model.settings import VcsSettingsModel
55
57
56
58
57 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
58
60
59
61
60 class RepoModel(BaseModel):
62 class RepoModel(BaseModel):
61
63
62 cls = Repository
64 cls = Repository
63
65
64 def _get_user_group(self, users_group):
66 def _get_user_group(self, users_group):
65 return self._get_instance(UserGroup, users_group,
67 return self._get_instance(UserGroup, users_group,
66 callback=UserGroup.get_by_group_name)
68 callback=UserGroup.get_by_group_name)
67
69
68 def _get_repo_group(self, repo_group):
70 def _get_repo_group(self, repo_group):
69 return self._get_instance(RepoGroup, repo_group,
71 return self._get_instance(RepoGroup, repo_group,
70 callback=RepoGroup.get_by_group_name)
72 callback=RepoGroup.get_by_group_name)
71
73
72 def _create_default_perms(self, repository, private):
74 def _create_default_perms(self, repository, private):
73 # create default permission
75 # create default permission
74 default = 'repository.read'
76 default = 'repository.read'
75 def_user = User.get_default_user()
77 def_user = User.get_default_user()
76 for p in def_user.user_perms:
78 for p in def_user.user_perms:
77 if p.permission.permission_name.startswith('repository.'):
79 if p.permission.permission_name.startswith('repository.'):
78 default = p.permission.permission_name
80 default = p.permission.permission_name
79 break
81 break
80
82
81 default_perm = 'repository.none' if private else default
83 default_perm = 'repository.none' if private else default
82
84
83 repo_to_perm = UserRepoToPerm()
85 repo_to_perm = UserRepoToPerm()
84 repo_to_perm.permission = Permission.get_by_key(default_perm)
86 repo_to_perm.permission = Permission.get_by_key(default_perm)
85
87
86 repo_to_perm.repository = repository
88 repo_to_perm.repository = repository
87 repo_to_perm.user_id = def_user.user_id
89 repo_to_perm.user_id = def_user.user_id
88
90
89 return repo_to_perm
91 return repo_to_perm
90
92
91 @LazyProperty
93 @LazyProperty
92 def repos_path(self):
94 def repos_path(self):
93 """
95 """
94 Gets the repositories root path from database
96 Gets the repositories root path from database
95 """
97 """
96 settings_model = VcsSettingsModel(sa=self.sa)
98 settings_model = VcsSettingsModel(sa=self.sa)
97 return settings_model.get_repos_location()
99 return settings_model.get_repos_location()
98
100
99 def get(self, repo_id, cache=False):
101 def get(self, repo_id, cache=False):
100 repo = self.sa.query(Repository) \
102 repo = self.sa.query(Repository) \
101 .filter(Repository.repo_id == repo_id)
103 .filter(Repository.repo_id == repo_id)
102
104
103 if cache:
105 if cache:
104 repo = repo.options(FromCache("sql_cache_short",
106 repo = repo.options(FromCache("sql_cache_short",
105 "get_repo_%s" % repo_id))
107 "get_repo_%s" % repo_id))
106 return repo.scalar()
108 return repo.scalar()
107
109
108 def get_repo(self, repository):
110 def get_repo(self, repository):
109 return self._get_repo(repository)
111 return self._get_repo(repository)
110
112
111 def get_by_repo_name(self, repo_name, cache=False):
113 def get_by_repo_name(self, repo_name, cache=False):
112 repo = self.sa.query(Repository) \
114 repo = self.sa.query(Repository) \
113 .filter(Repository.repo_name == repo_name)
115 .filter(Repository.repo_name == repo_name)
114
116
115 if cache:
117 if cache:
116 repo = repo.options(FromCache("sql_cache_short",
118 repo = repo.options(FromCache("sql_cache_short",
117 "get_repo_%s" % repo_name))
119 "get_repo_%s" % repo_name))
118 return repo.scalar()
120 return repo.scalar()
119
121
120 def _extract_id_from_repo_name(self, repo_name):
122 def _extract_id_from_repo_name(self, repo_name):
121 if repo_name.startswith('/'):
123 if repo_name.startswith('/'):
122 repo_name = repo_name.lstrip('/')
124 repo_name = repo_name.lstrip('/')
123 by_id_match = re.match(r'^_(\d{1,})', repo_name)
125 by_id_match = re.match(r'^_(\d{1,})', repo_name)
124 if by_id_match:
126 if by_id_match:
125 return by_id_match.groups()[0]
127 return by_id_match.groups()[0]
126
128
127 def get_repo_by_id(self, repo_name):
129 def get_repo_by_id(self, repo_name):
128 """
130 """
129 Extracts repo_name by id from special urls.
131 Extracts repo_name by id from special urls.
130 Example url is _11/repo_name
132 Example url is _11/repo_name
131
133
132 :param repo_name:
134 :param repo_name:
133 :return: repo object if matched else None
135 :return: repo object if matched else None
134 """
136 """
135 try:
137 try:
136 _repo_id = self._extract_id_from_repo_name(repo_name)
138 _repo_id = self._extract_id_from_repo_name(repo_name)
137 if _repo_id:
139 if _repo_id:
138 return self.get(_repo_id)
140 return self.get(_repo_id)
139 except Exception:
141 except Exception:
140 log.exception('Failed to extract repo_name from URL')
142 log.exception('Failed to extract repo_name from URL')
141
143
142 return None
144 return None
143
145
144 def get_url(self, repo):
146 def get_url(self, repo):
145 return h.url('summary_home', repo_name=safe_str(repo.repo_name),
147 return h.url('summary_home', repo_name=safe_str(repo.repo_name),
146 qualified=True)
148 qualified=True)
147
149
148 def get_users(self, name_contains=None, limit=20, only_active=True):
150 def get_users(self, name_contains=None, limit=20, only_active=True):
149 # TODO: mikhail: move this method to the UserModel.
151 # TODO: mikhail: move this method to the UserModel.
150 query = self.sa.query(User)
152 query = self.sa.query(User)
151 if only_active:
153 if only_active:
152 query = query.filter(User.active == true())
154 query = query.filter(User.active == true())
153
155
154 if name_contains:
156 if name_contains:
155 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
157 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
156 query = query.filter(
158 query = query.filter(
157 or_(
159 or_(
158 User.name.ilike(ilike_expression),
160 User.name.ilike(ilike_expression),
159 User.lastname.ilike(ilike_expression),
161 User.lastname.ilike(ilike_expression),
160 User.username.ilike(ilike_expression)
162 User.username.ilike(ilike_expression)
161 )
163 )
162 )
164 )
163 query = query.limit(limit)
165 query = query.limit(limit)
164 users = query.all()
166 users = query.all()
165
167
166 _users = [
168 _users = [
167 {
169 {
168 'id': user.user_id,
170 'id': user.user_id,
169 'first_name': user.name,
171 'first_name': user.name,
170 'last_name': user.lastname,
172 'last_name': user.lastname,
171 'username': user.username,
173 'username': user.username,
172 'icon_link': h.gravatar_url(user.email, 14),
174 'icon_link': h.gravatar_url(user.email, 14),
173 'value_display': h.person(user.email),
175 'value_display': h.person(user.email),
174 'value': user.username,
176 'value': user.username,
175 'value_type': 'user',
177 'value_type': 'user',
176 'active': user.active,
178 'active': user.active,
177 }
179 }
178 for user in users
180 for user in users
179 ]
181 ]
180 return _users
182 return _users
181
183
182 def get_user_groups(self, name_contains=None, limit=20, only_active=True):
184 def get_user_groups(self, name_contains=None, limit=20, only_active=True):
183 # TODO: mikhail: move this method to the UserGroupModel.
185 # TODO: mikhail: move this method to the UserGroupModel.
184 query = self.sa.query(UserGroup)
186 query = self.sa.query(UserGroup)
185 if only_active:
187 if only_active:
186 query = query.filter(UserGroup.users_group_active == true())
188 query = query.filter(UserGroup.users_group_active == true())
187
189
188 if name_contains:
190 if name_contains:
189 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
191 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
190 query = query.filter(
192 query = query.filter(
191 UserGroup.users_group_name.ilike(ilike_expression))\
193 UserGroup.users_group_name.ilike(ilike_expression))\
192 .order_by(func.length(UserGroup.users_group_name))\
194 .order_by(func.length(UserGroup.users_group_name))\
193 .order_by(UserGroup.users_group_name)
195 .order_by(UserGroup.users_group_name)
194
196
195 query = query.limit(limit)
197 query = query.limit(limit)
196 user_groups = query.all()
198 user_groups = query.all()
197 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
199 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
198 user_groups = UserGroupList(user_groups, perm_set=perm_set)
200 user_groups = UserGroupList(user_groups, perm_set=perm_set)
199
201
200 _groups = [
202 _groups = [
201 {
203 {
202 'id': group.users_group_id,
204 'id': group.users_group_id,
203 # TODO: marcink figure out a way to generate the url for the
205 # TODO: marcink figure out a way to generate the url for the
204 # icon
206 # icon
205 'icon_link': '',
207 'icon_link': '',
206 'value_display': 'Group: %s (%d members)' % (
208 'value_display': 'Group: %s (%d members)' % (
207 group.users_group_name, len(group.members),),
209 group.users_group_name, len(group.members),),
208 'value': group.users_group_name,
210 'value': group.users_group_name,
209 'value_type': 'user_group',
211 'value_type': 'user_group',
210 'active': group.users_group_active,
212 'active': group.users_group_active,
211 }
213 }
212 for group in user_groups
214 for group in user_groups
213 ]
215 ]
214 return _groups
216 return _groups
215
217
216 @classmethod
218 @classmethod
217 def update_repoinfo(cls, repositories=None):
219 def update_repoinfo(cls, repositories=None):
218 if not repositories:
220 if not repositories:
219 repositories = Repository.getAll()
221 repositories = Repository.getAll()
220 for repo in repositories:
222 for repo in repositories:
221 repo.update_commit_cache()
223 repo.update_commit_cache()
222
224
223 def get_repos_as_dict(self, repo_list=None, admin=False,
225 def get_repos_as_dict(self, repo_list=None, admin=False,
224 super_user_actions=False):
226 super_user_actions=False):
225
227
226 from rhodecode.lib.utils import PartialRenderer
228 from rhodecode.lib.utils import PartialRenderer
227 _render = PartialRenderer('data_table/_dt_elements.html')
229 _render = PartialRenderer('data_table/_dt_elements.html')
228 c = _render.c
230 c = _render.c
229
231
230 def quick_menu(repo_name):
232 def quick_menu(repo_name):
231 return _render('quick_menu', repo_name)
233 return _render('quick_menu', repo_name)
232
234
233 def repo_lnk(name, rtype, rstate, private, fork_of):
235 def repo_lnk(name, rtype, rstate, private, fork_of):
234 return _render('repo_name', name, rtype, rstate, private, fork_of,
236 return _render('repo_name', name, rtype, rstate, private, fork_of,
235 short_name=not admin, admin=False)
237 short_name=not admin, admin=False)
236
238
237 def last_change(last_change):
239 def last_change(last_change):
238 return _render("last_change", last_change)
240 return _render("last_change", last_change)
239
241
240 def rss_lnk(repo_name):
242 def rss_lnk(repo_name):
241 return _render("rss", repo_name)
243 return _render("rss", repo_name)
242
244
243 def atom_lnk(repo_name):
245 def atom_lnk(repo_name):
244 return _render("atom", repo_name)
246 return _render("atom", repo_name)
245
247
246 def last_rev(repo_name, cs_cache):
248 def last_rev(repo_name, cs_cache):
247 return _render('revision', repo_name, cs_cache.get('revision'),
249 return _render('revision', repo_name, cs_cache.get('revision'),
248 cs_cache.get('raw_id'), cs_cache.get('author'),
250 cs_cache.get('raw_id'), cs_cache.get('author'),
249 cs_cache.get('message'))
251 cs_cache.get('message'))
250
252
251 def desc(desc):
253 def desc(desc):
252 if c.visual.stylify_metatags:
254 if c.visual.stylify_metatags:
253 return h.urlify_text(h.escaped_stylize(h.truncate(desc, 60)))
255 return h.urlify_text(h.escaped_stylize(h.truncate(desc, 60)))
254 else:
256 else:
255 return h.urlify_text(h.html_escape(h.truncate(desc, 60)))
257 return h.urlify_text(h.html_escape(h.truncate(desc, 60)))
256
258
257 def state(repo_state):
259 def state(repo_state):
258 return _render("repo_state", repo_state)
260 return _render("repo_state", repo_state)
259
261
260 def repo_actions(repo_name):
262 def repo_actions(repo_name):
261 return _render('repo_actions', repo_name, super_user_actions)
263 return _render('repo_actions', repo_name, super_user_actions)
262
264
263 def user_profile(username):
265 def user_profile(username):
264 return _render('user_profile', username)
266 return _render('user_profile', username)
265
267
266 repos_data = []
268 repos_data = []
267 for repo in repo_list:
269 for repo in repo_list:
268 cs_cache = repo.changeset_cache
270 cs_cache = repo.changeset_cache
269 row = {
271 row = {
270 "menu": quick_menu(repo.repo_name),
272 "menu": quick_menu(repo.repo_name),
271
273
272 "name": repo_lnk(repo.repo_name, repo.repo_type,
274 "name": repo_lnk(repo.repo_name, repo.repo_type,
273 repo.repo_state, repo.private, repo.fork),
275 repo.repo_state, repo.private, repo.fork),
274 "name_raw": repo.repo_name.lower(),
276 "name_raw": repo.repo_name.lower(),
275
277
276 "last_change": last_change(repo.last_db_change),
278 "last_change": last_change(repo.last_db_change),
277 "last_change_raw": datetime_to_time(repo.last_db_change),
279 "last_change_raw": datetime_to_time(repo.last_db_change),
278
280
279 "last_changeset": last_rev(repo.repo_name, cs_cache),
281 "last_changeset": last_rev(repo.repo_name, cs_cache),
280 "last_changeset_raw": cs_cache.get('revision'),
282 "last_changeset_raw": cs_cache.get('revision'),
281
283
282 "desc": desc(repo.description),
284 "desc": desc(repo.description),
283 "owner": user_profile(repo.user.username),
285 "owner": user_profile(repo.user.username),
284
286
285 "state": state(repo.repo_state),
287 "state": state(repo.repo_state),
286 "rss": rss_lnk(repo.repo_name),
288 "rss": rss_lnk(repo.repo_name),
287
289
288 "atom": atom_lnk(repo.repo_name),
290 "atom": atom_lnk(repo.repo_name),
289 }
291 }
290 if admin:
292 if admin:
291 row.update({
293 row.update({
292 "action": repo_actions(repo.repo_name),
294 "action": repo_actions(repo.repo_name),
293 })
295 })
294 repos_data.append(row)
296 repos_data.append(row)
295
297
296 return repos_data
298 return repos_data
297
299
298 def _get_defaults(self, repo_name):
300 def _get_defaults(self, repo_name):
299 """
301 """
300 Gets information about repository, and returns a dict for
302 Gets information about repository, and returns a dict for
301 usage in forms
303 usage in forms
302
304
303 :param repo_name:
305 :param repo_name:
304 """
306 """
305
307
306 repo_info = Repository.get_by_repo_name(repo_name)
308 repo_info = Repository.get_by_repo_name(repo_name)
307
309
308 if repo_info is None:
310 if repo_info is None:
309 return None
311 return None
310
312
311 defaults = repo_info.get_dict()
313 defaults = repo_info.get_dict()
312 defaults['repo_name'] = repo_info.just_name
314 defaults['repo_name'] = repo_info.just_name
313
315
314 groups = repo_info.groups_with_parents
316 groups = repo_info.groups_with_parents
315 parent_group = groups[-1] if groups else None
317 parent_group = groups[-1] if groups else None
316
318
317 # we use -1 as this is how in HTML, we mark an empty group
319 # we use -1 as this is how in HTML, we mark an empty group
318 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
320 defaults['repo_group'] = getattr(parent_group, 'group_id', -1)
319
321
320 keys_to_process = (
322 keys_to_process = (
321 {'k': 'repo_type', 'strip': False},
323 {'k': 'repo_type', 'strip': False},
322 {'k': 'repo_enable_downloads', 'strip': True},
324 {'k': 'repo_enable_downloads', 'strip': True},
323 {'k': 'repo_description', 'strip': True},
325 {'k': 'repo_description', 'strip': True},
324 {'k': 'repo_enable_locking', 'strip': True},
326 {'k': 'repo_enable_locking', 'strip': True},
325 {'k': 'repo_landing_rev', 'strip': True},
327 {'k': 'repo_landing_rev', 'strip': True},
326 {'k': 'clone_uri', 'strip': False},
328 {'k': 'clone_uri', 'strip': False},
327 {'k': 'repo_private', 'strip': True},
329 {'k': 'repo_private', 'strip': True},
328 {'k': 'repo_enable_statistics', 'strip': True}
330 {'k': 'repo_enable_statistics', 'strip': True}
329 )
331 )
330
332
331 for item in keys_to_process:
333 for item in keys_to_process:
332 attr = item['k']
334 attr = item['k']
333 if item['strip']:
335 if item['strip']:
334 attr = remove_prefix(item['k'], 'repo_')
336 attr = remove_prefix(item['k'], 'repo_')
335
337
336 val = defaults[attr]
338 val = defaults[attr]
337 if item['k'] == 'repo_landing_rev':
339 if item['k'] == 'repo_landing_rev':
338 val = ':'.join(defaults[attr])
340 val = ':'.join(defaults[attr])
339 defaults[item['k']] = val
341 defaults[item['k']] = val
340 if item['k'] == 'clone_uri':
342 if item['k'] == 'clone_uri':
341 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
343 defaults['clone_uri_hidden'] = repo_info.clone_uri_hidden
342
344
343 # fill owner
345 # fill owner
344 if repo_info.user:
346 if repo_info.user:
345 defaults.update({'user': repo_info.user.username})
347 defaults.update({'user': repo_info.user.username})
346 else:
348 else:
347 replacement_user = User.get_first_super_admin().username
349 replacement_user = User.get_first_super_admin().username
348 defaults.update({'user': replacement_user})
350 defaults.update({'user': replacement_user})
349
351
350 # fill repository users
352 # fill repository users
351 for p in repo_info.repo_to_perm:
353 for p in repo_info.repo_to_perm:
352 defaults.update({'u_perm_%s' % p.user.user_id:
354 defaults.update({'u_perm_%s' % p.user.user_id:
353 p.permission.permission_name})
355 p.permission.permission_name})
354
356
355 # fill repository groups
357 # fill repository groups
356 for p in repo_info.users_group_to_perm:
358 for p in repo_info.users_group_to_perm:
357 defaults.update({'g_perm_%s' % p.users_group.users_group_id:
359 defaults.update({'g_perm_%s' % p.users_group.users_group_id:
358 p.permission.permission_name})
360 p.permission.permission_name})
359
361
360 return defaults
362 return defaults
361
363
362 def update(self, repo, **kwargs):
364 def update(self, repo, **kwargs):
363 try:
365 try:
364 cur_repo = self._get_repo(repo)
366 cur_repo = self._get_repo(repo)
365 source_repo_name = cur_repo.repo_name
367 source_repo_name = cur_repo.repo_name
366 if 'user' in kwargs:
368 if 'user' in kwargs:
367 cur_repo.user = User.get_by_username(kwargs['user'])
369 cur_repo.user = User.get_by_username(kwargs['user'])
368
370
369 if 'repo_group' in kwargs:
371 if 'repo_group' in kwargs:
370 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
372 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
371 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
373 log.debug('Updating repo %s with params:%s', cur_repo, kwargs)
372
374
373 update_keys = [
375 update_keys = [
374 (1, 'repo_enable_downloads'),
376 (1, 'repo_enable_downloads'),
375 (1, 'repo_description'),
377 (1, 'repo_description'),
376 (1, 'repo_enable_locking'),
378 (1, 'repo_enable_locking'),
377 (1, 'repo_landing_rev'),
379 (1, 'repo_landing_rev'),
378 (1, 'repo_private'),
380 (1, 'repo_private'),
379 (1, 'repo_enable_statistics'),
381 (1, 'repo_enable_statistics'),
380 (0, 'clone_uri'),
382 (0, 'clone_uri'),
381 (0, 'fork_id')
383 (0, 'fork_id')
382 ]
384 ]
383 for strip, k in update_keys:
385 for strip, k in update_keys:
384 if k in kwargs:
386 if k in kwargs:
385 val = kwargs[k]
387 val = kwargs[k]
386 if strip:
388 if strip:
387 k = remove_prefix(k, 'repo_')
389 k = remove_prefix(k, 'repo_')
388 if k == 'clone_uri':
390 if k == 'clone_uri':
389 from rhodecode.model.validators import Missing
391 from rhodecode.model.validators import Missing
390 _change = kwargs.get('clone_uri_change')
392 _change = kwargs.get('clone_uri_change')
391 if _change in [Missing, 'OLD']:
393 if _change in [Missing, 'OLD']:
392 # we don't change the value, so use original one
394 # we don't change the value, so use original one
393 val = cur_repo.clone_uri
395 val = cur_repo.clone_uri
394
396
395 setattr(cur_repo, k, val)
397 setattr(cur_repo, k, val)
396
398
397 new_name = cur_repo.get_new_name(kwargs['repo_name'])
399 new_name = cur_repo.get_new_name(kwargs['repo_name'])
398 cur_repo.repo_name = new_name
400 cur_repo.repo_name = new_name
399
401
400 # if private flag is set, reset default permission to NONE
402 # if private flag is set, reset default permission to NONE
401 if kwargs.get('repo_private'):
403 if kwargs.get('repo_private'):
402 EMPTY_PERM = 'repository.none'
404 EMPTY_PERM = 'repository.none'
403 RepoModel().grant_user_permission(
405 RepoModel().grant_user_permission(
404 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
406 repo=cur_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM
405 )
407 )
406
408
407 # handle extra fields
409 # handle extra fields
408 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
410 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX),
409 kwargs):
411 kwargs):
410 k = RepositoryField.un_prefix_key(field)
412 k = RepositoryField.un_prefix_key(field)
411 ex_field = RepositoryField.get_by_key_name(
413 ex_field = RepositoryField.get_by_key_name(
412 key=k, repo=cur_repo)
414 key=k, repo=cur_repo)
413 if ex_field:
415 if ex_field:
414 ex_field.field_value = kwargs[field]
416 ex_field.field_value = kwargs[field]
415 self.sa.add(ex_field)
417 self.sa.add(ex_field)
416 self.sa.add(cur_repo)
418 self.sa.add(cur_repo)
417
419
418 if source_repo_name != new_name:
420 if source_repo_name != new_name:
419 # rename repository
421 # rename repository
420 self._rename_filesystem_repo(
422 self._rename_filesystem_repo(
421 old=source_repo_name, new=new_name)
423 old=source_repo_name, new=new_name)
422
424
423 return cur_repo
425 return cur_repo
424 except Exception:
426 except Exception:
425 log.error(traceback.format_exc())
427 log.error(traceback.format_exc())
426 raise
428 raise
427
429
428 def _create_repo(self, repo_name, repo_type, description, owner,
430 def _create_repo(self, repo_name, repo_type, description, owner,
429 private=False, clone_uri=None, repo_group=None,
431 private=False, clone_uri=None, repo_group=None,
430 landing_rev='rev:tip', fork_of=None,
432 landing_rev='rev:tip', fork_of=None,
431 copy_fork_permissions=False, enable_statistics=False,
433 copy_fork_permissions=False, enable_statistics=False,
432 enable_locking=False, enable_downloads=False,
434 enable_locking=False, enable_downloads=False,
433 copy_group_permissions=False,
435 copy_group_permissions=False,
434 state=Repository.STATE_PENDING):
436 state=Repository.STATE_PENDING):
435 """
437 """
436 Create repository inside database with PENDING state, this should be
438 Create repository inside database with PENDING state, this should be
437 only executed by create() repo. With exception of importing existing
439 only executed by create() repo. With exception of importing existing
438 repos
440 repos
439 """
441 """
440 from rhodecode.model.scm import ScmModel
442 from rhodecode.model.scm import ScmModel
441
443
442 owner = self._get_user(owner)
444 owner = self._get_user(owner)
443 fork_of = self._get_repo(fork_of)
445 fork_of = self._get_repo(fork_of)
444 repo_group = self._get_repo_group(safe_int(repo_group))
446 repo_group = self._get_repo_group(safe_int(repo_group))
445
447
446 try:
448 try:
447 repo_name = safe_unicode(repo_name)
449 repo_name = safe_unicode(repo_name)
448 description = safe_unicode(description)
450 description = safe_unicode(description)
449 # repo name is just a name of repository
451 # repo name is just a name of repository
450 # while repo_name_full is a full qualified name that is combined
452 # while repo_name_full is a full qualified name that is combined
451 # with name and path of group
453 # with name and path of group
452 repo_name_full = repo_name
454 repo_name_full = repo_name
453 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
455 repo_name = repo_name.split(Repository.NAME_SEP)[-1]
454
456
455 new_repo = Repository()
457 new_repo = Repository()
456 new_repo.repo_state = state
458 new_repo.repo_state = state
457 new_repo.enable_statistics = False
459 new_repo.enable_statistics = False
458 new_repo.repo_name = repo_name_full
460 new_repo.repo_name = repo_name_full
459 new_repo.repo_type = repo_type
461 new_repo.repo_type = repo_type
460 new_repo.user = owner
462 new_repo.user = owner
461 new_repo.group = repo_group
463 new_repo.group = repo_group
462 new_repo.description = description or repo_name
464 new_repo.description = description or repo_name
463 new_repo.private = private
465 new_repo.private = private
464 new_repo.clone_uri = clone_uri
466 new_repo.clone_uri = clone_uri
465 new_repo.landing_rev = landing_rev
467 new_repo.landing_rev = landing_rev
466
468
467 new_repo.enable_statistics = enable_statistics
469 new_repo.enable_statistics = enable_statistics
468 new_repo.enable_locking = enable_locking
470 new_repo.enable_locking = enable_locking
469 new_repo.enable_downloads = enable_downloads
471 new_repo.enable_downloads = enable_downloads
470
472
471 if repo_group:
473 if repo_group:
472 new_repo.enable_locking = repo_group.enable_locking
474 new_repo.enable_locking = repo_group.enable_locking
473
475
474 if fork_of:
476 if fork_of:
475 parent_repo = fork_of
477 parent_repo = fork_of
476 new_repo.fork = parent_repo
478 new_repo.fork = parent_repo
477
479
478 events.trigger(events.RepoPreCreateEvent(new_repo))
480 events.trigger(events.RepoPreCreateEvent(new_repo))
479
481
480 self.sa.add(new_repo)
482 self.sa.add(new_repo)
481
483
482 EMPTY_PERM = 'repository.none'
484 EMPTY_PERM = 'repository.none'
483 if fork_of and copy_fork_permissions:
485 if fork_of and copy_fork_permissions:
484 repo = fork_of
486 repo = fork_of
485 user_perms = UserRepoToPerm.query() \
487 user_perms = UserRepoToPerm.query() \
486 .filter(UserRepoToPerm.repository == repo).all()
488 .filter(UserRepoToPerm.repository == repo).all()
487 group_perms = UserGroupRepoToPerm.query() \
489 group_perms = UserGroupRepoToPerm.query() \
488 .filter(UserGroupRepoToPerm.repository == repo).all()
490 .filter(UserGroupRepoToPerm.repository == repo).all()
489
491
490 for perm in user_perms:
492 for perm in user_perms:
491 UserRepoToPerm.create(
493 UserRepoToPerm.create(
492 perm.user, new_repo, perm.permission)
494 perm.user, new_repo, perm.permission)
493
495
494 for perm in group_perms:
496 for perm in group_perms:
495 UserGroupRepoToPerm.create(
497 UserGroupRepoToPerm.create(
496 perm.users_group, new_repo, perm.permission)
498 perm.users_group, new_repo, perm.permission)
497 # in case we copy permissions and also set this repo to private
499 # in case we copy permissions and also set this repo to private
498 # override the default user permission to make it a private
500 # override the default user permission to make it a private
499 # repo
501 # repo
500 if private:
502 if private:
501 RepoModel(self.sa).grant_user_permission(
503 RepoModel(self.sa).grant_user_permission(
502 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
504 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
503
505
504 elif repo_group and copy_group_permissions:
506 elif repo_group and copy_group_permissions:
505 user_perms = UserRepoGroupToPerm.query() \
507 user_perms = UserRepoGroupToPerm.query() \
506 .filter(UserRepoGroupToPerm.group == repo_group).all()
508 .filter(UserRepoGroupToPerm.group == repo_group).all()
507
509
508 group_perms = UserGroupRepoGroupToPerm.query() \
510 group_perms = UserGroupRepoGroupToPerm.query() \
509 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
511 .filter(UserGroupRepoGroupToPerm.group == repo_group).all()
510
512
511 for perm in user_perms:
513 for perm in user_perms:
512 perm_name = perm.permission.permission_name.replace(
514 perm_name = perm.permission.permission_name.replace(
513 'group.', 'repository.')
515 'group.', 'repository.')
514 perm_obj = Permission.get_by_key(perm_name)
516 perm_obj = Permission.get_by_key(perm_name)
515 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
517 UserRepoToPerm.create(perm.user, new_repo, perm_obj)
516
518
517 for perm in group_perms:
519 for perm in group_perms:
518 perm_name = perm.permission.permission_name.replace(
520 perm_name = perm.permission.permission_name.replace(
519 'group.', 'repository.')
521 'group.', 'repository.')
520 perm_obj = Permission.get_by_key(perm_name)
522 perm_obj = Permission.get_by_key(perm_name)
521 UserGroupRepoToPerm.create(
523 UserGroupRepoToPerm.create(
522 perm.users_group, new_repo, perm_obj)
524 perm.users_group, new_repo, perm_obj)
523
525
524 if private:
526 if private:
525 RepoModel(self.sa).grant_user_permission(
527 RepoModel(self.sa).grant_user_permission(
526 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
528 repo=new_repo, user=User.DEFAULT_USER, perm=EMPTY_PERM)
527
529
528 else:
530 else:
529 perm_obj = self._create_default_perms(new_repo, private)
531 perm_obj = self._create_default_perms(new_repo, private)
530 self.sa.add(perm_obj)
532 self.sa.add(perm_obj)
531
533
532 # now automatically start following this repository as owner
534 # now automatically start following this repository as owner
533 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
535 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
534 owner.user_id)
536 owner.user_id)
535
537
536 # we need to flush here, in order to check if database won't
538 # we need to flush here, in order to check if database won't
537 # throw any exceptions, create filesystem dirs at the very end
539 # throw any exceptions, create filesystem dirs at the very end
538 self.sa.flush()
540 self.sa.flush()
539 events.trigger(events.RepoCreateEvent(new_repo))
541 events.trigger(events.RepoCreateEvent(new_repo))
540 return new_repo
542 return new_repo
541
543
542 except Exception:
544 except Exception:
543 log.error(traceback.format_exc())
545 log.error(traceback.format_exc())
544 raise
546 raise
545
547
546 def create(self, form_data, cur_user):
548 def create(self, form_data, cur_user):
547 """
549 """
548 Create repository using celery tasks
550 Create repository using celery tasks
549
551
550 :param form_data:
552 :param form_data:
551 :param cur_user:
553 :param cur_user:
552 """
554 """
553 from rhodecode.lib.celerylib import tasks, run_task
555 from rhodecode.lib.celerylib import tasks, run_task
554 return run_task(tasks.create_repo, form_data, cur_user)
556 return run_task(tasks.create_repo, form_data, cur_user)
555
557
556 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
558 def update_permissions(self, repo, perm_additions=None, perm_updates=None,
557 perm_deletions=None, check_perms=True,
559 perm_deletions=None, check_perms=True,
558 cur_user=None):
560 cur_user=None):
559 if not perm_additions:
561 if not perm_additions:
560 perm_additions = []
562 perm_additions = []
561 if not perm_updates:
563 if not perm_updates:
562 perm_updates = []
564 perm_updates = []
563 if not perm_deletions:
565 if not perm_deletions:
564 perm_deletions = []
566 perm_deletions = []
565
567
566 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
568 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
567
569
568 # update permissions
570 # update permissions
569 for member_id, perm, member_type in perm_updates:
571 for member_id, perm, member_type in perm_updates:
570 member_id = int(member_id)
572 member_id = int(member_id)
571 if member_type == 'user':
573 if member_type == 'user':
572 # this updates also current one if found
574 # this updates also current one if found
573 self.grant_user_permission(
575 self.grant_user_permission(
574 repo=repo, user=member_id, perm=perm)
576 repo=repo, user=member_id, perm=perm)
575 else: # set for user group
577 else: # set for user group
576 # check if we have permissions to alter this usergroup
578 # check if we have permissions to alter this usergroup
577 member_name = UserGroup.get(member_id).users_group_name
579 member_name = UserGroup.get(member_id).users_group_name
578 if not check_perms or HasUserGroupPermissionAny(
580 if not check_perms or HasUserGroupPermissionAny(
579 *req_perms)(member_name, user=cur_user):
581 *req_perms)(member_name, user=cur_user):
580 self.grant_user_group_permission(
582 self.grant_user_group_permission(
581 repo=repo, group_name=member_id, perm=perm)
583 repo=repo, group_name=member_id, perm=perm)
582
584
583 # set new permissions
585 # set new permissions
584 for member_id, perm, member_type in perm_additions:
586 for member_id, perm, member_type in perm_additions:
585 member_id = int(member_id)
587 member_id = int(member_id)
586 if member_type == 'user':
588 if member_type == 'user':
587 self.grant_user_permission(
589 self.grant_user_permission(
588 repo=repo, user=member_id, perm=perm)
590 repo=repo, user=member_id, perm=perm)
589 else: # set for user group
591 else: # set for user group
590 # check if we have permissions to alter this usergroup
592 # check if we have permissions to alter this usergroup
591 member_name = UserGroup.get(member_id).users_group_name
593 member_name = UserGroup.get(member_id).users_group_name
592 if not check_perms or HasUserGroupPermissionAny(
594 if not check_perms or HasUserGroupPermissionAny(
593 *req_perms)(member_name, user=cur_user):
595 *req_perms)(member_name, user=cur_user):
594 self.grant_user_group_permission(
596 self.grant_user_group_permission(
595 repo=repo, group_name=member_id, perm=perm)
597 repo=repo, group_name=member_id, perm=perm)
596
598
597 # delete permissions
599 # delete permissions
598 for member_id, perm, member_type in perm_deletions:
600 for member_id, perm, member_type in perm_deletions:
599 member_id = int(member_id)
601 member_id = int(member_id)
600 if member_type == 'user':
602 if member_type == 'user':
601 self.revoke_user_permission(repo=repo, user=member_id)
603 self.revoke_user_permission(repo=repo, user=member_id)
602 else: # set for user group
604 else: # set for user group
603 # check if we have permissions to alter this usergroup
605 # check if we have permissions to alter this usergroup
604 member_name = UserGroup.get(member_id).users_group_name
606 member_name = UserGroup.get(member_id).users_group_name
605 if not check_perms or HasUserGroupPermissionAny(
607 if not check_perms or HasUserGroupPermissionAny(
606 *req_perms)(member_name, user=cur_user):
608 *req_perms)(member_name, user=cur_user):
607 self.revoke_user_group_permission(
609 self.revoke_user_group_permission(
608 repo=repo, group_name=member_id)
610 repo=repo, group_name=member_id)
609
611
610 def create_fork(self, form_data, cur_user):
612 def create_fork(self, form_data, cur_user):
611 """
613 """
612 Simple wrapper into executing celery task for fork creation
614 Simple wrapper into executing celery task for fork creation
613
615
614 :param form_data:
616 :param form_data:
615 :param cur_user:
617 :param cur_user:
616 """
618 """
617 from rhodecode.lib.celerylib import tasks, run_task
619 from rhodecode.lib.celerylib import tasks, run_task
618 return run_task(tasks.create_repo_fork, form_data, cur_user)
620 return run_task(tasks.create_repo_fork, form_data, cur_user)
619
621
620 def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
622 def delete(self, repo, forks=None, fs_remove=True, cur_user=None):
621 """
623 """
622 Delete given repository, forks parameter defines what do do with
624 Delete given repository, forks parameter defines what do do with
623 attached forks. Throws AttachedForksError if deleted repo has attached
625 attached forks. Throws AttachedForksError if deleted repo has attached
624 forks
626 forks
625
627
626 :param repo:
628 :param repo:
627 :param forks: str 'delete' or 'detach'
629 :param forks: str 'delete' or 'detach'
628 :param fs_remove: remove(archive) repo from filesystem
630 :param fs_remove: remove(archive) repo from filesystem
629 """
631 """
630 if not cur_user:
632 if not cur_user:
631 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
633 cur_user = getattr(get_current_rhodecode_user(), 'username', None)
632 repo = self._get_repo(repo)
634 repo = self._get_repo(repo)
633 if repo:
635 if repo:
634 if forks == 'detach':
636 if forks == 'detach':
635 for r in repo.forks:
637 for r in repo.forks:
636 r.fork = None
638 r.fork = None
637 self.sa.add(r)
639 self.sa.add(r)
638 elif forks == 'delete':
640 elif forks == 'delete':
639 for r in repo.forks:
641 for r in repo.forks:
640 self.delete(r, forks='delete')
642 self.delete(r, forks='delete')
641 elif [f for f in repo.forks]:
643 elif [f for f in repo.forks]:
642 raise AttachedForksError()
644 raise AttachedForksError()
643
645
644 old_repo_dict = repo.get_dict()
646 old_repo_dict = repo.get_dict()
645 events.trigger(events.RepoPreDeleteEvent(repo))
647 events.trigger(events.RepoPreDeleteEvent(repo))
646 try:
648 try:
647 self.sa.delete(repo)
649 self.sa.delete(repo)
648 if fs_remove:
650 if fs_remove:
649 self._delete_filesystem_repo(repo)
651 self._delete_filesystem_repo(repo)
650 else:
652 else:
651 log.debug('skipping removal from filesystem')
653 log.debug('skipping removal from filesystem')
652 old_repo_dict.update({
654 old_repo_dict.update({
653 'deleted_by': cur_user,
655 'deleted_by': cur_user,
654 'deleted_on': time.time(),
656 'deleted_on': time.time(),
655 })
657 })
656 log_delete_repository(**old_repo_dict)
658 log_delete_repository(**old_repo_dict)
657 events.trigger(events.RepoDeleteEvent(repo))
659 events.trigger(events.RepoDeleteEvent(repo))
658 except Exception:
660 except Exception:
659 log.error(traceback.format_exc())
661 log.error(traceback.format_exc())
660 raise
662 raise
661
663
662 def grant_user_permission(self, repo, user, perm):
664 def grant_user_permission(self, repo, user, perm):
663 """
665 """
664 Grant permission for user on given repository, or update existing one
666 Grant permission for user on given repository, or update existing one
665 if found
667 if found
666
668
667 :param repo: Instance of Repository, repository_id, or repository name
669 :param repo: Instance of Repository, repository_id, or repository name
668 :param user: Instance of User, user_id or username
670 :param user: Instance of User, user_id or username
669 :param perm: Instance of Permission, or permission_name
671 :param perm: Instance of Permission, or permission_name
670 """
672 """
671 user = self._get_user(user)
673 user = self._get_user(user)
672 repo = self._get_repo(repo)
674 repo = self._get_repo(repo)
673 permission = self._get_perm(perm)
675 permission = self._get_perm(perm)
674
676
675 # check if we have that permission already
677 # check if we have that permission already
676 obj = self.sa.query(UserRepoToPerm) \
678 obj = self.sa.query(UserRepoToPerm) \
677 .filter(UserRepoToPerm.user == user) \
679 .filter(UserRepoToPerm.user == user) \
678 .filter(UserRepoToPerm.repository == repo) \
680 .filter(UserRepoToPerm.repository == repo) \
679 .scalar()
681 .scalar()
680 if obj is None:
682 if obj is None:
681 # create new !
683 # create new !
682 obj = UserRepoToPerm()
684 obj = UserRepoToPerm()
683 obj.repository = repo
685 obj.repository = repo
684 obj.user = user
686 obj.user = user
685 obj.permission = permission
687 obj.permission = permission
686 self.sa.add(obj)
688 self.sa.add(obj)
687 log.debug('Granted perm %s to %s on %s', perm, user, repo)
689 log.debug('Granted perm %s to %s on %s', perm, user, repo)
688 action_logger_generic(
690 action_logger_generic(
689 'granted permission: {} to user: {} on repo: {}'.format(
691 'granted permission: {} to user: {} on repo: {}'.format(
690 perm, user, repo), namespace='security.repo')
692 perm, user, repo), namespace='security.repo')
691 return obj
693 return obj
692
694
693 def revoke_user_permission(self, repo, user):
695 def revoke_user_permission(self, repo, user):
694 """
696 """
695 Revoke permission for user on given repository
697 Revoke permission for user on given repository
696
698
697 :param repo: Instance of Repository, repository_id, or repository name
699 :param repo: Instance of Repository, repository_id, or repository name
698 :param user: Instance of User, user_id or username
700 :param user: Instance of User, user_id or username
699 """
701 """
700
702
701 user = self._get_user(user)
703 user = self._get_user(user)
702 repo = self._get_repo(repo)
704 repo = self._get_repo(repo)
703
705
704 obj = self.sa.query(UserRepoToPerm) \
706 obj = self.sa.query(UserRepoToPerm) \
705 .filter(UserRepoToPerm.repository == repo) \
707 .filter(UserRepoToPerm.repository == repo) \
706 .filter(UserRepoToPerm.user == user) \
708 .filter(UserRepoToPerm.user == user) \
707 .scalar()
709 .scalar()
708 if obj:
710 if obj:
709 self.sa.delete(obj)
711 self.sa.delete(obj)
710 log.debug('Revoked perm on %s on %s', repo, user)
712 log.debug('Revoked perm on %s on %s', repo, user)
711 action_logger_generic(
713 action_logger_generic(
712 'revoked permission from user: {} on repo: {}'.format(
714 'revoked permission from user: {} on repo: {}'.format(
713 user, repo), namespace='security.repo')
715 user, repo), namespace='security.repo')
714
716
715 def grant_user_group_permission(self, repo, group_name, perm):
717 def grant_user_group_permission(self, repo, group_name, perm):
716 """
718 """
717 Grant permission for user group on given repository, or update
719 Grant permission for user group on given repository, or update
718 existing one if found
720 existing one if found
719
721
720 :param repo: Instance of Repository, repository_id, or repository name
722 :param repo: Instance of Repository, repository_id, or repository name
721 :param group_name: Instance of UserGroup, users_group_id,
723 :param group_name: Instance of UserGroup, users_group_id,
722 or user group name
724 or user group name
723 :param perm: Instance of Permission, or permission_name
725 :param perm: Instance of Permission, or permission_name
724 """
726 """
725 repo = self._get_repo(repo)
727 repo = self._get_repo(repo)
726 group_name = self._get_user_group(group_name)
728 group_name = self._get_user_group(group_name)
727 permission = self._get_perm(perm)
729 permission = self._get_perm(perm)
728
730
729 # check if we have that permission already
731 # check if we have that permission already
730 obj = self.sa.query(UserGroupRepoToPerm) \
732 obj = self.sa.query(UserGroupRepoToPerm) \
731 .filter(UserGroupRepoToPerm.users_group == group_name) \
733 .filter(UserGroupRepoToPerm.users_group == group_name) \
732 .filter(UserGroupRepoToPerm.repository == repo) \
734 .filter(UserGroupRepoToPerm.repository == repo) \
733 .scalar()
735 .scalar()
734
736
735 if obj is None:
737 if obj is None:
736 # create new
738 # create new
737 obj = UserGroupRepoToPerm()
739 obj = UserGroupRepoToPerm()
738
740
739 obj.repository = repo
741 obj.repository = repo
740 obj.users_group = group_name
742 obj.users_group = group_name
741 obj.permission = permission
743 obj.permission = permission
742 self.sa.add(obj)
744 self.sa.add(obj)
743 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
745 log.debug('Granted perm %s to %s on %s', perm, group_name, repo)
744 action_logger_generic(
746 action_logger_generic(
745 'granted permission: {} to usergroup: {} on repo: {}'.format(
747 'granted permission: {} to usergroup: {} on repo: {}'.format(
746 perm, group_name, repo), namespace='security.repo')
748 perm, group_name, repo), namespace='security.repo')
747
749
748 return obj
750 return obj
749
751
750 def revoke_user_group_permission(self, repo, group_name):
752 def revoke_user_group_permission(self, repo, group_name):
751 """
753 """
752 Revoke permission for user group on given repository
754 Revoke permission for user group on given repository
753
755
754 :param repo: Instance of Repository, repository_id, or repository name
756 :param repo: Instance of Repository, repository_id, or repository name
755 :param group_name: Instance of UserGroup, users_group_id,
757 :param group_name: Instance of UserGroup, users_group_id,
756 or user group name
758 or user group name
757 """
759 """
758 repo = self._get_repo(repo)
760 repo = self._get_repo(repo)
759 group_name = self._get_user_group(group_name)
761 group_name = self._get_user_group(group_name)
760
762
761 obj = self.sa.query(UserGroupRepoToPerm) \
763 obj = self.sa.query(UserGroupRepoToPerm) \
762 .filter(UserGroupRepoToPerm.repository == repo) \
764 .filter(UserGroupRepoToPerm.repository == repo) \
763 .filter(UserGroupRepoToPerm.users_group == group_name) \
765 .filter(UserGroupRepoToPerm.users_group == group_name) \
764 .scalar()
766 .scalar()
765 if obj:
767 if obj:
766 self.sa.delete(obj)
768 self.sa.delete(obj)
767 log.debug('Revoked perm to %s on %s', repo, group_name)
769 log.debug('Revoked perm to %s on %s', repo, group_name)
768 action_logger_generic(
770 action_logger_generic(
769 'revoked permission from usergroup: {} on repo: {}'.format(
771 'revoked permission from usergroup: {} on repo: {}'.format(
770 group_name, repo), namespace='security.repo')
772 group_name, repo), namespace='security.repo')
771
773
772 def delete_stats(self, repo_name):
774 def delete_stats(self, repo_name):
773 """
775 """
774 removes stats for given repo
776 removes stats for given repo
775
777
776 :param repo_name:
778 :param repo_name:
777 """
779 """
778 repo = self._get_repo(repo_name)
780 repo = self._get_repo(repo_name)
779 try:
781 try:
780 obj = self.sa.query(Statistics) \
782 obj = self.sa.query(Statistics) \
781 .filter(Statistics.repository == repo).scalar()
783 .filter(Statistics.repository == repo).scalar()
782 if obj:
784 if obj:
783 self.sa.delete(obj)
785 self.sa.delete(obj)
784 except Exception:
786 except Exception:
785 log.error(traceback.format_exc())
787 log.error(traceback.format_exc())
786 raise
788 raise
787
789
788 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
790 def add_repo_field(self, repo_name, field_key, field_label, field_value='',
789 field_type='str', field_desc=''):
791 field_type='str', field_desc=''):
790
792
791 repo = self._get_repo(repo_name)
793 repo = self._get_repo(repo_name)
792
794
793 new_field = RepositoryField()
795 new_field = RepositoryField()
794 new_field.repository = repo
796 new_field.repository = repo
795 new_field.field_key = field_key
797 new_field.field_key = field_key
796 new_field.field_type = field_type # python type
798 new_field.field_type = field_type # python type
797 new_field.field_value = field_value
799 new_field.field_value = field_value
798 new_field.field_desc = field_desc
800 new_field.field_desc = field_desc
799 new_field.field_label = field_label
801 new_field.field_label = field_label
800 self.sa.add(new_field)
802 self.sa.add(new_field)
801 return new_field
803 return new_field
802
804
803 def delete_repo_field(self, repo_name, field_key):
805 def delete_repo_field(self, repo_name, field_key):
804 repo = self._get_repo(repo_name)
806 repo = self._get_repo(repo_name)
805 field = RepositoryField.get_by_key_name(field_key, repo)
807 field = RepositoryField.get_by_key_name(field_key, repo)
806 if field:
808 if field:
807 self.sa.delete(field)
809 self.sa.delete(field)
808
810
809 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
811 def _create_filesystem_repo(self, repo_name, repo_type, repo_group,
810 clone_uri=None, repo_store_location=None,
812 clone_uri=None, repo_store_location=None,
811 use_global_config=False):
813 use_global_config=False):
812 """
814 """
813 makes repository on filesystem. It's group aware means it'll create
815 makes repository on filesystem. It's group aware means it'll create
814 a repository within a group, and alter the paths accordingly of
816 a repository within a group, and alter the paths accordingly of
815 group location
817 group location
816
818
817 :param repo_name:
819 :param repo_name:
818 :param alias:
820 :param alias:
819 :param parent:
821 :param parent:
820 :param clone_uri:
822 :param clone_uri:
821 :param repo_store_location:
823 :param repo_store_location:
822 """
824 """
823 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
825 from rhodecode.lib.utils import is_valid_repo, is_valid_repo_group
824 from rhodecode.model.scm import ScmModel
826 from rhodecode.model.scm import ScmModel
825
827
826 if Repository.NAME_SEP in repo_name:
828 if Repository.NAME_SEP in repo_name:
827 raise ValueError(
829 raise ValueError(
828 'repo_name must not contain groups got `%s`' % repo_name)
830 'repo_name must not contain groups got `%s`' % repo_name)
829
831
830 if isinstance(repo_group, RepoGroup):
832 if isinstance(repo_group, RepoGroup):
831 new_parent_path = os.sep.join(repo_group.full_path_splitted)
833 new_parent_path = os.sep.join(repo_group.full_path_splitted)
832 else:
834 else:
833 new_parent_path = repo_group or ''
835 new_parent_path = repo_group or ''
834
836
835 if repo_store_location:
837 if repo_store_location:
836 _paths = [repo_store_location]
838 _paths = [repo_store_location]
837 else:
839 else:
838 _paths = [self.repos_path, new_parent_path, repo_name]
840 _paths = [self.repos_path, new_parent_path, repo_name]
839 # we need to make it str for mercurial
841 # we need to make it str for mercurial
840 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
842 repo_path = os.path.join(*map(lambda x: safe_str(x), _paths))
841
843
842 # check if this path is not a repository
844 # check if this path is not a repository
843 if is_valid_repo(repo_path, self.repos_path):
845 if is_valid_repo(repo_path, self.repos_path):
844 raise Exception('This path %s is a valid repository' % repo_path)
846 raise Exception('This path %s is a valid repository' % repo_path)
845
847
846 # check if this path is a group
848 # check if this path is a group
847 if is_valid_repo_group(repo_path, self.repos_path):
849 if is_valid_repo_group(repo_path, self.repos_path):
848 raise Exception('This path %s is a valid group' % repo_path)
850 raise Exception('This path %s is a valid group' % repo_path)
849
851
850 log.info('creating repo %s in %s from url: `%s`',
852 log.info('creating repo %s in %s from url: `%s`',
851 repo_name, safe_unicode(repo_path),
853 repo_name, safe_unicode(repo_path),
852 obfuscate_url_pw(clone_uri))
854 obfuscate_url_pw(clone_uri))
853
855
854 backend = get_backend(repo_type)
856 backend = get_backend(repo_type)
855
857
856 config_repo = None if use_global_config else repo_name
858 config_repo = None if use_global_config else repo_name
857 if config_repo and new_parent_path:
859 if config_repo and new_parent_path:
858 config_repo = Repository.NAME_SEP.join(
860 config_repo = Repository.NAME_SEP.join(
859 (new_parent_path, config_repo))
861 (new_parent_path, config_repo))
860 config = make_db_config(clear_session=False, repo=config_repo)
862 config = make_db_config(clear_session=False, repo=config_repo)
861 config.set('extensions', 'largefiles', '')
863 config.set('extensions', 'largefiles', '')
862
864
863 # patch and reset hooks section of UI config to not run any
865 # patch and reset hooks section of UI config to not run any
864 # hooks on creating remote repo
866 # hooks on creating remote repo
865 config.clear_section('hooks')
867 config.clear_section('hooks')
866
868
867 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
869 # TODO: johbo: Unify this, hardcoded "bare=True" does not look nice
868 if repo_type == 'git':
870 if repo_type == 'git':
869 repo = backend(
871 repo = backend(
870 repo_path, config=config, create=True, src_url=clone_uri,
872 repo_path, config=config, create=True, src_url=clone_uri,
871 bare=True)
873 bare=True)
872 else:
874 else:
873 repo = backend(
875 repo = backend(
874 repo_path, config=config, create=True, src_url=clone_uri)
876 repo_path, config=config, create=True, src_url=clone_uri)
875
877
876 ScmModel().install_hooks(repo, repo_type=repo_type)
878 ScmModel().install_hooks(repo, repo_type=repo_type)
877
879
878 log.debug('Created repo %s with %s backend',
880 log.debug('Created repo %s with %s backend',
879 safe_unicode(repo_name), safe_unicode(repo_type))
881 safe_unicode(repo_name), safe_unicode(repo_type))
880 return repo
882 return repo
881
883
882 def _rename_filesystem_repo(self, old, new):
884 def _rename_filesystem_repo(self, old, new):
883 """
885 """
884 renames repository on filesystem
886 renames repository on filesystem
885
887
886 :param old: old name
888 :param old: old name
887 :param new: new name
889 :param new: new name
888 """
890 """
889 log.info('renaming repo from %s to %s', old, new)
891 log.info('renaming repo from %s to %s', old, new)
890
892
891 old_path = os.path.join(self.repos_path, old)
893 old_path = os.path.join(self.repos_path, old)
892 new_path = os.path.join(self.repos_path, new)
894 new_path = os.path.join(self.repos_path, new)
893 if os.path.isdir(new_path):
895 if os.path.isdir(new_path):
894 raise Exception(
896 raise Exception(
895 'Was trying to rename to already existing dir %s' % new_path
897 'Was trying to rename to already existing dir %s' % new_path
896 )
898 )
897 shutil.move(old_path, new_path)
899 shutil.move(old_path, new_path)
898
900
899 def _delete_filesystem_repo(self, repo):
901 def _delete_filesystem_repo(self, repo):
900 """
902 """
901 removes repo from filesystem, the removal is acctually made by
903 removes repo from filesystem, the removal is acctually made by
902 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
904 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
903 repository is no longer valid for rhodecode, can be undeleted later on
905 repository is no longer valid for rhodecode, can be undeleted later on
904 by reverting the renames on this repository
906 by reverting the renames on this repository
905
907
906 :param repo: repo object
908 :param repo: repo object
907 """
909 """
908 rm_path = os.path.join(self.repos_path, repo.repo_name)
910 rm_path = os.path.join(self.repos_path, repo.repo_name)
909 repo_group = repo.group
911 repo_group = repo.group
910 log.info("Removing repository %s", rm_path)
912 log.info("Removing repository %s", rm_path)
911 # disable hg/git internal that it doesn't get detected as repo
913 # disable hg/git internal that it doesn't get detected as repo
912 alias = repo.repo_type
914 alias = repo.repo_type
913
915
914 config = make_db_config(clear_session=False)
916 config = make_db_config(clear_session=False)
915 config.set('extensions', 'largefiles', '')
917 config.set('extensions', 'largefiles', '')
916 bare = getattr(repo.scm_instance(config=config), 'bare', False)
918 bare = getattr(repo.scm_instance(config=config), 'bare', False)
917
919
918 # skip this for bare git repos
920 # skip this for bare git repos
919 if not bare:
921 if not bare:
920 # disable VCS repo
922 # disable VCS repo
921 vcs_path = os.path.join(rm_path, '.%s' % alias)
923 vcs_path = os.path.join(rm_path, '.%s' % alias)
922 if os.path.exists(vcs_path):
924 if os.path.exists(vcs_path):
923 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
925 shutil.move(vcs_path, os.path.join(rm_path, 'rm__.%s' % alias))
924
926
925 _now = datetime.now()
927 _now = datetime.now()
926 _ms = str(_now.microsecond).rjust(6, '0')
928 _ms = str(_now.microsecond).rjust(6, '0')
927 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
929 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
928 repo.just_name)
930 repo.just_name)
929 if repo_group:
931 if repo_group:
930 # if repository is in group, prefix the removal path with the group
932 # if repository is in group, prefix the removal path with the group
931 args = repo_group.full_path_splitted + [_d]
933 args = repo_group.full_path_splitted + [_d]
932 _d = os.path.join(*args)
934 _d = os.path.join(*args)
933
935
934 if os.path.isdir(rm_path):
936 if os.path.isdir(rm_path):
935 shutil.move(rm_path, os.path.join(self.repos_path, _d))
937 shutil.move(rm_path, os.path.join(self.repos_path, _d))
938
939
940 class ReadmeFinder:
941 """
942 Utility which knows how to find a readme for a specific commit.
943
944 The main idea is that this is a configurable algorithm. When creating an
945 instance you can define parameters, currently only the `default_renderer`.
946 Based on this configuration the method :meth:`search` behaves slightly
947 different.
948 """
949
950 def __init__(self, default_renderer):
951 self._default_renderer = default_renderer
952
953 def search(self, commit):
954 """
955 Try to find a readme in the given `commit`.
956 """
957 renderer = MarkupRenderer()
958 for f in renderer.pick_readme_order(self._default_renderer):
959 log.debug("Trying README %s", f)
960 try:
961 node = commit.get_node(f)
962 except NodeDoesNotExistError:
963 continue
964
965 if not node.is_file():
966 continue
967
968 return f
General Comments 0
You need to be logged in to leave comments. Login now