diff --git a/rhodecode/controllers/admin/gists.py b/rhodecode/controllers/admin/gists.py --- a/rhodecode/controllers/admin/gists.py +++ b/rhodecode/controllers/admin/gists.py @@ -1,15 +1,4 @@ # -*- coding: utf-8 -*- -""" - rhodecode.controllers.admin.gist - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - gist controller for RhodeCode - - :created_on: May 9, 2013 - :author: marcink - :copyright: (C) 2010-2013 Marcin Kuzminski - :license: GPLv3, see COPYING for more details. -""" # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -22,6 +11,18 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +""" +rhodecode.controllers.admin.gist +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +gist controller for RhodeCode + +:created_on: May 9, 2013 +:author: marcink +:copyright: (c) 2013 RhodeCode GmbH. +:license: GPLv3, see LICENSE for more details. +""" + import time import logging import traceback @@ -35,15 +36,16 @@ from pylons.i18n.translation import _ from rhodecode.model.forms import GistForm from rhodecode.model.gist import GistModel from rhodecode.model.meta import Session -from rhodecode.model.db import Gist +from rhodecode.model.db import Gist, User from rhodecode.lib import helpers as h from rhodecode.lib.base import BaseController, render from rhodecode.lib.auth import LoginRequired, NotAnonymous +from rhodecode.lib.utils import jsonify from rhodecode.lib.utils2 import safe_str, safe_int, time_to_datetime from rhodecode.lib.helpers import Page from webob.exc import HTTPNotFound, HTTPForbidden from sqlalchemy.sql.expression import or_ -from rhodecode.lib.vcs.exceptions import VCSError +from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError log = logging.getLogger(__name__) @@ -51,7 +53,7 @@ log = logging.getLogger(__name__) class GistsController(BaseController): """REST Controller styled on the Atom Publishing Protocol""" - def __load_defaults(self): + def __load_defaults(self, extra_values=None): c.lifetime_values = [ (str(-1), _('forever')), (str(5), _('5 minutes')), @@ -59,27 +61,42 @@ class GistsController(BaseController): (str(60 * 24), _('1 day')), (str(60 * 24 * 30), _('1 month')), ] + if extra_values: + c.lifetime_values.append(extra_values) c.lifetime_options = [(c.lifetime_values, _("Lifetime"))] @LoginRequired() - def index(self, format='html'): + def index(self): """GET /admin/gists: All items in the collection""" # url('gists') - c.show_private = request.GET.get('private') and c.rhodecode_user.username != 'default' - c.show_public = request.GET.get('public') and c.rhodecode_user.username != 'default' + not_default_user = c.rhodecode_user.username != User.DEFAULT_USER + c.show_private = request.GET.get('private') and not_default_user + c.show_public = request.GET.get('public') and not_default_user gists = Gist().query()\ .filter(or_(Gist.gist_expires == -1, Gist.gist_expires >= time.time()))\ .order_by(Gist.created_on.desc()) - if c.show_private: - c.gists = gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\ + + # MY private + if c.show_private and not c.show_public: + gists = gists.filter(Gist.gist_type == Gist.GIST_PRIVATE)\ .filter(Gist.gist_owner == c.rhodecode_user.user_id) - elif c.show_public: - c.gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\ + # MY public + elif c.show_public and not c.show_private: + gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC)\ .filter(Gist.gist_owner == c.rhodecode_user.user_id) - else: - c.gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) + # MY public+private + elif c.show_private and c.show_public: + gists = gists.filter(or_(Gist.gist_type == Gist.GIST_PUBLIC, + Gist.gist_type == Gist.GIST_PRIVATE))\ + .filter(Gist.gist_owner == c.rhodecode_user.user_id) + + # default show ALL public gists + if not c.show_public and not c.show_private: + gists = gists.filter(Gist.gist_type == Gist.GIST_PUBLIC) + + c.gists = gists p = safe_int(request.GET.get('page', 1), 1) c.gists_pager = Page(c.gists, page=p, items_per_page=10) return render('admin/gists/index.html') @@ -94,7 +111,7 @@ class GistsController(BaseController): try: form_result = gist_form.to_python(dict(request.POST)) #TODO: multiple files support, from the form - filename = form_result['filename'] or 'gistfile1.txt' + filename = form_result['filename'] or Gist.DEFAULT_FILENAME nodes = { filename: { 'content': form_result['content'], @@ -105,7 +122,7 @@ class GistsController(BaseController): gist_type = Gist.GIST_PUBLIC if _public else Gist.GIST_PRIVATE gist = GistModel().create( description=form_result['description'], - owner=c.rhodecode_user, + owner=c.rhodecode_user.user_id, gist_mapping=nodes, gist_type=gist_type, lifetime=form_result['lifetime'] @@ -170,7 +187,7 @@ class GistsController(BaseController): return redirect(url('gists')) @LoginRequired() - def show(self, gist_id, format='html', revision='tip', f_path=None): + def show(self, gist_id, revision='tip', format='html', f_path=None): """GET /admin/gists/gist_id: Show a specific item""" # url('gist', gist_id=ID) c.gist = Gist.get_or_404(gist_id) @@ -182,7 +199,8 @@ class GistsController(BaseController): (time_to_datetime(c.gist.gist_expires))) raise HTTPNotFound() try: - c.file_changeset, c.files = GistModel().get_gist_files(gist_id) + c.file_changeset, c.files = GistModel().get_gist_files(gist_id, + revision=revision) except VCSError: log.error(traceback.format_exc()) raise HTTPNotFound() @@ -197,3 +215,78 @@ class GistsController(BaseController): def edit(self, gist_id, format='html'): """GET /admin/gists/gist_id/edit: Form to edit an existing item""" # url('edit_gist', gist_id=ID) + c.gist = Gist.get_or_404(gist_id) + + #check if this gist is not expired + if c.gist.gist_expires != -1: + if time.time() > c.gist.gist_expires: + log.error('Gist expired at %s' % + (time_to_datetime(c.gist.gist_expires))) + raise HTTPNotFound() + try: + c.file_changeset, c.files = GistModel().get_gist_files(gist_id) + except VCSError: + log.error(traceback.format_exc()) + raise HTTPNotFound() + + self.__load_defaults(extra_values=('0', _('unmodified'))) + rendered = render('admin/gists/edit.html') + + if request.POST: + rpost = request.POST + nodes = {} + for org_filename, filename, mimetype, content in zip( + rpost.getall('org_files'), + rpost.getall('files'), + rpost.getall('mimetypes'), + rpost.getall('contents')): + + nodes[org_filename] = { + 'org_filename': org_filename, + 'filename': filename, + 'content': content, + 'lexer': mimetype, + } + try: + GistModel().update( + gist=c.gist, + description=rpost['description'], + owner=c.gist.owner, + gist_mapping=nodes, + gist_type=c.gist.gist_type, + lifetime=rpost['lifetime'] + ) + + Session().commit() + h.flash(_('Successfully updated gist content'), category='success') + except NodeNotChangedError: + # raised if nothing was changed in repo itself. We anyway then + # store only DB stuff for gist + Session().commit() + h.flash(_('Successfully updated gist data'), category='success') + except Exception: + log.error(traceback.format_exc()) + h.flash(_('Error occurred during update of gist %s') % gist_id, + category='error') + + return redirect(url('gist', gist_id=gist_id)) + + return rendered + + @LoginRequired() + @NotAnonymous() + @jsonify + def check_revision(self, gist_id): + c.gist = Gist.get_or_404(gist_id) + last_rev = c.gist.scm_instance.get_changeset() + success = True + revision = request.POST.get('revision') + + ##TODO: maybe move this to model ? + if revision != last_rev.raw_id: + log.error('Last revision %s is different then submited %s' + % (revision, last_rev)) + # our gist has newer version than we + success = False + + return {'success': success}