lodgeit-main / lodgeit / controllers / pastes.py

# -*- coding: utf-8 -*-
"""
    lodgeit.controllers.pastes
    ~~~~~~~~~~~~~~~~~~~~~~~~~~

    The paste controller

    :copyright: 2007-2008 by Armin Ronacher, Christopher Grebs.
    :license: BSD
"""
from werkzeug import redirect, Response
from werkzeug.exceptions import NotFound
from hashlib import sha1
from random import random
import time

from flask import request, session, render_template, url_for
from lodgeit.lib import antispam
#from lodgeit.i18n import list_languages as i18n_list_languages, _
from lodgeit.models import Paste, db
from lodgeit.lib.highlighting import list_languages, STYLES
from lodgeit.lib.pagination import generate_pagination
from lodgeit.lib.captcha import check_hashed_solution, Captcha
from flask.ext.babel import gettext as _


from flask import Blueprint
pastes = Blueprint('pastes', __name__)


def generate_user_hash():
    """Generates an more or less unique SHA1 hash."""
    return sha1('%s|%s' % (random(), time.time())).hexdigest()


@pastes.before_request
def add_userhash():
    """\
    automatically creates a new
    `user_hash` and sets `request.first_visit` to `True` if it's a new user.
    """
    if 'user_hash' not in session:
        request.first_visit = True
        session['user_hash'] = generate_user_hash()
    else:
        request.first_visit = False



@pastes.route('/', methods=['GET', 'POST'])
@pastes.route('/+<language>', methods=['GET', 'POST'])
def new_paste(language=None):
    """The 'create a new paste' view."""
    language = request.args.get('language', language)
    if language is None:
        language = session.get('language', 'text')

    code = error = ''
    show_captcha = private = False
    parent = None
    getform = request.form.get

    if request.method == 'POST':
        code = getform('code', u'')
        language = getform('language')

        parent_id = getform('parent')
        if parent_id is not None:
            parent = Paste.get(parent_id)

        spam = getform('webpage') or antispam.is_spam(code)
        if spam:
            error = _('your paste contains spam')
            captcha = getform('captcha')
            if captcha:
                if check_hashed_solution(captcha):
                    error = None
                else:
                    error = _('your paste contains spam and the '
                              'CAPTCHA solution was incorrect')
            show_captcha = True
        if code and language and not error:
            paste = Paste(code, language, parent, session['user_hash'],
                          'private' in request.form)
            db.session.add(paste)
            db.session.commit()
            session['language'] = language
            return redirect(url_for('.show_paste', identifier=paste.identifier))

    else:
        parent_id = request.values.get('reply_to')
        if parent_id is not None:
            parent = Paste.get(parent_id)
            if parent is not None:
                code = parent.code
                language = parent.language
                private = parent.private

    return render_template('new_paste.html',
        languages=list_languages(),
        parent=parent,
        code=code,
        language=language,
        error=error,
        show_captcha=show_captcha,
        private=private
    )


@pastes.route('/show/<identifier>')
def show_paste(identifier, raw=False):
    """Show an existing paste."""
    linenos = request.args.get('linenos') != 'no'
    paste = Paste.get(identifier)
    if paste is None:
        raise NotFound()
    if raw:
        return Response(paste.code, mimetype='text/plain; charset=utf-8')

    return render_template('show_paste.html',
        paste=paste,
        styles=STYLES,
        linenos=linenos,
    )

@pastes.route('/raw/<identifier>')
def raw_paste(identifier):
    """Show an existing paste in raw mode."""
    return show_paste(identifier, raw=True)


@pastes.route('/tree/<identifier>')
def show_tree(identifier):
    """Display the tree of some related pastes."""
    paste = Paste.resolve_root(identifier)
    if paste is None:
        raise NotFound()
    return render_template('paste_tree.html',
        paste=paste,
        current=identifier
    )

@pastes.route('/all/', defaults={'page':1})
@pastes.route('/all/<int:page>')
def show_all(page=1):
    """Paginated list of pages."""
    def link(page):
        if page == 1:
            return request.get_url('pastes/show_all')
        return request.get_url('pastes/show_all', page=page)

    form_args = request.args
    query = Paste.find_all()

    pastes = query.limit(10).offset(10 * (page - 1)).all()
    if not pastes and page != 1:
        raise NotFound()

    return render_template('show_all.html',
        pastes=pastes,
        pagination=generate_pagination(page, 10, query.count(), link),
        show_personal='show_personal' in form_args
    )


@pastes.route('/compare/')
@pastes.route('/compare/<new_id>/<old_id>/')
def compare_paste(new_id=None, old_id=None):
    """Render a diff view for two pastes."""
    getform = request.form.get
    # redirect for the compare form box
    if old_id is None:
        old_id = getform('old', '-1').lstrip('#')
        new_id = getform('new', '-1').lstrip('#')
        return redirect(url_for('pastes.compare_paste', new_id=new_id, old_id=old_id))

    old = Paste.query.get_or_404(old_id)
    new = Paste.query.get_or_404(new_id)

    return render_template('compare_paste.html',
        old=old,
        new=new,
        diff=old.compare_to(new, template=True)
    )

@pastes.route('/unidiff/<new_id>/<old_id>/')
def unidiff_paste(new_id=None, old_id=None):
    """Render an udiff for the two pastes."""
    old = Paste.query.get_or_404(old_id)
    new = Paste.query.get_or_404(new_id)
    return Response(old.compare_to(new),
                    mimetype='text/plain')

@pastes.route('/colorscheme/')
def set_colorscheme():
    """Minimal view that updates the style session cookie. Redirects
    back to the page the user is coming from.
    """
    style_name = request.form.get('style')
    resp = redirect(request.environ.get('HTTP_REFERER') or url_for('pastes.new_paste'))
    if style_name in STYLES:
        resp.set_cookie('style', style_name)
    return resp

@pastes.route('/language/', defaults={'lang': 'en'})
@pastes.route('/language/<lang>/')
def set_language(lang='en'):
    """Minimal view that sets a different language. Redirects
    back to the page the user is coming from."""
    for key, value in i18n_list_languages():
        if key == lang:
            request.set_language(lang)
            break
    return redirect(request.headers.get('HTTP_REFERER') or url_for('pastes.new_paste'))


@pastes.route('/_captcha.png')
def show_captcha():
    """Show a captcha."""
    return Captcha().get_response(set_cookie=True)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.