##// END OF EJS Templates
gists: handle 500 error on sending unsupported format
dan -
r3538:e456c2e1 default
parent child Browse files
Show More
@@ -1,412 +1,414 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2013-2019 RhodeCode GmbH
3 # Copyright (C) 2013-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 time
21 import time
22 import logging
22 import logging
23
23
24 import formencode
24 import formencode
25 import formencode.htmlfill
25 import formencode.htmlfill
26 import peppercorn
26 import peppercorn
27
27
28 from pyramid.httpexceptions import HTTPNotFound, HTTPFound
28 from pyramid.httpexceptions import HTTPNotFound, HTTPFound, HTTPBadRequest
29 from pyramid.view import view_config
29 from pyramid.view import view_config
30 from pyramid.renderers import render
30 from pyramid.renderers import render
31 from pyramid.response import Response
31 from pyramid.response import Response
32
32
33 from rhodecode.apps._base import BaseAppView
33 from rhodecode.apps._base import BaseAppView
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
35 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
36 from rhodecode.lib.utils2 import time_to_datetime
36 from rhodecode.lib.utils2 import time_to_datetime
37 from rhodecode.lib.ext_json import json
37 from rhodecode.lib.ext_json import json
38 from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError
38 from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError
39 from rhodecode.model.gist import GistModel
39 from rhodecode.model.gist import GistModel
40 from rhodecode.model.meta import Session
40 from rhodecode.model.meta import Session
41 from rhodecode.model.db import Gist, User, or_
41 from rhodecode.model.db import Gist, User, or_
42 from rhodecode.model import validation_schema
42 from rhodecode.model import validation_schema
43 from rhodecode.model.validation_schema.schemas import gist_schema
43 from rhodecode.model.validation_schema.schemas import gist_schema
44
44
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class GistView(BaseAppView):
49 class GistView(BaseAppView):
50
50
51 def load_default_context(self):
51 def load_default_context(self):
52 _ = self.request.translate
52 _ = self.request.translate
53 c = self._get_local_tmpl_context()
53 c = self._get_local_tmpl_context()
54 c.user = c.auth_user.get_instance()
54 c.user = c.auth_user.get_instance()
55
55
56 c.lifetime_values = [
56 c.lifetime_values = [
57 (-1, _('forever')),
57 (-1, _('forever')),
58 (5, _('5 minutes')),
58 (5, _('5 minutes')),
59 (60, _('1 hour')),
59 (60, _('1 hour')),
60 (60 * 24, _('1 day')),
60 (60 * 24, _('1 day')),
61 (60 * 24 * 30, _('1 month')),
61 (60 * 24 * 30, _('1 month')),
62 ]
62 ]
63
63
64 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
64 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
65 c.acl_options = [
65 c.acl_options = [
66 (Gist.ACL_LEVEL_PRIVATE, _("Requires registered account")),
66 (Gist.ACL_LEVEL_PRIVATE, _("Requires registered account")),
67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
67 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
68 ]
68 ]
69
69
70 return c
70 return c
71
71
72 @LoginRequired()
72 @LoginRequired()
73 @view_config(
73 @view_config(
74 route_name='gists_show', request_method='GET',
74 route_name='gists_show', request_method='GET',
75 renderer='rhodecode:templates/admin/gists/index.mako')
75 renderer='rhodecode:templates/admin/gists/index.mako')
76 def gist_show_all(self):
76 def gist_show_all(self):
77 c = self.load_default_context()
77 c = self.load_default_context()
78
78
79 not_default_user = self._rhodecode_user.username != User.DEFAULT_USER
79 not_default_user = self._rhodecode_user.username != User.DEFAULT_USER
80 c.show_private = self.request.GET.get('private') and not_default_user
80 c.show_private = self.request.GET.get('private') and not_default_user
81 c.show_public = self.request.GET.get('public') and not_default_user
81 c.show_public = self.request.GET.get('public') and not_default_user
82 c.show_all = self.request.GET.get('all') and self._rhodecode_user.admin
82 c.show_all = self.request.GET.get('all') and self._rhodecode_user.admin
83
83
84 gists = _gists = Gist().query()\
84 gists = _gists = Gist().query()\
85 .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
85 .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
86 .order_by(Gist.created_on.desc())
86 .order_by(Gist.created_on.desc())
87
87
88 c.active = 'public'
88 c.active = 'public'
89 # MY private
89 # MY private
90 if c.show_private and not c.show_public:
90 if c.show_private and not c.show_public:
91 gists = _gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\
91 gists = _gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\
92 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
92 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
93 c.active = 'my_private'
93 c.active = 'my_private'
94 # MY public
94 # MY public
95 elif c.show_public and not c.show_private:
95 elif c.show_public and not c.show_private:
96 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\
96 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\
97 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
97 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
98 c.active = 'my_public'
98 c.active = 'my_public'
99 # MY public+private
99 # MY public+private
100 elif c.show_private and c.show_public:
100 elif c.show_private and c.show_public:
101 gists = _gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC,
101 gists = _gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC,
102 Gist.gist_type == Gist.GIST_PRIVATE))\
102 Gist.gist_type == Gist.GIST_PRIVATE))\
103 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
103 .filter(Gist.gist_owner == self._rhodecode_user.user_id)
104 c.active = 'my_all'
104 c.active = 'my_all'
105 # Show all by super-admin
105 # Show all by super-admin
106 elif c.show_all:
106 elif c.show_all:
107 c.active = 'all'
107 c.active = 'all'
108 gists = _gists
108 gists = _gists
109
109
110 # default show ALL public gists
110 # default show ALL public gists
111 if not c.show_public and not c.show_private and not c.show_all:
111 if not c.show_public and not c.show_private and not c.show_all:
112 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)
112 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)
113 c.active = 'public'
113 c.active = 'public'
114
114
115 _render = self.request.get_partial_renderer(
115 _render = self.request.get_partial_renderer(
116 'rhodecode:templates/data_table/_dt_elements.mako')
116 'rhodecode:templates/data_table/_dt_elements.mako')
117
117
118 data = []
118 data = []
119
119
120 for gist in gists:
120 for gist in gists:
121 data.append({
121 data.append({
122 'created_on': _render('gist_created', gist.created_on),
122 'created_on': _render('gist_created', gist.created_on),
123 'created_on_raw': gist.created_on,
123 'created_on_raw': gist.created_on,
124 'type': _render('gist_type', gist.gist_type),
124 'type': _render('gist_type', gist.gist_type),
125 'access_id': _render('gist_access_id', gist.gist_access_id, gist.owner.full_contact),
125 'access_id': _render('gist_access_id', gist.gist_access_id, gist.owner.full_contact),
126 'author': _render('gist_author', gist.owner.full_contact, gist.created_on, gist.gist_expires),
126 'author': _render('gist_author', gist.owner.full_contact, gist.created_on, gist.gist_expires),
127 'author_raw': h.escape(gist.owner.full_contact),
127 'author_raw': h.escape(gist.owner.full_contact),
128 'expires': _render('gist_expires', gist.gist_expires),
128 'expires': _render('gist_expires', gist.gist_expires),
129 'description': _render('gist_description', gist.gist_description)
129 'description': _render('gist_description', gist.gist_description)
130 })
130 })
131 c.data = json.dumps(data)
131 c.data = json.dumps(data)
132
132
133 return self._get_template_context(c)
133 return self._get_template_context(c)
134
134
135 @LoginRequired()
135 @LoginRequired()
136 @NotAnonymous()
136 @NotAnonymous()
137 @view_config(
137 @view_config(
138 route_name='gists_new', request_method='GET',
138 route_name='gists_new', request_method='GET',
139 renderer='rhodecode:templates/admin/gists/new.mako')
139 renderer='rhodecode:templates/admin/gists/new.mako')
140 def gist_new(self):
140 def gist_new(self):
141 c = self.load_default_context()
141 c = self.load_default_context()
142 return self._get_template_context(c)
142 return self._get_template_context(c)
143
143
144 @LoginRequired()
144 @LoginRequired()
145 @NotAnonymous()
145 @NotAnonymous()
146 @CSRFRequired()
146 @CSRFRequired()
147 @view_config(
147 @view_config(
148 route_name='gists_create', request_method='POST',
148 route_name='gists_create', request_method='POST',
149 renderer='rhodecode:templates/admin/gists/new.mako')
149 renderer='rhodecode:templates/admin/gists/new.mako')
150 def gist_create(self):
150 def gist_create(self):
151 _ = self.request.translate
151 _ = self.request.translate
152 c = self.load_default_context()
152 c = self.load_default_context()
153
153
154 data = dict(self.request.POST)
154 data = dict(self.request.POST)
155 data['filename'] = data.get('filename') or Gist.DEFAULT_FILENAME
155 data['filename'] = data.get('filename') or Gist.DEFAULT_FILENAME
156 data['nodes'] = [{
156 data['nodes'] = [{
157 'filename': data['filename'],
157 'filename': data['filename'],
158 'content': data.get('content'),
158 'content': data.get('content'),
159 'mimetype': data.get('mimetype') # None is autodetect
159 'mimetype': data.get('mimetype') # None is autodetect
160 }]
160 }]
161
161
162 data['gist_type'] = (
162 data['gist_type'] = (
163 Gist.GIST_PUBLIC if data.get('public') else Gist.GIST_PRIVATE)
163 Gist.GIST_PUBLIC if data.get('public') else Gist.GIST_PRIVATE)
164 data['gist_acl_level'] = (
164 data['gist_acl_level'] = (
165 data.get('gist_acl_level') or Gist.ACL_LEVEL_PRIVATE)
165 data.get('gist_acl_level') or Gist.ACL_LEVEL_PRIVATE)
166
166
167 schema = gist_schema.GistSchema().bind(
167 schema = gist_schema.GistSchema().bind(
168 lifetime_options=[x[0] for x in c.lifetime_values])
168 lifetime_options=[x[0] for x in c.lifetime_values])
169
169
170 try:
170 try:
171
171
172 schema_data = schema.deserialize(data)
172 schema_data = schema.deserialize(data)
173 # convert to safer format with just KEYs so we sure no duplicates
173 # convert to safer format with just KEYs so we sure no duplicates
174 schema_data['nodes'] = gist_schema.sequence_to_nodes(
174 schema_data['nodes'] = gist_schema.sequence_to_nodes(
175 schema_data['nodes'])
175 schema_data['nodes'])
176
176
177 gist = GistModel().create(
177 gist = GistModel().create(
178 gist_id=schema_data['gistid'], # custom access id not real ID
178 gist_id=schema_data['gistid'], # custom access id not real ID
179 description=schema_data['description'],
179 description=schema_data['description'],
180 owner=self._rhodecode_user.user_id,
180 owner=self._rhodecode_user.user_id,
181 gist_mapping=schema_data['nodes'],
181 gist_mapping=schema_data['nodes'],
182 gist_type=schema_data['gist_type'],
182 gist_type=schema_data['gist_type'],
183 lifetime=schema_data['lifetime'],
183 lifetime=schema_data['lifetime'],
184 gist_acl_level=schema_data['gist_acl_level']
184 gist_acl_level=schema_data['gist_acl_level']
185 )
185 )
186 Session().commit()
186 Session().commit()
187 new_gist_id = gist.gist_access_id
187 new_gist_id = gist.gist_access_id
188 except validation_schema.Invalid as errors:
188 except validation_schema.Invalid as errors:
189 defaults = data
189 defaults = data
190 errors = errors.asdict()
190 errors = errors.asdict()
191
191
192 if 'nodes.0.content' in errors:
192 if 'nodes.0.content' in errors:
193 errors['content'] = errors['nodes.0.content']
193 errors['content'] = errors['nodes.0.content']
194 del errors['nodes.0.content']
194 del errors['nodes.0.content']
195 if 'nodes.0.filename' in errors:
195 if 'nodes.0.filename' in errors:
196 errors['filename'] = errors['nodes.0.filename']
196 errors['filename'] = errors['nodes.0.filename']
197 del errors['nodes.0.filename']
197 del errors['nodes.0.filename']
198
198
199 data = render('rhodecode:templates/admin/gists/new.mako',
199 data = render('rhodecode:templates/admin/gists/new.mako',
200 self._get_template_context(c), self.request)
200 self._get_template_context(c), self.request)
201 html = formencode.htmlfill.render(
201 html = formencode.htmlfill.render(
202 data,
202 data,
203 defaults=defaults,
203 defaults=defaults,
204 errors=errors,
204 errors=errors,
205 prefix_error=False,
205 prefix_error=False,
206 encoding="UTF-8",
206 encoding="UTF-8",
207 force_defaults=False
207 force_defaults=False
208 )
208 )
209 return Response(html)
209 return Response(html)
210
210
211 except Exception:
211 except Exception:
212 log.exception("Exception while trying to create a gist")
212 log.exception("Exception while trying to create a gist")
213 h.flash(_('Error occurred during gist creation'), category='error')
213 h.flash(_('Error occurred during gist creation'), category='error')
214 raise HTTPFound(h.route_url('gists_new'))
214 raise HTTPFound(h.route_url('gists_new'))
215 raise HTTPFound(h.route_url('gist_show', gist_id=new_gist_id))
215 raise HTTPFound(h.route_url('gist_show', gist_id=new_gist_id))
216
216
217 @LoginRequired()
217 @LoginRequired()
218 @NotAnonymous()
218 @NotAnonymous()
219 @CSRFRequired()
219 @CSRFRequired()
220 @view_config(
220 @view_config(
221 route_name='gist_delete', request_method='POST')
221 route_name='gist_delete', request_method='POST')
222 def gist_delete(self):
222 def gist_delete(self):
223 _ = self.request.translate
223 _ = self.request.translate
224 gist_id = self.request.matchdict['gist_id']
224 gist_id = self.request.matchdict['gist_id']
225
225
226 c = self.load_default_context()
226 c = self.load_default_context()
227 c.gist = Gist.get_or_404(gist_id)
227 c.gist = Gist.get_or_404(gist_id)
228
228
229 owner = c.gist.gist_owner == self._rhodecode_user.user_id
229 owner = c.gist.gist_owner == self._rhodecode_user.user_id
230 if not (h.HasPermissionAny('hg.admin')() or owner):
230 if not (h.HasPermissionAny('hg.admin')() or owner):
231 log.warning('Deletion of Gist was forbidden '
231 log.warning('Deletion of Gist was forbidden '
232 'by unauthorized user: `%s`', self._rhodecode_user)
232 'by unauthorized user: `%s`', self._rhodecode_user)
233 raise HTTPNotFound()
233 raise HTTPNotFound()
234
234
235 GistModel().delete(c.gist)
235 GistModel().delete(c.gist)
236 Session().commit()
236 Session().commit()
237 h.flash(_('Deleted gist %s') % c.gist.gist_access_id, category='success')
237 h.flash(_('Deleted gist %s') % c.gist.gist_access_id, category='success')
238
238
239 raise HTTPFound(h.route_url('gists_show'))
239 raise HTTPFound(h.route_url('gists_show'))
240
240
241 def _get_gist(self, gist_id):
241 def _get_gist(self, gist_id):
242
242
243 gist = Gist.get_or_404(gist_id)
243 gist = Gist.get_or_404(gist_id)
244
244
245 # Check if this gist is expired
245 # Check if this gist is expired
246 if gist.gist_expires != -1:
246 if gist.gist_expires != -1:
247 if time.time() > gist.gist_expires:
247 if time.time() > gist.gist_expires:
248 log.error(
248 log.error(
249 'Gist expired at %s', time_to_datetime(gist.gist_expires))
249 'Gist expired at %s', time_to_datetime(gist.gist_expires))
250 raise HTTPNotFound()
250 raise HTTPNotFound()
251
251
252 # check if this gist requires a login
252 # check if this gist requires a login
253 is_default_user = self._rhodecode_user.username == User.DEFAULT_USER
253 is_default_user = self._rhodecode_user.username == User.DEFAULT_USER
254 if gist.acl_level == Gist.ACL_LEVEL_PRIVATE and is_default_user:
254 if gist.acl_level == Gist.ACL_LEVEL_PRIVATE and is_default_user:
255 log.error("Anonymous user %s tried to access protected gist `%s`",
255 log.error("Anonymous user %s tried to access protected gist `%s`",
256 self._rhodecode_user, gist_id)
256 self._rhodecode_user, gist_id)
257 raise HTTPNotFound()
257 raise HTTPNotFound()
258 return gist
258 return gist
259
259
260 @LoginRequired()
260 @LoginRequired()
261 @view_config(
261 @view_config(
262 route_name='gist_show', request_method='GET',
262 route_name='gist_show', request_method='GET',
263 renderer='rhodecode:templates/admin/gists/show.mako')
263 renderer='rhodecode:templates/admin/gists/show.mako')
264 @view_config(
264 @view_config(
265 route_name='gist_show_rev', request_method='GET',
265 route_name='gist_show_rev', request_method='GET',
266 renderer='rhodecode:templates/admin/gists/show.mako')
266 renderer='rhodecode:templates/admin/gists/show.mako')
267 @view_config(
267 @view_config(
268 route_name='gist_show_formatted', request_method='GET',
268 route_name='gist_show_formatted', request_method='GET',
269 renderer=None)
269 renderer=None)
270 @view_config(
270 @view_config(
271 route_name='gist_show_formatted_path', request_method='GET',
271 route_name='gist_show_formatted_path', request_method='GET',
272 renderer=None)
272 renderer=None)
273 def gist_show(self):
273 def gist_show(self):
274 gist_id = self.request.matchdict['gist_id']
274 gist_id = self.request.matchdict['gist_id']
275
275
276 # TODO(marcink): expose those via matching dict
276 # TODO(marcink): expose those via matching dict
277 revision = self.request.matchdict.get('revision', 'tip')
277 revision = self.request.matchdict.get('revision', 'tip')
278 f_path = self.request.matchdict.get('f_path', None)
278 f_path = self.request.matchdict.get('f_path', None)
279 return_format = self.request.matchdict.get('format')
279 return_format = self.request.matchdict.get('format')
280
280
281 c = self.load_default_context()
281 c = self.load_default_context()
282 c.gist = self._get_gist(gist_id)
282 c.gist = self._get_gist(gist_id)
283 c.render = not self.request.GET.get('no-render', False)
283 c.render = not self.request.GET.get('no-render', False)
284
284
285 try:
285 try:
286 c.file_last_commit, c.files = GistModel().get_gist_files(
286 c.file_last_commit, c.files = GistModel().get_gist_files(
287 gist_id, revision=revision)
287 gist_id, revision=revision)
288 except VCSError:
288 except VCSError:
289 log.exception("Exception in gist show")
289 log.exception("Exception in gist show")
290 raise HTTPNotFound()
290 raise HTTPNotFound()
291
291
292 if return_format == 'raw':
292 if return_format == 'raw':
293 content = '\n\n'.join([f.content for f in c.files
293 content = '\n\n'.join([f.content for f in c.files
294 if (f_path is None or f.path == f_path)])
294 if (f_path is None or f.path == f_path)])
295 response = Response(content)
295 response = Response(content)
296 response.content_type = 'text/plain'
296 response.content_type = 'text/plain'
297 return response
297 return response
298 elif return_format:
299 raise HTTPBadRequest()
298
300
299 return self._get_template_context(c)
301 return self._get_template_context(c)
300
302
301 @LoginRequired()
303 @LoginRequired()
302 @NotAnonymous()
304 @NotAnonymous()
303 @view_config(
305 @view_config(
304 route_name='gist_edit', request_method='GET',
306 route_name='gist_edit', request_method='GET',
305 renderer='rhodecode:templates/admin/gists/edit.mako')
307 renderer='rhodecode:templates/admin/gists/edit.mako')
306 def gist_edit(self):
308 def gist_edit(self):
307 _ = self.request.translate
309 _ = self.request.translate
308 gist_id = self.request.matchdict['gist_id']
310 gist_id = self.request.matchdict['gist_id']
309 c = self.load_default_context()
311 c = self.load_default_context()
310 c.gist = self._get_gist(gist_id)
312 c.gist = self._get_gist(gist_id)
311
313
312 owner = c.gist.gist_owner == self._rhodecode_user.user_id
314 owner = c.gist.gist_owner == self._rhodecode_user.user_id
313 if not (h.HasPermissionAny('hg.admin')() or owner):
315 if not (h.HasPermissionAny('hg.admin')() or owner):
314 raise HTTPNotFound()
316 raise HTTPNotFound()
315
317
316 try:
318 try:
317 c.file_last_commit, c.files = GistModel().get_gist_files(gist_id)
319 c.file_last_commit, c.files = GistModel().get_gist_files(gist_id)
318 except VCSError:
320 except VCSError:
319 log.exception("Exception in gist edit")
321 log.exception("Exception in gist edit")
320 raise HTTPNotFound()
322 raise HTTPNotFound()
321
323
322 if c.gist.gist_expires == -1:
324 if c.gist.gist_expires == -1:
323 expiry = _('never')
325 expiry = _('never')
324 else:
326 else:
325 # this cannot use timeago, since it's used in select2 as a value
327 # this cannot use timeago, since it's used in select2 as a value
326 expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
328 expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
327
329
328 c.lifetime_values.append(
330 c.lifetime_values.append(
329 (0, _('%(expiry)s - current value') % {'expiry': _(expiry)})
331 (0, _('%(expiry)s - current value') % {'expiry': _(expiry)})
330 )
332 )
331
333
332 return self._get_template_context(c)
334 return self._get_template_context(c)
333
335
334 @LoginRequired()
336 @LoginRequired()
335 @NotAnonymous()
337 @NotAnonymous()
336 @CSRFRequired()
338 @CSRFRequired()
337 @view_config(
339 @view_config(
338 route_name='gist_update', request_method='POST',
340 route_name='gist_update', request_method='POST',
339 renderer='rhodecode:templates/admin/gists/edit.mako')
341 renderer='rhodecode:templates/admin/gists/edit.mako')
340 def gist_update(self):
342 def gist_update(self):
341 _ = self.request.translate
343 _ = self.request.translate
342 gist_id = self.request.matchdict['gist_id']
344 gist_id = self.request.matchdict['gist_id']
343 c = self.load_default_context()
345 c = self.load_default_context()
344 c.gist = self._get_gist(gist_id)
346 c.gist = self._get_gist(gist_id)
345
347
346 owner = c.gist.gist_owner == self._rhodecode_user.user_id
348 owner = c.gist.gist_owner == self._rhodecode_user.user_id
347 if not (h.HasPermissionAny('hg.admin')() or owner):
349 if not (h.HasPermissionAny('hg.admin')() or owner):
348 raise HTTPNotFound()
350 raise HTTPNotFound()
349
351
350 data = peppercorn.parse(self.request.POST.items())
352 data = peppercorn.parse(self.request.POST.items())
351
353
352 schema = gist_schema.GistSchema()
354 schema = gist_schema.GistSchema()
353 schema = schema.bind(
355 schema = schema.bind(
354 # '0' is special value to leave lifetime untouched
356 # '0' is special value to leave lifetime untouched
355 lifetime_options=[x[0] for x in c.lifetime_values] + [0],
357 lifetime_options=[x[0] for x in c.lifetime_values] + [0],
356 )
358 )
357
359
358 try:
360 try:
359 schema_data = schema.deserialize(data)
361 schema_data = schema.deserialize(data)
360 # convert to safer format with just KEYs so we sure no duplicates
362 # convert to safer format with just KEYs so we sure no duplicates
361 schema_data['nodes'] = gist_schema.sequence_to_nodes(
363 schema_data['nodes'] = gist_schema.sequence_to_nodes(
362 schema_data['nodes'])
364 schema_data['nodes'])
363
365
364 GistModel().update(
366 GistModel().update(
365 gist=c.gist,
367 gist=c.gist,
366 description=schema_data['description'],
368 description=schema_data['description'],
367 owner=c.gist.owner,
369 owner=c.gist.owner,
368 gist_mapping=schema_data['nodes'],
370 gist_mapping=schema_data['nodes'],
369 lifetime=schema_data['lifetime'],
371 lifetime=schema_data['lifetime'],
370 gist_acl_level=schema_data['gist_acl_level']
372 gist_acl_level=schema_data['gist_acl_level']
371 )
373 )
372
374
373 Session().commit()
375 Session().commit()
374 h.flash(_('Successfully updated gist content'), category='success')
376 h.flash(_('Successfully updated gist content'), category='success')
375 except NodeNotChangedError:
377 except NodeNotChangedError:
376 # raised if nothing was changed in repo itself. We anyway then
378 # raised if nothing was changed in repo itself. We anyway then
377 # store only DB stuff for gist
379 # store only DB stuff for gist
378 Session().commit()
380 Session().commit()
379 h.flash(_('Successfully updated gist data'), category='success')
381 h.flash(_('Successfully updated gist data'), category='success')
380 except validation_schema.Invalid as errors:
382 except validation_schema.Invalid as errors:
381 errors = h.escape(errors.asdict())
383 errors = h.escape(errors.asdict())
382 h.flash(_('Error occurred during update of gist {}: {}').format(
384 h.flash(_('Error occurred during update of gist {}: {}').format(
383 gist_id, errors), category='error')
385 gist_id, errors), category='error')
384 except Exception:
386 except Exception:
385 log.exception("Exception in gist edit")
387 log.exception("Exception in gist edit")
386 h.flash(_('Error occurred during update of gist %s') % gist_id,
388 h.flash(_('Error occurred during update of gist %s') % gist_id,
387 category='error')
389 category='error')
388
390
389 raise HTTPFound(h.route_url('gist_show', gist_id=gist_id))
391 raise HTTPFound(h.route_url('gist_show', gist_id=gist_id))
390
392
391 @LoginRequired()
393 @LoginRequired()
392 @NotAnonymous()
394 @NotAnonymous()
393 @view_config(
395 @view_config(
394 route_name='gist_edit_check_revision', request_method='GET',
396 route_name='gist_edit_check_revision', request_method='GET',
395 renderer='json_ext')
397 renderer='json_ext')
396 def gist_edit_check_revision(self):
398 def gist_edit_check_revision(self):
397 _ = self.request.translate
399 _ = self.request.translate
398 gist_id = self.request.matchdict['gist_id']
400 gist_id = self.request.matchdict['gist_id']
399 c = self.load_default_context()
401 c = self.load_default_context()
400 c.gist = self._get_gist(gist_id)
402 c.gist = self._get_gist(gist_id)
401
403
402 last_rev = c.gist.scm_instance().get_commit()
404 last_rev = c.gist.scm_instance().get_commit()
403 success = True
405 success = True
404 revision = self.request.GET.get('revision')
406 revision = self.request.GET.get('revision')
405
407
406 if revision != last_rev.raw_id:
408 if revision != last_rev.raw_id:
407 log.error('Last revision %s is different then submitted %s',
409 log.error('Last revision %s is different then submitted %s',
408 revision, last_rev)
410 revision, last_rev)
409 # our gist has newer version than we
411 # our gist has newer version than we
410 success = False
412 success = False
411
413
412 return {'success': success}
414 return {'success': success}
General Comments 0
You need to be logged in to leave comments. Login now