##// END OF EJS Templates
gists: fixed translation for age component which uses pyramid translate component.
marcink -
r1346:b11e64ec default
parent child Browse files
Show More
@@ -1,365 +1,369 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2013-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 """
23 23 gist controller for RhodeCode
24 24 """
25 25
26 26 import time
27 27 import logging
28 28
29 29 import formencode
30 30 import peppercorn
31 31
32 32 from pylons import request, response, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35 from webob.exc import HTTPNotFound, HTTPForbidden
36 36 from sqlalchemy.sql.expression import or_
37 37
38 38
39 39 from rhodecode.model.gist import GistModel
40 40 from rhodecode.model.meta import Session
41 41 from rhodecode.model.db import Gist, User
42 42 from rhodecode.lib import auth
43 43 from rhodecode.lib import helpers as h
44 44 from rhodecode.lib.base import BaseController, render
45 45 from rhodecode.lib.auth import LoginRequired, NotAnonymous
46 46 from rhodecode.lib.utils import jsonify
47 47 from rhodecode.lib.utils2 import time_to_datetime
48 48 from rhodecode.lib.ext_json import json
49 49 from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError
50 50 from rhodecode.model import validation_schema
51 51 from rhodecode.model.validation_schema.schemas import gist_schema
52 52
53 53
54 54 log = logging.getLogger(__name__)
55 55
56 56
57 57 class GistsController(BaseController):
58 58 """REST Controller styled on the Atom Publishing Protocol"""
59 59
60 60 def __load_defaults(self, extra_values=None):
61 61 c.lifetime_values = [
62 62 (-1, _('forever')),
63 63 (5, _('5 minutes')),
64 64 (60, _('1 hour')),
65 65 (60 * 24, _('1 day')),
66 66 (60 * 24 * 30, _('1 month')),
67 67 ]
68 68 if extra_values:
69 69 c.lifetime_values.append(extra_values)
70 70 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
71 71 c.acl_options = [
72 72 (Gist.ACL_LEVEL_PRIVATE, _("Requires registered account")),
73 73 (Gist.ACL_LEVEL_PUBLIC, _("Can be accessed by anonymous users"))
74 74 ]
75 75
76 76 @LoginRequired()
77 77 def index(self):
78 78 """GET /admin/gists: All items in the collection"""
79 79 # url('gists')
80 80 not_default_user = c.rhodecode_user.username != User.DEFAULT_USER
81 81 c.show_private = request.GET.get('private') and not_default_user
82 82 c.show_public = request.GET.get('public') and not_default_user
83 83 c.show_all = request.GET.get('all') and c.rhodecode_user.admin
84 84
85 85 gists = _gists = Gist().query()\
86 86 .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\
87 87 .order_by(Gist.created_on.desc())
88 88
89 89 c.active = 'public'
90 90 # MY private
91 91 if c.show_private and not c.show_public:
92 92 gists = _gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\
93 93 .filter(Gist.gist_owner == c.rhodecode_user.user_id)
94 94 c.active = 'my_private'
95 95 # MY public
96 96 elif c.show_public and not c.show_private:
97 97 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\
98 98 .filter(Gist.gist_owner == c.rhodecode_user.user_id)
99 99 c.active = 'my_public'
100 100 # MY public+private
101 101 elif c.show_private and c.show_public:
102 102 gists = _gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC,
103 103 Gist.gist_type == Gist.GIST_PRIVATE))\
104 104 .filter(Gist.gist_owner == c.rhodecode_user.user_id)
105 105 c.active = 'my_all'
106 106 # Show all by super-admin
107 107 elif c.show_all:
108 108 c.active = 'all'
109 109 gists = _gists
110 110
111 111 # default show ALL public gists
112 112 if not c.show_public and not c.show_private and not c.show_all:
113 113 gists = _gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)
114 114 c.active = 'public'
115 115
116 116 from rhodecode.lib.utils import PartialRenderer
117 117 _render = PartialRenderer('data_table/_dt_elements.mako')
118 118
119 119 data = []
120 120
121 121 for gist in gists:
122 122 data.append({
123 123 'created_on': _render('gist_created', gist.created_on),
124 124 'created_on_raw': gist.created_on,
125 125 'type': _render('gist_type', gist.gist_type),
126 126 'access_id': _render('gist_access_id', gist.gist_access_id, gist.owner.full_contact),
127 127 'author': _render('gist_author', gist.owner.full_contact, gist.created_on, gist.gist_expires),
128 128 'author_raw': h.escape(gist.owner.full_contact),
129 129 'expires': _render('gist_expires', gist.gist_expires),
130 130 'description': _render('gist_description', gist.gist_description)
131 131 })
132 132 c.data = json.dumps(data)
133 133 return render('admin/gists/index.mako')
134 134
135 135 @LoginRequired()
136 136 @NotAnonymous()
137 137 @auth.CSRFRequired()
138 138 def create(self):
139 139 """POST /admin/gists: Create a new item"""
140 140 # url('gists')
141 141 self.__load_defaults()
142 142
143 143 data = dict(request.POST)
144 144 data['filename'] = data.get('filename') or Gist.DEFAULT_FILENAME
145 145 data['nodes'] = [{
146 146 'filename': data['filename'],
147 147 'content': data.get('content'),
148 148 'mimetype': data.get('mimetype') # None is autodetect
149 149 }]
150 150
151 151 data['gist_type'] = (
152 152 Gist.GIST_PUBLIC if data.get('public') else Gist.GIST_PRIVATE)
153 153 data['gist_acl_level'] = (
154 154 data.get('gist_acl_level') or Gist.ACL_LEVEL_PRIVATE)
155 155
156 156 schema = gist_schema.GistSchema().bind(
157 157 lifetime_options=[x[0] for x in c.lifetime_values])
158 158
159 159 try:
160 160
161 161 schema_data = schema.deserialize(data)
162 162 # convert to safer format with just KEYs so we sure no duplicates
163 163 schema_data['nodes'] = gist_schema.sequence_to_nodes(
164 164 schema_data['nodes'])
165 165
166 166 gist = GistModel().create(
167 167 gist_id=schema_data['gistid'], # custom access id not real ID
168 168 description=schema_data['description'],
169 169 owner=c.rhodecode_user.user_id,
170 170 gist_mapping=schema_data['nodes'],
171 171 gist_type=schema_data['gist_type'],
172 172 lifetime=schema_data['lifetime'],
173 173 gist_acl_level=schema_data['gist_acl_level']
174 174 )
175 175 Session().commit()
176 176 new_gist_id = gist.gist_access_id
177 177 except validation_schema.Invalid as errors:
178 178 defaults = data
179 179 errors = errors.asdict()
180 180
181 181 if 'nodes.0.content' in errors:
182 182 errors['content'] = errors['nodes.0.content']
183 183 del errors['nodes.0.content']
184 184 if 'nodes.0.filename' in errors:
185 185 errors['filename'] = errors['nodes.0.filename']
186 186 del errors['nodes.0.filename']
187 187
188 188 return formencode.htmlfill.render(
189 189 render('admin/gists/new.mako'),
190 190 defaults=defaults,
191 191 errors=errors,
192 192 prefix_error=False,
193 193 encoding="UTF-8",
194 194 force_defaults=False
195 195 )
196 196
197 197 except Exception:
198 198 log.exception("Exception while trying to create a gist")
199 199 h.flash(_('Error occurred during gist creation'), category='error')
200 200 return redirect(url('new_gist'))
201 201 return redirect(url('gist', gist_id=new_gist_id))
202 202
203 203 @LoginRequired()
204 204 @NotAnonymous()
205 def new(self, format='html'):
205 def new(self):
206 206 """GET /admin/gists/new: Form to create a new item"""
207 207 # url('new_gist')
208 208 self.__load_defaults()
209 209 return render('admin/gists/new.mako')
210 210
211 211 @LoginRequired()
212 212 @NotAnonymous()
213 213 @auth.CSRFRequired()
214 214 def delete(self, gist_id):
215 215 """DELETE /admin/gists/gist_id: Delete an existing item"""
216 216 # Forms posted to this method should contain a hidden field:
217 217 # <input type="hidden" name="_method" value="DELETE" />
218 218 # Or using helpers:
219 219 # h.form(url('gist', gist_id=ID),
220 220 # method='delete')
221 221 # url('gist', gist_id=ID)
222 222 c.gist = Gist.get_or_404(gist_id)
223 223
224 224 owner = c.gist.gist_owner == c.rhodecode_user.user_id
225 225 if not (h.HasPermissionAny('hg.admin')() or owner):
226 226 raise HTTPForbidden()
227 227
228 228 GistModel().delete(c.gist)
229 229 Session().commit()
230 230 h.flash(_('Deleted gist %s') % c.gist.gist_access_id, category='success')
231 231
232 232 return redirect(url('gists'))
233 233
234 234 def _add_gist_to_context(self, gist_id):
235 235 c.gist = Gist.get_or_404(gist_id)
236 236
237 237 # Check if this gist is expired
238 238 if c.gist.gist_expires != -1:
239 239 if time.time() > c.gist.gist_expires:
240 240 log.error(
241 241 'Gist expired at %s', time_to_datetime(c.gist.gist_expires))
242 242 raise HTTPNotFound()
243 243
244 244 # check if this gist requires a login
245 245 is_default_user = c.rhodecode_user.username == User.DEFAULT_USER
246 246 if c.gist.acl_level == Gist.ACL_LEVEL_PRIVATE and is_default_user:
247 247 log.error("Anonymous user %s tried to access protected gist `%s`",
248 248 c.rhodecode_user, gist_id)
249 249 raise HTTPNotFound()
250 250
251 251 @LoginRequired()
252 252 def show(self, gist_id, revision='tip', format='html', f_path=None):
253 253 """GET /admin/gists/gist_id: Show a specific item"""
254 254 # url('gist', gist_id=ID)
255 255 self._add_gist_to_context(gist_id)
256 256 c.render = not request.GET.get('no-render', False)
257 257
258 258 try:
259 259 c.file_last_commit, c.files = GistModel().get_gist_files(
260 260 gist_id, revision=revision)
261 261 except VCSError:
262 262 log.exception("Exception in gist show")
263 263 raise HTTPNotFound()
264 264 if format == 'raw':
265 265 content = '\n\n'.join([f.content for f in c.files
266 266 if (f_path is None or f.path == f_path)])
267 267 response.content_type = 'text/plain'
268 268 return content
269 269 return render('admin/gists/show.mako')
270 270
271 271 @LoginRequired()
272 272 @NotAnonymous()
273 273 @auth.CSRFRequired()
274 274 def edit(self, gist_id):
275 275 self.__load_defaults()
276 276 self._add_gist_to_context(gist_id)
277 277
278 278 owner = c.gist.gist_owner == c.rhodecode_user.user_id
279 279 if not (h.HasPermissionAny('hg.admin')() or owner):
280 280 raise HTTPForbidden()
281 281
282 282 data = peppercorn.parse(request.POST.items())
283 283
284 284 schema = gist_schema.GistSchema()
285 285 schema = schema.bind(
286 286 # '0' is special value to leave lifetime untouched
287 287 lifetime_options=[x[0] for x in c.lifetime_values] + [0],
288 288 )
289 289
290 290 try:
291 291 schema_data = schema.deserialize(data)
292 292 # convert to safer format with just KEYs so we sure no duplicates
293 293 schema_data['nodes'] = gist_schema.sequence_to_nodes(
294 294 schema_data['nodes'])
295 295
296 296 GistModel().update(
297 297 gist=c.gist,
298 298 description=schema_data['description'],
299 299 owner=c.gist.owner,
300 300 gist_mapping=schema_data['nodes'],
301 301 lifetime=schema_data['lifetime'],
302 302 gist_acl_level=schema_data['gist_acl_level']
303 303 )
304 304
305 305 Session().commit()
306 306 h.flash(_('Successfully updated gist content'), category='success')
307 307 except NodeNotChangedError:
308 308 # raised if nothing was changed in repo itself. We anyway then
309 309 # store only DB stuff for gist
310 310 Session().commit()
311 311 h.flash(_('Successfully updated gist data'), category='success')
312 312 except validation_schema.Invalid as errors:
313 313 errors = errors.asdict()
314 314 h.flash(_('Error occurred during update of gist {}: {}').format(
315 315 gist_id, errors), category='error')
316 316 except Exception:
317 317 log.exception("Exception in gist edit")
318 318 h.flash(_('Error occurred during update of gist %s') % gist_id,
319 319 category='error')
320 320
321 321 return redirect(url('gist', gist_id=gist_id))
322 322
323 323 @LoginRequired()
324 324 @NotAnonymous()
325 def edit_form(self, gist_id, format='html'):
325 def edit_form(self, gist_id):
326 translate = _ = c.pyramid_request.translate
327
326 328 """GET /admin/gists/gist_id/edit: Form to edit an existing item"""
327 329 # url('edit_gist', gist_id=ID)
328 330 self._add_gist_to_context(gist_id)
329 331
330 332 owner = c.gist.gist_owner == c.rhodecode_user.user_id
331 333 if not (h.HasPermissionAny('hg.admin')() or owner):
332 334 raise HTTPForbidden()
333 335
334 336 try:
335 337 c.file_last_commit, c.files = GistModel().get_gist_files(gist_id)
336 338 except VCSError:
337 339 log.exception("Exception in gist edit")
338 340 raise HTTPNotFound()
339 341
340 342 if c.gist.gist_expires == -1:
341 343 expiry = _('never')
342 344 else:
343 345 # this cannot use timeago, since it's used in select2 as a value
344 346 expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
347
348 expiry = translate(expiry)
345 349 self.__load_defaults(
346 350 extra_values=(0, _('%(expiry)s - current value') % {'expiry': expiry}))
347 351 return render('admin/gists/edit.mako')
348 352
349 353 @LoginRequired()
350 354 @NotAnonymous()
351 355 @jsonify
352 356 def check_revision(self, gist_id):
353 357 c.gist = Gist.get_or_404(gist_id)
354 358 last_rev = c.gist.scm_instance().get_commit()
355 359 success = True
356 360 revision = request.GET.get('revision')
357 361
358 362 ##TODO: maybe move this to model ?
359 363 if revision != last_rev.raw_id:
360 364 log.error('Last revision %s is different then submitted %s'
361 365 % (revision, last_rev))
362 366 # our gist has newer version than we
363 367 success = False
364 368
365 369 return {'success': success}
General Comments 0
You need to be logged in to leave comments. Login now