##// END OF EJS Templates
gists: define and use explicit Mercurial backend to speed up creation and fetching of backend repo
marcink -
r3536:5ee2c115 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

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