##// END OF EJS Templates
forks: fixed forking with new landing rev....
marcink -
r3969:f86c0abc default
parent child Browse files
Show More
@@ -1,336 +1,333 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests import TestController, assert_session_flash, HG_FORK, GIT_FORK
23 from rhodecode.tests import TestController, assert_session_flash, HG_FORK, GIT_FORK
24
24
25 from rhodecode.tests.fixture import Fixture
25 from rhodecode.tests.fixture import Fixture
26 from rhodecode.lib import helpers as h
26 from rhodecode.lib import helpers as h
27
27
28 from rhodecode.model.db import Repository
28 from rhodecode.model.db import Repository
29 from rhodecode.model.repo import RepoModel
29 from rhodecode.model.repo import RepoModel
30 from rhodecode.model.user import UserModel
30 from rhodecode.model.user import UserModel
31 from rhodecode.model.meta import Session
31 from rhodecode.model.meta import Session
32
32
33 fixture = Fixture()
33 fixture = Fixture()
34
34
35
35
36 def route_path(name, params=None, **kwargs):
36 def route_path(name, params=None, **kwargs):
37 import urllib
37 import urllib
38
38
39 base_url = {
39 base_url = {
40 'repo_summary': '/{repo_name}',
40 'repo_summary': '/{repo_name}',
41 'repo_creating_check': '/{repo_name}/repo_creating_check',
41 'repo_creating_check': '/{repo_name}/repo_creating_check',
42 'repo_fork_new': '/{repo_name}/fork',
42 'repo_fork_new': '/{repo_name}/fork',
43 'repo_fork_create': '/{repo_name}/fork/create',
43 'repo_fork_create': '/{repo_name}/fork/create',
44 'repo_forks_show_all': '/{repo_name}/forks',
44 'repo_forks_show_all': '/{repo_name}/forks',
45 'repo_forks_data': '/{repo_name}/forks/data',
45 'repo_forks_data': '/{repo_name}/forks/data',
46 }[name].format(**kwargs)
46 }[name].format(**kwargs)
47
47
48 if params:
48 if params:
49 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
49 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
50 return base_url
50 return base_url
51
51
52
52
53 FORK_NAME = {
53 FORK_NAME = {
54 'hg': HG_FORK,
54 'hg': HG_FORK,
55 'git': GIT_FORK
55 'git': GIT_FORK
56 }
56 }
57
57
58
58
59 @pytest.mark.skip_backends('svn')
59 @pytest.mark.skip_backends('svn')
60 class TestRepoForkViewTests(TestController):
60 class TestRepoForkViewTests(TestController):
61
61
62 def test_show_forks(self, backend, xhr_header):
62 def test_show_forks(self, backend, xhr_header):
63 self.log_user()
63 self.log_user()
64 response = self.app.get(
64 response = self.app.get(
65 route_path('repo_forks_data', repo_name=backend.repo_name),
65 route_path('repo_forks_data', repo_name=backend.repo_name),
66 extra_environ=xhr_header)
66 extra_environ=xhr_header)
67
67
68 assert response.json == {u'data': [], u'draw': None,
68 assert response.json == {u'data': [], u'draw': None,
69 u'recordsFiltered': 0, u'recordsTotal': 0}
69 u'recordsFiltered': 0, u'recordsTotal': 0}
70
70
71 def test_no_permissions_to_fork_page(self, backend, user_util):
71 def test_no_permissions_to_fork_page(self, backend, user_util):
72 user = user_util.create_user(password='qweqwe')
72 user = user_util.create_user(password='qweqwe')
73 user_id = user.user_id
73 user_id = user.user_id
74 self.log_user(user.username, 'qweqwe')
74 self.log_user(user.username, 'qweqwe')
75
75
76 user_model = UserModel()
76 user_model = UserModel()
77 user_model.revoke_perm(user_id, 'hg.fork.repository')
77 user_model.revoke_perm(user_id, 'hg.fork.repository')
78 user_model.grant_perm(user_id, 'hg.fork.none')
78 user_model.grant_perm(user_id, 'hg.fork.none')
79 u = UserModel().get(user_id)
79 u = UserModel().get(user_id)
80 u.inherit_default_permissions = False
80 u.inherit_default_permissions = False
81 Session().commit()
81 Session().commit()
82 # try create a fork
82 # try create a fork
83 self.app.get(
83 self.app.get(
84 route_path('repo_fork_new', repo_name=backend.repo_name),
84 route_path('repo_fork_new', repo_name=backend.repo_name),
85 status=404)
85 status=404)
86
86
87 def test_no_permissions_to_fork_submit(self, backend, csrf_token, user_util):
87 def test_no_permissions_to_fork_submit(self, backend, csrf_token, user_util):
88 user = user_util.create_user(password='qweqwe')
88 user = user_util.create_user(password='qweqwe')
89 user_id = user.user_id
89 user_id = user.user_id
90 self.log_user(user.username, 'qweqwe')
90 self.log_user(user.username, 'qweqwe')
91
91
92 user_model = UserModel()
92 user_model = UserModel()
93 user_model.revoke_perm(user_id, 'hg.fork.repository')
93 user_model.revoke_perm(user_id, 'hg.fork.repository')
94 user_model.grant_perm(user_id, 'hg.fork.none')
94 user_model.grant_perm(user_id, 'hg.fork.none')
95 u = UserModel().get(user_id)
95 u = UserModel().get(user_id)
96 u.inherit_default_permissions = False
96 u.inherit_default_permissions = False
97 Session().commit()
97 Session().commit()
98 # try create a fork
98 # try create a fork
99 self.app.post(
99 self.app.post(
100 route_path('repo_fork_create', repo_name=backend.repo_name),
100 route_path('repo_fork_create', repo_name=backend.repo_name),
101 {'csrf_token': csrf_token},
101 {'csrf_token': csrf_token},
102 status=404)
102 status=404)
103
103
104 def test_fork_missing_data(self, autologin_user, backend, csrf_token):
104 def test_fork_missing_data(self, autologin_user, backend, csrf_token):
105 # try create a fork
105 # try create a fork
106 response = self.app.post(
106 response = self.app.post(
107 route_path('repo_fork_create', repo_name=backend.repo_name),
107 route_path('repo_fork_create', repo_name=backend.repo_name),
108 {'csrf_token': csrf_token},
108 {'csrf_token': csrf_token},
109 status=200)
109 status=200)
110 # test if html fill works fine
110 # test if html fill works fine
111 response.mustcontain('Missing value')
111 response.mustcontain('Missing value')
112
112
113 def test_create_fork_page(self, autologin_user, backend):
113 def test_create_fork_page(self, autologin_user, backend):
114 self.app.get(
114 self.app.get(
115 route_path('repo_fork_new', repo_name=backend.repo_name),
115 route_path('repo_fork_new', repo_name=backend.repo_name),
116 status=200)
116 status=200)
117
117
118 def test_create_and_show_fork(
118 def test_create_and_show_fork(
119 self, autologin_user, backend, csrf_token, xhr_header):
119 self, autologin_user, backend, csrf_token, xhr_header):
120
120
121 # create a fork
121 # create a fork
122 fork_name = FORK_NAME[backend.alias]
122 fork_name = FORK_NAME[backend.alias]
123 description = 'fork of vcs test'
123 description = 'fork of vcs test'
124 repo_name = backend.repo_name
124 repo_name = backend.repo_name
125 source_repo = Repository.get_by_repo_name(repo_name)
125 source_repo = Repository.get_by_repo_name(repo_name)
126 creation_args = {
126 creation_args = {
127 'repo_name': fork_name,
127 'repo_name': fork_name,
128 'repo_group': '',
128 'repo_group': '',
129 'fork_parent_id': source_repo.repo_id,
129 'fork_parent_id': source_repo.repo_id,
130 'repo_type': backend.alias,
130 'repo_type': backend.alias,
131 'description': description,
131 'description': description,
132 'private': 'False',
132 'private': 'False',
133 'landing_rev': 'rev:tip',
134 'csrf_token': csrf_token,
133 'csrf_token': csrf_token,
135 }
134 }
136
135
137 self.app.post(
136 self.app.post(
138 route_path('repo_fork_create', repo_name=repo_name), creation_args)
137 route_path('repo_fork_create', repo_name=repo_name), creation_args)
139
138
140 response = self.app.get(
139 response = self.app.get(
141 route_path('repo_forks_data', repo_name=repo_name),
140 route_path('repo_forks_data', repo_name=repo_name),
142 extra_environ=xhr_header)
141 extra_environ=xhr_header)
143
142
144 assert response.json['data'][0]['fork_name'] == \
143 assert response.json['data'][0]['fork_name'] == \
145 """<a href="/%s">%s</a>""" % (fork_name, fork_name)
144 """<a href="/%s">%s</a>""" % (fork_name, fork_name)
146
145
147 # remove this fork
146 # remove this fork
148 fixture.destroy_repo(fork_name)
147 fixture.destroy_repo(fork_name)
149
148
150 def test_fork_create(self, autologin_user, backend, csrf_token):
149 def test_fork_create(self, autologin_user, backend, csrf_token):
151 fork_name = FORK_NAME[backend.alias]
150 fork_name = FORK_NAME[backend.alias]
152 description = 'fork of vcs test'
151 description = 'fork of vcs test'
153 repo_name = backend.repo_name
152 repo_name = backend.repo_name
154 source_repo = Repository.get_by_repo_name(repo_name)
153 source_repo = Repository.get_by_repo_name(repo_name)
155 creation_args = {
154 creation_args = {
156 'repo_name': fork_name,
155 'repo_name': fork_name,
157 'repo_group': '',
156 'repo_group': '',
158 'fork_parent_id': source_repo.repo_id,
157 'fork_parent_id': source_repo.repo_id,
159 'repo_type': backend.alias,
158 'repo_type': backend.alias,
160 'description': description,
159 'description': description,
161 'private': 'False',
160 'private': 'False',
162 'landing_rev': 'rev:tip',
163 'csrf_token': csrf_token,
161 'csrf_token': csrf_token,
164 }
162 }
165 self.app.post(
163 self.app.post(
166 route_path('repo_fork_create', repo_name=repo_name), creation_args)
164 route_path('repo_fork_create', repo_name=repo_name), creation_args)
167 repo = Repository.get_by_repo_name(FORK_NAME[backend.alias])
165 repo = Repository.get_by_repo_name(FORK_NAME[backend.alias])
168 assert repo.fork.repo_name == backend.repo_name
166 assert repo.fork.repo_name == backend.repo_name
169
167
170 # run the check page that triggers the flash message
168 # run the check page that triggers the flash message
171 response = self.app.get(
169 response = self.app.get(
172 route_path('repo_creating_check', repo_name=fork_name))
170 route_path('repo_creating_check', repo_name=fork_name))
173 # test if we have a message that fork is ok
171 # test if we have a message that fork is ok
174 assert_session_flash(response,
172 assert_session_flash(response,
175 'Forked repository %s as <a href="/%s">%s</a>'
173 'Forked repository %s as <a href="/%s">%s</a>' % (
176 % (repo_name, fork_name, fork_name))
174 repo_name, fork_name, fork_name))
177
175
178 # test if the fork was created in the database
176 # test if the fork was created in the database
179 fork_repo = Session().query(Repository)\
177 fork_repo = Session().query(Repository)\
180 .filter(Repository.repo_name == fork_name).one()
178 .filter(Repository.repo_name == fork_name).one()
181
179
182 assert fork_repo.repo_name == fork_name
180 assert fork_repo.repo_name == fork_name
183 assert fork_repo.fork.repo_name == repo_name
181 assert fork_repo.fork.repo_name == repo_name
184
182
185 # test if the repository is visible in the list ?
183 # test if the repository is visible in the list ?
186 response = self.app.get(
184 response = self.app.get(
187 h.route_path('repo_summary', repo_name=fork_name))
185 h.route_path('repo_summary', repo_name=fork_name))
188 response.mustcontain(fork_name)
186 response.mustcontain(fork_name)
189 response.mustcontain(backend.alias)
187 response.mustcontain(backend.alias)
190 response.mustcontain('Fork of')
188 response.mustcontain('Fork of')
191 response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
189 response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
192
190
193 def test_fork_create_into_group(self, autologin_user, backend, csrf_token):
191 def test_fork_create_into_group(self, autologin_user, backend, csrf_token):
194 group = fixture.create_repo_group('vc')
192 group = fixture.create_repo_group('vc')
195 group_id = group.group_id
193 group_id = group.group_id
196 fork_name = FORK_NAME[backend.alias]
194 fork_name = FORK_NAME[backend.alias]
197 fork_name_full = 'vc/%s' % fork_name
195 fork_name_full = 'vc/%s' % fork_name
198 description = 'fork of vcs test'
196 description = 'fork of vcs test'
199 repo_name = backend.repo_name
197 repo_name = backend.repo_name
200 source_repo = Repository.get_by_repo_name(repo_name)
198 source_repo = Repository.get_by_repo_name(repo_name)
201 creation_args = {
199 creation_args = {
202 'repo_name': fork_name,
200 'repo_name': fork_name,
203 'repo_group': group_id,
201 'repo_group': group_id,
204 'fork_parent_id': source_repo.repo_id,
202 'fork_parent_id': source_repo.repo_id,
205 'repo_type': backend.alias,
203 'repo_type': backend.alias,
206 'description': description,
204 'description': description,
207 'private': 'False',
205 'private': 'False',
208 'landing_rev': 'rev:tip',
209 'csrf_token': csrf_token,
206 'csrf_token': csrf_token,
210 }
207 }
211 self.app.post(
208 self.app.post(
212 route_path('repo_fork_create', repo_name=repo_name), creation_args)
209 route_path('repo_fork_create', repo_name=repo_name), creation_args)
213 repo = Repository.get_by_repo_name(fork_name_full)
210 repo = Repository.get_by_repo_name(fork_name_full)
214 assert repo.fork.repo_name == backend.repo_name
211 assert repo.fork.repo_name == backend.repo_name
215
212
216 # run the check page that triggers the flash message
213 # run the check page that triggers the flash message
217 response = self.app.get(
214 response = self.app.get(
218 route_path('repo_creating_check', repo_name=fork_name_full))
215 route_path('repo_creating_check', repo_name=fork_name_full))
219 # test if we have a message that fork is ok
216 # test if we have a message that fork is ok
220 assert_session_flash(response,
217 assert_session_flash(response,
221 'Forked repository %s as <a href="/%s">%s</a>'
218 'Forked repository %s as <a href="/%s">%s</a>' % (
222 % (repo_name, fork_name_full, fork_name_full))
219 repo_name, fork_name_full, fork_name_full))
223
220
224 # test if the fork was created in the database
221 # test if the fork was created in the database
225 fork_repo = Session().query(Repository)\
222 fork_repo = Session().query(Repository)\
226 .filter(Repository.repo_name == fork_name_full).one()
223 .filter(Repository.repo_name == fork_name_full).one()
227
224
228 assert fork_repo.repo_name == fork_name_full
225 assert fork_repo.repo_name == fork_name_full
229 assert fork_repo.fork.repo_name == repo_name
226 assert fork_repo.fork.repo_name == repo_name
230
227
231 # test if the repository is visible in the list ?
228 # test if the repository is visible in the list ?
232 response = self.app.get(
229 response = self.app.get(
233 h.route_path('repo_summary', repo_name=fork_name_full))
230 h.route_path('repo_summary', repo_name=fork_name_full))
234 response.mustcontain(fork_name_full)
231 response.mustcontain(fork_name_full)
235 response.mustcontain(backend.alias)
232 response.mustcontain(backend.alias)
236
233
237 response.mustcontain('Fork of')
234 response.mustcontain('Fork of')
238 response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
235 response.mustcontain('<a href="/%s">%s</a>' % (repo_name, repo_name))
239
236
240 fixture.destroy_repo(fork_name_full)
237 fixture.destroy_repo(fork_name_full)
241 fixture.destroy_repo_group(group_id)
238 fixture.destroy_repo_group(group_id)
242
239
243 def test_fork_read_permission(self, backend, xhr_header, user_util):
240 def test_fork_read_permission(self, backend, xhr_header, user_util):
244 user = user_util.create_user(password='qweqwe')
241 user = user_util.create_user(password='qweqwe')
245 user_id = user.user_id
242 user_id = user.user_id
246 self.log_user(user.username, 'qweqwe')
243 self.log_user(user.username, 'qweqwe')
247
244
248 # create a fake fork
245 # create a fake fork
249 fork = user_util.create_repo(repo_type=backend.alias)
246 fork = user_util.create_repo(repo_type=backend.alias)
250 source = user_util.create_repo(repo_type=backend.alias)
247 source = user_util.create_repo(repo_type=backend.alias)
251 repo_name = source.repo_name
248 repo_name = source.repo_name
252
249
253 fork.fork_id = source.repo_id
250 fork.fork_id = source.repo_id
254 fork_name = fork.repo_name
251 fork_name = fork.repo_name
255 Session().commit()
252 Session().commit()
256
253
257 forks = Repository.query()\
254 forks = Repository.query()\
258 .filter(Repository.repo_type == backend.alias)\
255 .filter(Repository.repo_type == backend.alias)\
259 .filter(Repository.fork_id == source.repo_id).all()
256 .filter(Repository.fork_id == source.repo_id).all()
260 assert 1 == len(forks)
257 assert 1 == len(forks)
261
258
262 # set read permissions for this
259 # set read permissions for this
263 RepoModel().grant_user_permission(
260 RepoModel().grant_user_permission(
264 repo=forks[0], user=user_id, perm='repository.read')
261 repo=forks[0], user=user_id, perm='repository.read')
265 Session().commit()
262 Session().commit()
266
263
267 response = self.app.get(
264 response = self.app.get(
268 route_path('repo_forks_data', repo_name=repo_name),
265 route_path('repo_forks_data', repo_name=repo_name),
269 extra_environ=xhr_header)
266 extra_environ=xhr_header)
270
267
271 assert response.json['data'][0]['fork_name'] == \
268 assert response.json['data'][0]['fork_name'] == \
272 """<a href="/%s">%s</a>""" % (fork_name, fork_name)
269 """<a href="/%s">%s</a>""" % (fork_name, fork_name)
273
270
274 def test_fork_none_permission(self, backend, xhr_header, user_util):
271 def test_fork_none_permission(self, backend, xhr_header, user_util):
275 user = user_util.create_user(password='qweqwe')
272 user = user_util.create_user(password='qweqwe')
276 user_id = user.user_id
273 user_id = user.user_id
277 self.log_user(user.username, 'qweqwe')
274 self.log_user(user.username, 'qweqwe')
278
275
279 # create a fake fork
276 # create a fake fork
280 fork = user_util.create_repo(repo_type=backend.alias)
277 fork = user_util.create_repo(repo_type=backend.alias)
281 source = user_util.create_repo(repo_type=backend.alias)
278 source = user_util.create_repo(repo_type=backend.alias)
282 repo_name = source.repo_name
279 repo_name = source.repo_name
283
280
284 fork.fork_id = source.repo_id
281 fork.fork_id = source.repo_id
285
282
286 Session().commit()
283 Session().commit()
287
284
288 forks = Repository.query()\
285 forks = Repository.query()\
289 .filter(Repository.repo_type == backend.alias)\
286 .filter(Repository.repo_type == backend.alias)\
290 .filter(Repository.fork_id == source.repo_id).all()
287 .filter(Repository.fork_id == source.repo_id).all()
291 assert 1 == len(forks)
288 assert 1 == len(forks)
292
289
293 # set none
290 # set none
294 RepoModel().grant_user_permission(
291 RepoModel().grant_user_permission(
295 repo=forks[0], user=user_id, perm='repository.none')
292 repo=forks[0], user=user_id, perm='repository.none')
296 Session().commit()
293 Session().commit()
297
294
298 # fork shouldn't be there
295 # fork shouldn't be there
299 response = self.app.get(
296 response = self.app.get(
300 route_path('repo_forks_data', repo_name=repo_name),
297 route_path('repo_forks_data', repo_name=repo_name),
301 extra_environ=xhr_header)
298 extra_environ=xhr_header)
302
299
303 assert response.json == {u'data': [], u'draw': None,
300 assert response.json == {u'data': [], u'draw': None,
304 u'recordsFiltered': 0, u'recordsTotal': 0}
301 u'recordsFiltered': 0, u'recordsTotal': 0}
305
302
306 @pytest.mark.parametrize('url_type', [
303 @pytest.mark.parametrize('url_type', [
307 'repo_fork_new',
304 'repo_fork_new',
308 'repo_fork_create'
305 'repo_fork_create'
309 ])
306 ])
310 def test_fork_is_forbidden_on_archived_repo(self, backend, xhr_header, user_util, url_type):
307 def test_fork_is_forbidden_on_archived_repo(self, backend, xhr_header, user_util, url_type):
311 user = user_util.create_user(password='qweqwe')
308 user = user_util.create_user(password='qweqwe')
312 self.log_user(user.username, 'qweqwe')
309 self.log_user(user.username, 'qweqwe')
313
310
314 # create a temporary repo
311 # create a temporary repo
315 source = user_util.create_repo(repo_type=backend.alias)
312 source = user_util.create_repo(repo_type=backend.alias)
316 repo_name = source.repo_name
313 repo_name = source.repo_name
317 repo = Repository.get_by_repo_name(repo_name)
314 repo = Repository.get_by_repo_name(repo_name)
318 repo.archived = True
315 repo.archived = True
319 Session().commit()
316 Session().commit()
320
317
321 response = self.app.get(
318 response = self.app.get(
322 route_path(url_type, repo_name=repo_name), status=302)
319 route_path(url_type, repo_name=repo_name), status=302)
323
320
324 msg = 'Action not supported for archived repository.'
321 msg = 'Action not supported for archived repository.'
325 assert_session_flash(response, msg)
322 assert_session_flash(response, msg)
326
323
327
324
328 class TestSVNFork(TestController):
325 class TestSVNFork(TestController):
329 @pytest.mark.parametrize('route_name', [
326 @pytest.mark.parametrize('route_name', [
330 'repo_fork_create', 'repo_fork_new'
327 'repo_fork_create', 'repo_fork_new'
331 ])
328 ])
332 def test_fork_redirects(self, autologin_user, backend_svn, route_name):
329 def test_fork_redirects(self, autologin_user, backend_svn, route_name):
333
330
334 self.app.get(route_path(
331 self.app.get(route_path(
335 route_name, repo_name=backend_svn.repo_name),
332 route_name, repo_name=backend_svn.repo_name),
336 status=404)
333 status=404)
@@ -1,265 +1,266 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import datetime
22 import datetime
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25
25
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28 from pyramid.renderers import render
28 from pyramid.renderers import render
29 from pyramid.response import Response
29 from pyramid.response import Response
30
30
31 from rhodecode import events
31 from rhodecode import events
32 from rhodecode.apps._base import RepoAppView, DataGridAppView
32 from rhodecode.apps._base import RepoAppView, DataGridAppView
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
34 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
35 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
35 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
36 import rhodecode.lib.helpers as h
36 import rhodecode.lib.helpers as h
37 from rhodecode.lib.celerylib.utils import get_task_id
37 from rhodecode.lib.celerylib.utils import get_task_id
38 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
38 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
39 from rhodecode.model.permission import PermissionModel
39 from rhodecode.model.permission import PermissionModel
40 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.forms import RepoForkForm
41 from rhodecode.model.forms import RepoForkForm
42 from rhodecode.model.scm import ScmModel, RepoGroupList
42 from rhodecode.model.scm import ScmModel, RepoGroupList
43 from rhodecode.lib.utils2 import safe_int, safe_unicode
43 from rhodecode.lib.utils2 import safe_int, safe_unicode
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class RepoForksView(RepoAppView, DataGridAppView):
48 class RepoForksView(RepoAppView, DataGridAppView):
49
49
50 def load_default_context(self):
50 def load_default_context(self):
51 c = self._get_local_tmpl_context(include_app_defaults=True)
51 c = self._get_local_tmpl_context(include_app_defaults=True)
52 c.rhodecode_repo = self.rhodecode_vcs_repo
52 c.rhodecode_repo = self.rhodecode_vcs_repo
53
53
54 acl_groups = RepoGroupList(
54 acl_groups = RepoGroupList(
55 RepoGroup.query().all(),
55 RepoGroup.query().all(),
56 perm_set=['group.write', 'group.admin'])
56 perm_set=['group.write', 'group.admin'])
57 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
57 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
58 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
58 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
59
59
60 c.personal_repo_group = c.rhodecode_user.personal_repo_group
60 c.personal_repo_group = c.rhodecode_user.personal_repo_group
61
61
62 return c
62 return c
63
63
64 @LoginRequired()
64 @LoginRequired()
65 @HasRepoPermissionAnyDecorator(
65 @HasRepoPermissionAnyDecorator(
66 'repository.read', 'repository.write', 'repository.admin')
66 'repository.read', 'repository.write', 'repository.admin')
67 @view_config(
67 @view_config(
68 route_name='repo_forks_show_all', request_method='GET',
68 route_name='repo_forks_show_all', request_method='GET',
69 renderer='rhodecode:templates/forks/forks.mako')
69 renderer='rhodecode:templates/forks/forks.mako')
70 def repo_forks_show_all(self):
70 def repo_forks_show_all(self):
71 c = self.load_default_context()
71 c = self.load_default_context()
72 return self._get_template_context(c)
72 return self._get_template_context(c)
73
73
74 @LoginRequired()
74 @LoginRequired()
75 @HasRepoPermissionAnyDecorator(
75 @HasRepoPermissionAnyDecorator(
76 'repository.read', 'repository.write', 'repository.admin')
76 'repository.read', 'repository.write', 'repository.admin')
77 @view_config(
77 @view_config(
78 route_name='repo_forks_data', request_method='GET',
78 route_name='repo_forks_data', request_method='GET',
79 renderer='json_ext', xhr=True)
79 renderer='json_ext', xhr=True)
80 def repo_forks_data(self):
80 def repo_forks_data(self):
81 _ = self.request.translate
81 _ = self.request.translate
82 self.load_default_context()
82 self.load_default_context()
83 column_map = {
83 column_map = {
84 'fork_name': 'repo_name',
84 'fork_name': 'repo_name',
85 'fork_date': 'created_on',
85 'fork_date': 'created_on',
86 'last_activity': 'updated_on'
86 'last_activity': 'updated_on'
87 }
87 }
88 draw, start, limit = self._extract_chunk(self.request)
88 draw, start, limit = self._extract_chunk(self.request)
89 search_q, order_by, order_dir = self._extract_ordering(
89 search_q, order_by, order_dir = self._extract_ordering(
90 self.request, column_map=column_map)
90 self.request, column_map=column_map)
91
91
92 acl_check = HasRepoPermissionAny(
92 acl_check = HasRepoPermissionAny(
93 'repository.read', 'repository.write', 'repository.admin')
93 'repository.read', 'repository.write', 'repository.admin')
94 repo_id = self.db_repo.repo_id
94 repo_id = self.db_repo.repo_id
95 allowed_ids = [-1]
95 allowed_ids = [-1]
96 for f in Repository.query().filter(Repository.fork_id == repo_id):
96 for f in Repository.query().filter(Repository.fork_id == repo_id):
97 if acl_check(f.repo_name, 'get forks check'):
97 if acl_check(f.repo_name, 'get forks check'):
98 allowed_ids.append(f.repo_id)
98 allowed_ids.append(f.repo_id)
99
99
100 forks_data_total_count = Repository.query()\
100 forks_data_total_count = Repository.query()\
101 .filter(Repository.fork_id == repo_id)\
101 .filter(Repository.fork_id == repo_id)\
102 .filter(Repository.repo_id.in_(allowed_ids))\
102 .filter(Repository.repo_id.in_(allowed_ids))\
103 .count()
103 .count()
104
104
105 # json generate
105 # json generate
106 base_q = Repository.query()\
106 base_q = Repository.query()\
107 .filter(Repository.fork_id == repo_id)\
107 .filter(Repository.fork_id == repo_id)\
108 .filter(Repository.repo_id.in_(allowed_ids))\
108 .filter(Repository.repo_id.in_(allowed_ids))\
109
109
110 if search_q:
110 if search_q:
111 like_expression = u'%{}%'.format(safe_unicode(search_q))
111 like_expression = u'%{}%'.format(safe_unicode(search_q))
112 base_q = base_q.filter(or_(
112 base_q = base_q.filter(or_(
113 Repository.repo_name.ilike(like_expression),
113 Repository.repo_name.ilike(like_expression),
114 Repository.description.ilike(like_expression),
114 Repository.description.ilike(like_expression),
115 ))
115 ))
116
116
117 forks_data_total_filtered_count = base_q.count()
117 forks_data_total_filtered_count = base_q.count()
118
118
119 sort_col = getattr(Repository, order_by, None)
119 sort_col = getattr(Repository, order_by, None)
120 if sort_col:
120 if sort_col:
121 if order_dir == 'asc':
121 if order_dir == 'asc':
122 # handle null values properly to order by NULL last
122 # handle null values properly to order by NULL last
123 if order_by in ['last_activity']:
123 if order_by in ['last_activity']:
124 sort_col = coalesce(sort_col, datetime.date.max)
124 sort_col = coalesce(sort_col, datetime.date.max)
125 sort_col = sort_col.asc()
125 sort_col = sort_col.asc()
126 else:
126 else:
127 # handle null values properly to order by NULL last
127 # handle null values properly to order by NULL last
128 if order_by in ['last_activity']:
128 if order_by in ['last_activity']:
129 sort_col = coalesce(sort_col, datetime.date.min)
129 sort_col = coalesce(sort_col, datetime.date.min)
130 sort_col = sort_col.desc()
130 sort_col = sort_col.desc()
131
131
132 base_q = base_q.order_by(sort_col)
132 base_q = base_q.order_by(sort_col)
133 base_q = base_q.offset(start).limit(limit)
133 base_q = base_q.offset(start).limit(limit)
134
134
135 fork_list = base_q.all()
135 fork_list = base_q.all()
136
136
137 def fork_actions(fork):
137 def fork_actions(fork):
138 url_link = h.route_path(
138 url_link = h.route_path(
139 'repo_compare',
139 'repo_compare',
140 repo_name=fork.repo_name,
140 repo_name=fork.repo_name,
141 source_ref_type=self.db_repo.landing_rev[0],
141 source_ref_type=self.db_repo.landing_rev[0],
142 source_ref=self.db_repo.landing_rev[1],
142 source_ref=self.db_repo.landing_rev[1],
143 target_ref_type=self.db_repo.landing_rev[0],
143 target_ref_type=self.db_repo.landing_rev[0],
144 target_ref=self.db_repo.landing_rev[1],
144 target_ref=self.db_repo.landing_rev[1],
145 _query=dict(merge=1, target_repo=f.repo_name))
145 _query=dict(merge=1, target_repo=f.repo_name))
146 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
146 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
147
147
148 def fork_name(fork):
148 def fork_name(fork):
149 return h.link_to(fork.repo_name,
149 return h.link_to(fork.repo_name,
150 h.route_path('repo_summary', repo_name=fork.repo_name))
150 h.route_path('repo_summary', repo_name=fork.repo_name))
151
151
152 forks_data = []
152 forks_data = []
153 for fork in fork_list:
153 for fork in fork_list:
154 forks_data.append({
154 forks_data.append({
155 "username": h.gravatar_with_user(self.request, fork.user.username),
155 "username": h.gravatar_with_user(self.request, fork.user.username),
156 "fork_name": fork_name(fork),
156 "fork_name": fork_name(fork),
157 "description": fork.description_safe,
157 "description": fork.description_safe,
158 "fork_date": h.age_component(fork.created_on, time_is_local=True),
158 "fork_date": h.age_component(fork.created_on, time_is_local=True),
159 "last_activity": h.format_date(fork.updated_on),
159 "last_activity": h.format_date(fork.updated_on),
160 "action": fork_actions(fork),
160 "action": fork_actions(fork),
161 })
161 })
162
162
163 data = ({
163 data = ({
164 'draw': draw,
164 'draw': draw,
165 'data': forks_data,
165 'data': forks_data,
166 'recordsTotal': forks_data_total_count,
166 'recordsTotal': forks_data_total_count,
167 'recordsFiltered': forks_data_total_filtered_count,
167 'recordsFiltered': forks_data_total_filtered_count,
168 })
168 })
169
169
170 return data
170 return data
171
171
172 @LoginRequired()
172 @LoginRequired()
173 @NotAnonymous()
173 @NotAnonymous()
174 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
174 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
175 @HasRepoPermissionAnyDecorator(
175 @HasRepoPermissionAnyDecorator(
176 'repository.read', 'repository.write', 'repository.admin')
176 'repository.read', 'repository.write', 'repository.admin')
177 @view_config(
177 @view_config(
178 route_name='repo_fork_new', request_method='GET',
178 route_name='repo_fork_new', request_method='GET',
179 renderer='rhodecode:templates/forks/forks.mako')
179 renderer='rhodecode:templates/forks/forks.mako')
180 def repo_fork_new(self):
180 def repo_fork_new(self):
181 c = self.load_default_context()
181 c = self.load_default_context()
182
182
183 defaults = RepoModel()._get_defaults(self.db_repo_name)
183 defaults = RepoModel()._get_defaults(self.db_repo_name)
184 # alter the description to indicate a fork
184 # alter the description to indicate a fork
185 defaults['description'] = (
185 defaults['description'] = (
186 'fork of repository: %s \n%s' % (
186 'fork of repository: %s \n%s' % (
187 defaults['repo_name'], defaults['description']))
187 defaults['repo_name'], defaults['description']))
188 # add suffix to fork
188 # add suffix to fork
189 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
189 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
190
190
191 data = render('rhodecode:templates/forks/fork.mako',
191 data = render('rhodecode:templates/forks/fork.mako',
192 self._get_template_context(c), self.request)
192 self._get_template_context(c), self.request)
193 html = formencode.htmlfill.render(
193 html = formencode.htmlfill.render(
194 data,
194 data,
195 defaults=defaults,
195 defaults=defaults,
196 encoding="UTF-8",
196 encoding="UTF-8",
197 force_defaults=False
197 force_defaults=False
198 )
198 )
199 return Response(html)
199 return Response(html)
200
200
201 @LoginRequired()
201 @LoginRequired()
202 @NotAnonymous()
202 @NotAnonymous()
203 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
203 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
204 @HasRepoPermissionAnyDecorator(
204 @HasRepoPermissionAnyDecorator(
205 'repository.read', 'repository.write', 'repository.admin')
205 'repository.read', 'repository.write', 'repository.admin')
206 @CSRFRequired()
206 @CSRFRequired()
207 @view_config(
207 @view_config(
208 route_name='repo_fork_create', request_method='POST',
208 route_name='repo_fork_create', request_method='POST',
209 renderer='rhodecode:templates/forks/fork.mako')
209 renderer='rhodecode:templates/forks/fork.mako')
210 def repo_fork_create(self):
210 def repo_fork_create(self):
211 _ = self.request.translate
211 _ = self.request.translate
212 c = self.load_default_context()
212 c = self.load_default_context()
213
213
214 _form = RepoForkForm(self.request.translate,
214 _form = RepoForkForm(self.request.translate,
215 old_data={'repo_type': self.db_repo.repo_type},
215 old_data={'repo_type': self.db_repo.repo_type},
216 repo_groups=c.repo_groups_choices)()
216 repo_groups=c.repo_groups_choices)()
217 post_data = dict(self.request.POST)
217 post_data = dict(self.request.POST)
218
218
219 # forbid injecting other repo by forging a request
219 # forbid injecting other repo by forging a request
220 post_data['fork_parent_id'] = self.db_repo.repo_id
220 post_data['fork_parent_id'] = self.db_repo.repo_id
221 post_data['landing_rev'] = self.db_repo._landing_revision
221
222
222 form_result = {}
223 form_result = {}
223 task_id = None
224 task_id = None
224 try:
225 try:
225 form_result = _form.to_python(post_data)
226 form_result = _form.to_python(post_data)
226 copy_permissions = form_result.get('copy_permissions')
227 copy_permissions = form_result.get('copy_permissions')
227 # create fork is done sometimes async on celery, db transaction
228 # create fork is done sometimes async on celery, db transaction
228 # management is handled there.
229 # management is handled there.
229 task = RepoModel().create_fork(
230 task = RepoModel().create_fork(
230 form_result, c.rhodecode_user.user_id)
231 form_result, c.rhodecode_user.user_id)
231
232
232 task_id = get_task_id(task)
233 task_id = get_task_id(task)
233 except formencode.Invalid as errors:
234 except formencode.Invalid as errors:
234 c.rhodecode_db_repo = self.db_repo
235 c.rhodecode_db_repo = self.db_repo
235
236
236 data = render('rhodecode:templates/forks/fork.mako',
237 data = render('rhodecode:templates/forks/fork.mako',
237 self._get_template_context(c), self.request)
238 self._get_template_context(c), self.request)
238 html = formencode.htmlfill.render(
239 html = formencode.htmlfill.render(
239 data,
240 data,
240 defaults=errors.value,
241 defaults=errors.value,
241 errors=errors.error_dict or {},
242 errors=errors.error_dict or {},
242 prefix_error=False,
243 prefix_error=False,
243 encoding="UTF-8",
244 encoding="UTF-8",
244 force_defaults=False
245 force_defaults=False
245 )
246 )
246 return Response(html)
247 return Response(html)
247 except Exception:
248 except Exception:
248 log.exception(
249 log.exception(
249 u'Exception while trying to fork the repository %s', self.db_repo_name)
250 u'Exception while trying to fork the repository %s', self.db_repo_name)
250 msg = _('An error occurred during repository forking %s') % (self.db_repo_name, )
251 msg = _('An error occurred during repository forking %s') % (self.db_repo_name, )
251 h.flash(msg, category='error')
252 h.flash(msg, category='error')
252 raise HTTPFound(h.route_path('home'))
253 raise HTTPFound(h.route_path('home'))
253
254
254 repo_name = form_result.get('repo_name_full', self.db_repo_name)
255 repo_name = form_result.get('repo_name_full', self.db_repo_name)
255
256
256 affected_user_ids = [self._rhodecode_user.user_id]
257 affected_user_ids = [self._rhodecode_user.user_id]
257 if copy_permissions:
258 if copy_permissions:
258 # permission flush is done in repo creating
259 # permission flush is done in repo creating
259 pass
260 pass
260
261
261 PermissionModel().trigger_permission_flush(affected_user_ids)
262 PermissionModel().trigger_permission_flush(affected_user_ids)
262
263
263 raise HTTPFound(
264 raise HTTPFound(
264 h.route_path('repo_creating', repo_name=repo_name,
265 h.route_path('repo_creating', repo_name=repo_name,
265 _query=dict(task_id=task_id)))
266 _query=dict(task_id=task_id)))
@@ -1,343 +1,343 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2019 RhodeCode GmbH
3 # Copyright (C) 2012-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 RhodeCode task modules, containing all task that suppose to be run
22 RhodeCode task modules, containing all task that suppose to be run
23 by celery daemon
23 by celery daemon
24 """
24 """
25
25
26 import os
26 import os
27 import time
27 import time
28
28
29 from pyramid import compat
29 from pyramid import compat
30 from pyramid_mailer.mailer import Mailer
30 from pyramid_mailer.mailer import Mailer
31 from pyramid_mailer.message import Message
31 from pyramid_mailer.message import Message
32
32
33 import rhodecode
33 import rhodecode
34 from rhodecode.lib import audit_logger
34 from rhodecode.lib import audit_logger
35 from rhodecode.lib.celerylib import get_logger, async_task, RequestContextTask
35 from rhodecode.lib.celerylib import get_logger, async_task, RequestContextTask
36 from rhodecode.lib.hooks_base import log_create_repository
36 from rhodecode.lib.hooks_base import log_create_repository
37 from rhodecode.lib.utils2 import safe_int, str2bool
37 from rhodecode.lib.utils2 import safe_int, str2bool
38 from rhodecode.model.db import Session, IntegrityError, Repository, User, true
38 from rhodecode.model.db import Session, IntegrityError, Repository, User, true
39
39
40
40
41 @async_task(ignore_result=True, base=RequestContextTask)
41 @async_task(ignore_result=True, base=RequestContextTask)
42 def send_email(recipients, subject, body='', html_body='', email_config=None):
42 def send_email(recipients, subject, body='', html_body='', email_config=None):
43 """
43 """
44 Sends an email with defined parameters from the .ini files.
44 Sends an email with defined parameters from the .ini files.
45
45
46 :param recipients: list of recipients, it this is empty the defined email
46 :param recipients: list of recipients, it this is empty the defined email
47 address from field 'email_to' is used instead
47 address from field 'email_to' is used instead
48 :param subject: subject of the mail
48 :param subject: subject of the mail
49 :param body: body of the mail
49 :param body: body of the mail
50 :param html_body: html version of body
50 :param html_body: html version of body
51 """
51 """
52 log = get_logger(send_email)
52 log = get_logger(send_email)
53
53
54 email_config = email_config or rhodecode.CONFIG
54 email_config = email_config or rhodecode.CONFIG
55
55
56 mail_server = email_config.get('smtp_server') or None
56 mail_server = email_config.get('smtp_server') or None
57 if mail_server is None:
57 if mail_server is None:
58 log.error("SMTP server information missing. Sending email failed. "
58 log.error("SMTP server information missing. Sending email failed. "
59 "Make sure that `smtp_server` variable is configured "
59 "Make sure that `smtp_server` variable is configured "
60 "inside the .ini file")
60 "inside the .ini file")
61 return False
61 return False
62
62
63 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
63 subject = "%s %s" % (email_config.get('email_prefix', ''), subject)
64
64
65 if recipients:
65 if recipients:
66 if isinstance(recipients, compat.string_types):
66 if isinstance(recipients, compat.string_types):
67 recipients = recipients.split(',')
67 recipients = recipients.split(',')
68 else:
68 else:
69 # if recipients are not defined we send to email_config + all admins
69 # if recipients are not defined we send to email_config + all admins
70 admins = []
70 admins = []
71 for u in User.query().filter(User.admin == true()).all():
71 for u in User.query().filter(User.admin == true()).all():
72 if u.email:
72 if u.email:
73 admins.append(u.email)
73 admins.append(u.email)
74 recipients = []
74 recipients = []
75 config_email = email_config.get('email_to')
75 config_email = email_config.get('email_to')
76 if config_email:
76 if config_email:
77 recipients += [config_email]
77 recipients += [config_email]
78 recipients += admins
78 recipients += admins
79
79
80 # translate our LEGACY config into the one that pyramid_mailer supports
80 # translate our LEGACY config into the one that pyramid_mailer supports
81 email_conf = dict(
81 email_conf = dict(
82 host=mail_server,
82 host=mail_server,
83 port=email_config.get('smtp_port', 25),
83 port=email_config.get('smtp_port', 25),
84 username=email_config.get('smtp_username'),
84 username=email_config.get('smtp_username'),
85 password=email_config.get('smtp_password'),
85 password=email_config.get('smtp_password'),
86
86
87 tls=str2bool(email_config.get('smtp_use_tls')),
87 tls=str2bool(email_config.get('smtp_use_tls')),
88 ssl=str2bool(email_config.get('smtp_use_ssl')),
88 ssl=str2bool(email_config.get('smtp_use_ssl')),
89
89
90 # SSL key file
90 # SSL key file
91 # keyfile='',
91 # keyfile='',
92
92
93 # SSL certificate file
93 # SSL certificate file
94 # certfile='',
94 # certfile='',
95
95
96 # Location of maildir
96 # Location of maildir
97 # queue_path='',
97 # queue_path='',
98
98
99 default_sender=email_config.get('app_email_from', 'RhodeCode'),
99 default_sender=email_config.get('app_email_from', 'RhodeCode'),
100
100
101 debug=str2bool(email_config.get('smtp_debug')),
101 debug=str2bool(email_config.get('smtp_debug')),
102 # /usr/sbin/sendmail Sendmail executable
102 # /usr/sbin/sendmail Sendmail executable
103 # sendmail_app='',
103 # sendmail_app='',
104
104
105 # {sendmail_app} -t -i -f {sender} Template for sendmail execution
105 # {sendmail_app} -t -i -f {sender} Template for sendmail execution
106 # sendmail_template='',
106 # sendmail_template='',
107 )
107 )
108
108
109 try:
109 try:
110 mailer = Mailer(**email_conf)
110 mailer = Mailer(**email_conf)
111
111
112 message = Message(subject=subject,
112 message = Message(subject=subject,
113 sender=email_conf['default_sender'],
113 sender=email_conf['default_sender'],
114 recipients=recipients,
114 recipients=recipients,
115 body=body, html=html_body)
115 body=body, html=html_body)
116 mailer.send_immediately(message)
116 mailer.send_immediately(message)
117
117
118 except Exception:
118 except Exception:
119 log.exception('Mail sending failed')
119 log.exception('Mail sending failed')
120 return False
120 return False
121 return True
121 return True
122
122
123
123
124 @async_task(ignore_result=True, base=RequestContextTask)
124 @async_task(ignore_result=True, base=RequestContextTask)
125 def create_repo(form_data, cur_user):
125 def create_repo(form_data, cur_user):
126 from rhodecode.model.repo import RepoModel
126 from rhodecode.model.repo import RepoModel
127 from rhodecode.model.user import UserModel
127 from rhodecode.model.user import UserModel
128 from rhodecode.model.scm import ScmModel
128 from rhodecode.model.scm import ScmModel
129 from rhodecode.model.settings import SettingsModel
129 from rhodecode.model.settings import SettingsModel
130
130
131 log = get_logger(create_repo)
131 log = get_logger(create_repo)
132
132
133 cur_user = UserModel()._get_user(cur_user)
133 cur_user = UserModel()._get_user(cur_user)
134 owner = cur_user
134 owner = cur_user
135
135
136 repo_name = form_data['repo_name']
136 repo_name = form_data['repo_name']
137 repo_name_full = form_data['repo_name_full']
137 repo_name_full = form_data['repo_name_full']
138 repo_type = form_data['repo_type']
138 repo_type = form_data['repo_type']
139 description = form_data['repo_description']
139 description = form_data['repo_description']
140 private = form_data['repo_private']
140 private = form_data['repo_private']
141 clone_uri = form_data.get('clone_uri')
141 clone_uri = form_data.get('clone_uri')
142 repo_group = safe_int(form_data['repo_group'])
142 repo_group = safe_int(form_data['repo_group'])
143 copy_fork_permissions = form_data.get('copy_permissions')
143 copy_fork_permissions = form_data.get('copy_permissions')
144 copy_group_permissions = form_data.get('repo_copy_permissions')
144 copy_group_permissions = form_data.get('repo_copy_permissions')
145 fork_of = form_data.get('fork_parent_id')
145 fork_of = form_data.get('fork_parent_id')
146 state = form_data.get('repo_state', Repository.STATE_PENDING)
146 state = form_data.get('repo_state', Repository.STATE_PENDING)
147
147
148 # repo creation defaults, private and repo_type are filled in form
148 # repo creation defaults, private and repo_type are filled in form
149 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
149 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
150 enable_statistics = form_data.get(
150 enable_statistics = form_data.get(
151 'enable_statistics', defs.get('repo_enable_statistics'))
151 'enable_statistics', defs.get('repo_enable_statistics'))
152 enable_locking = form_data.get(
152 enable_locking = form_data.get(
153 'enable_locking', defs.get('repo_enable_locking'))
153 'enable_locking', defs.get('repo_enable_locking'))
154 enable_downloads = form_data.get(
154 enable_downloads = form_data.get(
155 'enable_downloads', defs.get('repo_enable_downloads'))
155 'enable_downloads', defs.get('repo_enable_downloads'))
156
156
157 # set landing rev based on default branches for SCM
157 # set landing rev based on default branches for SCM
158 landing_ref, _label = ScmModel.backend_landing_ref(repo_type)
158 landing_ref, _label = ScmModel.backend_landing_ref(repo_type)
159
159
160 try:
160 try:
161 RepoModel()._create_repo(
161 RepoModel()._create_repo(
162 repo_name=repo_name_full,
162 repo_name=repo_name_full,
163 repo_type=repo_type,
163 repo_type=repo_type,
164 description=description,
164 description=description,
165 owner=owner,
165 owner=owner,
166 private=private,
166 private=private,
167 clone_uri=clone_uri,
167 clone_uri=clone_uri,
168 repo_group=repo_group,
168 repo_group=repo_group,
169 landing_rev=landing_ref,
169 landing_rev=landing_ref,
170 fork_of=fork_of,
170 fork_of=fork_of,
171 copy_fork_permissions=copy_fork_permissions,
171 copy_fork_permissions=copy_fork_permissions,
172 copy_group_permissions=copy_group_permissions,
172 copy_group_permissions=copy_group_permissions,
173 enable_statistics=enable_statistics,
173 enable_statistics=enable_statistics,
174 enable_locking=enable_locking,
174 enable_locking=enable_locking,
175 enable_downloads=enable_downloads,
175 enable_downloads=enable_downloads,
176 state=state
176 state=state
177 )
177 )
178 Session().commit()
178 Session().commit()
179
179
180 # now create this repo on Filesystem
180 # now create this repo on Filesystem
181 RepoModel()._create_filesystem_repo(
181 RepoModel()._create_filesystem_repo(
182 repo_name=repo_name,
182 repo_name=repo_name,
183 repo_type=repo_type,
183 repo_type=repo_type,
184 repo_group=RepoModel()._get_repo_group(repo_group),
184 repo_group=RepoModel()._get_repo_group(repo_group),
185 clone_uri=clone_uri,
185 clone_uri=clone_uri,
186 )
186 )
187 repo = Repository.get_by_repo_name(repo_name_full)
187 repo = Repository.get_by_repo_name(repo_name_full)
188 log_create_repository(created_by=owner.username, **repo.get_dict())
188 log_create_repository(created_by=owner.username, **repo.get_dict())
189
189
190 # update repo commit caches initially
190 # update repo commit caches initially
191 repo.update_commit_cache()
191 repo.update_commit_cache()
192
192
193 # set new created state
193 # set new created state
194 repo.set_state(Repository.STATE_CREATED)
194 repo.set_state(Repository.STATE_CREATED)
195 repo_id = repo.repo_id
195 repo_id = repo.repo_id
196 repo_data = repo.get_api_data()
196 repo_data = repo.get_api_data()
197
197
198 audit_logger.store(
198 audit_logger.store(
199 'repo.create', action_data={'data': repo_data},
199 'repo.create', action_data={'data': repo_data},
200 user=cur_user,
200 user=cur_user,
201 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
201 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
202
202
203 Session().commit()
203 Session().commit()
204 except Exception as e:
204 except Exception as e:
205 log.warning('Exception occurred when creating repository, '
205 log.warning('Exception occurred when creating repository, '
206 'doing cleanup...', exc_info=True)
206 'doing cleanup...', exc_info=True)
207 if isinstance(e, IntegrityError):
207 if isinstance(e, IntegrityError):
208 Session().rollback()
208 Session().rollback()
209
209
210 # rollback things manually !
210 # rollback things manually !
211 repo = Repository.get_by_repo_name(repo_name_full)
211 repo = Repository.get_by_repo_name(repo_name_full)
212 if repo:
212 if repo:
213 Repository.delete(repo.repo_id)
213 Repository.delete(repo.repo_id)
214 Session().commit()
214 Session().commit()
215 RepoModel()._delete_filesystem_repo(repo)
215 RepoModel()._delete_filesystem_repo(repo)
216 log.info('Cleanup of repo %s finished', repo_name_full)
216 log.info('Cleanup of repo %s finished', repo_name_full)
217 raise
217 raise
218
218
219 return True
219 return True
220
220
221
221
222 @async_task(ignore_result=True, base=RequestContextTask)
222 @async_task(ignore_result=True, base=RequestContextTask)
223 def create_repo_fork(form_data, cur_user):
223 def create_repo_fork(form_data, cur_user):
224 """
224 """
225 Creates a fork of repository using internal VCS methods
225 Creates a fork of repository using internal VCS methods
226 """
226 """
227 from rhodecode.model.repo import RepoModel
227 from rhodecode.model.repo import RepoModel
228 from rhodecode.model.user import UserModel
228 from rhodecode.model.user import UserModel
229
229
230 log = get_logger(create_repo_fork)
230 log = get_logger(create_repo_fork)
231
231
232 cur_user = UserModel()._get_user(cur_user)
232 cur_user = UserModel()._get_user(cur_user)
233 owner = cur_user
233 owner = cur_user
234
234
235 repo_name = form_data['repo_name'] # fork in this case
235 repo_name = form_data['repo_name'] # fork in this case
236 repo_name_full = form_data['repo_name_full']
236 repo_name_full = form_data['repo_name_full']
237 repo_type = form_data['repo_type']
237 repo_type = form_data['repo_type']
238 description = form_data['description']
238 description = form_data['description']
239 private = form_data['private']
239 private = form_data['private']
240 clone_uri = form_data.get('clone_uri')
240 clone_uri = form_data.get('clone_uri')
241 repo_group = safe_int(form_data['repo_group'])
241 repo_group = safe_int(form_data['repo_group'])
242 landing_rev = form_data['landing_rev']
242 landing_ref = form_data['landing_rev']
243 copy_fork_permissions = form_data.get('copy_permissions')
243 copy_fork_permissions = form_data.get('copy_permissions')
244 fork_id = safe_int(form_data.get('fork_parent_id'))
244 fork_id = safe_int(form_data.get('fork_parent_id'))
245
245
246 try:
246 try:
247 fork_of = RepoModel()._get_repo(fork_id)
247 fork_of = RepoModel()._get_repo(fork_id)
248 RepoModel()._create_repo(
248 RepoModel()._create_repo(
249 repo_name=repo_name_full,
249 repo_name=repo_name_full,
250 repo_type=repo_type,
250 repo_type=repo_type,
251 description=description,
251 description=description,
252 owner=owner,
252 owner=owner,
253 private=private,
253 private=private,
254 clone_uri=clone_uri,
254 clone_uri=clone_uri,
255 repo_group=repo_group,
255 repo_group=repo_group,
256 landing_rev=landing_rev,
256 landing_rev=landing_ref,
257 fork_of=fork_of,
257 fork_of=fork_of,
258 copy_fork_permissions=copy_fork_permissions
258 copy_fork_permissions=copy_fork_permissions
259 )
259 )
260
260
261 Session().commit()
261 Session().commit()
262
262
263 base_path = Repository.base_path()
263 base_path = Repository.base_path()
264 source_repo_path = os.path.join(base_path, fork_of.repo_name)
264 source_repo_path = os.path.join(base_path, fork_of.repo_name)
265
265
266 # now create this repo on Filesystem
266 # now create this repo on Filesystem
267 RepoModel()._create_filesystem_repo(
267 RepoModel()._create_filesystem_repo(
268 repo_name=repo_name,
268 repo_name=repo_name,
269 repo_type=repo_type,
269 repo_type=repo_type,
270 repo_group=RepoModel()._get_repo_group(repo_group),
270 repo_group=RepoModel()._get_repo_group(repo_group),
271 clone_uri=source_repo_path,
271 clone_uri=source_repo_path,
272 )
272 )
273 repo = Repository.get_by_repo_name(repo_name_full)
273 repo = Repository.get_by_repo_name(repo_name_full)
274 log_create_repository(created_by=owner.username, **repo.get_dict())
274 log_create_repository(created_by=owner.username, **repo.get_dict())
275
275
276 # update repo commit caches initially
276 # update repo commit caches initially
277 config = repo._config
277 config = repo._config
278 config.set('extensions', 'largefiles', '')
278 config.set('extensions', 'largefiles', '')
279 repo.update_commit_cache(config=config)
279 repo.update_commit_cache(config=config)
280
280
281 # set new created state
281 # set new created state
282 repo.set_state(Repository.STATE_CREATED)
282 repo.set_state(Repository.STATE_CREATED)
283
283
284 repo_id = repo.repo_id
284 repo_id = repo.repo_id
285 repo_data = repo.get_api_data()
285 repo_data = repo.get_api_data()
286 audit_logger.store(
286 audit_logger.store(
287 'repo.fork', action_data={'data': repo_data},
287 'repo.fork', action_data={'data': repo_data},
288 user=cur_user,
288 user=cur_user,
289 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
289 repo=audit_logger.RepoWrap(repo_name=repo_name, repo_id=repo_id))
290
290
291 Session().commit()
291 Session().commit()
292 except Exception as e:
292 except Exception as e:
293 log.warning('Exception occurred when forking repository, '
293 log.warning('Exception occurred when forking repository, '
294 'doing cleanup...', exc_info=True)
294 'doing cleanup...', exc_info=True)
295 if isinstance(e, IntegrityError):
295 if isinstance(e, IntegrityError):
296 Session().rollback()
296 Session().rollback()
297
297
298 # rollback things manually !
298 # rollback things manually !
299 repo = Repository.get_by_repo_name(repo_name_full)
299 repo = Repository.get_by_repo_name(repo_name_full)
300 if repo:
300 if repo:
301 Repository.delete(repo.repo_id)
301 Repository.delete(repo.repo_id)
302 Session().commit()
302 Session().commit()
303 RepoModel()._delete_filesystem_repo(repo)
303 RepoModel()._delete_filesystem_repo(repo)
304 log.info('Cleanup of repo %s finished', repo_name_full)
304 log.info('Cleanup of repo %s finished', repo_name_full)
305 raise
305 raise
306
306
307 return True
307 return True
308
308
309
309
310 @async_task(ignore_result=True)
310 @async_task(ignore_result=True)
311 def repo_maintenance(repoid):
311 def repo_maintenance(repoid):
312 from rhodecode.lib import repo_maintenance as repo_maintenance_lib
312 from rhodecode.lib import repo_maintenance as repo_maintenance_lib
313 log = get_logger(repo_maintenance)
313 log = get_logger(repo_maintenance)
314 repo = Repository.get_by_id_or_repo_name(repoid)
314 repo = Repository.get_by_id_or_repo_name(repoid)
315 if repo:
315 if repo:
316 maintenance = repo_maintenance_lib.RepoMaintenance()
316 maintenance = repo_maintenance_lib.RepoMaintenance()
317 tasks = maintenance.get_tasks_for_repo(repo)
317 tasks = maintenance.get_tasks_for_repo(repo)
318 log.debug('Executing %s tasks on repo `%s`', tasks, repoid)
318 log.debug('Executing %s tasks on repo `%s`', tasks, repoid)
319 executed_types = maintenance.execute(repo)
319 executed_types = maintenance.execute(repo)
320 log.debug('Got execution results %s', executed_types)
320 log.debug('Got execution results %s', executed_types)
321 else:
321 else:
322 log.debug('Repo `%s` not found or without a clone_url', repoid)
322 log.debug('Repo `%s` not found or without a clone_url', repoid)
323
323
324
324
325 @async_task(ignore_result=True)
325 @async_task(ignore_result=True)
326 def check_for_update():
326 def check_for_update():
327 from rhodecode.model.update import UpdateModel
327 from rhodecode.model.update import UpdateModel
328 update_url = UpdateModel().get_update_url()
328 update_url = UpdateModel().get_update_url()
329 cur_ver = rhodecode.__version__
329 cur_ver = rhodecode.__version__
330
330
331 try:
331 try:
332 data = UpdateModel().get_update_data(update_url)
332 data = UpdateModel().get_update_data(update_url)
333 latest = data['versions'][0]
333 latest = data['versions'][0]
334 UpdateModel().store_version(latest['version'])
334 UpdateModel().store_version(latest['version'])
335 except Exception:
335 except Exception:
336 pass
336 pass
337
337
338
338
339 @async_task(ignore_result=False)
339 @async_task(ignore_result=False)
340 def beat_check(*args, **kwargs):
340 def beat_check(*args, **kwargs):
341 log = get_logger(beat_check)
341 log = get_logger(beat_check)
342 log.info('Got args: %r and kwargs %r', args, kwargs)
342 log.info('Got args: %r and kwargs %r', args, kwargs)
343 return time.time()
343 return time.time()
General Comments 0
You need to be logged in to leave comments. Login now