##// END OF EJS Templates
repo-forks: security, fix issue when forging fork_repo_id could allow reading...
marcink -
r2172:f94ee74b default
parent child Browse files
Show More
@@ -1,181 +1,182 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 formencode
22 import formencode
23 import formencode.htmlfill
23 import formencode.htmlfill
24
24
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27 from pyramid.renderers import render
27 from pyramid.renderers import render
28 from pyramid.response import Response
28 from pyramid.response import Response
29
29
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
31
31
32 from rhodecode.lib.ext_json import json
32 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 LoginRequired, CSRFRequired, NotAnonymous,
34 LoginRequired, CSRFRequired, NotAnonymous,
35 HasPermissionAny, HasRepoGroupPermissionAny)
35 HasPermissionAny, HasRepoGroupPermissionAny)
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37 from rhodecode.lib.utils import repo_name_slug
37 from rhodecode.lib.utils import repo_name_slug
38 from rhodecode.lib.utils2 import safe_int, safe_unicode
38 from rhodecode.lib.utils2 import safe_int, safe_unicode
39 from rhodecode.model.forms import RepoForm
39 from rhodecode.model.forms import RepoForm
40 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel
41 from rhodecode.model.scm import RepoList, RepoGroupList, ScmModel
42 from rhodecode.model.settings import SettingsModel
42 from rhodecode.model.settings import SettingsModel
43 from rhodecode.model.db import Repository, RepoGroup
43 from rhodecode.model.db import Repository, RepoGroup
44
44
45 log = logging.getLogger(__name__)
45 log = logging.getLogger(__name__)
46
46
47
47
48 class AdminReposView(BaseAppView, DataGridAppView):
48 class AdminReposView(BaseAppView, DataGridAppView):
49
49
50 def load_default_context(self):
50 def load_default_context(self):
51 c = self._get_local_tmpl_context()
51 c = self._get_local_tmpl_context()
52 self._register_global_c(c)
52 self._register_global_c(c)
53 return c
53 return c
54
54
55 def _load_form_data(self, c):
55 def _load_form_data(self, c):
56 acl_groups = RepoGroupList(RepoGroup.query().all(),
56 acl_groups = RepoGroupList(RepoGroup.query().all(),
57 perm_set=['group.write', 'group.admin'])
57 perm_set=['group.write', 'group.admin'])
58 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
58 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
59 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
59 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
60 c.landing_revs_choices, c.landing_revs = \
60 c.landing_revs_choices, c.landing_revs = \
61 ScmModel().get_repo_landing_revs()
61 ScmModel().get_repo_landing_revs()
62 c.personal_repo_group = self._rhodecode_user.personal_repo_group
62 c.personal_repo_group = self._rhodecode_user.personal_repo_group
63
63
64 @LoginRequired()
64 @LoginRequired()
65 @NotAnonymous()
65 @NotAnonymous()
66 # perms check inside
66 @view_config(
67 @view_config(
67 route_name='repos', request_method='GET',
68 route_name='repos', request_method='GET',
68 renderer='rhodecode:templates/admin/repos/repos.mako')
69 renderer='rhodecode:templates/admin/repos/repos.mako')
69 def repository_list(self):
70 def repository_list(self):
70 c = self.load_default_context()
71 c = self.load_default_context()
71
72
72 repo_list = Repository.get_all_repos()
73 repo_list = Repository.get_all_repos()
73 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
74 c.repo_list = RepoList(repo_list, perm_set=['repository.admin'])
74 repos_data = RepoModel().get_repos_as_dict(
75 repos_data = RepoModel().get_repos_as_dict(
75 repo_list=c.repo_list, admin=True, super_user_actions=True)
76 repo_list=c.repo_list, admin=True, super_user_actions=True)
76 # json used to render the grid
77 # json used to render the grid
77 c.data = json.dumps(repos_data)
78 c.data = json.dumps(repos_data)
78
79
79 return self._get_template_context(c)
80 return self._get_template_context(c)
80
81
81 @LoginRequired()
82 @LoginRequired()
82 @NotAnonymous()
83 @NotAnonymous()
83 # perms check inside
84 # perms check inside
84 @view_config(
85 @view_config(
85 route_name='repo_new', request_method='GET',
86 route_name='repo_new', request_method='GET',
86 renderer='rhodecode:templates/admin/repos/repo_add.mako')
87 renderer='rhodecode:templates/admin/repos/repo_add.mako')
87 def repository_new(self):
88 def repository_new(self):
88 c = self.load_default_context()
89 c = self.load_default_context()
89
90
90 new_repo = self.request.GET.get('repo', '')
91 new_repo = self.request.GET.get('repo', '')
91 parent_group = safe_int(self.request.GET.get('parent_group'))
92 parent_group = safe_int(self.request.GET.get('parent_group'))
92 _gr = RepoGroup.get(parent_group)
93 _gr = RepoGroup.get(parent_group)
93
94
94 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
95 if not HasPermissionAny('hg.admin', 'hg.create.repository')():
95 # you're not super admin nor have global create permissions,
96 # you're not super admin nor have global create permissions,
96 # but maybe you have at least write permission to a parent group ?
97 # but maybe you have at least write permission to a parent group ?
97
98
98 gr_name = _gr.group_name if _gr else None
99 gr_name = _gr.group_name if _gr else None
99 # create repositories with write permission on group is set to true
100 # create repositories with write permission on group is set to true
100 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
101 create_on_write = HasPermissionAny('hg.create.write_on_repogroup.true')()
101 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
102 group_admin = HasRepoGroupPermissionAny('group.admin')(group_name=gr_name)
102 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
103 group_write = HasRepoGroupPermissionAny('group.write')(group_name=gr_name)
103 if not (group_admin or (group_write and create_on_write)):
104 if not (group_admin or (group_write and create_on_write)):
104 raise HTTPForbidden()
105 raise HTTPForbidden()
105
106
106 self._load_form_data(c)
107 self._load_form_data(c)
107 c.new_repo = repo_name_slug(new_repo)
108 c.new_repo = repo_name_slug(new_repo)
108
109
109 # apply the defaults from defaults page
110 # apply the defaults from defaults page
110 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
111 defaults = SettingsModel().get_default_repo_settings(strip_prefix=True)
111 # set checkbox to autochecked
112 # set checkbox to autochecked
112 defaults['repo_copy_permissions'] = True
113 defaults['repo_copy_permissions'] = True
113
114
114 parent_group_choice = '-1'
115 parent_group_choice = '-1'
115 if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group:
116 if not self._rhodecode_user.is_admin and self._rhodecode_user.personal_repo_group:
116 parent_group_choice = self._rhodecode_user.personal_repo_group
117 parent_group_choice = self._rhodecode_user.personal_repo_group
117
118
118 if parent_group and _gr:
119 if parent_group and _gr:
119 if parent_group in [x[0] for x in c.repo_groups]:
120 if parent_group in [x[0] for x in c.repo_groups]:
120 parent_group_choice = safe_unicode(parent_group)
121 parent_group_choice = safe_unicode(parent_group)
121
122
122 defaults.update({'repo_group': parent_group_choice})
123 defaults.update({'repo_group': parent_group_choice})
123
124
124 data = render('rhodecode:templates/admin/repos/repo_add.mako',
125 data = render('rhodecode:templates/admin/repos/repo_add.mako',
125 self._get_template_context(c), self.request)
126 self._get_template_context(c), self.request)
126 html = formencode.htmlfill.render(
127 html = formencode.htmlfill.render(
127 data,
128 data,
128 defaults=defaults,
129 defaults=defaults,
129 encoding="UTF-8",
130 encoding="UTF-8",
130 force_defaults=False
131 force_defaults=False
131 )
132 )
132 return Response(html)
133 return Response(html)
133
134
134 @LoginRequired()
135 @LoginRequired()
135 @NotAnonymous()
136 @NotAnonymous()
136 @CSRFRequired()
137 @CSRFRequired()
137 # perms check inside
138 # perms check inside
138 @view_config(
139 @view_config(
139 route_name='repo_create', request_method='POST',
140 route_name='repo_create', request_method='POST',
140 renderer='rhodecode:templates/admin/repos/repos.mako')
141 renderer='rhodecode:templates/admin/repos/repos.mako')
141 def repository_create(self):
142 def repository_create(self):
142 c = self.load_default_context()
143 c = self.load_default_context()
143
144
144 form_result = {}
145 form_result = {}
145 task_id = None
146 task_id = None
146 self._load_form_data(c)
147 self._load_form_data(c)
147
148
148 try:
149 try:
149 # CanWriteToGroup validators checks permissions of this POST
150 # CanWriteToGroup validators checks permissions of this POST
150 form_result = RepoForm(repo_groups=c.repo_groups_choices,
151 form_result = RepoForm(repo_groups=c.repo_groups_choices,
151 landing_revs=c.landing_revs_choices)()\
152 landing_revs=c.landing_revs_choices)()\
152 .to_python(dict(self.request.POST))
153 .to_python(dict(self.request.POST))
153
154
154 # create is done sometimes async on celery, db transaction
155 # create is done sometimes async on celery, db transaction
155 # management is handled there.
156 # management is handled there.
156 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
157 task = RepoModel().create(form_result, self._rhodecode_user.user_id)
157 from celery.result import BaseAsyncResult
158 from celery.result import BaseAsyncResult
158 if isinstance(task, BaseAsyncResult):
159 if isinstance(task, BaseAsyncResult):
159 task_id = task.task_id
160 task_id = task.task_id
160 except formencode.Invalid as errors:
161 except formencode.Invalid as errors:
161 data = render('rhodecode:templates/admin/repos/repo_add.mako',
162 data = render('rhodecode:templates/admin/repos/repo_add.mako',
162 self._get_template_context(c), self.request)
163 self._get_template_context(c), self.request)
163 html = formencode.htmlfill.render(
164 html = formencode.htmlfill.render(
164 data,
165 data,
165 defaults=errors.value,
166 defaults=errors.value,
166 errors=errors.error_dict or {},
167 errors=errors.error_dict or {},
167 prefix_error=False,
168 prefix_error=False,
168 encoding="UTF-8",
169 encoding="UTF-8",
169 force_defaults=False
170 force_defaults=False
170 )
171 )
171 return Response(html)
172 return Response(html)
172
173
173 except Exception as e:
174 except Exception as e:
174 msg = self._log_creation_exception(e, form_result.get('repo_name'))
175 msg = self._log_creation_exception(e, form_result.get('repo_name'))
175 h.flash(msg, category='error')
176 h.flash(msg, category='error')
176 raise HTTPFound(h.route_path('home'))
177 raise HTTPFound(h.route_path('home'))
177
178
178 raise HTTPFound(
179 raise HTTPFound(
179 h.route_path('repo_creating',
180 h.route_path('repo_creating',
180 repo_name=form_result['repo_name_full'],
181 repo_name=form_result['repo_name_full'],
181 _query=dict(task_id=task_id)))
182 _query=dict(task_id=task_id)))
@@ -1,253 +1,258 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2017 RhodeCode GmbH
3 # Copyright (C) 2011-2017 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.apps._base import RepoAppView, DataGridAppView
31 from rhodecode.apps._base import RepoAppView, DataGridAppView
32 from rhodecode.lib.auth import (
32 from rhodecode.lib.auth import (
33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
33 LoginRequired, HasRepoPermissionAnyDecorator, NotAnonymous,
34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
34 HasRepoPermissionAny, HasPermissionAnyDecorator, CSRFRequired)
35 import rhodecode.lib.helpers as h
35 import rhodecode.lib.helpers as h
36 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
36 from rhodecode.model.db import coalesce, or_, Repository, RepoGroup
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.forms import RepoForkForm
38 from rhodecode.model.forms import RepoForkForm
39 from rhodecode.model.scm import ScmModel, RepoGroupList
39 from rhodecode.model.scm import ScmModel, RepoGroupList
40 from rhodecode.lib.utils2 import safe_int, safe_unicode
40 from rhodecode.lib.utils2 import safe_int, safe_unicode
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 class RepoForksView(RepoAppView, DataGridAppView):
45 class RepoForksView(RepoAppView, DataGridAppView):
46
46
47 def load_default_context(self):
47 def load_default_context(self):
48 c = self._get_local_tmpl_context(include_app_defaults=True)
48 c = self._get_local_tmpl_context(include_app_defaults=True)
49 c.rhodecode_repo = self.rhodecode_vcs_repo
49 c.rhodecode_repo = self.rhodecode_vcs_repo
50
50
51 acl_groups = RepoGroupList(
51 acl_groups = RepoGroupList(
52 RepoGroup.query().all(),
52 RepoGroup.query().all(),
53 perm_set=['group.write', 'group.admin'])
53 perm_set=['group.write', 'group.admin'])
54 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
54 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
55 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
55 c.repo_groups_choices = map(lambda k: safe_unicode(k[0]), c.repo_groups)
56 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
56 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
57 c.landing_revs_choices = choices
57 c.landing_revs_choices = choices
58 c.personal_repo_group = c.rhodecode_user.personal_repo_group
58 c.personal_repo_group = c.rhodecode_user.personal_repo_group
59
59
60 self._register_global_c(c)
60 self._register_global_c(c)
61 return c
61 return c
62
62
63 @LoginRequired()
63 @LoginRequired()
64 @HasRepoPermissionAnyDecorator(
64 @HasRepoPermissionAnyDecorator(
65 'repository.read', 'repository.write', 'repository.admin')
65 'repository.read', 'repository.write', 'repository.admin')
66 @view_config(
66 @view_config(
67 route_name='repo_forks_show_all', request_method='GET',
67 route_name='repo_forks_show_all', request_method='GET',
68 renderer='rhodecode:templates/forks/forks.mako')
68 renderer='rhodecode:templates/forks/forks.mako')
69 def repo_forks_show_all(self):
69 def repo_forks_show_all(self):
70 c = self.load_default_context()
70 c = self.load_default_context()
71 return self._get_template_context(c)
71 return self._get_template_context(c)
72
72
73 @LoginRequired()
73 @LoginRequired()
74 @HasRepoPermissionAnyDecorator(
74 @HasRepoPermissionAnyDecorator(
75 'repository.read', 'repository.write', 'repository.admin')
75 'repository.read', 'repository.write', 'repository.admin')
76 @view_config(
76 @view_config(
77 route_name='repo_forks_data', request_method='GET',
77 route_name='repo_forks_data', request_method='GET',
78 renderer='json_ext', xhr=True)
78 renderer='json_ext', xhr=True)
79 def repo_forks_data(self):
79 def repo_forks_data(self):
80 _ = self.request.translate
80 _ = self.request.translate
81 column_map = {
81 column_map = {
82 'fork_name': 'repo_name',
82 'fork_name': 'repo_name',
83 'fork_date': 'created_on',
83 'fork_date': 'created_on',
84 'last_activity': 'updated_on'
84 'last_activity': 'updated_on'
85 }
85 }
86 draw, start, limit = self._extract_chunk(self.request)
86 draw, start, limit = self._extract_chunk(self.request)
87 search_q, order_by, order_dir = self._extract_ordering(
87 search_q, order_by, order_dir = self._extract_ordering(
88 self.request, column_map=column_map)
88 self.request, column_map=column_map)
89
89
90 acl_check = HasRepoPermissionAny(
90 acl_check = HasRepoPermissionAny(
91 'repository.read', 'repository.write', 'repository.admin')
91 'repository.read', 'repository.write', 'repository.admin')
92 repo_id = self.db_repo.repo_id
92 repo_id = self.db_repo.repo_id
93 allowed_ids = []
93 allowed_ids = []
94 for f in Repository.query().filter(Repository.fork_id == repo_id):
94 for f in Repository.query().filter(Repository.fork_id == repo_id):
95 if acl_check(f.repo_name, 'get forks check'):
95 if acl_check(f.repo_name, 'get forks check'):
96 allowed_ids.append(f.repo_id)
96 allowed_ids.append(f.repo_id)
97
97
98 forks_data_total_count = Repository.query()\
98 forks_data_total_count = Repository.query()\
99 .filter(Repository.fork_id == repo_id)\
99 .filter(Repository.fork_id == repo_id)\
100 .filter(Repository.repo_id.in_(allowed_ids))\
100 .filter(Repository.repo_id.in_(allowed_ids))\
101 .count()
101 .count()
102
102
103 # json generate
103 # json generate
104 base_q = Repository.query()\
104 base_q = Repository.query()\
105 .filter(Repository.fork_id == repo_id)\
105 .filter(Repository.fork_id == repo_id)\
106 .filter(Repository.repo_id.in_(allowed_ids))\
106 .filter(Repository.repo_id.in_(allowed_ids))\
107
107
108 if search_q:
108 if search_q:
109 like_expression = u'%{}%'.format(safe_unicode(search_q))
109 like_expression = u'%{}%'.format(safe_unicode(search_q))
110 base_q = base_q.filter(or_(
110 base_q = base_q.filter(or_(
111 Repository.repo_name.ilike(like_expression),
111 Repository.repo_name.ilike(like_expression),
112 Repository.description.ilike(like_expression),
112 Repository.description.ilike(like_expression),
113 ))
113 ))
114
114
115 forks_data_total_filtered_count = base_q.count()
115 forks_data_total_filtered_count = base_q.count()
116
116
117 sort_col = getattr(Repository, order_by, None)
117 sort_col = getattr(Repository, order_by, None)
118 if sort_col:
118 if sort_col:
119 if order_dir == 'asc':
119 if order_dir == 'asc':
120 # handle null values properly to order by NULL last
120 # handle null values properly to order by NULL last
121 if order_by in ['last_activity']:
121 if order_by in ['last_activity']:
122 sort_col = coalesce(sort_col, datetime.date.max)
122 sort_col = coalesce(sort_col, datetime.date.max)
123 sort_col = sort_col.asc()
123 sort_col = sort_col.asc()
124 else:
124 else:
125 # handle null values properly to order by NULL last
125 # handle null values properly to order by NULL last
126 if order_by in ['last_activity']:
126 if order_by in ['last_activity']:
127 sort_col = coalesce(sort_col, datetime.date.min)
127 sort_col = coalesce(sort_col, datetime.date.min)
128 sort_col = sort_col.desc()
128 sort_col = sort_col.desc()
129
129
130 base_q = base_q.order_by(sort_col)
130 base_q = base_q.order_by(sort_col)
131 base_q = base_q.offset(start).limit(limit)
131 base_q = base_q.offset(start).limit(limit)
132
132
133 fork_list = base_q.all()
133 fork_list = base_q.all()
134
134
135 def fork_actions(fork):
135 def fork_actions(fork):
136 url_link = h.route_path(
136 url_link = h.route_path(
137 'repo_compare',
137 'repo_compare',
138 repo_name=fork.repo_name,
138 repo_name=fork.repo_name,
139 source_ref_type=self.db_repo.landing_rev[0],
139 source_ref_type=self.db_repo.landing_rev[0],
140 source_ref=self.db_repo.landing_rev[1],
140 source_ref=self.db_repo.landing_rev[1],
141 target_ref_type=self.db_repo.landing_rev[0],
141 target_ref_type=self.db_repo.landing_rev[0],
142 target_ref=self.db_repo.landing_rev[1],
142 target_ref=self.db_repo.landing_rev[1],
143 _query=dict(merge=1, target_repo=f.repo_name))
143 _query=dict(merge=1, target_repo=f.repo_name))
144 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
144 return h.link_to(_('Compare fork'), url_link, class_='btn-link')
145
145
146 def fork_name(fork):
146 def fork_name(fork):
147 return h.link_to(fork.repo_name,
147 return h.link_to(fork.repo_name,
148 h.route_path('repo_summary', repo_name=fork.repo_name))
148 h.route_path('repo_summary', repo_name=fork.repo_name))
149
149
150 forks_data = []
150 forks_data = []
151 for fork in fork_list:
151 for fork in fork_list:
152 forks_data.append({
152 forks_data.append({
153 "username": h.gravatar_with_user(self.request, fork.user.username),
153 "username": h.gravatar_with_user(self.request, fork.user.username),
154 "fork_name": fork_name(fork),
154 "fork_name": fork_name(fork),
155 "description": fork.description,
155 "description": fork.description,
156 "fork_date": h.age_component(fork.created_on, time_is_local=True),
156 "fork_date": h.age_component(fork.created_on, time_is_local=True),
157 "last_activity": h.format_date(fork.updated_on),
157 "last_activity": h.format_date(fork.updated_on),
158 "action": fork_actions(fork),
158 "action": fork_actions(fork),
159 })
159 })
160
160
161 data = ({
161 data = ({
162 'draw': draw,
162 'draw': draw,
163 'data': forks_data,
163 'data': forks_data,
164 'recordsTotal': forks_data_total_count,
164 'recordsTotal': forks_data_total_count,
165 'recordsFiltered': forks_data_total_filtered_count,
165 'recordsFiltered': forks_data_total_filtered_count,
166 })
166 })
167
167
168 return data
168 return data
169
169
170 @LoginRequired()
170 @LoginRequired()
171 @NotAnonymous()
171 @NotAnonymous()
172 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
172 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
173 @HasRepoPermissionAnyDecorator(
173 @HasRepoPermissionAnyDecorator(
174 'repository.read', 'repository.write', 'repository.admin')
174 'repository.read', 'repository.write', 'repository.admin')
175 @view_config(
175 @view_config(
176 route_name='repo_fork_new', request_method='GET',
176 route_name='repo_fork_new', request_method='GET',
177 renderer='rhodecode:templates/forks/forks.mako')
177 renderer='rhodecode:templates/forks/forks.mako')
178 def repo_fork_new(self):
178 def repo_fork_new(self):
179 c = self.load_default_context()
179 c = self.load_default_context()
180
180
181 defaults = RepoModel()._get_defaults(self.db_repo_name)
181 defaults = RepoModel()._get_defaults(self.db_repo_name)
182 # alter the description to indicate a fork
182 # alter the description to indicate a fork
183 defaults['description'] = (
183 defaults['description'] = (
184 'fork of repository: %s \n%s' % (
184 'fork of repository: %s \n%s' % (
185 defaults['repo_name'], defaults['description']))
185 defaults['repo_name'], defaults['description']))
186 # add suffix to fork
186 # add suffix to fork
187 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
187 defaults['repo_name'] = '%s-fork' % defaults['repo_name']
188
188
189 data = render('rhodecode:templates/forks/fork.mako',
189 data = render('rhodecode:templates/forks/fork.mako',
190 self._get_template_context(c), self.request)
190 self._get_template_context(c), self.request)
191 html = formencode.htmlfill.render(
191 html = formencode.htmlfill.render(
192 data,
192 data,
193 defaults=defaults,
193 defaults=defaults,
194 encoding="UTF-8",
194 encoding="UTF-8",
195 force_defaults=False
195 force_defaults=False
196 )
196 )
197 return Response(html)
197 return Response(html)
198
198
199 @LoginRequired()
199 @LoginRequired()
200 @NotAnonymous()
200 @NotAnonymous()
201 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
201 @HasPermissionAnyDecorator('hg.admin', 'hg.fork.repository')
202 @HasRepoPermissionAnyDecorator(
202 @HasRepoPermissionAnyDecorator(
203 'repository.read', 'repository.write', 'repository.admin')
203 'repository.read', 'repository.write', 'repository.admin')
204 @CSRFRequired()
204 @CSRFRequired()
205 @view_config(
205 @view_config(
206 route_name='repo_fork_create', request_method='POST',
206 route_name='repo_fork_create', request_method='POST',
207 renderer='rhodecode:templates/forks/fork.mako')
207 renderer='rhodecode:templates/forks/fork.mako')
208 def repo_fork_create(self):
208 def repo_fork_create(self):
209 _ = self.request.translate
209 _ = self.request.translate
210 c = self.load_default_context()
210 c = self.load_default_context()
211
211
212 _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
212 _form = RepoForkForm(old_data={'repo_type': self.db_repo.repo_type},
213 repo_groups=c.repo_groups_choices,
213 repo_groups=c.repo_groups_choices,
214 landing_revs=c.landing_revs_choices)()
214 landing_revs=c.landing_revs_choices)()
215 post_data = dict(self.request.POST)
216
217 # forbid injecting other repo by forging a request
218 post_data['fork_parent_id'] = self.db_repo.repo_id
219
215 form_result = {}
220 form_result = {}
216 task_id = None
221 task_id = None
217 try:
222 try:
218 form_result = _form.to_python(dict(self.request.POST))
223 form_result = _form.to_python(post_data)
219 # create fork is done sometimes async on celery, db transaction
224 # create fork is done sometimes async on celery, db transaction
220 # management is handled there.
225 # management is handled there.
221 task = RepoModel().create_fork(
226 task = RepoModel().create_fork(
222 form_result, c.rhodecode_user.user_id)
227 form_result, c.rhodecode_user.user_id)
223 from celery.result import BaseAsyncResult
228 from celery.result import BaseAsyncResult
224 if isinstance(task, BaseAsyncResult):
229 if isinstance(task, BaseAsyncResult):
225 task_id = task.task_id
230 task_id = task.task_id
226 except formencode.Invalid as errors:
231 except formencode.Invalid as errors:
227 c.rhodecode_db_repo = self.db_repo
232 c.rhodecode_db_repo = self.db_repo
228
233
229 data = render('rhodecode:templates/forks/fork.mako',
234 data = render('rhodecode:templates/forks/fork.mako',
230 self._get_template_context(c), self.request)
235 self._get_template_context(c), self.request)
231 html = formencode.htmlfill.render(
236 html = formencode.htmlfill.render(
232 data,
237 data,
233 defaults=errors.value,
238 defaults=errors.value,
234 errors=errors.error_dict or {},
239 errors=errors.error_dict or {},
235 prefix_error=False,
240 prefix_error=False,
236 encoding="UTF-8",
241 encoding="UTF-8",
237 force_defaults=False
242 force_defaults=False
238 )
243 )
239 return Response(html)
244 return Response(html)
240 except Exception:
245 except Exception:
241 log.exception(
246 log.exception(
242 u'Exception while trying to fork the repository %s',
247 u'Exception while trying to fork the repository %s',
243 self.db_repo_name)
248 self.db_repo_name)
244 msg = (
249 msg = (
245 _('An error occurred during repository forking %s') % (
250 _('An error occurred during repository forking %s') % (
246 self.db_repo_name, ))
251 self.db_repo_name, ))
247 h.flash(msg, category='error')
252 h.flash(msg, category='error')
248
253
249 repo_name = form_result.get('repo_name_full', self.db_repo_name)
254 repo_name = form_result.get('repo_name_full', self.db_repo_name)
250 raise HTTPFound(
255 raise HTTPFound(
251 h.route_path('repo_creating',
256 h.route_path('repo_creating',
252 repo_name=repo_name,
257 repo_name=repo_name,
253 _query=dict(task_id=task_id)))
258 _query=dict(task_id=task_id)))
General Comments 0
You need to be logged in to leave comments. Login now