##// END OF EJS Templates
invalidation: don't create CacheInvalidation records on startup...
Mads Kiilerich -
r3774:60335b70 beta
parent child Browse files
Show More
@@ -1,242 +1,242 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.summary
3 rhodecode.controllers.summary
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Summary controller for Rhodecode
6 Summary controller for Rhodecode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import traceback
26 import traceback
27 import calendar
27 import calendar
28 import logging
28 import logging
29 import urllib
29 import urllib
30 from time import mktime
30 from time import mktime
31 from datetime import timedelta, date
31 from datetime import timedelta, date
32 from urlparse import urlparse
32 from urlparse import urlparse
33
33
34 from pylons import tmpl_context as c, request, url, config
34 from pylons import tmpl_context as c, request, url, config
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36 from webob.exc import HTTPBadRequest
36 from webob.exc import HTTPBadRequest
37
37
38 from beaker.cache import cache_region, region_invalidate
38 from beaker.cache import cache_region, region_invalidate
39
39
40 from rhodecode.lib import helpers as h
40 from rhodecode.lib import helpers as h
41 from rhodecode.lib.compat import product
41 from rhodecode.lib.compat import product
42 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
42 from rhodecode.lib.vcs.exceptions import ChangesetError, EmptyRepositoryError, \
43 NodeDoesNotExistError
43 NodeDoesNotExistError
44 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
44 from rhodecode.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP
45 from rhodecode.model.db import Statistics, CacheInvalidation
45 from rhodecode.model.db import Statistics, CacheInvalidation
46 from rhodecode.lib.utils import jsonify
46 from rhodecode.lib.utils import jsonify
47 from rhodecode.lib.utils2 import safe_unicode, safe_str
47 from rhodecode.lib.utils2 import safe_unicode, safe_str
48 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
48 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
49 NotAnonymous
49 NotAnonymous
50 from rhodecode.lib.base import BaseRepoController, render
50 from rhodecode.lib.base import BaseRepoController, render
51 from rhodecode.lib.vcs.backends.base import EmptyChangeset
51 from rhodecode.lib.vcs.backends.base import EmptyChangeset
52 from rhodecode.lib.markup_renderer import MarkupRenderer
52 from rhodecode.lib.markup_renderer import MarkupRenderer
53 from rhodecode.lib.celerylib import run_task
53 from rhodecode.lib.celerylib import run_task
54 from rhodecode.lib.celerylib.tasks import get_commits_stats
54 from rhodecode.lib.celerylib.tasks import get_commits_stats
55 from rhodecode.lib.helpers import RepoPage
55 from rhodecode.lib.helpers import RepoPage
56 from rhodecode.lib.compat import json, OrderedDict
56 from rhodecode.lib.compat import json, OrderedDict
57 from rhodecode.lib.vcs.nodes import FileNode
57 from rhodecode.lib.vcs.nodes import FileNode
58 from rhodecode.controllers.changelog import _load_changelog_summary
58 from rhodecode.controllers.changelog import _load_changelog_summary
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
62 README_FILES = [''.join([x[0][0], x[1][0]]) for x in
63 sorted(list(product(ALL_READMES, ALL_EXTS)),
63 sorted(list(product(ALL_READMES, ALL_EXTS)),
64 key=lambda y:y[0][1] + y[1][1])]
64 key=lambda y:y[0][1] + y[1][1])]
65
65
66
66
67 class SummaryController(BaseRepoController):
67 class SummaryController(BaseRepoController):
68
68
69 def __before__(self):
69 def __before__(self):
70 super(SummaryController, self).__before__()
70 super(SummaryController, self).__before__()
71
71
72 def _get_download_links(self, repo):
72 def _get_download_links(self, repo):
73
73
74 download_l = []
74 download_l = []
75
75
76 branches_group = ([], _("Branches"))
76 branches_group = ([], _("Branches"))
77 tags_group = ([], _("Tags"))
77 tags_group = ([], _("Tags"))
78
78
79 for name, chs in c.rhodecode_repo.branches.items():
79 for name, chs in c.rhodecode_repo.branches.items():
80 #chs = chs.split(':')[-1]
80 #chs = chs.split(':')[-1]
81 branches_group[0].append((chs, name),)
81 branches_group[0].append((chs, name),)
82 download_l.append(branches_group)
82 download_l.append(branches_group)
83
83
84 for name, chs in c.rhodecode_repo.tags.items():
84 for name, chs in c.rhodecode_repo.tags.items():
85 #chs = chs.split(':')[-1]
85 #chs = chs.split(':')[-1]
86 tags_group[0].append((chs, name),)
86 tags_group[0].append((chs, name),)
87 download_l.append(tags_group)
87 download_l.append(tags_group)
88
88
89 return download_l
89 return download_l
90
90
91 def __get_readme_data(self, db_repo):
91 def __get_readme_data(self, db_repo):
92 repo_name = db_repo.repo_name
92 repo_name = db_repo.repo_name
93
93
94 @cache_region('long_term')
94 @cache_region('long_term')
95 def _get_readme_from_cache(key, kind):
95 def _get_readme_from_cache(key, kind):
96 readme_data = None
96 readme_data = None
97 readme_file = None
97 readme_file = None
98 log.debug('Looking for README file')
98 log.debug('Looking for README file')
99 try:
99 try:
100 # get's the landing revision! or tip if fails
100 # get's the landing revision! or tip if fails
101 cs = db_repo.get_landing_changeset()
101 cs = db_repo.get_landing_changeset()
102 if isinstance(cs, EmptyChangeset):
102 if isinstance(cs, EmptyChangeset):
103 raise EmptyRepositoryError()
103 raise EmptyRepositoryError()
104 renderer = MarkupRenderer()
104 renderer = MarkupRenderer()
105 for f in README_FILES:
105 for f in README_FILES:
106 try:
106 try:
107 readme = cs.get_node(f)
107 readme = cs.get_node(f)
108 if not isinstance(readme, FileNode):
108 if not isinstance(readme, FileNode):
109 continue
109 continue
110 readme_file = f
110 readme_file = f
111 log.debug('Found README file `%s` rendering...' %
111 log.debug('Found README file `%s` rendering...' %
112 readme_file)
112 readme_file)
113 readme_data = renderer.render(readme.content, f)
113 readme_data = renderer.render(readme.content, f)
114 break
114 break
115 except NodeDoesNotExistError:
115 except NodeDoesNotExistError:
116 continue
116 continue
117 except ChangesetError:
117 except ChangesetError:
118 log.error(traceback.format_exc())
118 log.error(traceback.format_exc())
119 pass
119 pass
120 except EmptyRepositoryError:
120 except EmptyRepositoryError:
121 pass
121 pass
122 except Exception:
122 except Exception:
123 log.error(traceback.format_exc())
123 log.error(traceback.format_exc())
124
124
125 return readme_data, readme_file
125 return readme_data, readme_file
126
126
127 kind = 'README'
127 kind = 'README'
128 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
128 valid = CacheInvalidation.test_and_set_valid(repo_name, kind)
129 if not valid:
129 if not valid:
130 region_invalidate(_get_readme_from_cache, None, repo_name, kind)
130 region_invalidate(_get_readme_from_cache, None, repo_name, kind)
131 return _get_readme_from_cache(repo_name, kind)
131 return _get_readme_from_cache(repo_name, kind)
132
132
133 @LoginRequired()
133 @LoginRequired()
134 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
134 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
135 'repository.admin')
135 'repository.admin')
136 def index(self, repo_name):
136 def index(self, repo_name):
137 c.dbrepo = dbrepo = c.rhodecode_db_repo
137 c.dbrepo = dbrepo = c.rhodecode_db_repo
138 _load_changelog_summary()
138 _load_changelog_summary()
139 if self.rhodecode_user.username == 'default':
139 if self.rhodecode_user.username == 'default':
140 # for default(anonymous) user we don't need to pass credentials
140 # for default(anonymous) user we don't need to pass credentials
141 username = ''
141 username = ''
142 password = ''
142 password = ''
143 else:
143 else:
144 username = str(self.rhodecode_user.username)
144 username = str(self.rhodecode_user.username)
145 password = '@'
145 password = '@'
146
146
147 parsed_url = urlparse(url.current(qualified=True))
147 parsed_url = urlparse(url.current(qualified=True))
148
148
149 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
149 default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}'
150
150
151 uri_tmpl = config.get('clone_uri', default_clone_uri)
151 uri_tmpl = config.get('clone_uri', default_clone_uri)
152 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
152 uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s')
153 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
153 decoded_path = safe_unicode(urllib.unquote(parsed_url.path))
154 uri_dict = {
154 uri_dict = {
155 'user': urllib.quote(username),
155 'user': urllib.quote(username),
156 'pass': password,
156 'pass': password,
157 'scheme': parsed_url.scheme,
157 'scheme': parsed_url.scheme,
158 'netloc': parsed_url.netloc,
158 'netloc': parsed_url.netloc,
159 'path': urllib.quote(safe_str(decoded_path))
159 'path': urllib.quote(safe_str(decoded_path))
160 }
160 }
161
161
162 uri = (uri_tmpl % uri_dict)
162 uri = (uri_tmpl % uri_dict)
163 # generate another clone url by id
163 # generate another clone url by id
164 uri_dict.update(
164 uri_dict.update(
165 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
165 {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)}
166 )
166 )
167 uri_id = uri_tmpl % uri_dict
167 uri_id = uri_tmpl % uri_dict
168
168
169 c.clone_repo_url = uri
169 c.clone_repo_url = uri
170 c.clone_repo_url_id = uri_id
170 c.clone_repo_url_id = uri_id
171
171
172 td = date.today() + timedelta(days=1)
172 td = date.today() + timedelta(days=1)
173 td_1m = td - timedelta(days=calendar.mdays[td.month])
173 td_1m = td - timedelta(days=calendar.mdays[td.month])
174 td_1y = td - timedelta(days=365)
174 td_1y = td - timedelta(days=365)
175
175
176 ts_min_m = mktime(td_1m.timetuple())
176 ts_min_m = mktime(td_1m.timetuple())
177 ts_min_y = mktime(td_1y.timetuple())
177 ts_min_y = mktime(td_1y.timetuple())
178 ts_max_y = mktime(td.timetuple())
178 ts_max_y = mktime(td.timetuple())
179
179
180 if dbrepo.enable_statistics:
180 if dbrepo.enable_statistics:
181 c.show_stats = True
181 c.show_stats = True
182 c.no_data_msg = _('No data loaded yet')
182 c.no_data_msg = _('No data loaded yet')
183 recurse_limit = 500 # don't recurse more than 500 times when parsing
183 recurse_limit = 500 # don't recurse more than 500 times when parsing
184 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y,
184 run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y,
185 ts_max_y, recurse_limit)
185 ts_max_y, recurse_limit)
186 else:
186 else:
187 c.show_stats = False
187 c.show_stats = False
188 c.no_data_msg = _('Statistics are disabled for this repository')
188 c.no_data_msg = _('Statistics are disabled for this repository')
189 c.ts_min = ts_min_m
189 c.ts_min = ts_min_m
190 c.ts_max = ts_max_y
190 c.ts_max = ts_max_y
191
191
192 stats = self.sa.query(Statistics)\
192 stats = self.sa.query(Statistics)\
193 .filter(Statistics.repository == dbrepo)\
193 .filter(Statistics.repository == dbrepo)\
194 .scalar()
194 .scalar()
195
195
196 c.stats_percentage = 0
196 c.stats_percentage = 0
197
197
198 if stats and stats.languages:
198 if stats and stats.languages:
199 c.no_data = False is dbrepo.enable_statistics
199 c.no_data = False is dbrepo.enable_statistics
200 lang_stats_d = json.loads(stats.languages)
200 lang_stats_d = json.loads(stats.languages)
201 c.commit_data = stats.commit_activity
201 c.commit_data = stats.commit_activity
202 c.overview_data = stats.commit_activity_combined
202 c.overview_data = stats.commit_activity_combined
203
203
204 lang_stats = ((x, {"count": y,
204 lang_stats = ((x, {"count": y,
205 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
205 "desc": LANGUAGES_EXTENSIONS_MAP.get(x)})
206 for x, y in lang_stats_d.items())
206 for x, y in lang_stats_d.items())
207
207
208 c.trending_languages = json.dumps(
208 c.trending_languages = json.dumps(
209 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
209 sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]
210 )
210 )
211 last_rev = stats.stat_on_revision + 1
211 last_rev = stats.stat_on_revision + 1
212 c.repo_last_rev = c.rhodecode_repo.count()\
212 c.repo_last_rev = c.rhodecode_repo.count()\
213 if c.rhodecode_repo.revisions else 0
213 if c.rhodecode_repo.revisions else 0
214 if last_rev == 0 or c.repo_last_rev == 0:
214 if last_rev == 0 or c.repo_last_rev == 0:
215 pass
215 pass
216 else:
216 else:
217 c.stats_percentage = '%.2f' % ((float((last_rev)) /
217 c.stats_percentage = '%.2f' % ((float((last_rev)) /
218 c.repo_last_rev) * 100)
218 c.repo_last_rev) * 100)
219 else:
219 else:
220 c.commit_data = json.dumps({})
220 c.commit_data = json.dumps({})
221 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
221 c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]])
222 c.trending_languages = json.dumps({})
222 c.trending_languages = json.dumps({})
223 c.no_data = True
223 c.no_data = True
224
224
225 c.enable_downloads = dbrepo.enable_downloads
225 c.enable_downloads = dbrepo.enable_downloads
226 if c.enable_downloads:
226 if c.enable_downloads:
227 c.download_options = self._get_download_links(c.rhodecode_repo)
227 c.download_options = self._get_download_links(c.rhodecode_repo)
228
228
229 c.readme_data, c.readme_file = \
229 c.readme_data, c.readme_file = \
230 self.__get_readme_data(c.rhodecode_db_repo)
230 self.__get_readme_data(c.rhodecode_db_repo)
231 return render('summary/summary.html')
231 return render('summary/summary.html')
232
232
233 @LoginRequired()
233 @LoginRequired()
234 @NotAnonymous()
234 @NotAnonymous()
235 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
235 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
236 'repository.admin')
236 'repository.admin')
237 @jsonify
237 @jsonify
238 def repo_size(self, repo_name):
238 def repo_size(self, repo_name):
239 if request.is_xhr:
239 if request.is_xhr:
240 return c.rhodecode_db_repo._repo_size()
240 return c.rhodecode_db_repo._repo_size()
241 else:
241 else:
242 raise HTTPBadRequest()
242 raise HTTPBadRequest()
@@ -1,799 +1,794 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 import decorator
35 import decorator
36 import warnings
36 import warnings
37 from os.path import abspath
37 from os.path import abspath
38 from os.path import dirname as dn, join as jn
38 from os.path import dirname as dn, join as jn
39
39
40 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
41
41
42 from mercurial import ui, config
42 from mercurial import ui, config
43
43
44 from webhelpers.text import collapse, remove_formatting, strip_tags
44 from webhelpers.text import collapse, remove_formatting, strip_tags
45
45
46 from rhodecode.lib.vcs import get_backend
46 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
49 from rhodecode.lib.vcs.utils.helpers import get_scm
49 from rhodecode.lib.vcs.utils.helpers import get_scm
50 from rhodecode.lib.vcs.exceptions import VCSError
50 from rhodecode.lib.vcs.exceptions import VCSError
51
51
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model import meta
54 from rhodecode.model import meta
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
57 from rhodecode.model.meta import Session
57 from rhodecode.model.meta import Session
58 from rhodecode.model.repos_group import ReposGroupModel
58 from rhodecode.model.repos_group import ReposGroupModel
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
60 from rhodecode.lib.vcs.utils.fakemod import create_module
60 from rhodecode.lib.vcs.utils.fakemod import create_module
61 from rhodecode.model.users_group import UserGroupModel
61 from rhodecode.model.users_group import UserGroupModel
62
62
63 log = logging.getLogger(__name__)
63 log = logging.getLogger(__name__)
64
64
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
66
66
67
67
68 def recursive_replace(str_, replace=' '):
68 def recursive_replace(str_, replace=' '):
69 """
69 """
70 Recursive replace of given sign to just one instance
70 Recursive replace of given sign to just one instance
71
71
72 :param str_: given string
72 :param str_: given string
73 :param replace: char to find and replace multiple instances
73 :param replace: char to find and replace multiple instances
74
74
75 Examples::
75 Examples::
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
77 'Mighty-Mighty-Bo-sstones'
77 'Mighty-Mighty-Bo-sstones'
78 """
78 """
79
79
80 if str_.find(replace * 2) == -1:
80 if str_.find(replace * 2) == -1:
81 return str_
81 return str_
82 else:
82 else:
83 str_ = str_.replace(replace * 2, replace)
83 str_ = str_.replace(replace * 2, replace)
84 return recursive_replace(str_, replace)
84 return recursive_replace(str_, replace)
85
85
86
86
87 def repo_name_slug(value):
87 def repo_name_slug(value):
88 """
88 """
89 Return slug of name of repository
89 Return slug of name of repository
90 This function is called on each creation/modification
90 This function is called on each creation/modification
91 of repository to prevent bad names in repo
91 of repository to prevent bad names in repo
92 """
92 """
93
93
94 slug = remove_formatting(value)
94 slug = remove_formatting(value)
95 slug = strip_tags(slug)
95 slug = strip_tags(slug)
96
96
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
98 slug = slug.replace(c, '-')
98 slug = slug.replace(c, '-')
99 slug = recursive_replace(slug, '-')
99 slug = recursive_replace(slug, '-')
100 slug = collapse(slug, '-')
100 slug = collapse(slug, '-')
101 return slug
101 return slug
102
102
103
103
104 #==============================================================================
104 #==============================================================================
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
106 #==============================================================================
106 #==============================================================================
107 def get_repo_slug(request):
107 def get_repo_slug(request):
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
109 if _repo:
109 if _repo:
110 _repo = _repo.rstrip('/')
110 _repo = _repo.rstrip('/')
111 return _repo
111 return _repo
112
112
113
113
114 def get_repos_group_slug(request):
114 def get_repos_group_slug(request):
115 _group = request.environ['pylons.routes_dict'].get('group_name')
115 _group = request.environ['pylons.routes_dict'].get('group_name')
116 if _group:
116 if _group:
117 _group = _group.rstrip('/')
117 _group = _group.rstrip('/')
118 return _group
118 return _group
119
119
120
120
121 def get_user_group_slug(request):
121 def get_user_group_slug(request):
122 _group = request.environ['pylons.routes_dict'].get('id')
122 _group = request.environ['pylons.routes_dict'].get('id')
123 try:
123 try:
124 _group = UserGroup.get(_group)
124 _group = UserGroup.get(_group)
125 if _group:
125 if _group:
126 _group = _group.users_group_name
126 _group = _group.users_group_name
127 except Exception:
127 except Exception:
128 log.debug(traceback.format_exc())
128 log.debug(traceback.format_exc())
129 #catch all failures here
129 #catch all failures here
130 pass
130 pass
131
131
132 return _group
132 return _group
133
133
134
134
135 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
135 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
136 """
136 """
137 Action logger for various actions made by users
137 Action logger for various actions made by users
138
138
139 :param user: user that made this action, can be a unique username string or
139 :param user: user that made this action, can be a unique username string or
140 object containing user_id attribute
140 object containing user_id attribute
141 :param action: action to log, should be on of predefined unique actions for
141 :param action: action to log, should be on of predefined unique actions for
142 easy translations
142 easy translations
143 :param repo: string name of repository or object containing repo_id,
143 :param repo: string name of repository or object containing repo_id,
144 that action was made on
144 that action was made on
145 :param ipaddr: optional ip address from what the action was made
145 :param ipaddr: optional ip address from what the action was made
146 :param sa: optional sqlalchemy session
146 :param sa: optional sqlalchemy session
147
147
148 """
148 """
149
149
150 if not sa:
150 if not sa:
151 sa = meta.Session()
151 sa = meta.Session()
152
152
153 try:
153 try:
154 if hasattr(user, 'user_id'):
154 if hasattr(user, 'user_id'):
155 user_obj = User.get(user.user_id)
155 user_obj = User.get(user.user_id)
156 elif isinstance(user, basestring):
156 elif isinstance(user, basestring):
157 user_obj = User.get_by_username(user)
157 user_obj = User.get_by_username(user)
158 else:
158 else:
159 raise Exception('You have to provide a user object or a username')
159 raise Exception('You have to provide a user object or a username')
160
160
161 if hasattr(repo, 'repo_id'):
161 if hasattr(repo, 'repo_id'):
162 repo_obj = Repository.get(repo.repo_id)
162 repo_obj = Repository.get(repo.repo_id)
163 repo_name = repo_obj.repo_name
163 repo_name = repo_obj.repo_name
164 elif isinstance(repo, basestring):
164 elif isinstance(repo, basestring):
165 repo_name = repo.lstrip('/')
165 repo_name = repo.lstrip('/')
166 repo_obj = Repository.get_by_repo_name(repo_name)
166 repo_obj = Repository.get_by_repo_name(repo_name)
167 else:
167 else:
168 repo_obj = None
168 repo_obj = None
169 repo_name = ''
169 repo_name = ''
170
170
171 user_log = UserLog()
171 user_log = UserLog()
172 user_log.user_id = user_obj.user_id
172 user_log.user_id = user_obj.user_id
173 user_log.username = user_obj.username
173 user_log.username = user_obj.username
174 user_log.action = safe_unicode(action)
174 user_log.action = safe_unicode(action)
175
175
176 user_log.repository = repo_obj
176 user_log.repository = repo_obj
177 user_log.repository_name = repo_name
177 user_log.repository_name = repo_name
178
178
179 user_log.action_date = datetime.datetime.now()
179 user_log.action_date = datetime.datetime.now()
180 user_log.user_ip = ipaddr
180 user_log.user_ip = ipaddr
181 sa.add(user_log)
181 sa.add(user_log)
182
182
183 log.info('Logging action:%s on %s by user:%s ip:%s' %
183 log.info('Logging action:%s on %s by user:%s ip:%s' %
184 (action, safe_unicode(repo), user_obj, ipaddr))
184 (action, safe_unicode(repo), user_obj, ipaddr))
185 if commit:
185 if commit:
186 sa.commit()
186 sa.commit()
187 except Exception:
187 except Exception:
188 log.error(traceback.format_exc())
188 log.error(traceback.format_exc())
189 raise
189 raise
190
190
191
191
192 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
192 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
193 """
193 """
194 Scans given path for repos and return (name,(type,path)) tuple
194 Scans given path for repos and return (name,(type,path)) tuple
195
195
196 :param path: path to scan for repositories
196 :param path: path to scan for repositories
197 :param recursive: recursive search and return names with subdirs in front
197 :param recursive: recursive search and return names with subdirs in front
198 """
198 """
199
199
200 # remove ending slash for better results
200 # remove ending slash for better results
201 path = path.rstrip(os.sep)
201 path = path.rstrip(os.sep)
202 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
202 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
203
203
204 def _get_repos(p):
204 def _get_repos(p):
205 if not os.access(p, os.W_OK):
205 if not os.access(p, os.W_OK):
206 log.warn('ignoring repo path without write access: %s', p)
206 log.warn('ignoring repo path without write access: %s', p)
207 return
207 return
208 for dirpath in os.listdir(p):
208 for dirpath in os.listdir(p):
209 if os.path.isfile(os.path.join(p, dirpath)):
209 if os.path.isfile(os.path.join(p, dirpath)):
210 continue
210 continue
211 cur_path = os.path.join(p, dirpath)
211 cur_path = os.path.join(p, dirpath)
212
212
213 # skip removed repos
213 # skip removed repos
214 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
214 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
215 continue
215 continue
216
216
217 #skip .<somethin> dirs
217 #skip .<somethin> dirs
218 if dirpath.startswith('.'):
218 if dirpath.startswith('.'):
219 continue
219 continue
220
220
221 try:
221 try:
222 scm_info = get_scm(cur_path)
222 scm_info = get_scm(cur_path)
223 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
223 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
224 except VCSError:
224 except VCSError:
225 if not recursive:
225 if not recursive:
226 continue
226 continue
227 #check if this dir containts other repos for recursive scan
227 #check if this dir containts other repos for recursive scan
228 rec_path = os.path.join(p, dirpath)
228 rec_path = os.path.join(p, dirpath)
229 if os.path.isdir(rec_path):
229 if os.path.isdir(rec_path):
230 for inner_scm in _get_repos(rec_path):
230 for inner_scm in _get_repos(rec_path):
231 yield inner_scm
231 yield inner_scm
232
232
233 return _get_repos(path)
233 return _get_repos(path)
234
234
235
235
236 def is_valid_repo(repo_name, base_path, scm=None):
236 def is_valid_repo(repo_name, base_path, scm=None):
237 """
237 """
238 Returns True if given path is a valid repository False otherwise.
238 Returns True if given path is a valid repository False otherwise.
239 If scm param is given also compare if given scm is the same as expected
239 If scm param is given also compare if given scm is the same as expected
240 from scm parameter
240 from scm parameter
241
241
242 :param repo_name:
242 :param repo_name:
243 :param base_path:
243 :param base_path:
244 :param scm:
244 :param scm:
245
245
246 :return True: if given path is a valid repository
246 :return True: if given path is a valid repository
247 """
247 """
248 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
248 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
249
249
250 try:
250 try:
251 scm_ = get_scm(full_path)
251 scm_ = get_scm(full_path)
252 if scm:
252 if scm:
253 return scm_[0] == scm
253 return scm_[0] == scm
254 return True
254 return True
255 except VCSError:
255 except VCSError:
256 return False
256 return False
257
257
258
258
259 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
259 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
260 """
260 """
261 Returns True if given path is a repository group False otherwise
261 Returns True if given path is a repository group False otherwise
262
262
263 :param repo_name:
263 :param repo_name:
264 :param base_path:
264 :param base_path:
265 """
265 """
266 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
266 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
267
267
268 # check if it's not a repo
268 # check if it's not a repo
269 if is_valid_repo(repos_group_name, base_path):
269 if is_valid_repo(repos_group_name, base_path):
270 return False
270 return False
271
271
272 try:
272 try:
273 # we need to check bare git repos at higher level
273 # we need to check bare git repos at higher level
274 # since we might match branches/hooks/info/objects or possible
274 # since we might match branches/hooks/info/objects or possible
275 # other things inside bare git repo
275 # other things inside bare git repo
276 get_scm(os.path.dirname(full_path))
276 get_scm(os.path.dirname(full_path))
277 return False
277 return False
278 except VCSError:
278 except VCSError:
279 pass
279 pass
280
280
281 # check if it's a valid path
281 # check if it's a valid path
282 if skip_path_check or os.path.isdir(full_path):
282 if skip_path_check or os.path.isdir(full_path):
283 return True
283 return True
284
284
285 return False
285 return False
286
286
287
287
288 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
288 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
289 while True:
289 while True:
290 ok = raw_input(prompt)
290 ok = raw_input(prompt)
291 if ok in ('y', 'ye', 'yes'):
291 if ok in ('y', 'ye', 'yes'):
292 return True
292 return True
293 if ok in ('n', 'no', 'nop', 'nope'):
293 if ok in ('n', 'no', 'nop', 'nope'):
294 return False
294 return False
295 retries = retries - 1
295 retries = retries - 1
296 if retries < 0:
296 if retries < 0:
297 raise IOError
297 raise IOError
298 print complaint
298 print complaint
299
299
300 #propagated from mercurial documentation
300 #propagated from mercurial documentation
301 ui_sections = ['alias', 'auth',
301 ui_sections = ['alias', 'auth',
302 'decode/encode', 'defaults',
302 'decode/encode', 'defaults',
303 'diff', 'email',
303 'diff', 'email',
304 'extensions', 'format',
304 'extensions', 'format',
305 'merge-patterns', 'merge-tools',
305 'merge-patterns', 'merge-tools',
306 'hooks', 'http_proxy',
306 'hooks', 'http_proxy',
307 'smtp', 'patch',
307 'smtp', 'patch',
308 'paths', 'profiling',
308 'paths', 'profiling',
309 'server', 'trusted',
309 'server', 'trusted',
310 'ui', 'web', ]
310 'ui', 'web', ]
311
311
312
312
313 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
313 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
314 """
314 """
315 A function that will read python rc files or database
315 A function that will read python rc files or database
316 and make an mercurial ui object from read options
316 and make an mercurial ui object from read options
317
317
318 :param path: path to mercurial config file
318 :param path: path to mercurial config file
319 :param checkpaths: check the path
319 :param checkpaths: check the path
320 :param read_from: read from 'file' or 'db'
320 :param read_from: read from 'file' or 'db'
321 """
321 """
322
322
323 baseui = ui.ui()
323 baseui = ui.ui()
324
324
325 # clean the baseui object
325 # clean the baseui object
326 baseui._ocfg = config.config()
326 baseui._ocfg = config.config()
327 baseui._ucfg = config.config()
327 baseui._ucfg = config.config()
328 baseui._tcfg = config.config()
328 baseui._tcfg = config.config()
329
329
330 if read_from == 'file':
330 if read_from == 'file':
331 if not os.path.isfile(path):
331 if not os.path.isfile(path):
332 log.debug('hgrc file is not present at %s, skipping...' % path)
332 log.debug('hgrc file is not present at %s, skipping...' % path)
333 return False
333 return False
334 log.debug('reading hgrc from %s' % path)
334 log.debug('reading hgrc from %s' % path)
335 cfg = config.config()
335 cfg = config.config()
336 cfg.read(path)
336 cfg.read(path)
337 for section in ui_sections:
337 for section in ui_sections:
338 for k, v in cfg.items(section):
338 for k, v in cfg.items(section):
339 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
339 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
340 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
340 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
341
341
342 elif read_from == 'db':
342 elif read_from == 'db':
343 sa = meta.Session()
343 sa = meta.Session()
344 ret = sa.query(RhodeCodeUi)\
344 ret = sa.query(RhodeCodeUi)\
345 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
345 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
346 .all()
346 .all()
347
347
348 hg_ui = ret
348 hg_ui = ret
349 for ui_ in hg_ui:
349 for ui_ in hg_ui:
350 if ui_.ui_active:
350 if ui_.ui_active:
351 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
351 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
352 ui_.ui_key, ui_.ui_value)
352 ui_.ui_key, ui_.ui_value)
353 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
353 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
354 safe_str(ui_.ui_value))
354 safe_str(ui_.ui_value))
355 if ui_.ui_key == 'push_ssl':
355 if ui_.ui_key == 'push_ssl':
356 # force set push_ssl requirement to False, rhodecode
356 # force set push_ssl requirement to False, rhodecode
357 # handles that
357 # handles that
358 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
358 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
359 False)
359 False)
360 if clear_session:
360 if clear_session:
361 meta.Session.remove()
361 meta.Session.remove()
362 return baseui
362 return baseui
363
363
364
364
365 def set_rhodecode_config(config):
365 def set_rhodecode_config(config):
366 """
366 """
367 Updates pylons config with new settings from database
367 Updates pylons config with new settings from database
368
368
369 :param config:
369 :param config:
370 """
370 """
371 hgsettings = RhodeCodeSetting.get_app_settings()
371 hgsettings = RhodeCodeSetting.get_app_settings()
372
372
373 for k, v in hgsettings.items():
373 for k, v in hgsettings.items():
374 config[k] = v
374 config[k] = v
375
375
376
376
377 def map_groups(path):
377 def map_groups(path):
378 """
378 """
379 Given a full path to a repository, create all nested groups that this
379 Given a full path to a repository, create all nested groups that this
380 repo is inside. This function creates parent-child relationships between
380 repo is inside. This function creates parent-child relationships between
381 groups and creates default perms for all new groups.
381 groups and creates default perms for all new groups.
382
382
383 :param paths: full path to repository
383 :param paths: full path to repository
384 """
384 """
385 sa = meta.Session()
385 sa = meta.Session()
386 groups = path.split(Repository.url_sep())
386 groups = path.split(Repository.url_sep())
387 parent = None
387 parent = None
388 group = None
388 group = None
389
389
390 # last element is repo in nested groups structure
390 # last element is repo in nested groups structure
391 groups = groups[:-1]
391 groups = groups[:-1]
392 rgm = ReposGroupModel(sa)
392 rgm = ReposGroupModel(sa)
393 owner = User.get_first_admin()
393 owner = User.get_first_admin()
394 for lvl, group_name in enumerate(groups):
394 for lvl, group_name in enumerate(groups):
395 group_name = '/'.join(groups[:lvl] + [group_name])
395 group_name = '/'.join(groups[:lvl] + [group_name])
396 group = RepoGroup.get_by_group_name(group_name)
396 group = RepoGroup.get_by_group_name(group_name)
397 desc = '%s group' % group_name
397 desc = '%s group' % group_name
398
398
399 # skip folders that are now removed repos
399 # skip folders that are now removed repos
400 if REMOVED_REPO_PAT.match(group_name):
400 if REMOVED_REPO_PAT.match(group_name):
401 break
401 break
402
402
403 if group is None:
403 if group is None:
404 log.debug('creating group level: %s group_name: %s'
404 log.debug('creating group level: %s group_name: %s'
405 % (lvl, group_name))
405 % (lvl, group_name))
406 group = RepoGroup(group_name, parent)
406 group = RepoGroup(group_name, parent)
407 group.group_description = desc
407 group.group_description = desc
408 group.user = owner
408 group.user = owner
409 sa.add(group)
409 sa.add(group)
410 perm_obj = rgm._create_default_perms(group)
410 perm_obj = rgm._create_default_perms(group)
411 sa.add(perm_obj)
411 sa.add(perm_obj)
412 sa.flush()
412 sa.flush()
413
413
414 parent = group
414 parent = group
415 return group
415 return group
416
416
417
417
418 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
418 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
419 install_git_hook=False):
419 install_git_hook=False):
420 """
420 """
421 maps all repos given in initial_repo_list, non existing repositories
421 maps all repos given in initial_repo_list, non existing repositories
422 are created, if remove_obsolete is True it also check for db entries
422 are created, if remove_obsolete is True it also check for db entries
423 that are not in initial_repo_list and removes them.
423 that are not in initial_repo_list and removes them.
424
424
425 :param initial_repo_list: list of repositories found by scanning methods
425 :param initial_repo_list: list of repositories found by scanning methods
426 :param remove_obsolete: check for obsolete entries in database
426 :param remove_obsolete: check for obsolete entries in database
427 :param install_git_hook: if this is True, also check and install githook
427 :param install_git_hook: if this is True, also check and install githook
428 for a repo if missing
428 for a repo if missing
429 """
429 """
430 from rhodecode.model.repo import RepoModel
430 from rhodecode.model.repo import RepoModel
431 from rhodecode.model.scm import ScmModel
431 from rhodecode.model.scm import ScmModel
432 sa = meta.Session()
432 sa = meta.Session()
433 rm = RepoModel()
433 rm = RepoModel()
434 user = User.get_first_admin()
434 user = User.get_first_admin()
435 added = []
435 added = []
436
436
437 ##creation defaults
437 ##creation defaults
438 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
438 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
439 enable_statistics = defs.get('repo_enable_statistics')
439 enable_statistics = defs.get('repo_enable_statistics')
440 enable_locking = defs.get('repo_enable_locking')
440 enable_locking = defs.get('repo_enable_locking')
441 enable_downloads = defs.get('repo_enable_downloads')
441 enable_downloads = defs.get('repo_enable_downloads')
442 private = defs.get('repo_private')
442 private = defs.get('repo_private')
443
443
444 for name, repo in initial_repo_list.items():
444 for name, repo in initial_repo_list.items():
445 group = map_groups(name)
445 group = map_groups(name)
446 db_repo = rm.get_by_repo_name(name)
446 db_repo = rm.get_by_repo_name(name)
447 # found repo that is on filesystem not in RhodeCode database
447 # found repo that is on filesystem not in RhodeCode database
448 if not db_repo:
448 if not db_repo:
449 log.info('repository %s not found, creating now' % name)
449 log.info('repository %s not found, creating now' % name)
450 added.append(name)
450 added.append(name)
451 desc = (repo.description
451 desc = (repo.description
452 if repo.description != 'unknown'
452 if repo.description != 'unknown'
453 else '%s repository' % name)
453 else '%s repository' % name)
454
454
455 new_repo = rm.create_repo(
455 new_repo = rm.create_repo(
456 repo_name=name,
456 repo_name=name,
457 repo_type=repo.alias,
457 repo_type=repo.alias,
458 description=desc,
458 description=desc,
459 repos_group=getattr(group, 'group_id', None),
459 repos_group=getattr(group, 'group_id', None),
460 owner=user,
460 owner=user,
461 just_db=True,
461 just_db=True,
462 enable_locking=enable_locking,
462 enable_locking=enable_locking,
463 enable_downloads=enable_downloads,
463 enable_downloads=enable_downloads,
464 enable_statistics=enable_statistics,
464 enable_statistics=enable_statistics,
465 private=private
465 private=private
466 )
466 )
467 # we added that repo just now, and make sure it has githook
467 # we added that repo just now, and make sure it has githook
468 # installed
468 # installed
469 if new_repo.repo_type == 'git':
469 if new_repo.repo_type == 'git':
470 ScmModel().install_git_hook(new_repo.scm_instance)
470 ScmModel().install_git_hook(new_repo.scm_instance)
471 new_repo.update_changeset_cache()
471 new_repo.update_changeset_cache()
472 elif install_git_hook:
472 elif install_git_hook:
473 if db_repo.repo_type == 'git':
473 if db_repo.repo_type == 'git':
474 ScmModel().install_git_hook(db_repo.scm_instance)
474 ScmModel().install_git_hook(db_repo.scm_instance)
475 # during starting install all cache keys for all repositories in the
476 # system, this will register all repos and multiple instances
477 cache_key = CacheInvalidation._get_cache_key(name)
478 log.debug("Creating invalidation cache key for %s: %s", name, cache_key)
479 CacheInvalidation.test_and_set_valid(name, None)
480
475
481 sa.commit()
476 sa.commit()
482 removed = []
477 removed = []
483 if remove_obsolete:
478 if remove_obsolete:
484 # remove from database those repositories that are not in the filesystem
479 # remove from database those repositories that are not in the filesystem
485 for repo in sa.query(Repository).all():
480 for repo in sa.query(Repository).all():
486 if repo.repo_name not in initial_repo_list.keys():
481 if repo.repo_name not in initial_repo_list.keys():
487 log.debug("Removing non-existing repository found in db `%s`" %
482 log.debug("Removing non-existing repository found in db `%s`" %
488 repo.repo_name)
483 repo.repo_name)
489 try:
484 try:
490 removed.append(repo.repo_name)
485 removed.append(repo.repo_name)
491 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
486 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
492 sa.commit()
487 sa.commit()
493 except Exception:
488 except Exception:
494 #don't hold further removals on error
489 #don't hold further removals on error
495 log.error(traceback.format_exc())
490 log.error(traceback.format_exc())
496 sa.rollback()
491 sa.rollback()
497 return added, removed
492 return added, removed
498
493
499
494
500 # set cache regions for beaker so celery can utilise it
495 # set cache regions for beaker so celery can utilise it
501 def add_cache(settings):
496 def add_cache(settings):
502 cache_settings = {'regions': None}
497 cache_settings = {'regions': None}
503 for key in settings.keys():
498 for key in settings.keys():
504 for prefix in ['beaker.cache.', 'cache.']:
499 for prefix in ['beaker.cache.', 'cache.']:
505 if key.startswith(prefix):
500 if key.startswith(prefix):
506 name = key.split(prefix)[1].strip()
501 name = key.split(prefix)[1].strip()
507 cache_settings[name] = settings[key].strip()
502 cache_settings[name] = settings[key].strip()
508 if cache_settings['regions']:
503 if cache_settings['regions']:
509 for region in cache_settings['regions'].split(','):
504 for region in cache_settings['regions'].split(','):
510 region = region.strip()
505 region = region.strip()
511 region_settings = {}
506 region_settings = {}
512 for key, value in cache_settings.items():
507 for key, value in cache_settings.items():
513 if key.startswith(region):
508 if key.startswith(region):
514 region_settings[key.split('.')[1]] = value
509 region_settings[key.split('.')[1]] = value
515 region_settings['expire'] = int(region_settings.get('expire',
510 region_settings['expire'] = int(region_settings.get('expire',
516 60))
511 60))
517 region_settings.setdefault('lock_dir',
512 region_settings.setdefault('lock_dir',
518 cache_settings.get('lock_dir'))
513 cache_settings.get('lock_dir'))
519 region_settings.setdefault('data_dir',
514 region_settings.setdefault('data_dir',
520 cache_settings.get('data_dir'))
515 cache_settings.get('data_dir'))
521
516
522 if 'type' not in region_settings:
517 if 'type' not in region_settings:
523 region_settings['type'] = cache_settings.get('type',
518 region_settings['type'] = cache_settings.get('type',
524 'memory')
519 'memory')
525 beaker.cache.cache_regions[region] = region_settings
520 beaker.cache.cache_regions[region] = region_settings
526
521
527
522
528 def load_rcextensions(root_path):
523 def load_rcextensions(root_path):
529 import rhodecode
524 import rhodecode
530 from rhodecode.config import conf
525 from rhodecode.config import conf
531
526
532 path = os.path.join(root_path, 'rcextensions', '__init__.py')
527 path = os.path.join(root_path, 'rcextensions', '__init__.py')
533 if os.path.isfile(path):
528 if os.path.isfile(path):
534 rcext = create_module('rc', path)
529 rcext = create_module('rc', path)
535 EXT = rhodecode.EXTENSIONS = rcext
530 EXT = rhodecode.EXTENSIONS = rcext
536 log.debug('Found rcextensions now loading %s...' % rcext)
531 log.debug('Found rcextensions now loading %s...' % rcext)
537
532
538 # Additional mappings that are not present in the pygments lexers
533 # Additional mappings that are not present in the pygments lexers
539 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
534 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
540
535
541 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
536 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
542
537
543 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
538 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
544 log.debug('settings custom INDEX_EXTENSIONS')
539 log.debug('settings custom INDEX_EXTENSIONS')
545 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
540 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
546
541
547 #ADDITIONAL MAPPINGS
542 #ADDITIONAL MAPPINGS
548 log.debug('adding extra into INDEX_EXTENSIONS')
543 log.debug('adding extra into INDEX_EXTENSIONS')
549 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
544 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
550
545
551 # auto check if the module is not missing any data, set to default if is
546 # auto check if the module is not missing any data, set to default if is
552 # this will help autoupdate new feature of rcext module
547 # this will help autoupdate new feature of rcext module
553 from rhodecode.config import rcextensions
548 from rhodecode.config import rcextensions
554 for k in dir(rcextensions):
549 for k in dir(rcextensions):
555 if not k.startswith('_') and not hasattr(EXT, k):
550 if not k.startswith('_') and not hasattr(EXT, k):
556 setattr(EXT, k, getattr(rcextensions, k))
551 setattr(EXT, k, getattr(rcextensions, k))
557
552
558
553
559 def get_custom_lexer(extension):
554 def get_custom_lexer(extension):
560 """
555 """
561 returns a custom lexer if it's defined in rcextensions module, or None
556 returns a custom lexer if it's defined in rcextensions module, or None
562 if there's no custom lexer defined
557 if there's no custom lexer defined
563 """
558 """
564 import rhodecode
559 import rhodecode
565 from pygments import lexers
560 from pygments import lexers
566 #check if we didn't define this extension as other lexer
561 #check if we didn't define this extension as other lexer
567 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
562 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
568 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
563 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
569 return lexers.get_lexer_by_name(_lexer_name)
564 return lexers.get_lexer_by_name(_lexer_name)
570
565
571
566
572 #==============================================================================
567 #==============================================================================
573 # TEST FUNCTIONS AND CREATORS
568 # TEST FUNCTIONS AND CREATORS
574 #==============================================================================
569 #==============================================================================
575 def create_test_index(repo_location, config, full_index):
570 def create_test_index(repo_location, config, full_index):
576 """
571 """
577 Makes default test index
572 Makes default test index
578
573
579 :param config: test config
574 :param config: test config
580 :param full_index:
575 :param full_index:
581 """
576 """
582
577
583 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
578 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
584 from rhodecode.lib.pidlock import DaemonLock, LockHeld
579 from rhodecode.lib.pidlock import DaemonLock, LockHeld
585
580
586 repo_location = repo_location
581 repo_location = repo_location
587
582
588 index_location = os.path.join(config['app_conf']['index_dir'])
583 index_location = os.path.join(config['app_conf']['index_dir'])
589 if not os.path.exists(index_location):
584 if not os.path.exists(index_location):
590 os.makedirs(index_location)
585 os.makedirs(index_location)
591
586
592 try:
587 try:
593 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
588 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
594 WhooshIndexingDaemon(index_location=index_location,
589 WhooshIndexingDaemon(index_location=index_location,
595 repo_location=repo_location)\
590 repo_location=repo_location)\
596 .run(full_index=full_index)
591 .run(full_index=full_index)
597 l.release()
592 l.release()
598 except LockHeld:
593 except LockHeld:
599 pass
594 pass
600
595
601
596
602 def create_test_env(repos_test_path, config):
597 def create_test_env(repos_test_path, config):
603 """
598 """
604 Makes a fresh database and
599 Makes a fresh database and
605 install test repository into tmp dir
600 install test repository into tmp dir
606 """
601 """
607 from rhodecode.lib.db_manage import DbManage
602 from rhodecode.lib.db_manage import DbManage
608 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
603 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
609
604
610 # PART ONE create db
605 # PART ONE create db
611 dbconf = config['sqlalchemy.db1.url']
606 dbconf = config['sqlalchemy.db1.url']
612 log.debug('making test db %s' % dbconf)
607 log.debug('making test db %s' % dbconf)
613
608
614 # create test dir if it doesn't exist
609 # create test dir if it doesn't exist
615 if not os.path.isdir(repos_test_path):
610 if not os.path.isdir(repos_test_path):
616 log.debug('Creating testdir %s' % repos_test_path)
611 log.debug('Creating testdir %s' % repos_test_path)
617 os.makedirs(repos_test_path)
612 os.makedirs(repos_test_path)
618
613
619 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
614 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
620 tests=True)
615 tests=True)
621 dbmanage.create_tables(override=True)
616 dbmanage.create_tables(override=True)
622 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
617 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
623 dbmanage.create_default_user()
618 dbmanage.create_default_user()
624 dbmanage.admin_prompt()
619 dbmanage.admin_prompt()
625 dbmanage.create_permissions()
620 dbmanage.create_permissions()
626 dbmanage.populate_default_permissions()
621 dbmanage.populate_default_permissions()
627 Session().commit()
622 Session().commit()
628 # PART TWO make test repo
623 # PART TWO make test repo
629 log.debug('making test vcs repositories')
624 log.debug('making test vcs repositories')
630
625
631 idx_path = config['app_conf']['index_dir']
626 idx_path = config['app_conf']['index_dir']
632 data_path = config['app_conf']['cache_dir']
627 data_path = config['app_conf']['cache_dir']
633
628
634 #clean index and data
629 #clean index and data
635 if idx_path and os.path.exists(idx_path):
630 if idx_path and os.path.exists(idx_path):
636 log.debug('remove %s' % idx_path)
631 log.debug('remove %s' % idx_path)
637 shutil.rmtree(idx_path)
632 shutil.rmtree(idx_path)
638
633
639 if data_path and os.path.exists(data_path):
634 if data_path and os.path.exists(data_path):
640 log.debug('remove %s' % data_path)
635 log.debug('remove %s' % data_path)
641 shutil.rmtree(data_path)
636 shutil.rmtree(data_path)
642
637
643 #CREATE DEFAULT TEST REPOS
638 #CREATE DEFAULT TEST REPOS
644 cur_dir = dn(dn(abspath(__file__)))
639 cur_dir = dn(dn(abspath(__file__)))
645 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
640 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
646 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
641 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
647 tar.close()
642 tar.close()
648
643
649 cur_dir = dn(dn(abspath(__file__)))
644 cur_dir = dn(dn(abspath(__file__)))
650 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
645 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
651 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
646 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
652 tar.close()
647 tar.close()
653
648
654 #LOAD VCS test stuff
649 #LOAD VCS test stuff
655 from rhodecode.tests.vcs import setup_package
650 from rhodecode.tests.vcs import setup_package
656 setup_package()
651 setup_package()
657
652
658
653
659 #==============================================================================
654 #==============================================================================
660 # PASTER COMMANDS
655 # PASTER COMMANDS
661 #==============================================================================
656 #==============================================================================
662 class BasePasterCommand(Command):
657 class BasePasterCommand(Command):
663 """
658 """
664 Abstract Base Class for paster commands.
659 Abstract Base Class for paster commands.
665
660
666 The celery commands are somewhat aggressive about loading
661 The celery commands are somewhat aggressive about loading
667 celery.conf, and since our module sets the `CELERY_LOADER`
662 celery.conf, and since our module sets the `CELERY_LOADER`
668 environment variable to our loader, we have to bootstrap a bit and
663 environment variable to our loader, we have to bootstrap a bit and
669 make sure we've had a chance to load the pylons config off of the
664 make sure we've had a chance to load the pylons config off of the
670 command line, otherwise everything fails.
665 command line, otherwise everything fails.
671 """
666 """
672 min_args = 1
667 min_args = 1
673 min_args_error = "Please provide a paster config file as an argument."
668 min_args_error = "Please provide a paster config file as an argument."
674 takes_config_file = 1
669 takes_config_file = 1
675 requires_config_file = True
670 requires_config_file = True
676
671
677 def notify_msg(self, msg, log=False):
672 def notify_msg(self, msg, log=False):
678 """Make a notification to user, additionally if logger is passed
673 """Make a notification to user, additionally if logger is passed
679 it logs this action using given logger
674 it logs this action using given logger
680
675
681 :param msg: message that will be printed to user
676 :param msg: message that will be printed to user
682 :param log: logging instance, to use to additionally log this message
677 :param log: logging instance, to use to additionally log this message
683
678
684 """
679 """
685 if log and isinstance(log, logging):
680 if log and isinstance(log, logging):
686 log(msg)
681 log(msg)
687
682
688 def run(self, args):
683 def run(self, args):
689 """
684 """
690 Overrides Command.run
685 Overrides Command.run
691
686
692 Checks for a config file argument and loads it.
687 Checks for a config file argument and loads it.
693 """
688 """
694 if len(args) < self.min_args:
689 if len(args) < self.min_args:
695 raise BadCommand(
690 raise BadCommand(
696 self.min_args_error % {'min_args': self.min_args,
691 self.min_args_error % {'min_args': self.min_args,
697 'actual_args': len(args)})
692 'actual_args': len(args)})
698
693
699 # Decrement because we're going to lob off the first argument.
694 # Decrement because we're going to lob off the first argument.
700 # @@ This is hacky
695 # @@ This is hacky
701 self.min_args -= 1
696 self.min_args -= 1
702 self.bootstrap_config(args[0])
697 self.bootstrap_config(args[0])
703 self.update_parser()
698 self.update_parser()
704 return super(BasePasterCommand, self).run(args[1:])
699 return super(BasePasterCommand, self).run(args[1:])
705
700
706 def update_parser(self):
701 def update_parser(self):
707 """
702 """
708 Abstract method. Allows for the class's parser to be updated
703 Abstract method. Allows for the class's parser to be updated
709 before the superclass's `run` method is called. Necessary to
704 before the superclass's `run` method is called. Necessary to
710 allow options/arguments to be passed through to the underlying
705 allow options/arguments to be passed through to the underlying
711 celery command.
706 celery command.
712 """
707 """
713 raise NotImplementedError("Abstract Method.")
708 raise NotImplementedError("Abstract Method.")
714
709
715 def bootstrap_config(self, conf):
710 def bootstrap_config(self, conf):
716 """
711 """
717 Loads the pylons configuration.
712 Loads the pylons configuration.
718 """
713 """
719 from pylons import config as pylonsconfig
714 from pylons import config as pylonsconfig
720
715
721 self.path_to_ini_file = os.path.realpath(conf)
716 self.path_to_ini_file = os.path.realpath(conf)
722 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
717 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
723 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
718 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
724
719
725 def _init_session(self):
720 def _init_session(self):
726 """
721 """
727 Inits SqlAlchemy Session
722 Inits SqlAlchemy Session
728 """
723 """
729 logging.config.fileConfig(self.path_to_ini_file)
724 logging.config.fileConfig(self.path_to_ini_file)
730 from pylons import config
725 from pylons import config
731 from rhodecode.model import init_model
726 from rhodecode.model import init_model
732 from rhodecode.lib.utils2 import engine_from_config
727 from rhodecode.lib.utils2 import engine_from_config
733
728
734 #get to remove repos !!
729 #get to remove repos !!
735 add_cache(config)
730 add_cache(config)
736 engine = engine_from_config(config, 'sqlalchemy.db1.')
731 engine = engine_from_config(config, 'sqlalchemy.db1.')
737 init_model(engine)
732 init_model(engine)
738
733
739
734
740 def check_git_version():
735 def check_git_version():
741 """
736 """
742 Checks what version of git is installed in system, and issues a warning
737 Checks what version of git is installed in system, and issues a warning
743 if it's too old for RhodeCode to properly work.
738 if it's too old for RhodeCode to properly work.
744 """
739 """
745 from rhodecode import BACKENDS
740 from rhodecode import BACKENDS
746 from rhodecode.lib.vcs.backends.git.repository import GitRepository
741 from rhodecode.lib.vcs.backends.git.repository import GitRepository
747 from distutils.version import StrictVersion
742 from distutils.version import StrictVersion
748
743
749 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
744 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
750 _safe=True)
745 _safe=True)
751
746
752 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
747 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
753 if len(ver.split('.')) > 3:
748 if len(ver.split('.')) > 3:
754 #StrictVersion needs to be only 3 element type
749 #StrictVersion needs to be only 3 element type
755 ver = '.'.join(ver.split('.')[:3])
750 ver = '.'.join(ver.split('.')[:3])
756 try:
751 try:
757 _ver = StrictVersion(ver)
752 _ver = StrictVersion(ver)
758 except Exception:
753 except Exception:
759 _ver = StrictVersion('0.0.0')
754 _ver = StrictVersion('0.0.0')
760 stderr = traceback.format_exc()
755 stderr = traceback.format_exc()
761
756
762 req_ver = '1.7.4'
757 req_ver = '1.7.4'
763 to_old_git = False
758 to_old_git = False
764 if _ver < StrictVersion(req_ver):
759 if _ver < StrictVersion(req_ver):
765 to_old_git = True
760 to_old_git = True
766
761
767 if 'git' in BACKENDS:
762 if 'git' in BACKENDS:
768 log.debug('GIT version detected: %s' % stdout)
763 log.debug('GIT version detected: %s' % stdout)
769 if stderr:
764 if stderr:
770 log.warning('Unable to detect git version, org error was: %r' % stderr)
765 log.warning('Unable to detect git version, org error was: %r' % stderr)
771 elif to_old_git:
766 elif to_old_git:
772 log.warning('RhodeCode detected git version %s, which is too old '
767 log.warning('RhodeCode detected git version %s, which is too old '
773 'for the system to function properly. Make sure '
768 'for the system to function properly. Make sure '
774 'its version is at least %s' % (ver, req_ver))
769 'its version is at least %s' % (ver, req_ver))
775 return _ver
770 return _ver
776
771
777
772
778 @decorator.decorator
773 @decorator.decorator
779 def jsonify(func, *args, **kwargs):
774 def jsonify(func, *args, **kwargs):
780 """Action decorator that formats output for JSON
775 """Action decorator that formats output for JSON
781
776
782 Given a function that will return content, this decorator will turn
777 Given a function that will return content, this decorator will turn
783 the result into JSON, with a content-type of 'application/json' and
778 the result into JSON, with a content-type of 'application/json' and
784 output it.
779 output it.
785
780
786 """
781 """
787 from pylons.decorators.util import get_pylons
782 from pylons.decorators.util import get_pylons
788 from rhodecode.lib.compat import json
783 from rhodecode.lib.compat import json
789 pylons = get_pylons(args)
784 pylons = get_pylons(args)
790 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
785 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
791 data = func(*args, **kwargs)
786 data = func(*args, **kwargs)
792 if isinstance(data, (list, tuple)):
787 if isinstance(data, (list, tuple)):
793 msg = "JSON responses with Array envelopes are susceptible to " \
788 msg = "JSON responses with Array envelopes are susceptible to " \
794 "cross-site data leak attacks, see " \
789 "cross-site data leak attacks, see " \
795 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
790 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
796 warnings.warn(msg, Warning, 2)
791 warnings.warn(msg, Warning, 2)
797 log.warning(msg)
792 log.warning(msg)
798 log.debug("Returning JSON wrapped action output")
793 log.debug("Returning JSON wrapped action output")
799 return json.dumps(data, encoding='utf-8')
794 return json.dumps(data, encoding='utf-8')
@@ -1,1307 +1,1310 b''
1 from __future__ import with_statement
1 from __future__ import with_statement
2 import random
2 import random
3 import mock
3 import mock
4
4
5 from rhodecode.tests import *
5 from rhodecode.tests import *
6 from rhodecode.tests.fixture import Fixture
6 from rhodecode.tests.fixture import Fixture
7 from rhodecode.lib.compat import json
7 from rhodecode.lib.compat import json
8 from rhodecode.lib.auth import AuthUser
8 from rhodecode.lib.auth import AuthUser
9 from rhodecode.model.user import UserModel
9 from rhodecode.model.user import UserModel
10 from rhodecode.model.users_group import UserGroupModel
10 from rhodecode.model.users_group import UserGroupModel
11 from rhodecode.model.repo import RepoModel
11 from rhodecode.model.repo import RepoModel
12 from rhodecode.model.meta import Session
12 from rhodecode.model.meta import Session
13 from rhodecode.model.scm import ScmModel
13 from rhodecode.model.scm import ScmModel
14 from rhodecode.model.db import Repository
14 from rhodecode.model.db import Repository
15
15
16
16
17 API_URL = '/_admin/api'
17 API_URL = '/_admin/api'
18 TEST_USER_GROUP = 'test_users_group'
18 TEST_USER_GROUP = 'test_users_group'
19
19
20 fixture = Fixture()
20 fixture = Fixture()
21
21
22
22
23 def _build_data(apikey, method, **kw):
23 def _build_data(apikey, method, **kw):
24 """
24 """
25 Builds API data with given random ID
25 Builds API data with given random ID
26
26
27 :param random_id:
27 :param random_id:
28 :type random_id:
28 :type random_id:
29 """
29 """
30 random_id = random.randrange(1, 9999)
30 random_id = random.randrange(1, 9999)
31 return random_id, json.dumps({
31 return random_id, json.dumps({
32 "id": random_id,
32 "id": random_id,
33 "api_key": apikey,
33 "api_key": apikey,
34 "method": method,
34 "method": method,
35 "args": kw
35 "args": kw
36 })
36 })
37
37
38 jsonify = lambda obj: json.loads(json.dumps(obj))
38 jsonify = lambda obj: json.loads(json.dumps(obj))
39
39
40
40
41 def crash(*args, **kwargs):
41 def crash(*args, **kwargs):
42 raise Exception('Total Crash !')
42 raise Exception('Total Crash !')
43
43
44
44
45 def api_call(test_obj, params):
45 def api_call(test_obj, params):
46 response = test_obj.app.post(API_URL, content_type='application/json',
46 response = test_obj.app.post(API_URL, content_type='application/json',
47 params=params)
47 params=params)
48 return response
48 return response
49
49
50
50
51 ## helpers
51 ## helpers
52 def make_users_group(name=TEST_USER_GROUP):
52 def make_users_group(name=TEST_USER_GROUP):
53 gr = fixture.create_user_group(name, cur_user=TEST_USER_ADMIN_LOGIN)
53 gr = fixture.create_user_group(name, cur_user=TEST_USER_ADMIN_LOGIN)
54 UserGroupModel().add_user_to_group(users_group=gr,
54 UserGroupModel().add_user_to_group(users_group=gr,
55 user=TEST_USER_ADMIN_LOGIN)
55 user=TEST_USER_ADMIN_LOGIN)
56 Session().commit()
56 Session().commit()
57 return gr
57 return gr
58
58
59
59
60 def destroy_users_group(name=TEST_USER_GROUP):
60 def destroy_users_group(name=TEST_USER_GROUP):
61 UserGroupModel().delete(users_group=name, force=True)
61 UserGroupModel().delete(users_group=name, force=True)
62 Session().commit()
62 Session().commit()
63
63
64
64
65 class BaseTestApi(object):
65 class BaseTestApi(object):
66 REPO = None
66 REPO = None
67 REPO_TYPE = None
67 REPO_TYPE = None
68
68
69 @classmethod
69 @classmethod
70 def setUpClass(self):
70 def setUpClass(self):
71 self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
71 self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
72 self.apikey = self.usr.api_key
72 self.apikey = self.usr.api_key
73 self.test_user = UserModel().create_or_update(
73 self.test_user = UserModel().create_or_update(
74 username='test-api',
74 username='test-api',
75 password='test',
75 password='test',
76 email='test@api.rhodecode.org',
76 email='test@api.rhodecode.org',
77 firstname='first',
77 firstname='first',
78 lastname='last'
78 lastname='last'
79 )
79 )
80 Session().commit()
80 Session().commit()
81 self.TEST_USER_LOGIN = self.test_user.username
81 self.TEST_USER_LOGIN = self.test_user.username
82 self.apikey_regular = self.test_user.api_key
82 self.apikey_regular = self.test_user.api_key
83
83
84 @classmethod
84 @classmethod
85 def teardownClass(self):
85 def teardownClass(self):
86 pass
86 pass
87
87
88 def setUp(self):
88 def setUp(self):
89 self.maxDiff = None
89 self.maxDiff = None
90 make_users_group()
90 make_users_group()
91
91
92 def tearDown(self):
92 def tearDown(self):
93 destroy_users_group()
93 destroy_users_group()
94
94
95 def _compare_ok(self, id_, expected, given):
95 def _compare_ok(self, id_, expected, given):
96 expected = jsonify({
96 expected = jsonify({
97 'id': id_,
97 'id': id_,
98 'error': None,
98 'error': None,
99 'result': expected
99 'result': expected
100 })
100 })
101 given = json.loads(given)
101 given = json.loads(given)
102 self.assertEqual(expected, given)
102 self.assertEqual(expected, given)
103
103
104 def _compare_error(self, id_, expected, given):
104 def _compare_error(self, id_, expected, given):
105 expected = jsonify({
105 expected = jsonify({
106 'id': id_,
106 'id': id_,
107 'error': expected,
107 'error': expected,
108 'result': None
108 'result': None
109 })
109 })
110 given = json.loads(given)
110 given = json.loads(given)
111 self.assertEqual(expected, given)
111 self.assertEqual(expected, given)
112
112
113 # def test_Optional(self):
113 # def test_Optional(self):
114 # from rhodecode.controllers.api.api import Optional
114 # from rhodecode.controllers.api.api import Optional
115 # option1 = Optional(None)
115 # option1 = Optional(None)
116 # self.assertEqual('<Optional:%s>' % None, repr(option1))
116 # self.assertEqual('<Optional:%s>' % None, repr(option1))
117 #
117 #
118 # self.assertEqual(1, Optional.extract(Optional(1)))
118 # self.assertEqual(1, Optional.extract(Optional(1)))
119 # self.assertEqual('trololo', Optional.extract('trololo'))
119 # self.assertEqual('trololo', Optional.extract('trololo'))
120
120
121 def test_api_wrong_key(self):
121 def test_api_wrong_key(self):
122 id_, params = _build_data('trololo', 'get_user')
122 id_, params = _build_data('trololo', 'get_user')
123 response = api_call(self, params)
123 response = api_call(self, params)
124
124
125 expected = 'Invalid API KEY'
125 expected = 'Invalid API KEY'
126 self._compare_error(id_, expected, given=response.body)
126 self._compare_error(id_, expected, given=response.body)
127
127
128 def test_api_missing_non_optional_param(self):
128 def test_api_missing_non_optional_param(self):
129 id_, params = _build_data(self.apikey, 'get_repo')
129 id_, params = _build_data(self.apikey, 'get_repo')
130 response = api_call(self, params)
130 response = api_call(self, params)
131
131
132 expected = 'Missing non optional `repoid` arg in JSON DATA'
132 expected = 'Missing non optional `repoid` arg in JSON DATA'
133 self._compare_error(id_, expected, given=response.body)
133 self._compare_error(id_, expected, given=response.body)
134
134
135 def test_api_missing_non_optional_param_args_null(self):
135 def test_api_missing_non_optional_param_args_null(self):
136 id_, params = _build_data(self.apikey, 'get_repo')
136 id_, params = _build_data(self.apikey, 'get_repo')
137 params = params.replace('"args": {}', '"args": null')
137 params = params.replace('"args": {}', '"args": null')
138 response = api_call(self, params)
138 response = api_call(self, params)
139
139
140 expected = 'Missing non optional `repoid` arg in JSON DATA'
140 expected = 'Missing non optional `repoid` arg in JSON DATA'
141 self._compare_error(id_, expected, given=response.body)
141 self._compare_error(id_, expected, given=response.body)
142
142
143 def test_api_missing_non_optional_param_args_bad(self):
143 def test_api_missing_non_optional_param_args_bad(self):
144 id_, params = _build_data(self.apikey, 'get_repo')
144 id_, params = _build_data(self.apikey, 'get_repo')
145 params = params.replace('"args": {}', '"args": 1')
145 params = params.replace('"args": {}', '"args": 1')
146 response = api_call(self, params)
146 response = api_call(self, params)
147
147
148 expected = 'Missing non optional `repoid` arg in JSON DATA'
148 expected = 'Missing non optional `repoid` arg in JSON DATA'
149 self._compare_error(id_, expected, given=response.body)
149 self._compare_error(id_, expected, given=response.body)
150
150
151 def test_api_args_is_null(self):
151 def test_api_args_is_null(self):
152 id_, params = _build_data(self.apikey, 'get_users',)
152 id_, params = _build_data(self.apikey, 'get_users',)
153 params = params.replace('"args": {}', '"args": null')
153 params = params.replace('"args": {}', '"args": null')
154 response = api_call(self, params)
154 response = api_call(self, params)
155 self.assertEqual(response.status, '200 OK')
155 self.assertEqual(response.status, '200 OK')
156
156
157 def test_api_args_is_bad(self):
157 def test_api_args_is_bad(self):
158 id_, params = _build_data(self.apikey, 'get_users',)
158 id_, params = _build_data(self.apikey, 'get_users',)
159 params = params.replace('"args": {}', '"args": 1')
159 params = params.replace('"args": {}', '"args": 1')
160 response = api_call(self, params)
160 response = api_call(self, params)
161 self.assertEqual(response.status, '200 OK')
161 self.assertEqual(response.status, '200 OK')
162
162
163 def test_api_get_users(self):
163 def test_api_get_users(self):
164 id_, params = _build_data(self.apikey, 'get_users',)
164 id_, params = _build_data(self.apikey, 'get_users',)
165 response = api_call(self, params)
165 response = api_call(self, params)
166 ret_all = []
166 ret_all = []
167 for usr in UserModel().get_all():
167 for usr in UserModel().get_all():
168 ret = usr.get_api_data()
168 ret = usr.get_api_data()
169 ret_all.append(jsonify(ret))
169 ret_all.append(jsonify(ret))
170 expected = ret_all
170 expected = ret_all
171 self._compare_ok(id_, expected, given=response.body)
171 self._compare_ok(id_, expected, given=response.body)
172
172
173 def test_api_get_user(self):
173 def test_api_get_user(self):
174 id_, params = _build_data(self.apikey, 'get_user',
174 id_, params = _build_data(self.apikey, 'get_user',
175 userid=TEST_USER_ADMIN_LOGIN)
175 userid=TEST_USER_ADMIN_LOGIN)
176 response = api_call(self, params)
176 response = api_call(self, params)
177
177
178 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
178 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
179 ret = usr.get_api_data()
179 ret = usr.get_api_data()
180 ret['permissions'] = AuthUser(usr.user_id).permissions
180 ret['permissions'] = AuthUser(usr.user_id).permissions
181
181
182 expected = ret
182 expected = ret
183 self._compare_ok(id_, expected, given=response.body)
183 self._compare_ok(id_, expected, given=response.body)
184
184
185 def test_api_get_user_that_does_not_exist(self):
185 def test_api_get_user_that_does_not_exist(self):
186 id_, params = _build_data(self.apikey, 'get_user',
186 id_, params = _build_data(self.apikey, 'get_user',
187 userid='trololo')
187 userid='trololo')
188 response = api_call(self, params)
188 response = api_call(self, params)
189
189
190 expected = "user `%s` does not exist" % 'trololo'
190 expected = "user `%s` does not exist" % 'trololo'
191 self._compare_error(id_, expected, given=response.body)
191 self._compare_error(id_, expected, given=response.body)
192
192
193 def test_api_get_user_without_giving_userid(self):
193 def test_api_get_user_without_giving_userid(self):
194 id_, params = _build_data(self.apikey, 'get_user')
194 id_, params = _build_data(self.apikey, 'get_user')
195 response = api_call(self, params)
195 response = api_call(self, params)
196
196
197 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
197 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
198 ret = usr.get_api_data()
198 ret = usr.get_api_data()
199 ret['permissions'] = AuthUser(usr.user_id).permissions
199 ret['permissions'] = AuthUser(usr.user_id).permissions
200
200
201 expected = ret
201 expected = ret
202 self._compare_ok(id_, expected, given=response.body)
202 self._compare_ok(id_, expected, given=response.body)
203
203
204 def test_api_get_user_without_giving_userid_non_admin(self):
204 def test_api_get_user_without_giving_userid_non_admin(self):
205 id_, params = _build_data(self.apikey_regular, 'get_user')
205 id_, params = _build_data(self.apikey_regular, 'get_user')
206 response = api_call(self, params)
206 response = api_call(self, params)
207
207
208 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
208 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
209 ret = usr.get_api_data()
209 ret = usr.get_api_data()
210 ret['permissions'] = AuthUser(usr.user_id).permissions
210 ret['permissions'] = AuthUser(usr.user_id).permissions
211
211
212 expected = ret
212 expected = ret
213 self._compare_ok(id_, expected, given=response.body)
213 self._compare_ok(id_, expected, given=response.body)
214
214
215 def test_api_get_user_with_giving_userid_non_admin(self):
215 def test_api_get_user_with_giving_userid_non_admin(self):
216 id_, params = _build_data(self.apikey_regular, 'get_user',
216 id_, params = _build_data(self.apikey_regular, 'get_user',
217 userid=self.TEST_USER_LOGIN)
217 userid=self.TEST_USER_LOGIN)
218 response = api_call(self, params)
218 response = api_call(self, params)
219
219
220 expected = 'userid is not the same as your user'
220 expected = 'userid is not the same as your user'
221 self._compare_error(id_, expected, given=response.body)
221 self._compare_error(id_, expected, given=response.body)
222
222
223 def test_api_pull(self):
223 def test_api_pull(self):
224 #TODO: issues with rhodecode_extras here.. not sure why !
224 #TODO: issues with rhodecode_extras here.. not sure why !
225 pass
225 pass
226
226
227 # repo_name = 'test_pull'
227 # repo_name = 'test_pull'
228 # r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
228 # r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
229 # r.clone_uri = TEST_self.REPO
229 # r.clone_uri = TEST_self.REPO
230 # Session.add(r)
230 # Session.add(r)
231 # Session.commit()
231 # Session.commit()
232 #
232 #
233 # id_, params = _build_data(self.apikey, 'pull',
233 # id_, params = _build_data(self.apikey, 'pull',
234 # repoid=repo_name,)
234 # repoid=repo_name,)
235 # response = self.app.post(API_URL, content_type='application/json',
235 # response = self.app.post(API_URL, content_type='application/json',
236 # params=params)
236 # params=params)
237 #
237 #
238 # expected = 'Pulled from `%s`' % repo_name
238 # expected = 'Pulled from `%s`' % repo_name
239 # self._compare_ok(id_, expected, given=response.body)
239 # self._compare_ok(id_, expected, given=response.body)
240 #
240 #
241 # fixture.destroy_repo(repo_name)
241 # fixture.destroy_repo(repo_name)
242
242
243 def test_api_pull_error(self):
243 def test_api_pull_error(self):
244 id_, params = _build_data(self.apikey, 'pull',
244 id_, params = _build_data(self.apikey, 'pull',
245 repoid=self.REPO,)
245 repoid=self.REPO,)
246 response = api_call(self, params)
246 response = api_call(self, params)
247
247
248 expected = 'Unable to pull changes from `%s`' % self.REPO
248 expected = 'Unable to pull changes from `%s`' % self.REPO
249 self._compare_error(id_, expected, given=response.body)
249 self._compare_error(id_, expected, given=response.body)
250
250
251 def test_api_rescan_repos(self):
251 def test_api_rescan_repos(self):
252 id_, params = _build_data(self.apikey, 'rescan_repos')
252 id_, params = _build_data(self.apikey, 'rescan_repos')
253 response = api_call(self, params)
253 response = api_call(self, params)
254
254
255 expected = {'added': [], 'removed': []}
255 expected = {'added': [], 'removed': []}
256 self._compare_ok(id_, expected, given=response.body)
256 self._compare_ok(id_, expected, given=response.body)
257
257
258 @mock.patch.object(ScmModel, 'repo_scan', crash)
258 @mock.patch.object(ScmModel, 'repo_scan', crash)
259 def test_api_rescann_error(self):
259 def test_api_rescann_error(self):
260 id_, params = _build_data(self.apikey, 'rescan_repos',)
260 id_, params = _build_data(self.apikey, 'rescan_repos',)
261 response = api_call(self, params)
261 response = api_call(self, params)
262
262
263 expected = 'Error occurred during rescan repositories action'
263 expected = 'Error occurred during rescan repositories action'
264 self._compare_error(id_, expected, given=response.body)
264 self._compare_error(id_, expected, given=response.body)
265
265
266 def test_api_invalidate_cache(self):
266 def test_api_invalidate_cache(self):
267 repo = RepoModel().get_by_repo_name(self.REPO)
268 repo.scm_instance_cached() # seed cache
269
267 id_, params = _build_data(self.apikey, 'invalidate_cache',
270 id_, params = _build_data(self.apikey, 'invalidate_cache',
268 repoid=self.REPO)
271 repoid=self.REPO)
269 response = api_call(self, params)
272 response = api_call(self, params)
270
273
271 expected = ("Caches of repository `%s` was invalidated" % (self.REPO))
274 expected = ("Caches of repository `%s` was invalidated" % (self.REPO))
272 self._compare_ok(id_, expected, given=response.body)
275 self._compare_ok(id_, expected, given=response.body)
273
276
274 @mock.patch.object(ScmModel, 'mark_for_invalidation', crash)
277 @mock.patch.object(ScmModel, 'mark_for_invalidation', crash)
275 def test_api_invalidate_cache_error(self):
278 def test_api_invalidate_cache_error(self):
276 id_, params = _build_data(self.apikey, 'invalidate_cache',
279 id_, params = _build_data(self.apikey, 'invalidate_cache',
277 repoid=self.REPO)
280 repoid=self.REPO)
278 response = api_call(self, params)
281 response = api_call(self, params)
279
282
280 expected = 'Error occurred during cache invalidation action'
283 expected = 'Error occurred during cache invalidation action'
281 self._compare_error(id_, expected, given=response.body)
284 self._compare_error(id_, expected, given=response.body)
282
285
283 def test_api_lock_repo_lock_aquire(self):
286 def test_api_lock_repo_lock_aquire(self):
284 id_, params = _build_data(self.apikey, 'lock',
287 id_, params = _build_data(self.apikey, 'lock',
285 userid=TEST_USER_ADMIN_LOGIN,
288 userid=TEST_USER_ADMIN_LOGIN,
286 repoid=self.REPO,
289 repoid=self.REPO,
287 locked=True)
290 locked=True)
288 response = api_call(self, params)
291 response = api_call(self, params)
289 expected = ('User `%s` set lock state for repo `%s` to `%s`'
292 expected = ('User `%s` set lock state for repo `%s` to `%s`'
290 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
293 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
291 self._compare_ok(id_, expected, given=response.body)
294 self._compare_ok(id_, expected, given=response.body)
292
295
293 def test_api_lock_repo_lock_aquire_by_non_admin(self):
296 def test_api_lock_repo_lock_aquire_by_non_admin(self):
294 repo_name = 'api_delete_me'
297 repo_name = 'api_delete_me'
295 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
298 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
296 cur_user=self.TEST_USER_LOGIN)
299 cur_user=self.TEST_USER_LOGIN)
297 try:
300 try:
298 id_, params = _build_data(self.apikey_regular, 'lock',
301 id_, params = _build_data(self.apikey_regular, 'lock',
299 repoid=repo_name,
302 repoid=repo_name,
300 locked=True)
303 locked=True)
301 response = api_call(self, params)
304 response = api_call(self, params)
302 expected = ('User `%s` set lock state for repo `%s` to `%s`'
305 expected = ('User `%s` set lock state for repo `%s` to `%s`'
303 % (self.TEST_USER_LOGIN, repo_name, True))
306 % (self.TEST_USER_LOGIN, repo_name, True))
304 self._compare_ok(id_, expected, given=response.body)
307 self._compare_ok(id_, expected, given=response.body)
305 finally:
308 finally:
306 fixture.destroy_repo(repo_name)
309 fixture.destroy_repo(repo_name)
307
310
308 def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
311 def test_api_lock_repo_lock_aquire_non_admin_with_userid(self):
309 repo_name = 'api_delete_me'
312 repo_name = 'api_delete_me'
310 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
313 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
311 cur_user=self.TEST_USER_LOGIN)
314 cur_user=self.TEST_USER_LOGIN)
312 try:
315 try:
313 id_, params = _build_data(self.apikey_regular, 'lock',
316 id_, params = _build_data(self.apikey_regular, 'lock',
314 userid=TEST_USER_ADMIN_LOGIN,
317 userid=TEST_USER_ADMIN_LOGIN,
315 repoid=repo_name,
318 repoid=repo_name,
316 locked=True)
319 locked=True)
317 response = api_call(self, params)
320 response = api_call(self, params)
318 expected = 'userid is not the same as your user'
321 expected = 'userid is not the same as your user'
319 self._compare_error(id_, expected, given=response.body)
322 self._compare_error(id_, expected, given=response.body)
320 finally:
323 finally:
321 fixture.destroy_repo(repo_name)
324 fixture.destroy_repo(repo_name)
322
325
323 def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self):
326 def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self):
324 id_, params = _build_data(self.apikey_regular, 'lock',
327 id_, params = _build_data(self.apikey_regular, 'lock',
325 repoid=self.REPO,
328 repoid=self.REPO,
326 locked=True)
329 locked=True)
327 response = api_call(self, params)
330 response = api_call(self, params)
328 expected = 'repository `%s` does not exist' % (self.REPO)
331 expected = 'repository `%s` does not exist' % (self.REPO)
329 self._compare_error(id_, expected, given=response.body)
332 self._compare_error(id_, expected, given=response.body)
330
333
331 def test_api_lock_repo_lock_release(self):
334 def test_api_lock_repo_lock_release(self):
332 id_, params = _build_data(self.apikey, 'lock',
335 id_, params = _build_data(self.apikey, 'lock',
333 userid=TEST_USER_ADMIN_LOGIN,
336 userid=TEST_USER_ADMIN_LOGIN,
334 repoid=self.REPO,
337 repoid=self.REPO,
335 locked=False)
338 locked=False)
336 response = api_call(self, params)
339 response = api_call(self, params)
337 expected = ('User `%s` set lock state for repo `%s` to `%s`'
340 expected = ('User `%s` set lock state for repo `%s` to `%s`'
338 % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
341 % (TEST_USER_ADMIN_LOGIN, self.REPO, False))
339 self._compare_ok(id_, expected, given=response.body)
342 self._compare_ok(id_, expected, given=response.body)
340
343
341 def test_api_lock_repo_lock_aquire_optional_userid(self):
344 def test_api_lock_repo_lock_aquire_optional_userid(self):
342 id_, params = _build_data(self.apikey, 'lock',
345 id_, params = _build_data(self.apikey, 'lock',
343 repoid=self.REPO,
346 repoid=self.REPO,
344 locked=True)
347 locked=True)
345 response = api_call(self, params)
348 response = api_call(self, params)
346 expected = ('User `%s` set lock state for repo `%s` to `%s`'
349 expected = ('User `%s` set lock state for repo `%s` to `%s`'
347 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
350 % (TEST_USER_ADMIN_LOGIN, self.REPO, True))
348 self._compare_ok(id_, expected, given=response.body)
351 self._compare_ok(id_, expected, given=response.body)
349
352
350 def test_api_lock_repo_lock_optional_locked(self):
353 def test_api_lock_repo_lock_optional_locked(self):
351 from rhodecode.lib.utils2 import time_to_datetime
354 from rhodecode.lib.utils2 import time_to_datetime
352 _locked_since = json.dumps(time_to_datetime(Repository\
355 _locked_since = json.dumps(time_to_datetime(Repository\
353 .get_by_repo_name(self.REPO).locked[1]))
356 .get_by_repo_name(self.REPO).locked[1]))
354 id_, params = _build_data(self.apikey, 'lock',
357 id_, params = _build_data(self.apikey, 'lock',
355 repoid=self.REPO)
358 repoid=self.REPO)
356 response = api_call(self, params)
359 response = api_call(self, params)
357 expected = ('Repo `%s` locked by `%s`. Locked=`True`. Locked since: `%s`'
360 expected = ('Repo `%s` locked by `%s`. Locked=`True`. Locked since: `%s`'
358 % (self.REPO, TEST_USER_ADMIN_LOGIN, _locked_since))
361 % (self.REPO, TEST_USER_ADMIN_LOGIN, _locked_since))
359 self._compare_ok(id_, expected, given=response.body)
362 self._compare_ok(id_, expected, given=response.body)
360
363
361 @mock.patch.object(Repository, 'lock', crash)
364 @mock.patch.object(Repository, 'lock', crash)
362 def test_api_lock_error(self):
365 def test_api_lock_error(self):
363 id_, params = _build_data(self.apikey, 'lock',
366 id_, params = _build_data(self.apikey, 'lock',
364 userid=TEST_USER_ADMIN_LOGIN,
367 userid=TEST_USER_ADMIN_LOGIN,
365 repoid=self.REPO,
368 repoid=self.REPO,
366 locked=True)
369 locked=True)
367 response = api_call(self, params)
370 response = api_call(self, params)
368
371
369 expected = 'Error occurred locking repository `%s`' % self.REPO
372 expected = 'Error occurred locking repository `%s`' % self.REPO
370 self._compare_error(id_, expected, given=response.body)
373 self._compare_error(id_, expected, given=response.body)
371
374
372 def test_api_get_locks_regular_user(self):
375 def test_api_get_locks_regular_user(self):
373 id_, params = _build_data(self.apikey_regular, 'get_locks')
376 id_, params = _build_data(self.apikey_regular, 'get_locks')
374 response = api_call(self, params)
377 response = api_call(self, params)
375 expected = []
378 expected = []
376 self._compare_ok(id_, expected, given=response.body)
379 self._compare_ok(id_, expected, given=response.body)
377
380
378 def test_api_get_locks_with_userid_regular_user(self):
381 def test_api_get_locks_with_userid_regular_user(self):
379 id_, params = _build_data(self.apikey_regular, 'get_locks',
382 id_, params = _build_data(self.apikey_regular, 'get_locks',
380 userid=TEST_USER_ADMIN_LOGIN)
383 userid=TEST_USER_ADMIN_LOGIN)
381 response = api_call(self, params)
384 response = api_call(self, params)
382 expected = 'userid is not the same as your user'
385 expected = 'userid is not the same as your user'
383 self._compare_error(id_, expected, given=response.body)
386 self._compare_error(id_, expected, given=response.body)
384
387
385 def test_api_get_locks(self):
388 def test_api_get_locks(self):
386 id_, params = _build_data(self.apikey, 'get_locks')
389 id_, params = _build_data(self.apikey, 'get_locks')
387 response = api_call(self, params)
390 response = api_call(self, params)
388 expected = []
391 expected = []
389 self._compare_ok(id_, expected, given=response.body)
392 self._compare_ok(id_, expected, given=response.body)
390
393
391 def test_api_get_locks_with_userid(self):
394 def test_api_get_locks_with_userid(self):
392 id_, params = _build_data(self.apikey, 'get_locks',
395 id_, params = _build_data(self.apikey, 'get_locks',
393 userid=TEST_USER_REGULAR_LOGIN)
396 userid=TEST_USER_REGULAR_LOGIN)
394 response = api_call(self, params)
397 response = api_call(self, params)
395 expected = []
398 expected = []
396 self._compare_ok(id_, expected, given=response.body)
399 self._compare_ok(id_, expected, given=response.body)
397
400
398 def test_api_create_existing_user(self):
401 def test_api_create_existing_user(self):
399 id_, params = _build_data(self.apikey, 'create_user',
402 id_, params = _build_data(self.apikey, 'create_user',
400 username=TEST_USER_ADMIN_LOGIN,
403 username=TEST_USER_ADMIN_LOGIN,
401 email='test@foo.com',
404 email='test@foo.com',
402 password='trololo')
405 password='trololo')
403 response = api_call(self, params)
406 response = api_call(self, params)
404
407
405 expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
408 expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN
406 self._compare_error(id_, expected, given=response.body)
409 self._compare_error(id_, expected, given=response.body)
407
410
408 def test_api_create_user_with_existing_email(self):
411 def test_api_create_user_with_existing_email(self):
409 id_, params = _build_data(self.apikey, 'create_user',
412 id_, params = _build_data(self.apikey, 'create_user',
410 username=TEST_USER_ADMIN_LOGIN + 'new',
413 username=TEST_USER_ADMIN_LOGIN + 'new',
411 email=TEST_USER_REGULAR_EMAIL,
414 email=TEST_USER_REGULAR_EMAIL,
412 password='trololo')
415 password='trololo')
413 response = api_call(self, params)
416 response = api_call(self, params)
414
417
415 expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
418 expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL
416 self._compare_error(id_, expected, given=response.body)
419 self._compare_error(id_, expected, given=response.body)
417
420
418 def test_api_create_user(self):
421 def test_api_create_user(self):
419 username = 'test_new_api_user'
422 username = 'test_new_api_user'
420 email = username + "@foo.com"
423 email = username + "@foo.com"
421
424
422 id_, params = _build_data(self.apikey, 'create_user',
425 id_, params = _build_data(self.apikey, 'create_user',
423 username=username,
426 username=username,
424 email=email,
427 email=email,
425 password='trololo')
428 password='trololo')
426 response = api_call(self, params)
429 response = api_call(self, params)
427
430
428 usr = UserModel().get_by_username(username)
431 usr = UserModel().get_by_username(username)
429 ret = dict(
432 ret = dict(
430 msg='created new user `%s`' % username,
433 msg='created new user `%s`' % username,
431 user=jsonify(usr.get_api_data())
434 user=jsonify(usr.get_api_data())
432 )
435 )
433
436
434 expected = ret
437 expected = ret
435 self._compare_ok(id_, expected, given=response.body)
438 self._compare_ok(id_, expected, given=response.body)
436
439
437 UserModel().delete(usr.user_id)
440 UserModel().delete(usr.user_id)
438 Session().commit()
441 Session().commit()
439
442
440 @mock.patch.object(UserModel, 'create_or_update', crash)
443 @mock.patch.object(UserModel, 'create_or_update', crash)
441 def test_api_create_user_when_exception_happened(self):
444 def test_api_create_user_when_exception_happened(self):
442
445
443 username = 'test_new_api_user'
446 username = 'test_new_api_user'
444 email = username + "@foo.com"
447 email = username + "@foo.com"
445
448
446 id_, params = _build_data(self.apikey, 'create_user',
449 id_, params = _build_data(self.apikey, 'create_user',
447 username=username,
450 username=username,
448 email=email,
451 email=email,
449 password='trololo')
452 password='trololo')
450 response = api_call(self, params)
453 response = api_call(self, params)
451 expected = 'failed to create user `%s`' % username
454 expected = 'failed to create user `%s`' % username
452 self._compare_error(id_, expected, given=response.body)
455 self._compare_error(id_, expected, given=response.body)
453
456
454 def test_api_delete_user(self):
457 def test_api_delete_user(self):
455 usr = UserModel().create_or_update(username=u'test_user',
458 usr = UserModel().create_or_update(username=u'test_user',
456 password=u'qweqwe',
459 password=u'qweqwe',
457 email=u'u232@rhodecode.org',
460 email=u'u232@rhodecode.org',
458 firstname=u'u1', lastname=u'u1')
461 firstname=u'u1', lastname=u'u1')
459 Session().commit()
462 Session().commit()
460 username = usr.username
463 username = usr.username
461 email = usr.email
464 email = usr.email
462 usr_id = usr.user_id
465 usr_id = usr.user_id
463 ## DELETE THIS USER NOW
466 ## DELETE THIS USER NOW
464
467
465 id_, params = _build_data(self.apikey, 'delete_user',
468 id_, params = _build_data(self.apikey, 'delete_user',
466 userid=username,)
469 userid=username,)
467 response = api_call(self, params)
470 response = api_call(self, params)
468
471
469 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
472 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
470 'user': None}
473 'user': None}
471 expected = ret
474 expected = ret
472 self._compare_ok(id_, expected, given=response.body)
475 self._compare_ok(id_, expected, given=response.body)
473
476
474 @mock.patch.object(UserModel, 'delete', crash)
477 @mock.patch.object(UserModel, 'delete', crash)
475 def test_api_delete_user_when_exception_happened(self):
478 def test_api_delete_user_when_exception_happened(self):
476 usr = UserModel().create_or_update(username=u'test_user',
479 usr = UserModel().create_or_update(username=u'test_user',
477 password=u'qweqwe',
480 password=u'qweqwe',
478 email=u'u232@rhodecode.org',
481 email=u'u232@rhodecode.org',
479 firstname=u'u1', lastname=u'u1')
482 firstname=u'u1', lastname=u'u1')
480 Session().commit()
483 Session().commit()
481 username = usr.username
484 username = usr.username
482
485
483 id_, params = _build_data(self.apikey, 'delete_user',
486 id_, params = _build_data(self.apikey, 'delete_user',
484 userid=username,)
487 userid=username,)
485 response = api_call(self, params)
488 response = api_call(self, params)
486 ret = 'failed to delete ID:%s %s' % (usr.user_id,
489 ret = 'failed to delete ID:%s %s' % (usr.user_id,
487 usr.username)
490 usr.username)
488 expected = ret
491 expected = ret
489 self._compare_error(id_, expected, given=response.body)
492 self._compare_error(id_, expected, given=response.body)
490
493
491 @parameterized.expand([('firstname', 'new_username'),
494 @parameterized.expand([('firstname', 'new_username'),
492 ('lastname', 'new_username'),
495 ('lastname', 'new_username'),
493 ('email', 'new_username'),
496 ('email', 'new_username'),
494 ('admin', True),
497 ('admin', True),
495 ('admin', False),
498 ('admin', False),
496 ('ldap_dn', 'test'),
499 ('ldap_dn', 'test'),
497 ('ldap_dn', None),
500 ('ldap_dn', None),
498 ('active', False),
501 ('active', False),
499 ('active', True),
502 ('active', True),
500 ('password', 'newpass')
503 ('password', 'newpass')
501 ])
504 ])
502 def test_api_update_user(self, name, expected):
505 def test_api_update_user(self, name, expected):
503 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
506 usr = UserModel().get_by_username(self.TEST_USER_LOGIN)
504 kw = {name: expected,
507 kw = {name: expected,
505 'userid': usr.user_id}
508 'userid': usr.user_id}
506 id_, params = _build_data(self.apikey, 'update_user', **kw)
509 id_, params = _build_data(self.apikey, 'update_user', **kw)
507 response = api_call(self, params)
510 response = api_call(self, params)
508
511
509 ret = {
512 ret = {
510 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
513 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN),
511 'user': jsonify(UserModel()\
514 'user': jsonify(UserModel()\
512 .get_by_username(self.TEST_USER_LOGIN)\
515 .get_by_username(self.TEST_USER_LOGIN)\
513 .get_api_data())
516 .get_api_data())
514 }
517 }
515
518
516 expected = ret
519 expected = ret
517 self._compare_ok(id_, expected, given=response.body)
520 self._compare_ok(id_, expected, given=response.body)
518
521
519 def test_api_update_user_no_changed_params(self):
522 def test_api_update_user_no_changed_params(self):
520 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
523 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
521 ret = jsonify(usr.get_api_data())
524 ret = jsonify(usr.get_api_data())
522 id_, params = _build_data(self.apikey, 'update_user',
525 id_, params = _build_data(self.apikey, 'update_user',
523 userid=TEST_USER_ADMIN_LOGIN)
526 userid=TEST_USER_ADMIN_LOGIN)
524
527
525 response = api_call(self, params)
528 response = api_call(self, params)
526 ret = {
529 ret = {
527 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
530 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
528 'user': ret
531 'user': ret
529 }
532 }
530 expected = ret
533 expected = ret
531 self._compare_ok(id_, expected, given=response.body)
534 self._compare_ok(id_, expected, given=response.body)
532
535
533 def test_api_update_user_by_user_id(self):
536 def test_api_update_user_by_user_id(self):
534 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
537 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
535 ret = jsonify(usr.get_api_data())
538 ret = jsonify(usr.get_api_data())
536 id_, params = _build_data(self.apikey, 'update_user',
539 id_, params = _build_data(self.apikey, 'update_user',
537 userid=usr.user_id)
540 userid=usr.user_id)
538
541
539 response = api_call(self, params)
542 response = api_call(self, params)
540 ret = {
543 ret = {
541 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
544 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN),
542 'user': ret
545 'user': ret
543 }
546 }
544 expected = ret
547 expected = ret
545 self._compare_ok(id_, expected, given=response.body)
548 self._compare_ok(id_, expected, given=response.body)
546
549
547 @mock.patch.object(UserModel, 'update_user', crash)
550 @mock.patch.object(UserModel, 'update_user', crash)
548 def test_api_update_user_when_exception_happens(self):
551 def test_api_update_user_when_exception_happens(self):
549 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
552 usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
550 ret = jsonify(usr.get_api_data())
553 ret = jsonify(usr.get_api_data())
551 id_, params = _build_data(self.apikey, 'update_user',
554 id_, params = _build_data(self.apikey, 'update_user',
552 userid=usr.user_id)
555 userid=usr.user_id)
553
556
554 response = api_call(self, params)
557 response = api_call(self, params)
555 ret = 'failed to update user `%s`' % usr.user_id
558 ret = 'failed to update user `%s`' % usr.user_id
556
559
557 expected = ret
560 expected = ret
558 self._compare_error(id_, expected, given=response.body)
561 self._compare_error(id_, expected, given=response.body)
559
562
560 def test_api_get_repo(self):
563 def test_api_get_repo(self):
561 new_group = 'some_new_group'
564 new_group = 'some_new_group'
562 make_users_group(new_group)
565 make_users_group(new_group)
563 RepoModel().grant_users_group_permission(repo=self.REPO,
566 RepoModel().grant_users_group_permission(repo=self.REPO,
564 group_name=new_group,
567 group_name=new_group,
565 perm='repository.read')
568 perm='repository.read')
566 Session().commit()
569 Session().commit()
567 id_, params = _build_data(self.apikey, 'get_repo',
570 id_, params = _build_data(self.apikey, 'get_repo',
568 repoid=self.REPO)
571 repoid=self.REPO)
569 response = api_call(self, params)
572 response = api_call(self, params)
570
573
571 repo = RepoModel().get_by_repo_name(self.REPO)
574 repo = RepoModel().get_by_repo_name(self.REPO)
572 ret = repo.get_api_data()
575 ret = repo.get_api_data()
573
576
574 members = []
577 members = []
575 followers = []
578 followers = []
576 for user in repo.repo_to_perm:
579 for user in repo.repo_to_perm:
577 perm = user.permission.permission_name
580 perm = user.permission.permission_name
578 user = user.user
581 user = user.user
579 user_data = user.get_api_data()
582 user_data = user.get_api_data()
580 user_data['type'] = "user"
583 user_data['type'] = "user"
581 user_data['permission'] = perm
584 user_data['permission'] = perm
582 members.append(user_data)
585 members.append(user_data)
583
586
584 for users_group in repo.users_group_to_perm:
587 for users_group in repo.users_group_to_perm:
585 perm = users_group.permission.permission_name
588 perm = users_group.permission.permission_name
586 users_group = users_group.users_group
589 users_group = users_group.users_group
587 users_group_data = users_group.get_api_data()
590 users_group_data = users_group.get_api_data()
588 users_group_data['type'] = "users_group"
591 users_group_data['type'] = "users_group"
589 users_group_data['permission'] = perm
592 users_group_data['permission'] = perm
590 members.append(users_group_data)
593 members.append(users_group_data)
591
594
592 for user in repo.followers:
595 for user in repo.followers:
593 followers.append(user.user.get_api_data())
596 followers.append(user.user.get_api_data())
594
597
595 ret['members'] = members
598 ret['members'] = members
596 ret['followers'] = followers
599 ret['followers'] = followers
597
600
598 expected = ret
601 expected = ret
599 self._compare_ok(id_, expected, given=response.body)
602 self._compare_ok(id_, expected, given=response.body)
600 destroy_users_group(new_group)
603 destroy_users_group(new_group)
601
604
602 def test_api_get_repo_by_non_admin(self):
605 def test_api_get_repo_by_non_admin(self):
603 id_, params = _build_data(self.apikey, 'get_repo',
606 id_, params = _build_data(self.apikey, 'get_repo',
604 repoid=self.REPO)
607 repoid=self.REPO)
605 response = api_call(self, params)
608 response = api_call(self, params)
606
609
607 repo = RepoModel().get_by_repo_name(self.REPO)
610 repo = RepoModel().get_by_repo_name(self.REPO)
608 ret = repo.get_api_data()
611 ret = repo.get_api_data()
609
612
610 members = []
613 members = []
611 followers = []
614 followers = []
612 for user in repo.repo_to_perm:
615 for user in repo.repo_to_perm:
613 perm = user.permission.permission_name
616 perm = user.permission.permission_name
614 user = user.user
617 user = user.user
615 user_data = user.get_api_data()
618 user_data = user.get_api_data()
616 user_data['type'] = "user"
619 user_data['type'] = "user"
617 user_data['permission'] = perm
620 user_data['permission'] = perm
618 members.append(user_data)
621 members.append(user_data)
619
622
620 for users_group in repo.users_group_to_perm:
623 for users_group in repo.users_group_to_perm:
621 perm = users_group.permission.permission_name
624 perm = users_group.permission.permission_name
622 users_group = users_group.users_group
625 users_group = users_group.users_group
623 users_group_data = users_group.get_api_data()
626 users_group_data = users_group.get_api_data()
624 users_group_data['type'] = "users_group"
627 users_group_data['type'] = "users_group"
625 users_group_data['permission'] = perm
628 users_group_data['permission'] = perm
626 members.append(users_group_data)
629 members.append(users_group_data)
627
630
628 for user in repo.followers:
631 for user in repo.followers:
629 followers.append(user.user.get_api_data())
632 followers.append(user.user.get_api_data())
630
633
631 ret['members'] = members
634 ret['members'] = members
632 ret['followers'] = followers
635 ret['followers'] = followers
633
636
634 expected = ret
637 expected = ret
635 self._compare_ok(id_, expected, given=response.body)
638 self._compare_ok(id_, expected, given=response.body)
636
639
637 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
640 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
638 RepoModel().grant_user_permission(repo=self.REPO,
641 RepoModel().grant_user_permission(repo=self.REPO,
639 user=self.TEST_USER_LOGIN,
642 user=self.TEST_USER_LOGIN,
640 perm='repository.none')
643 perm='repository.none')
641
644
642 id_, params = _build_data(self.apikey_regular, 'get_repo',
645 id_, params = _build_data(self.apikey_regular, 'get_repo',
643 repoid=self.REPO)
646 repoid=self.REPO)
644 response = api_call(self, params)
647 response = api_call(self, params)
645
648
646 expected = 'repository `%s` does not exist' % (self.REPO)
649 expected = 'repository `%s` does not exist' % (self.REPO)
647 self._compare_error(id_, expected, given=response.body)
650 self._compare_error(id_, expected, given=response.body)
648
651
649 def test_api_get_repo_that_doesn_not_exist(self):
652 def test_api_get_repo_that_doesn_not_exist(self):
650 id_, params = _build_data(self.apikey, 'get_repo',
653 id_, params = _build_data(self.apikey, 'get_repo',
651 repoid='no-such-repo')
654 repoid='no-such-repo')
652 response = api_call(self, params)
655 response = api_call(self, params)
653
656
654 ret = 'repository `%s` does not exist' % 'no-such-repo'
657 ret = 'repository `%s` does not exist' % 'no-such-repo'
655 expected = ret
658 expected = ret
656 self._compare_error(id_, expected, given=response.body)
659 self._compare_error(id_, expected, given=response.body)
657
660
658 def test_api_get_repos(self):
661 def test_api_get_repos(self):
659 id_, params = _build_data(self.apikey, 'get_repos')
662 id_, params = _build_data(self.apikey, 'get_repos')
660 response = api_call(self, params)
663 response = api_call(self, params)
661
664
662 result = []
665 result = []
663 for repo in RepoModel().get_all():
666 for repo in RepoModel().get_all():
664 result.append(repo.get_api_data())
667 result.append(repo.get_api_data())
665 ret = jsonify(result)
668 ret = jsonify(result)
666
669
667 expected = ret
670 expected = ret
668 self._compare_ok(id_, expected, given=response.body)
671 self._compare_ok(id_, expected, given=response.body)
669
672
670 def test_api_get_repos_non_admin(self):
673 def test_api_get_repos_non_admin(self):
671 id_, params = _build_data(self.apikey_regular, 'get_repos')
674 id_, params = _build_data(self.apikey_regular, 'get_repos')
672 response = api_call(self, params)
675 response = api_call(self, params)
673
676
674 result = []
677 result = []
675 for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN):
678 for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN):
676 result.append(repo.get_api_data())
679 result.append(repo.get_api_data())
677 ret = jsonify(result)
680 ret = jsonify(result)
678
681
679 expected = ret
682 expected = ret
680 self._compare_ok(id_, expected, given=response.body)
683 self._compare_ok(id_, expected, given=response.body)
681
684
682 @parameterized.expand([('all', 'all'),
685 @parameterized.expand([('all', 'all'),
683 ('dirs', 'dirs'),
686 ('dirs', 'dirs'),
684 ('files', 'files'), ])
687 ('files', 'files'), ])
685 def test_api_get_repo_nodes(self, name, ret_type):
688 def test_api_get_repo_nodes(self, name, ret_type):
686 rev = 'tip'
689 rev = 'tip'
687 path = '/'
690 path = '/'
688 id_, params = _build_data(self.apikey, 'get_repo_nodes',
691 id_, params = _build_data(self.apikey, 'get_repo_nodes',
689 repoid=self.REPO, revision=rev,
692 repoid=self.REPO, revision=rev,
690 root_path=path,
693 root_path=path,
691 ret_type=ret_type)
694 ret_type=ret_type)
692 response = api_call(self, params)
695 response = api_call(self, params)
693
696
694 # we don't the actual return types here since it's tested somewhere
697 # we don't the actual return types here since it's tested somewhere
695 # else
698 # else
696 expected = json.loads(response.body)['result']
699 expected = json.loads(response.body)['result']
697 self._compare_ok(id_, expected, given=response.body)
700 self._compare_ok(id_, expected, given=response.body)
698
701
699 def test_api_get_repo_nodes_bad_revisions(self):
702 def test_api_get_repo_nodes_bad_revisions(self):
700 rev = 'i-dont-exist'
703 rev = 'i-dont-exist'
701 path = '/'
704 path = '/'
702 id_, params = _build_data(self.apikey, 'get_repo_nodes',
705 id_, params = _build_data(self.apikey, 'get_repo_nodes',
703 repoid=self.REPO, revision=rev,
706 repoid=self.REPO, revision=rev,
704 root_path=path,)
707 root_path=path,)
705 response = api_call(self, params)
708 response = api_call(self, params)
706
709
707 expected = 'failed to get repo: `%s` nodes' % self.REPO
710 expected = 'failed to get repo: `%s` nodes' % self.REPO
708 self._compare_error(id_, expected, given=response.body)
711 self._compare_error(id_, expected, given=response.body)
709
712
710 def test_api_get_repo_nodes_bad_path(self):
713 def test_api_get_repo_nodes_bad_path(self):
711 rev = 'tip'
714 rev = 'tip'
712 path = '/idontexits'
715 path = '/idontexits'
713 id_, params = _build_data(self.apikey, 'get_repo_nodes',
716 id_, params = _build_data(self.apikey, 'get_repo_nodes',
714 repoid=self.REPO, revision=rev,
717 repoid=self.REPO, revision=rev,
715 root_path=path,)
718 root_path=path,)
716 response = api_call(self, params)
719 response = api_call(self, params)
717
720
718 expected = 'failed to get repo: `%s` nodes' % self.REPO
721 expected = 'failed to get repo: `%s` nodes' % self.REPO
719 self._compare_error(id_, expected, given=response.body)
722 self._compare_error(id_, expected, given=response.body)
720
723
721 def test_api_get_repo_nodes_bad_ret_type(self):
724 def test_api_get_repo_nodes_bad_ret_type(self):
722 rev = 'tip'
725 rev = 'tip'
723 path = '/'
726 path = '/'
724 ret_type = 'error'
727 ret_type = 'error'
725 id_, params = _build_data(self.apikey, 'get_repo_nodes',
728 id_, params = _build_data(self.apikey, 'get_repo_nodes',
726 repoid=self.REPO, revision=rev,
729 repoid=self.REPO, revision=rev,
727 root_path=path,
730 root_path=path,
728 ret_type=ret_type)
731 ret_type=ret_type)
729 response = api_call(self, params)
732 response = api_call(self, params)
730
733
731 expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all'])
734 expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all'])
732 self._compare_error(id_, expected, given=response.body)
735 self._compare_error(id_, expected, given=response.body)
733
736
734 def test_api_create_repo(self):
737 def test_api_create_repo(self):
735 repo_name = 'api-repo'
738 repo_name = 'api-repo'
736 id_, params = _build_data(self.apikey, 'create_repo',
739 id_, params = _build_data(self.apikey, 'create_repo',
737 repo_name=repo_name,
740 repo_name=repo_name,
738 owner=TEST_USER_ADMIN_LOGIN,
741 owner=TEST_USER_ADMIN_LOGIN,
739 repo_type='hg',
742 repo_type='hg',
740 )
743 )
741 response = api_call(self, params)
744 response = api_call(self, params)
742
745
743 repo = RepoModel().get_by_repo_name(repo_name)
746 repo = RepoModel().get_by_repo_name(repo_name)
744 ret = {
747 ret = {
745 'msg': 'Created new repository `%s`' % repo_name,
748 'msg': 'Created new repository `%s`' % repo_name,
746 'repo': jsonify(repo.get_api_data())
749 'repo': jsonify(repo.get_api_data())
747 }
750 }
748 expected = ret
751 expected = ret
749 self._compare_ok(id_, expected, given=response.body)
752 self._compare_ok(id_, expected, given=response.body)
750 fixture.destroy_repo(repo_name)
753 fixture.destroy_repo(repo_name)
751
754
752 def test_api_create_repo_unknown_owner(self):
755 def test_api_create_repo_unknown_owner(self):
753 repo_name = 'api-repo'
756 repo_name = 'api-repo'
754 owner = 'i-dont-exist'
757 owner = 'i-dont-exist'
755 id_, params = _build_data(self.apikey, 'create_repo',
758 id_, params = _build_data(self.apikey, 'create_repo',
756 repo_name=repo_name,
759 repo_name=repo_name,
757 owner=owner,
760 owner=owner,
758 repo_type='hg',
761 repo_type='hg',
759 )
762 )
760 response = api_call(self, params)
763 response = api_call(self, params)
761 expected = 'user `%s` does not exist' % owner
764 expected = 'user `%s` does not exist' % owner
762 self._compare_error(id_, expected, given=response.body)
765 self._compare_error(id_, expected, given=response.body)
763
766
764 def test_api_create_repo_dont_specify_owner(self):
767 def test_api_create_repo_dont_specify_owner(self):
765 repo_name = 'api-repo'
768 repo_name = 'api-repo'
766 owner = 'i-dont-exist'
769 owner = 'i-dont-exist'
767 id_, params = _build_data(self.apikey, 'create_repo',
770 id_, params = _build_data(self.apikey, 'create_repo',
768 repo_name=repo_name,
771 repo_name=repo_name,
769 repo_type='hg',
772 repo_type='hg',
770 )
773 )
771 response = api_call(self, params)
774 response = api_call(self, params)
772
775
773 repo = RepoModel().get_by_repo_name(repo_name)
776 repo = RepoModel().get_by_repo_name(repo_name)
774 ret = {
777 ret = {
775 'msg': 'Created new repository `%s`' % repo_name,
778 'msg': 'Created new repository `%s`' % repo_name,
776 'repo': jsonify(repo.get_api_data())
779 'repo': jsonify(repo.get_api_data())
777 }
780 }
778 expected = ret
781 expected = ret
779 self._compare_ok(id_, expected, given=response.body)
782 self._compare_ok(id_, expected, given=response.body)
780 fixture.destroy_repo(repo_name)
783 fixture.destroy_repo(repo_name)
781
784
782 def test_api_create_repo_by_non_admin(self):
785 def test_api_create_repo_by_non_admin(self):
783 repo_name = 'api-repo'
786 repo_name = 'api-repo'
784 owner = 'i-dont-exist'
787 owner = 'i-dont-exist'
785 id_, params = _build_data(self.apikey_regular, 'create_repo',
788 id_, params = _build_data(self.apikey_regular, 'create_repo',
786 repo_name=repo_name,
789 repo_name=repo_name,
787 repo_type='hg',
790 repo_type='hg',
788 )
791 )
789 response = api_call(self, params)
792 response = api_call(self, params)
790
793
791 repo = RepoModel().get_by_repo_name(repo_name)
794 repo = RepoModel().get_by_repo_name(repo_name)
792 ret = {
795 ret = {
793 'msg': 'Created new repository `%s`' % repo_name,
796 'msg': 'Created new repository `%s`' % repo_name,
794 'repo': jsonify(repo.get_api_data())
797 'repo': jsonify(repo.get_api_data())
795 }
798 }
796 expected = ret
799 expected = ret
797 self._compare_ok(id_, expected, given=response.body)
800 self._compare_ok(id_, expected, given=response.body)
798 fixture.destroy_repo(repo_name)
801 fixture.destroy_repo(repo_name)
799
802
800 def test_api_create_repo_by_non_admin_specify_owner(self):
803 def test_api_create_repo_by_non_admin_specify_owner(self):
801 repo_name = 'api-repo'
804 repo_name = 'api-repo'
802 owner = 'i-dont-exist'
805 owner = 'i-dont-exist'
803 id_, params = _build_data(self.apikey_regular, 'create_repo',
806 id_, params = _build_data(self.apikey_regular, 'create_repo',
804 repo_name=repo_name,
807 repo_name=repo_name,
805 repo_type='hg',
808 repo_type='hg',
806 owner=owner
809 owner=owner
807 )
810 )
808 response = api_call(self, params)
811 response = api_call(self, params)
809
812
810 expected = 'Only RhodeCode admin can specify `owner` param'
813 expected = 'Only RhodeCode admin can specify `owner` param'
811 self._compare_error(id_, expected, given=response.body)
814 self._compare_error(id_, expected, given=response.body)
812 fixture.destroy_repo(repo_name)
815 fixture.destroy_repo(repo_name)
813
816
814 def test_api_create_repo_exists(self):
817 def test_api_create_repo_exists(self):
815 repo_name = self.REPO
818 repo_name = self.REPO
816 id_, params = _build_data(self.apikey, 'create_repo',
819 id_, params = _build_data(self.apikey, 'create_repo',
817 repo_name=repo_name,
820 repo_name=repo_name,
818 owner=TEST_USER_ADMIN_LOGIN,
821 owner=TEST_USER_ADMIN_LOGIN,
819 repo_type='hg',
822 repo_type='hg',
820 )
823 )
821 response = api_call(self, params)
824 response = api_call(self, params)
822 expected = "repo `%s` already exist" % repo_name
825 expected = "repo `%s` already exist" % repo_name
823 self._compare_error(id_, expected, given=response.body)
826 self._compare_error(id_, expected, given=response.body)
824
827
825 @mock.patch.object(RepoModel, 'create_repo', crash)
828 @mock.patch.object(RepoModel, 'create_repo', crash)
826 def test_api_create_repo_exception_occurred(self):
829 def test_api_create_repo_exception_occurred(self):
827 repo_name = 'api-repo'
830 repo_name = 'api-repo'
828 id_, params = _build_data(self.apikey, 'create_repo',
831 id_, params = _build_data(self.apikey, 'create_repo',
829 repo_name=repo_name,
832 repo_name=repo_name,
830 owner=TEST_USER_ADMIN_LOGIN,
833 owner=TEST_USER_ADMIN_LOGIN,
831 repo_type='hg',
834 repo_type='hg',
832 )
835 )
833 response = api_call(self, params)
836 response = api_call(self, params)
834 expected = 'failed to create repository `%s`' % repo_name
837 expected = 'failed to create repository `%s`' % repo_name
835 self._compare_error(id_, expected, given=response.body)
838 self._compare_error(id_, expected, given=response.body)
836
839
837 def test_api_delete_repo(self):
840 def test_api_delete_repo(self):
838 repo_name = 'api_delete_me'
841 repo_name = 'api_delete_me'
839 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
842 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
840
843
841 id_, params = _build_data(self.apikey, 'delete_repo',
844 id_, params = _build_data(self.apikey, 'delete_repo',
842 repoid=repo_name,)
845 repoid=repo_name,)
843 response = api_call(self, params)
846 response = api_call(self, params)
844
847
845 ret = {
848 ret = {
846 'msg': 'Deleted repository `%s`' % repo_name,
849 'msg': 'Deleted repository `%s`' % repo_name,
847 'success': True
850 'success': True
848 }
851 }
849 expected = ret
852 expected = ret
850 self._compare_ok(id_, expected, given=response.body)
853 self._compare_ok(id_, expected, given=response.body)
851
854
852 def test_api_delete_repo_by_non_admin(self):
855 def test_api_delete_repo_by_non_admin(self):
853 repo_name = 'api_delete_me'
856 repo_name = 'api_delete_me'
854 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
857 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
855 cur_user=self.TEST_USER_LOGIN)
858 cur_user=self.TEST_USER_LOGIN)
856 try:
859 try:
857 id_, params = _build_data(self.apikey_regular, 'delete_repo',
860 id_, params = _build_data(self.apikey_regular, 'delete_repo',
858 repoid=repo_name,)
861 repoid=repo_name,)
859 response = api_call(self, params)
862 response = api_call(self, params)
860
863
861 ret = {
864 ret = {
862 'msg': 'Deleted repository `%s`' % repo_name,
865 'msg': 'Deleted repository `%s`' % repo_name,
863 'success': True
866 'success': True
864 }
867 }
865 expected = ret
868 expected = ret
866 self._compare_ok(id_, expected, given=response.body)
869 self._compare_ok(id_, expected, given=response.body)
867 finally:
870 finally:
868 fixture.destroy_repo(repo_name)
871 fixture.destroy_repo(repo_name)
869
872
870 def test_api_delete_repo_by_non_admin_no_permission(self):
873 def test_api_delete_repo_by_non_admin_no_permission(self):
871 repo_name = 'api_delete_me'
874 repo_name = 'api_delete_me'
872 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
875 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
873 try:
876 try:
874 id_, params = _build_data(self.apikey_regular, 'delete_repo',
877 id_, params = _build_data(self.apikey_regular, 'delete_repo',
875 repoid=repo_name,)
878 repoid=repo_name,)
876 response = api_call(self, params)
879 response = api_call(self, params)
877 expected = 'repository `%s` does not exist' % (repo_name)
880 expected = 'repository `%s` does not exist' % (repo_name)
878 self._compare_error(id_, expected, given=response.body)
881 self._compare_error(id_, expected, given=response.body)
879 finally:
882 finally:
880 fixture.destroy_repo(repo_name)
883 fixture.destroy_repo(repo_name)
881
884
882 def test_api_delete_repo_exception_occurred(self):
885 def test_api_delete_repo_exception_occurred(self):
883 repo_name = 'api_delete_me'
886 repo_name = 'api_delete_me'
884 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
887 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
885 try:
888 try:
886 with mock.patch.object(RepoModel, 'delete', crash):
889 with mock.patch.object(RepoModel, 'delete', crash):
887 id_, params = _build_data(self.apikey, 'delete_repo',
890 id_, params = _build_data(self.apikey, 'delete_repo',
888 repoid=repo_name,)
891 repoid=repo_name,)
889 response = api_call(self, params)
892 response = api_call(self, params)
890
893
891 expected = 'failed to delete repository `%s`' % repo_name
894 expected = 'failed to delete repository `%s`' % repo_name
892 self._compare_error(id_, expected, given=response.body)
895 self._compare_error(id_, expected, given=response.body)
893 finally:
896 finally:
894 fixture.destroy_repo(repo_name)
897 fixture.destroy_repo(repo_name)
895
898
896 def test_api_fork_repo(self):
899 def test_api_fork_repo(self):
897 fork_name = 'api-repo-fork'
900 fork_name = 'api-repo-fork'
898 id_, params = _build_data(self.apikey, 'fork_repo',
901 id_, params = _build_data(self.apikey, 'fork_repo',
899 repoid=self.REPO,
902 repoid=self.REPO,
900 fork_name=fork_name,
903 fork_name=fork_name,
901 owner=TEST_USER_ADMIN_LOGIN,
904 owner=TEST_USER_ADMIN_LOGIN,
902 )
905 )
903 response = api_call(self, params)
906 response = api_call(self, params)
904
907
905 ret = {
908 ret = {
906 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
909 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
907 fork_name),
910 fork_name),
908 'success': True
911 'success': True
909 }
912 }
910 expected = ret
913 expected = ret
911 self._compare_ok(id_, expected, given=response.body)
914 self._compare_ok(id_, expected, given=response.body)
912 fixture.destroy_repo(fork_name)
915 fixture.destroy_repo(fork_name)
913
916
914 def test_api_fork_repo_non_admin(self):
917 def test_api_fork_repo_non_admin(self):
915 fork_name = 'api-repo-fork'
918 fork_name = 'api-repo-fork'
916 id_, params = _build_data(self.apikey_regular, 'fork_repo',
919 id_, params = _build_data(self.apikey_regular, 'fork_repo',
917 repoid=self.REPO,
920 repoid=self.REPO,
918 fork_name=fork_name,
921 fork_name=fork_name,
919 )
922 )
920 response = api_call(self, params)
923 response = api_call(self, params)
921
924
922 ret = {
925 ret = {
923 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
926 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
924 fork_name),
927 fork_name),
925 'success': True
928 'success': True
926 }
929 }
927 expected = ret
930 expected = ret
928 self._compare_ok(id_, expected, given=response.body)
931 self._compare_ok(id_, expected, given=response.body)
929 fixture.destroy_repo(fork_name)
932 fixture.destroy_repo(fork_name)
930
933
931 def test_api_fork_repo_non_admin_specify_owner(self):
934 def test_api_fork_repo_non_admin_specify_owner(self):
932 fork_name = 'api-repo-fork'
935 fork_name = 'api-repo-fork'
933 id_, params = _build_data(self.apikey_regular, 'fork_repo',
936 id_, params = _build_data(self.apikey_regular, 'fork_repo',
934 repoid=self.REPO,
937 repoid=self.REPO,
935 fork_name=fork_name,
938 fork_name=fork_name,
936 owner=TEST_USER_ADMIN_LOGIN,
939 owner=TEST_USER_ADMIN_LOGIN,
937 )
940 )
938 response = api_call(self, params)
941 response = api_call(self, params)
939 expected = 'Only RhodeCode admin can specify `owner` param'
942 expected = 'Only RhodeCode admin can specify `owner` param'
940 self._compare_error(id_, expected, given=response.body)
943 self._compare_error(id_, expected, given=response.body)
941 fixture.destroy_repo(fork_name)
944 fixture.destroy_repo(fork_name)
942
945
943 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
946 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
944 RepoModel().grant_user_permission(repo=self.REPO,
947 RepoModel().grant_user_permission(repo=self.REPO,
945 user=self.TEST_USER_LOGIN,
948 user=self.TEST_USER_LOGIN,
946 perm='repository.none')
949 perm='repository.none')
947 fork_name = 'api-repo-fork'
950 fork_name = 'api-repo-fork'
948 id_, params = _build_data(self.apikey_regular, 'fork_repo',
951 id_, params = _build_data(self.apikey_regular, 'fork_repo',
949 repoid=self.REPO,
952 repoid=self.REPO,
950 fork_name=fork_name,
953 fork_name=fork_name,
951 )
954 )
952 response = api_call(self, params)
955 response = api_call(self, params)
953 expected = 'repository `%s` does not exist' % (self.REPO)
956 expected = 'repository `%s` does not exist' % (self.REPO)
954 self._compare_error(id_, expected, given=response.body)
957 self._compare_error(id_, expected, given=response.body)
955 fixture.destroy_repo(fork_name)
958 fixture.destroy_repo(fork_name)
956
959
957 def test_api_fork_repo_unknown_owner(self):
960 def test_api_fork_repo_unknown_owner(self):
958 fork_name = 'api-repo-fork'
961 fork_name = 'api-repo-fork'
959 owner = 'i-dont-exist'
962 owner = 'i-dont-exist'
960 id_, params = _build_data(self.apikey, 'fork_repo',
963 id_, params = _build_data(self.apikey, 'fork_repo',
961 repoid=self.REPO,
964 repoid=self.REPO,
962 fork_name=fork_name,
965 fork_name=fork_name,
963 owner=owner,
966 owner=owner,
964 )
967 )
965 response = api_call(self, params)
968 response = api_call(self, params)
966 expected = 'user `%s` does not exist' % owner
969 expected = 'user `%s` does not exist' % owner
967 self._compare_error(id_, expected, given=response.body)
970 self._compare_error(id_, expected, given=response.body)
968
971
969 def test_api_fork_repo_fork_exists(self):
972 def test_api_fork_repo_fork_exists(self):
970 fork_name = 'api-repo-fork'
973 fork_name = 'api-repo-fork'
971 fixture.create_fork(self.REPO, fork_name)
974 fixture.create_fork(self.REPO, fork_name)
972
975
973 try:
976 try:
974 fork_name = 'api-repo-fork'
977 fork_name = 'api-repo-fork'
975
978
976 id_, params = _build_data(self.apikey, 'fork_repo',
979 id_, params = _build_data(self.apikey, 'fork_repo',
977 repoid=self.REPO,
980 repoid=self.REPO,
978 fork_name=fork_name,
981 fork_name=fork_name,
979 owner=TEST_USER_ADMIN_LOGIN,
982 owner=TEST_USER_ADMIN_LOGIN,
980 )
983 )
981 response = api_call(self, params)
984 response = api_call(self, params)
982
985
983 expected = "fork `%s` already exist" % fork_name
986 expected = "fork `%s` already exist" % fork_name
984 self._compare_error(id_, expected, given=response.body)
987 self._compare_error(id_, expected, given=response.body)
985 finally:
988 finally:
986 fixture.destroy_repo(fork_name)
989 fixture.destroy_repo(fork_name)
987
990
988 def test_api_fork_repo_repo_exists(self):
991 def test_api_fork_repo_repo_exists(self):
989 fork_name = self.REPO
992 fork_name = self.REPO
990
993
991 id_, params = _build_data(self.apikey, 'fork_repo',
994 id_, params = _build_data(self.apikey, 'fork_repo',
992 repoid=self.REPO,
995 repoid=self.REPO,
993 fork_name=fork_name,
996 fork_name=fork_name,
994 owner=TEST_USER_ADMIN_LOGIN,
997 owner=TEST_USER_ADMIN_LOGIN,
995 )
998 )
996 response = api_call(self, params)
999 response = api_call(self, params)
997
1000
998 expected = "repo `%s` already exist" % fork_name
1001 expected = "repo `%s` already exist" % fork_name
999 self._compare_error(id_, expected, given=response.body)
1002 self._compare_error(id_, expected, given=response.body)
1000
1003
1001 @mock.patch.object(RepoModel, 'create_fork', crash)
1004 @mock.patch.object(RepoModel, 'create_fork', crash)
1002 def test_api_fork_repo_exception_occurred(self):
1005 def test_api_fork_repo_exception_occurred(self):
1003 fork_name = 'api-repo-fork'
1006 fork_name = 'api-repo-fork'
1004 id_, params = _build_data(self.apikey, 'fork_repo',
1007 id_, params = _build_data(self.apikey, 'fork_repo',
1005 repoid=self.REPO,
1008 repoid=self.REPO,
1006 fork_name=fork_name,
1009 fork_name=fork_name,
1007 owner=TEST_USER_ADMIN_LOGIN,
1010 owner=TEST_USER_ADMIN_LOGIN,
1008 )
1011 )
1009 response = api_call(self, params)
1012 response = api_call(self, params)
1010
1013
1011 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
1014 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
1012 fork_name)
1015 fork_name)
1013 self._compare_error(id_, expected, given=response.body)
1016 self._compare_error(id_, expected, given=response.body)
1014
1017
1015 def test_api_get_users_group(self):
1018 def test_api_get_users_group(self):
1016 id_, params = _build_data(self.apikey, 'get_users_group',
1019 id_, params = _build_data(self.apikey, 'get_users_group',
1017 usersgroupid=TEST_USER_GROUP)
1020 usersgroupid=TEST_USER_GROUP)
1018 response = api_call(self, params)
1021 response = api_call(self, params)
1019
1022
1020 users_group = UserGroupModel().get_group(TEST_USER_GROUP)
1023 users_group = UserGroupModel().get_group(TEST_USER_GROUP)
1021 members = []
1024 members = []
1022 for user in users_group.members:
1025 for user in users_group.members:
1023 user = user.user
1026 user = user.user
1024 members.append(user.get_api_data())
1027 members.append(user.get_api_data())
1025
1028
1026 ret = users_group.get_api_data()
1029 ret = users_group.get_api_data()
1027 ret['members'] = members
1030 ret['members'] = members
1028 expected = ret
1031 expected = ret
1029 self._compare_ok(id_, expected, given=response.body)
1032 self._compare_ok(id_, expected, given=response.body)
1030
1033
1031 def test_api_get_users_groups(self):
1034 def test_api_get_users_groups(self):
1032
1035
1033 make_users_group('test_users_group2')
1036 make_users_group('test_users_group2')
1034
1037
1035 id_, params = _build_data(self.apikey, 'get_users_groups',)
1038 id_, params = _build_data(self.apikey, 'get_users_groups',)
1036 response = api_call(self, params)
1039 response = api_call(self, params)
1037
1040
1038 expected = []
1041 expected = []
1039 for gr_name in [TEST_USER_GROUP, 'test_users_group2']:
1042 for gr_name in [TEST_USER_GROUP, 'test_users_group2']:
1040 users_group = UserGroupModel().get_group(gr_name)
1043 users_group = UserGroupModel().get_group(gr_name)
1041 ret = users_group.get_api_data()
1044 ret = users_group.get_api_data()
1042 expected.append(ret)
1045 expected.append(ret)
1043 self._compare_ok(id_, expected, given=response.body)
1046 self._compare_ok(id_, expected, given=response.body)
1044
1047
1045 UserGroupModel().delete(users_group='test_users_group2')
1048 UserGroupModel().delete(users_group='test_users_group2')
1046 Session().commit()
1049 Session().commit()
1047
1050
1048 def test_api_create_users_group(self):
1051 def test_api_create_users_group(self):
1049 group_name = 'some_new_group'
1052 group_name = 'some_new_group'
1050 id_, params = _build_data(self.apikey, 'create_users_group',
1053 id_, params = _build_data(self.apikey, 'create_users_group',
1051 group_name=group_name)
1054 group_name=group_name)
1052 response = api_call(self, params)
1055 response = api_call(self, params)
1053
1056
1054 ret = {
1057 ret = {
1055 'msg': 'created new user group `%s`' % group_name,
1058 'msg': 'created new user group `%s`' % group_name,
1056 'users_group': jsonify(UserGroupModel()\
1059 'users_group': jsonify(UserGroupModel()\
1057 .get_by_name(group_name)\
1060 .get_by_name(group_name)\
1058 .get_api_data())
1061 .get_api_data())
1059 }
1062 }
1060 expected = ret
1063 expected = ret
1061 self._compare_ok(id_, expected, given=response.body)
1064 self._compare_ok(id_, expected, given=response.body)
1062
1065
1063 destroy_users_group(group_name)
1066 destroy_users_group(group_name)
1064
1067
1065 def test_api_get_users_group_that_exist(self):
1068 def test_api_get_users_group_that_exist(self):
1066 id_, params = _build_data(self.apikey, 'create_users_group',
1069 id_, params = _build_data(self.apikey, 'create_users_group',
1067 group_name=TEST_USER_GROUP)
1070 group_name=TEST_USER_GROUP)
1068 response = api_call(self, params)
1071 response = api_call(self, params)
1069
1072
1070 expected = "user group `%s` already exist" % TEST_USER_GROUP
1073 expected = "user group `%s` already exist" % TEST_USER_GROUP
1071 self._compare_error(id_, expected, given=response.body)
1074 self._compare_error(id_, expected, given=response.body)
1072
1075
1073 @mock.patch.object(UserGroupModel, 'create', crash)
1076 @mock.patch.object(UserGroupModel, 'create', crash)
1074 def test_api_get_users_group_exception_occurred(self):
1077 def test_api_get_users_group_exception_occurred(self):
1075 group_name = 'exception_happens'
1078 group_name = 'exception_happens'
1076 id_, params = _build_data(self.apikey, 'create_users_group',
1079 id_, params = _build_data(self.apikey, 'create_users_group',
1077 group_name=group_name)
1080 group_name=group_name)
1078 response = api_call(self, params)
1081 response = api_call(self, params)
1079
1082
1080 expected = 'failed to create group `%s`' % group_name
1083 expected = 'failed to create group `%s`' % group_name
1081 self._compare_error(id_, expected, given=response.body)
1084 self._compare_error(id_, expected, given=response.body)
1082
1085
1083 def test_api_add_user_to_users_group(self):
1086 def test_api_add_user_to_users_group(self):
1084 gr_name = 'test_group'
1087 gr_name = 'test_group'
1085 fixture.create_user_group(gr_name)
1088 fixture.create_user_group(gr_name)
1086 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1089 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1087 usersgroupid=gr_name,
1090 usersgroupid=gr_name,
1088 userid=TEST_USER_ADMIN_LOGIN)
1091 userid=TEST_USER_ADMIN_LOGIN)
1089 response = api_call(self, params)
1092 response = api_call(self, params)
1090
1093
1091 expected = {
1094 expected = {
1092 'msg': 'added member `%s` to user group `%s`' % (
1095 'msg': 'added member `%s` to user group `%s`' % (
1093 TEST_USER_ADMIN_LOGIN, gr_name
1096 TEST_USER_ADMIN_LOGIN, gr_name
1094 ),
1097 ),
1095 'success': True}
1098 'success': True}
1096 self._compare_ok(id_, expected, given=response.body)
1099 self._compare_ok(id_, expected, given=response.body)
1097
1100
1098 UserGroupModel().delete(users_group=gr_name)
1101 UserGroupModel().delete(users_group=gr_name)
1099 Session().commit()
1102 Session().commit()
1100
1103
1101 def test_api_add_user_to_users_group_that_doesnt_exist(self):
1104 def test_api_add_user_to_users_group_that_doesnt_exist(self):
1102 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1105 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1103 usersgroupid='false-group',
1106 usersgroupid='false-group',
1104 userid=TEST_USER_ADMIN_LOGIN)
1107 userid=TEST_USER_ADMIN_LOGIN)
1105 response = api_call(self, params)
1108 response = api_call(self, params)
1106
1109
1107 expected = 'user group `%s` does not exist' % 'false-group'
1110 expected = 'user group `%s` does not exist' % 'false-group'
1108 self._compare_error(id_, expected, given=response.body)
1111 self._compare_error(id_, expected, given=response.body)
1109
1112
1110 @mock.patch.object(UserGroupModel, 'add_user_to_group', crash)
1113 @mock.patch.object(UserGroupModel, 'add_user_to_group', crash)
1111 def test_api_add_user_to_users_group_exception_occurred(self):
1114 def test_api_add_user_to_users_group_exception_occurred(self):
1112 gr_name = 'test_group'
1115 gr_name = 'test_group'
1113 fixture.create_user_group(gr_name)
1116 fixture.create_user_group(gr_name)
1114 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1117 id_, params = _build_data(self.apikey, 'add_user_to_users_group',
1115 usersgroupid=gr_name,
1118 usersgroupid=gr_name,
1116 userid=TEST_USER_ADMIN_LOGIN)
1119 userid=TEST_USER_ADMIN_LOGIN)
1117 response = api_call(self, params)
1120 response = api_call(self, params)
1118
1121
1119 expected = 'failed to add member to user group `%s`' % gr_name
1122 expected = 'failed to add member to user group `%s`' % gr_name
1120 self._compare_error(id_, expected, given=response.body)
1123 self._compare_error(id_, expected, given=response.body)
1121
1124
1122 UserGroupModel().delete(users_group=gr_name)
1125 UserGroupModel().delete(users_group=gr_name)
1123 Session().commit()
1126 Session().commit()
1124
1127
1125 def test_api_remove_user_from_users_group(self):
1128 def test_api_remove_user_from_users_group(self):
1126 gr_name = 'test_group_3'
1129 gr_name = 'test_group_3'
1127 gr = fixture.create_user_group(gr_name)
1130 gr = fixture.create_user_group(gr_name)
1128 UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1131 UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1129 Session().commit()
1132 Session().commit()
1130 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1133 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1131 usersgroupid=gr_name,
1134 usersgroupid=gr_name,
1132 userid=TEST_USER_ADMIN_LOGIN)
1135 userid=TEST_USER_ADMIN_LOGIN)
1133 response = api_call(self, params)
1136 response = api_call(self, params)
1134
1137
1135 expected = {
1138 expected = {
1136 'msg': 'removed member `%s` from user group `%s`' % (
1139 'msg': 'removed member `%s` from user group `%s`' % (
1137 TEST_USER_ADMIN_LOGIN, gr_name
1140 TEST_USER_ADMIN_LOGIN, gr_name
1138 ),
1141 ),
1139 'success': True}
1142 'success': True}
1140 self._compare_ok(id_, expected, given=response.body)
1143 self._compare_ok(id_, expected, given=response.body)
1141
1144
1142 UserGroupModel().delete(users_group=gr_name)
1145 UserGroupModel().delete(users_group=gr_name)
1143 Session().commit()
1146 Session().commit()
1144
1147
1145 @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash)
1148 @mock.patch.object(UserGroupModel, 'remove_user_from_group', crash)
1146 def test_api_remove_user_from_users_group_exception_occurred(self):
1149 def test_api_remove_user_from_users_group_exception_occurred(self):
1147 gr_name = 'test_group_3'
1150 gr_name = 'test_group_3'
1148 gr = fixture.create_user_group(gr_name)
1151 gr = fixture.create_user_group(gr_name)
1149 UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1152 UserGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN)
1150 Session().commit()
1153 Session().commit()
1151 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1154 id_, params = _build_data(self.apikey, 'remove_user_from_users_group',
1152 usersgroupid=gr_name,
1155 usersgroupid=gr_name,
1153 userid=TEST_USER_ADMIN_LOGIN)
1156 userid=TEST_USER_ADMIN_LOGIN)
1154 response = api_call(self, params)
1157 response = api_call(self, params)
1155
1158
1156 expected = 'failed to remove member from user group `%s`' % gr_name
1159 expected = 'failed to remove member from user group `%s`' % gr_name
1157 self._compare_error(id_, expected, given=response.body)
1160 self._compare_error(id_, expected, given=response.body)
1158
1161
1159 UserGroupModel().delete(users_group=gr_name)
1162 UserGroupModel().delete(users_group=gr_name)
1160 Session().commit()
1163 Session().commit()
1161
1164
1162 @parameterized.expand([('none', 'repository.none'),
1165 @parameterized.expand([('none', 'repository.none'),
1163 ('read', 'repository.read'),
1166 ('read', 'repository.read'),
1164 ('write', 'repository.write'),
1167 ('write', 'repository.write'),
1165 ('admin', 'repository.admin')])
1168 ('admin', 'repository.admin')])
1166 def test_api_grant_user_permission(self, name, perm):
1169 def test_api_grant_user_permission(self, name, perm):
1167 id_, params = _build_data(self.apikey, 'grant_user_permission',
1170 id_, params = _build_data(self.apikey, 'grant_user_permission',
1168 repoid=self.REPO,
1171 repoid=self.REPO,
1169 userid=TEST_USER_ADMIN_LOGIN,
1172 userid=TEST_USER_ADMIN_LOGIN,
1170 perm=perm)
1173 perm=perm)
1171 response = api_call(self, params)
1174 response = api_call(self, params)
1172
1175
1173 ret = {
1176 ret = {
1174 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1177 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1175 perm, TEST_USER_ADMIN_LOGIN, self.REPO
1178 perm, TEST_USER_ADMIN_LOGIN, self.REPO
1176 ),
1179 ),
1177 'success': True
1180 'success': True
1178 }
1181 }
1179 expected = ret
1182 expected = ret
1180 self._compare_ok(id_, expected, given=response.body)
1183 self._compare_ok(id_, expected, given=response.body)
1181
1184
1182 def test_api_grant_user_permission_wrong_permission(self):
1185 def test_api_grant_user_permission_wrong_permission(self):
1183 perm = 'haha.no.permission'
1186 perm = 'haha.no.permission'
1184 id_, params = _build_data(self.apikey, 'grant_user_permission',
1187 id_, params = _build_data(self.apikey, 'grant_user_permission',
1185 repoid=self.REPO,
1188 repoid=self.REPO,
1186 userid=TEST_USER_ADMIN_LOGIN,
1189 userid=TEST_USER_ADMIN_LOGIN,
1187 perm=perm)
1190 perm=perm)
1188 response = api_call(self, params)
1191 response = api_call(self, params)
1189
1192
1190 expected = 'permission `%s` does not exist' % perm
1193 expected = 'permission `%s` does not exist' % perm
1191 self._compare_error(id_, expected, given=response.body)
1194 self._compare_error(id_, expected, given=response.body)
1192
1195
1193 @mock.patch.object(RepoModel, 'grant_user_permission', crash)
1196 @mock.patch.object(RepoModel, 'grant_user_permission', crash)
1194 def test_api_grant_user_permission_exception_when_adding(self):
1197 def test_api_grant_user_permission_exception_when_adding(self):
1195 perm = 'repository.read'
1198 perm = 'repository.read'
1196 id_, params = _build_data(self.apikey, 'grant_user_permission',
1199 id_, params = _build_data(self.apikey, 'grant_user_permission',
1197 repoid=self.REPO,
1200 repoid=self.REPO,
1198 userid=TEST_USER_ADMIN_LOGIN,
1201 userid=TEST_USER_ADMIN_LOGIN,
1199 perm=perm)
1202 perm=perm)
1200 response = api_call(self, params)
1203 response = api_call(self, params)
1201
1204
1202 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1205 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1203 TEST_USER_ADMIN_LOGIN, self.REPO
1206 TEST_USER_ADMIN_LOGIN, self.REPO
1204 )
1207 )
1205 self._compare_error(id_, expected, given=response.body)
1208 self._compare_error(id_, expected, given=response.body)
1206
1209
1207 def test_api_revoke_user_permission(self):
1210 def test_api_revoke_user_permission(self):
1208 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1211 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1209 repoid=self.REPO,
1212 repoid=self.REPO,
1210 userid=TEST_USER_ADMIN_LOGIN,)
1213 userid=TEST_USER_ADMIN_LOGIN,)
1211 response = api_call(self, params)
1214 response = api_call(self, params)
1212
1215
1213 expected = {
1216 expected = {
1214 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1217 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1215 TEST_USER_ADMIN_LOGIN, self.REPO
1218 TEST_USER_ADMIN_LOGIN, self.REPO
1216 ),
1219 ),
1217 'success': True
1220 'success': True
1218 }
1221 }
1219 self._compare_ok(id_, expected, given=response.body)
1222 self._compare_ok(id_, expected, given=response.body)
1220
1223
1221 @mock.patch.object(RepoModel, 'revoke_user_permission', crash)
1224 @mock.patch.object(RepoModel, 'revoke_user_permission', crash)
1222 def test_api_revoke_user_permission_exception_when_adding(self):
1225 def test_api_revoke_user_permission_exception_when_adding(self):
1223 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1226 id_, params = _build_data(self.apikey, 'revoke_user_permission',
1224 repoid=self.REPO,
1227 repoid=self.REPO,
1225 userid=TEST_USER_ADMIN_LOGIN,)
1228 userid=TEST_USER_ADMIN_LOGIN,)
1226 response = api_call(self, params)
1229 response = api_call(self, params)
1227
1230
1228 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1231 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1229 TEST_USER_ADMIN_LOGIN, self.REPO
1232 TEST_USER_ADMIN_LOGIN, self.REPO
1230 )
1233 )
1231 self._compare_error(id_, expected, given=response.body)
1234 self._compare_error(id_, expected, given=response.body)
1232
1235
1233 @parameterized.expand([('none', 'repository.none'),
1236 @parameterized.expand([('none', 'repository.none'),
1234 ('read', 'repository.read'),
1237 ('read', 'repository.read'),
1235 ('write', 'repository.write'),
1238 ('write', 'repository.write'),
1236 ('admin', 'repository.admin')])
1239 ('admin', 'repository.admin')])
1237 def test_api_grant_users_group_permission(self, name, perm):
1240 def test_api_grant_users_group_permission(self, name, perm):
1238 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1241 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1239 repoid=self.REPO,
1242 repoid=self.REPO,
1240 usersgroupid=TEST_USER_GROUP,
1243 usersgroupid=TEST_USER_GROUP,
1241 perm=perm)
1244 perm=perm)
1242 response = api_call(self, params)
1245 response = api_call(self, params)
1243
1246
1244 ret = {
1247 ret = {
1245 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % (
1248 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % (
1246 perm, TEST_USER_GROUP, self.REPO
1249 perm, TEST_USER_GROUP, self.REPO
1247 ),
1250 ),
1248 'success': True
1251 'success': True
1249 }
1252 }
1250 expected = ret
1253 expected = ret
1251 self._compare_ok(id_, expected, given=response.body)
1254 self._compare_ok(id_, expected, given=response.body)
1252
1255
1253 def test_api_grant_users_group_permission_wrong_permission(self):
1256 def test_api_grant_users_group_permission_wrong_permission(self):
1254 perm = 'haha.no.permission'
1257 perm = 'haha.no.permission'
1255 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1258 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1256 repoid=self.REPO,
1259 repoid=self.REPO,
1257 usersgroupid=TEST_USER_GROUP,
1260 usersgroupid=TEST_USER_GROUP,
1258 perm=perm)
1261 perm=perm)
1259 response = api_call(self, params)
1262 response = api_call(self, params)
1260
1263
1261 expected = 'permission `%s` does not exist' % perm
1264 expected = 'permission `%s` does not exist' % perm
1262 self._compare_error(id_, expected, given=response.body)
1265 self._compare_error(id_, expected, given=response.body)
1263
1266
1264 @mock.patch.object(RepoModel, 'grant_users_group_permission', crash)
1267 @mock.patch.object(RepoModel, 'grant_users_group_permission', crash)
1265 def test_api_grant_users_group_permission_exception_when_adding(self):
1268 def test_api_grant_users_group_permission_exception_when_adding(self):
1266 perm = 'repository.read'
1269 perm = 'repository.read'
1267 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1270 id_, params = _build_data(self.apikey, 'grant_users_group_permission',
1268 repoid=self.REPO,
1271 repoid=self.REPO,
1269 usersgroupid=TEST_USER_GROUP,
1272 usersgroupid=TEST_USER_GROUP,
1270 perm=perm)
1273 perm=perm)
1271 response = api_call(self, params)
1274 response = api_call(self, params)
1272
1275
1273 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1276 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1274 TEST_USER_GROUP, self.REPO
1277 TEST_USER_GROUP, self.REPO
1275 )
1278 )
1276 self._compare_error(id_, expected, given=response.body)
1279 self._compare_error(id_, expected, given=response.body)
1277
1280
1278 def test_api_revoke_users_group_permission(self):
1281 def test_api_revoke_users_group_permission(self):
1279 RepoModel().grant_users_group_permission(repo=self.REPO,
1282 RepoModel().grant_users_group_permission(repo=self.REPO,
1280 group_name=TEST_USER_GROUP,
1283 group_name=TEST_USER_GROUP,
1281 perm='repository.read')
1284 perm='repository.read')
1282 Session().commit()
1285 Session().commit()
1283 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1286 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1284 repoid=self.REPO,
1287 repoid=self.REPO,
1285 usersgroupid=TEST_USER_GROUP,)
1288 usersgroupid=TEST_USER_GROUP,)
1286 response = api_call(self, params)
1289 response = api_call(self, params)
1287
1290
1288 expected = {
1291 expected = {
1289 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1292 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1290 TEST_USER_GROUP, self.REPO
1293 TEST_USER_GROUP, self.REPO
1291 ),
1294 ),
1292 'success': True
1295 'success': True
1293 }
1296 }
1294 self._compare_ok(id_, expected, given=response.body)
1297 self._compare_ok(id_, expected, given=response.body)
1295
1298
1296 @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash)
1299 @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash)
1297 def test_api_revoke_users_group_permission_exception_when_adding(self):
1300 def test_api_revoke_users_group_permission_exception_when_adding(self):
1298
1301
1299 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1302 id_, params = _build_data(self.apikey, 'revoke_users_group_permission',
1300 repoid=self.REPO,
1303 repoid=self.REPO,
1301 usersgroupid=TEST_USER_GROUP,)
1304 usersgroupid=TEST_USER_GROUP,)
1302 response = api_call(self, params)
1305 response = api_call(self, params)
1303
1306
1304 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1307 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1305 TEST_USER_GROUP, self.REPO
1308 TEST_USER_GROUP, self.REPO
1306 )
1309 )
1307 self._compare_error(id_, expected, given=response.body)
1310 self._compare_error(id_, expected, given=response.body)
General Comments 0
You need to be logged in to leave comments. Login now