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