##// END OF EJS Templates
gists: Remove gist_type from update method in model. #4243...
Martin Bornhold -
r851:7e3c29b0 default
parent child Browse files
Show More
@@ -1,366 +1,365 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2013-2016 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.html')
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.html')
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.html'),
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 205 def new(self, format='html'):
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.html')
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.html')
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 gist_type=schema_data['gist_type'],
302 301 lifetime=schema_data['lifetime'],
303 302 gist_acl_level=schema_data['gist_acl_level']
304 303 )
305 304
306 305 Session().commit()
307 306 h.flash(_('Successfully updated gist content'), category='success')
308 307 except NodeNotChangedError:
309 308 # raised if nothing was changed in repo itself. We anyway then
310 309 # store only DB stuff for gist
311 310 Session().commit()
312 311 h.flash(_('Successfully updated gist data'), category='success')
313 312 except validation_schema.Invalid as errors:
314 313 errors = errors.asdict()
315 314 h.flash(_('Error occurred during update of gist {}: {}').format(
316 315 gist_id, errors), category='error')
317 316 except Exception:
318 317 log.exception("Exception in gist edit")
319 318 h.flash(_('Error occurred during update of gist %s') % gist_id,
320 319 category='error')
321 320
322 321 return redirect(url('gist', gist_id=gist_id))
323 322
324 323 @LoginRequired()
325 324 @NotAnonymous()
326 325 def edit_form(self, gist_id, format='html'):
327 326 """GET /admin/gists/gist_id/edit: Form to edit an existing item"""
328 327 # url('edit_gist', gist_id=ID)
329 328 self._add_gist_to_context(gist_id)
330 329
331 330 owner = c.gist.gist_owner == c.rhodecode_user.user_id
332 331 if not (h.HasPermissionAny('hg.admin')() or owner):
333 332 raise HTTPForbidden()
334 333
335 334 try:
336 335 c.file_last_commit, c.files = GistModel().get_gist_files(gist_id)
337 336 except VCSError:
338 337 log.exception("Exception in gist edit")
339 338 raise HTTPNotFound()
340 339
341 340 if c.gist.gist_expires == -1:
342 341 expiry = _('never')
343 342 else:
344 343 # this cannot use timeago, since it's used in select2 as a value
345 344 expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
346 345 self.__load_defaults(
347 346 extra_values=(0, _('%(expiry)s - current value') % {'expiry': expiry}))
348 347 return render('admin/gists/edit.html')
349 348
350 349 @LoginRequired()
351 350 @NotAnonymous()
352 351 @jsonify
353 352 def check_revision(self, gist_id):
354 353 c.gist = Gist.get_or_404(gist_id)
355 354 last_rev = c.gist.scm_instance().get_commit()
356 355 success = True
357 356 revision = request.GET.get('revision')
358 357
359 358 ##TODO: maybe move this to model ?
360 359 if revision != last_rev.raw_id:
361 360 log.error('Last revision %s is different then submitted %s'
362 361 % (revision, last_rev))
363 362 # our gist has newer version than we
364 363 success = False
365 364
366 365 return {'success': success}
@@ -1,236 +1,235 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2013-2016 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 rhodecode.lib.utils2 import (
32 32 safe_unicode, unique_id, safe_int, time_to_datetime, AttributeDict)
33 33 from rhodecode.lib.ext_json import json
34 34 from rhodecode.model import BaseModel
35 35 from rhodecode.model.db import Gist
36 36 from rhodecode.model.repo import RepoModel
37 37 from rhodecode.model.scm import ScmModel
38 38
39 39 log = logging.getLogger(__name__)
40 40
41 41 GIST_STORE_LOC = '.rc_gist_store'
42 42 GIST_METADATA_FILE = '.rc_gist_metadata'
43 43
44 44
45 45 class GistModel(BaseModel):
46 46 cls = Gist
47 47
48 48 def _get_gist(self, gist):
49 49 """
50 50 Helper method to get gist by ID, or gist_access_id as a fallback
51 51
52 52 :param gist: GistID, gist_access_id, or Gist instance
53 53 """
54 54 return self._get_instance(Gist, gist, callback=Gist.get_by_access_id)
55 55
56 56 def __delete_gist(self, gist):
57 57 """
58 58 removes gist from filesystem
59 59
60 60 :param gist: gist object
61 61 """
62 62 root_path = RepoModel().repos_path
63 63 rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
64 64 log.info("Removing %s", rm_path)
65 65 shutil.rmtree(rm_path)
66 66
67 67 def _store_metadata(self, repo, gist_id, gist_access_id, user_id, username,
68 68 gist_type, gist_expires, gist_acl_level):
69 69 """
70 70 store metadata inside the gist repo, this can be later used for imports
71 71 or gist identification. Currently we use this inside RhodeCode tools
72 72 to do cleanup of gists that are in storage but not in database.
73 73 """
74 74 metadata = {
75 75 'metadata_version': '2',
76 76 'gist_db_id': gist_id,
77 77 'gist_access_id': gist_access_id,
78 78 'gist_owner_id': user_id,
79 79 'gist_owner_username': username,
80 80 'gist_type': gist_type,
81 81 'gist_expires': gist_expires,
82 82 'gist_updated': time.time(),
83 83 'gist_acl_level': gist_acl_level,
84 84 }
85 85 metadata_file = os.path.join(repo.path, '.hg', GIST_METADATA_FILE)
86 86 with open(metadata_file, 'wb') as f:
87 87 f.write(json.dumps(metadata))
88 88
89 89 def get_gist(self, gist):
90 90 return self._get_gist(gist)
91 91
92 92 def get_gist_files(self, gist_access_id, revision=None):
93 93 """
94 94 Get files for given gist
95 95
96 96 :param gist_access_id:
97 97 """
98 98 repo = Gist.get_by_access_id(gist_access_id)
99 99 commit = repo.scm_instance().get_commit(commit_id=revision)
100 100 return commit, [n for n in commit.get_node('/')]
101 101
102 102 def create(self, description, owner, gist_mapping,
103 103 gist_type=Gist.GIST_PUBLIC, lifetime=-1, gist_id=None,
104 104 gist_acl_level=Gist.ACL_LEVEL_PRIVATE):
105 105 """
106 106 Create a gist
107 107
108 108 :param description: description of the gist
109 109 :param owner: user who created this gist
110 110 :param gist_mapping: mapping [{'filename': 'file1.txt', 'content': content}, ...}]
111 111 :param gist_type: type of gist private/public
112 112 :param lifetime: in minutes, -1 == forever
113 113 :param gist_acl_level: acl level for this gist
114 114 """
115 115 owner = self._get_user(owner)
116 116 gist_id = safe_unicode(gist_id or unique_id(20))
117 117 lifetime = safe_int(lifetime, -1)
118 118 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
119 119 expiration = (time_to_datetime(gist_expires)
120 120 if gist_expires != -1 else 'forever')
121 121 log.debug('set GIST expiration date to: %s', expiration)
122 122 # create the Database version
123 123 gist = Gist()
124 124 gist.gist_description = description
125 125 gist.gist_access_id = gist_id
126 126 gist.gist_owner = owner.user_id
127 127 gist.gist_expires = gist_expires
128 128 gist.gist_type = safe_unicode(gist_type)
129 129 gist.acl_level = gist_acl_level
130 130 self.sa.add(gist)
131 131 self.sa.flush()
132 132 if gist_type == Gist.GIST_PUBLIC:
133 133 # use DB ID for easy to use GIST ID
134 134 gist_id = safe_unicode(gist.gist_id)
135 135 gist.gist_access_id = gist_id
136 136 self.sa.add(gist)
137 137
138 138 gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
139 139 log.debug('Creating new %s GIST repo in %s', gist_type, gist_repo_path)
140 140 repo = RepoModel()._create_filesystem_repo(
141 141 repo_name=gist_id, repo_type='hg', repo_group=GIST_STORE_LOC,
142 142 use_global_config=True)
143 143
144 144 # now create single multifile commit
145 145 message = 'added file'
146 146 message += 's: ' if len(gist_mapping) > 1 else ': '
147 147 message += ', '.join([x for x in gist_mapping])
148 148
149 149 # fake RhodeCode Repository object
150 150 fake_repo = AttributeDict({
151 151 'repo_name': gist_repo_path,
152 152 'scm_instance': lambda *args, **kwargs: repo,
153 153 })
154 154
155 155 ScmModel().create_nodes(
156 156 user=owner.user_id, repo=fake_repo,
157 157 message=message,
158 158 nodes=gist_mapping,
159 159 trigger_push_hook=False
160 160 )
161 161
162 162 self._store_metadata(repo, gist.gist_id, gist.gist_access_id,
163 163 owner.user_id, owner.username, gist.gist_type,
164 164 gist.gist_expires, gist_acl_level)
165 165 return gist
166 166
167 167 def delete(self, gist, fs_remove=True):
168 168 gist = self._get_gist(gist)
169 169 try:
170 170 self.sa.delete(gist)
171 171 if fs_remove:
172 172 self.__delete_gist(gist)
173 173 else:
174 174 log.debug('skipping removal from filesystem')
175 175 except Exception:
176 176 log.error(traceback.format_exc())
177 177 raise
178 178
179 def update(self, gist, description, owner, gist_mapping, gist_type,
180 lifetime, gist_acl_level):
179 def update(self, gist, description, owner, gist_mapping, lifetime,
180 gist_acl_level):
181 181 gist = self._get_gist(gist)
182 182 gist_repo = gist.scm_instance()
183 183
184 184 if lifetime == 0: # preserve old value
185 185 gist_expires = gist.gist_expires
186 186 else:
187 187 gist_expires = (
188 188 time.time() + (lifetime * 60) if lifetime != -1 else -1)
189 189
190 190 # calculate operation type based on given data
191 191 gist_mapping_op = {}
192 192 for k, v in gist_mapping.items():
193 193 # add, mod, del
194 194 if not v['filename_org'] and v['filename']:
195 195 op = 'add'
196 196 elif v['filename_org'] and not v['filename']:
197 197 op = 'del'
198 198 else:
199 199 op = 'mod'
200 200
201 201 v['op'] = op
202 202 gist_mapping_op[k] = v
203 203
204 204 gist.gist_description = description
205 205 gist.gist_expires = gist_expires
206 206 gist.owner = owner
207 gist.gist_type = gist_type
208 207 gist.acl_level = gist_acl_level
209 208 self.sa.add(gist)
210 209 self.sa.flush()
211 210
212 211 message = 'updated file'
213 212 message += 's: ' if len(gist_mapping) > 1 else ': '
214 213 message += ', '.join([x for x in gist_mapping])
215 214
216 215 # fake RhodeCode Repository object
217 216 fake_repo = AttributeDict({
218 217 'repo_name': gist_repo.path,
219 218 'scm_instance': lambda *args, **kwargs: gist_repo,
220 219 })
221 220
222 221 self._store_metadata(gist_repo, gist.gist_id, gist.gist_access_id,
223 222 owner.user_id, owner.username, gist.gist_type,
224 223 gist.gist_expires, gist_acl_level)
225 224
226 225 # this can throw NodeNotChangedError, if changes we're trying to commit
227 226 # are not actually changes...
228 227 ScmModel().update_nodes(
229 228 user=owner.user_id,
230 229 repo=fake_repo,
231 230 message=message,
232 231 nodes=gist_mapping_op,
233 232 trigger_push_hook=False
234 233 )
235 234
236 235 return gist
General Comments 0
You need to be logged in to leave comments. Login now