Implemented private pastes and improved some code. Added TODO file.
This commit is contained in:
parent
dffba5bfbf
commit
790402b5df
4
TODO
Normal file
4
TODO
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
* Put all cookie stuff into *one* securecookie
|
||||||
|
* Make it possible to tag and find pastes
|
||||||
|
* Add a button to find all the personal (and private) pastes
|
||||||
|
(cookie bound)
|
@ -17,7 +17,7 @@ from werkzeug import SharedDataMiddleware, ClosingIterator
|
|||||||
from werkzeug.exceptions import HTTPException, NotFound
|
from werkzeug.exceptions import HTTPException, NotFound
|
||||||
|
|
||||||
from lodgeit.utils import _local_manager, ctx, jinja_environment, \
|
from lodgeit.utils import _local_manager, ctx, jinja_environment, \
|
||||||
Request, generate_user_hash
|
Request
|
||||||
from lodgeit.database import metadata, session, Paste
|
from lodgeit.database import metadata, session, Paste
|
||||||
from lodgeit.urls import urlmap
|
from lodgeit.urls import urlmap
|
||||||
from lodgeit.controllers import get_controller
|
from lodgeit.controllers import get_controller
|
||||||
|
@ -27,18 +27,18 @@ class PasteController(BaseController):
|
|||||||
"""The 'create a new paste' view."""
|
"""The 'create a new paste' view."""
|
||||||
code = error = ''
|
code = error = ''
|
||||||
language = 'text'
|
language = 'text'
|
||||||
pastes = session.query(Paste)
|
show_captcha = private = False
|
||||||
show_captcha = False
|
parent = None
|
||||||
getform = ctx.request.form.get
|
getform = ctx.request.form.get
|
||||||
|
|
||||||
if ctx.request.method == 'POST':
|
if ctx.request.method == 'POST':
|
||||||
code = getform('code')
|
code = getform('code')
|
||||||
language = getform('language')
|
language = getform('language')
|
||||||
try:
|
|
||||||
parent = pastes.filter(Paste.paste_id ==
|
parent_id = getform('parent')
|
||||||
int(getform('parent'))).first()
|
if parent_id is not None:
|
||||||
except (ValueError, TypeError):
|
parent = Paste.get(parent_id)
|
||||||
parent = None
|
|
||||||
spam = ctx.request.form.get('webpage') or antispam.is_spam(code)
|
spam = ctx.request.form.get('webpage') or antispam.is_spam(code)
|
||||||
if spam:
|
if spam:
|
||||||
error = 'your paste contains spam'
|
error = 'your paste contains spam'
|
||||||
@ -51,16 +51,19 @@ class PasteController(BaseController):
|
|||||||
show_captcha = True
|
show_captcha = True
|
||||||
if code and language and not error:
|
if code and language and not error:
|
||||||
paste = Paste(code, language, parent, ctx.request.user_hash)
|
paste = Paste(code, language, parent, ctx.request.user_hash)
|
||||||
session.save(paste)
|
if 'private' in ctx.request.form:
|
||||||
|
paste.private = True
|
||||||
session.flush()
|
session.flush()
|
||||||
return redirect(paste.url)
|
return redirect(paste.url)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
parent = ctx.request.args.get('reply_to')
|
parent_id = ctx.request.args.get('reply_to')
|
||||||
if parent is not None and parent.isdigit():
|
if parent_id is not None:
|
||||||
parent = pastes.filter(Paste.paste_id == parent).first()
|
parent = Paste.get(parent_id)
|
||||||
code = parent.code
|
if parent is not None:
|
||||||
language = parent.language
|
code = parent.code
|
||||||
|
language = parent.language
|
||||||
|
private = parent.private
|
||||||
|
|
||||||
return render_template('new_paste.html',
|
return render_template('new_paste.html',
|
||||||
languages=LANGUAGES,
|
languages=LANGUAGES,
|
||||||
@ -68,14 +71,14 @@ class PasteController(BaseController):
|
|||||||
code=code,
|
code=code,
|
||||||
language=language,
|
language=language,
|
||||||
error=error,
|
error=error,
|
||||||
show_captcha=show_captcha
|
show_captcha=show_captcha,
|
||||||
|
private=private
|
||||||
)
|
)
|
||||||
|
|
||||||
def show_paste(self, paste_id, raw=False):
|
def show_paste(self, identifier, raw=False):
|
||||||
"""Show an existing paste."""
|
"""Show an existing paste."""
|
||||||
linenos = ctx.request.args.get('linenos') != 'no'
|
linenos = ctx.request.args.get('linenos') != 'no'
|
||||||
pastes = session.query(Paste)
|
paste = Paste.get(identifier)
|
||||||
paste = pastes.filter(Paste.c.paste_id == paste_id).first()
|
|
||||||
if paste is None:
|
if paste is None:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
if raw:
|
if raw:
|
||||||
@ -90,18 +93,18 @@ class PasteController(BaseController):
|
|||||||
linenos=linenos,
|
linenos=linenos,
|
||||||
)
|
)
|
||||||
|
|
||||||
def raw_paste(self, paste_id):
|
def raw_paste(self, identifier):
|
||||||
"""Show an existing paste in raw mode."""
|
"""Show an existing paste in raw mode."""
|
||||||
return self.show_paste(paste_id, raw=True)
|
return self.show_paste(identifier, raw=True)
|
||||||
|
|
||||||
def show_tree(self, paste_id):
|
def show_tree(self, identifier):
|
||||||
"""Display the tree of some related pastes."""
|
"""Display the tree of some related pastes."""
|
||||||
paste = Paste.resolve_root(paste_id)
|
paste = Paste.resolve_root(identifier)
|
||||||
if paste is None:
|
if paste is None:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
return render_template('paste_tree.html',
|
return render_template('paste_tree.html',
|
||||||
paste=paste,
|
paste=paste,
|
||||||
current=paste_id
|
current=identifier
|
||||||
)
|
)
|
||||||
|
|
||||||
def show_all(self, page=1):
|
def show_all(self, page=1):
|
||||||
@ -112,31 +115,30 @@ class PasteController(BaseController):
|
|||||||
return '/all/'
|
return '/all/'
|
||||||
return '/all/%d' % page
|
return '/all/%d' % page
|
||||||
|
|
||||||
pastes = session.query(Paste).order_by(
|
all = Paste.find_all()
|
||||||
Paste.c.pub_date.desc()
|
pastes = all.limit(10).offset(10 * (page -1)).all()
|
||||||
).limit(10).offset(10*(page-1)).all()
|
|
||||||
if not pastes and page != 1:
|
if not pastes and page != 1:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
return render_template('show_all.html',
|
return render_template('show_all.html',
|
||||||
pastes=pastes,
|
pastes=pastes,
|
||||||
pagination=generate_pagination(page, 10,
|
pagination=generate_pagination(page, 10, all.count(), link),
|
||||||
Paste.count(), link),
|
|
||||||
css=get_style(ctx.request)[1]
|
css=get_style(ctx.request)[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
def compare_paste(self, new_id=None, old_id=None):
|
def compare_paste(self, new_id=None, old_id=None):
|
||||||
"""Render a diff view for two pastes."""
|
"""Render a diff view for two pastes."""
|
||||||
# redirect for the compare form box
|
# redirect for the compare form box
|
||||||
if old_id is new_id is None:
|
if old_id is None:
|
||||||
old_id = ctx.request.form.get('old', '-1').lstrip('#')
|
old_id = ctx.request.form.get('old', '-1').lstrip('#')
|
||||||
new_id = ctx.request.form.get('new', '-1').lstrip('#')
|
new_id = ctx.request.form.get('new', '-1').lstrip('#')
|
||||||
return redirect('/compare/%s/%s' % (old_id, new_id))
|
return redirect('/compare/%s/%s' % (old_id, new_id))
|
||||||
pastes = session.query(Paste)
|
|
||||||
old = pastes.filter(Paste.c.paste_id == old_id).first()
|
old = Paste.get(old_id)
|
||||||
new = pastes.filter(Paste.c.paste_id == new_id).first()
|
new = Paste.get(new_id)
|
||||||
if old is None or new is None:
|
if old is None or new is None:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
return render_template('compare_paste.html',
|
return render_template('compare_paste.html',
|
||||||
old=old,
|
old=old,
|
||||||
new=new,
|
new=new,
|
||||||
@ -145,11 +147,12 @@ class PasteController(BaseController):
|
|||||||
|
|
||||||
def unidiff_paste(self, new_id=None, old_id=None):
|
def unidiff_paste(self, new_id=None, old_id=None):
|
||||||
"""Render an udiff for the two pastes."""
|
"""Render an udiff for the two pastes."""
|
||||||
pastes = session.query(Paste)
|
old = Paste.get(old_id)
|
||||||
old = pastes.filter(Paste.c.paste_id == old_id).first()
|
new = Paste.get(new_id)
|
||||||
new = pastes.filter(Paste.c.paste_id == new_id).first()
|
|
||||||
if old is None or new is None:
|
if old is None or new is None:
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
return Response(old.compare_to(new), mimetype='text/plain')
|
return Response(old.compare_to(new), mimetype='text/plain')
|
||||||
|
|
||||||
def set_colorscheme(self):
|
def set_colorscheme(self):
|
||||||
|
@ -34,10 +34,15 @@ def pastes_new_paste(language, code, parent_id=None,
|
|||||||
"""
|
"""
|
||||||
if not language:
|
if not language:
|
||||||
language = get_language_for(filename or '', mimetype or '')
|
language = get_language_for(filename or '', mimetype or '')
|
||||||
paste = Paste(code, language, parent_id)
|
parent = None
|
||||||
session.save(paste)
|
if parent_id:
|
||||||
|
parent = Paste.get(parent_id)
|
||||||
|
if parent is None:
|
||||||
|
raise ValueError('parent paste not found')
|
||||||
|
|
||||||
|
paste = Paste(code, language, parent)
|
||||||
session.flush()
|
session.flush()
|
||||||
return paste.paste_id
|
return paste.identifier
|
||||||
|
|
||||||
|
|
||||||
@exported('pastes.getPaste')
|
@exported('pastes.getPaste')
|
||||||
@ -48,8 +53,7 @@ def pastes_get_paste(paste_id):
|
|||||||
`paste_id`, `code`, `parsed_code`, `pub_date`, `language`,
|
`paste_id`, `code`, `parsed_code`, `pub_date`, `language`,
|
||||||
`parent_id`, `url`.
|
`parent_id`, `url`.
|
||||||
"""
|
"""
|
||||||
paste = session.query(Paste).filter(Paste.c.paste_id ==
|
paste = Paste.get(paste_id)
|
||||||
paste_id).first()
|
|
||||||
if paste is None:
|
if paste is None:
|
||||||
return False
|
return False
|
||||||
return paste.to_xmlrpc_dict()
|
return paste.to_xmlrpc_dict()
|
||||||
@ -58,11 +62,10 @@ def pastes_get_paste(paste_id):
|
|||||||
@exported('pastes.getDiff')
|
@exported('pastes.getDiff')
|
||||||
def pastes_get_diff(old_id, new_id):
|
def pastes_get_diff(old_id, new_id):
|
||||||
"""Compare the two pastes and return an unified diff."""
|
"""Compare the two pastes and return an unified diff."""
|
||||||
pastes = session.query(Paste)
|
old = Paste.get(old_id)
|
||||||
old = pastes.filter(Paste.c.paste_id == old_id).first()
|
new = Paste.get(new_id)
|
||||||
new = pastes.filter(Paste.c.paste_id == new_id).first()
|
|
||||||
if old is None or new is None:
|
if old is None or new is None:
|
||||||
return False
|
raise ValueError('argument error, paste not found')
|
||||||
return old.compare_to(new)
|
return old.compare_to(new)
|
||||||
|
|
||||||
|
|
||||||
@ -72,10 +75,7 @@ def pastes_get_recent(amount=5):
|
|||||||
`amount` pastes.
|
`amount` pastes.
|
||||||
"""
|
"""
|
||||||
amount = min(amount, 20)
|
amount = min(amount, 20)
|
||||||
return [x.to_xmlrpc_dict() for x in
|
return [x.to_xmlrpc_dict() for x in Paste.find_all().limit(amount)]
|
||||||
session.query(Paste).order_by(
|
|
||||||
Paste.pub_date.desc()
|
|
||||||
).limit(amount)]
|
|
||||||
|
|
||||||
|
|
||||||
@exported('pastes.getLast')
|
@exported('pastes.getLast')
|
||||||
|
@ -19,7 +19,7 @@ from sqlalchemy.orm import create_session, mapper, backref, relation
|
|||||||
from sqlalchemy.orm.scoping import ScopedSession
|
from sqlalchemy.orm.scoping import ScopedSession
|
||||||
from werkzeug import cached_property
|
from werkzeug import cached_property
|
||||||
|
|
||||||
from lodgeit.utils import _local_manager, ctx
|
from lodgeit.utils import _local_manager, ctx, generate_paste_hash
|
||||||
from lodgeit.lib.highlighting import highlight, LANGUAGES
|
from lodgeit.lib.highlighting import highlight, LANGUAGES
|
||||||
|
|
||||||
|
|
||||||
@ -29,9 +29,10 @@ metadata = MetaData()
|
|||||||
|
|
||||||
pastes = Table('pastes', metadata,
|
pastes = Table('pastes', metadata,
|
||||||
Column('paste_id', Integer, primary_key=True),
|
Column('paste_id', Integer, primary_key=True),
|
||||||
|
Column('private_id', String(40), unique=True, nullable=True),
|
||||||
Column('code', Text),
|
Column('code', Text),
|
||||||
Column('parent_id', Integer, ForeignKey('pastes.paste_id'),
|
Column('parent_id', Integer, ForeignKey('pastes.paste_id'),
|
||||||
nullable=True),
|
nullable=True),
|
||||||
Column('pub_date', DateTime),
|
Column('pub_date', DateTime),
|
||||||
Column('language', String(30)),
|
Column('language', String(30)),
|
||||||
Column('user_hash', String(40), nullable=True),
|
Column('user_hash', String(40), nullable=True),
|
||||||
@ -40,6 +41,7 @@ pastes = Table('pastes', metadata,
|
|||||||
|
|
||||||
|
|
||||||
class Paste(object):
|
class Paste(object):
|
||||||
|
"""Represents a paste."""
|
||||||
|
|
||||||
def __init__(self, code, language, parent=None, user_hash=None):
|
def __init__(self, code, language, parent=None, user_hash=None):
|
||||||
if language not in LANGUAGES:
|
if language not in LANGUAGES:
|
||||||
@ -54,16 +56,83 @@ class Paste(object):
|
|||||||
self.handled = False
|
self.handled = False
|
||||||
self.user_hash = user_hash
|
self.user_hash = user_hash
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(identifier):
|
||||||
|
"""Return the paste for an identifier. Private pastes must be loaded
|
||||||
|
with their unique hash and public with the paste id.
|
||||||
|
"""
|
||||||
|
if isinstance(identifier, basestring) and not identifier.isdigit():
|
||||||
|
return Paste.query.filter(Paste.private_id == identifier).first()
|
||||||
|
return Paste.query.filter(
|
||||||
|
(Paste.paste_id == int(identifier)) &
|
||||||
|
(Paste.private_id == None)
|
||||||
|
).first()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def find_all():
|
||||||
|
"""Return a query for all public pastes ordered by the publication
|
||||||
|
date in reverse order.
|
||||||
|
"""
|
||||||
|
return Paste.query.filter(Paste.private_id == None) \
|
||||||
|
.order_by(Paste.pub_date.desc())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def count():
|
||||||
|
"""COunt all pastes."""
|
||||||
|
s = select([func.count(pastes.c.paste_id)])
|
||||||
|
return session.execute(s).fetchone()[0]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def resolve_root(identifier):
|
||||||
|
"""Find the root paste for a paste tree."""
|
||||||
|
paste = Paste.get(identifier)
|
||||||
|
if paste is None:
|
||||||
|
return
|
||||||
|
while paste.parent_id is not None:
|
||||||
|
paste = paste.parent
|
||||||
|
return paste
|
||||||
|
|
||||||
|
def _get_private(self):
|
||||||
|
return self.private_id is not None
|
||||||
|
|
||||||
|
def _set_private(self, value):
|
||||||
|
if not value:
|
||||||
|
self.private_id = None
|
||||||
|
return
|
||||||
|
if self.private_id is None:
|
||||||
|
while 1:
|
||||||
|
self.private_id = generate_paste_hash()
|
||||||
|
paste = Paste.query.filter(Paste.private_id ==
|
||||||
|
self.private_id).first()
|
||||||
|
if paste is None:
|
||||||
|
break
|
||||||
|
private = property(_get_private, _set_private, doc='''
|
||||||
|
The private status of the paste. If the paste is private it gets
|
||||||
|
a unique hash as identifier, otherwise an integer.
|
||||||
|
''')
|
||||||
|
del _get_private, _set_private
|
||||||
|
|
||||||
|
@property
|
||||||
|
def identifier(self):
|
||||||
|
"""The paste identifier. This is a string, the same the `get`
|
||||||
|
method accepts.
|
||||||
|
"""
|
||||||
|
if self.private:
|
||||||
|
return self.private_id
|
||||||
|
return str(self.paste_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
return '/show/%d/' % self.paste_id
|
"""The URL to the paste."""
|
||||||
|
return '/show/%s/' % self.identifier
|
||||||
|
|
||||||
def compare_to(self, other, context_lines=4, template=False):
|
def compare_to(self, other, context_lines=4, template=False):
|
||||||
|
"""Compare the paste with another paste."""
|
||||||
udiff = u'\n'.join(difflib.unified_diff(
|
udiff = u'\n'.join(difflib.unified_diff(
|
||||||
self.code.splitlines(),
|
self.code.splitlines(),
|
||||||
other.code.splitlines(),
|
other.code.splitlines(),
|
||||||
fromfile='Paste #%d' % self.paste_id,
|
fromfile='Paste #%s' % self.identifier,
|
||||||
tofile='Paste #%d' % other.paste_id,
|
tofile='Paste #%s' % other.identifier,
|
||||||
lineterm='',
|
lineterm='',
|
||||||
n=context_lines
|
n=context_lines
|
||||||
))
|
))
|
||||||
@ -75,9 +144,11 @@ class Paste(object):
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def parsed_code(self):
|
def parsed_code(self):
|
||||||
|
"""The paste as rendered code."""
|
||||||
return highlight(self.code, self.language)
|
return highlight(self.code, self.language)
|
||||||
|
|
||||||
def to_xmlrpc_dict(self):
|
def to_xmlrpc_dict(self):
|
||||||
|
"""Convert the paste into a dict for XMLRCP."""
|
||||||
from lodgeit.lib.xmlrpc import strip_control_chars
|
from lodgeit.lib.xmlrpc import strip_control_chars
|
||||||
return {
|
return {
|
||||||
'paste_id': self.paste_id,
|
'paste_id': self.paste_id,
|
||||||
@ -90,6 +161,7 @@ class Paste(object):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def render_preview(self):
|
def render_preview(self):
|
||||||
|
"""Render a preview for this paste."""
|
||||||
try:
|
try:
|
||||||
start = self.parsed_code.index('</pre>')
|
start = self.parsed_code.index('</pre>')
|
||||||
code = self.parsed_code[
|
code = self.parsed_code[
|
||||||
@ -110,7 +182,7 @@ class Paste(object):
|
|||||||
Paste.user_hash == ctx.request.user_hash
|
Paste.user_hash == ctx.request.user_hash
|
||||||
)
|
)
|
||||||
|
|
||||||
paste_list = session.query(Paste).filter(and_(
|
paste_list = Paste.query.filter(and_(
|
||||||
Paste.parent_id.in_(s),
|
Paste.parent_id.in_(s),
|
||||||
Paste.handled == False,
|
Paste.handled == False,
|
||||||
Paste.user_hash != ctx.request.user_hash,
|
Paste.user_hash != ctx.request.user_hash,
|
||||||
@ -121,24 +193,8 @@ class Paste(object):
|
|||||||
values={'handled': True}))
|
values={'handled': True}))
|
||||||
return paste_list
|
return paste_list
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def count():
|
|
||||||
s = select([func.count(pastes.c.paste_id)])
|
|
||||||
return session.execute(s).fetchone()[0]
|
|
||||||
|
|
||||||
@staticmethod
|
session.mapper(Paste, pastes, properties={
|
||||||
def resolve_root(paste_id):
|
|
||||||
pastes = session.query(Paste)
|
|
||||||
while True:
|
|
||||||
paste = pastes.filter(Paste.c.paste_id == paste_id).first()
|
|
||||||
if paste is None:
|
|
||||||
return
|
|
||||||
if paste.parent_id is None:
|
|
||||||
return paste
|
|
||||||
paste_id = paste.parent_id
|
|
||||||
|
|
||||||
|
|
||||||
mapper(Paste, pastes, properties={
|
|
||||||
'children': relation(Paste,
|
'children': relation(Paste,
|
||||||
primaryjoin=pastes.c.parent_id==pastes.c.paste_id,
|
primaryjoin=pastes.c.parent_id==pastes.c.paste_id,
|
||||||
cascade='all',
|
cascade='all',
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
The URL mapping.
|
The URL mapping.
|
||||||
|
|
||||||
:copyright: 2007 by Armin Ronacher.
|
:copyright: 2007-2008 by Armin Ronacher.
|
||||||
:license: BSD
|
:license: BSD
|
||||||
"""
|
"""
|
||||||
from werkzeug.routing import Map, Rule
|
from werkzeug.routing import Map, Rule
|
||||||
@ -13,12 +13,12 @@ from werkzeug.routing import Map, Rule
|
|||||||
urlmap = Map([
|
urlmap = Map([
|
||||||
# paste interface
|
# paste interface
|
||||||
Rule('/', endpoint='pastes/new_paste'),
|
Rule('/', endpoint='pastes/new_paste'),
|
||||||
Rule('/show/<int:paste_id>/', endpoint='pastes/show_paste'),
|
Rule('/show/<identifier>/', endpoint='pastes/show_paste'),
|
||||||
Rule('/raw/<int:paste_id>/', endpoint='pastes/raw_paste'),
|
Rule('/raw/<identifier>/', endpoint='pastes/raw_paste'),
|
||||||
Rule('/compare/', endpoint='pastes/compare_paste'),
|
Rule('/compare/', endpoint='pastes/compare_paste'),
|
||||||
Rule('/compare/<int:new_id>/<int:old_id>/', endpoint='pastes/compare_paste'),
|
Rule('/compare/<new_id>/<old_id>/', endpoint='pastes/compare_paste'),
|
||||||
Rule('/unidiff/<int:new_id>/<int:old_id>/', endpoint='pastes/unidiff_paste'),
|
Rule('/unidiff/<new_id>/<old_id>/', endpoint='pastes/unidiff_paste'),
|
||||||
Rule('/tree/<int:paste_id>/', endpoint='pastes/show_tree'),
|
Rule('/tree/<identifier>/', endpoint='pastes/show_tree'),
|
||||||
|
|
||||||
# captcha for new paste
|
# captcha for new paste
|
||||||
Rule('/_captcha.png', endpoint='pastes/show_captcha'),
|
Rule('/_captcha.png', endpoint='pastes/show_captcha'),
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
:copyright: 2007 by Christopher Grebs.
|
:copyright: 2007 by Christopher Grebs.
|
||||||
:license: BSD
|
:license: BSD
|
||||||
"""
|
"""
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
from os import path
|
from os import path
|
||||||
try:
|
try:
|
||||||
@ -15,6 +16,7 @@ try:
|
|||||||
except:
|
except:
|
||||||
from sha import new as sha1
|
from sha import new as sha1
|
||||||
from random import random
|
from random import random
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from werkzeug import Local, LocalManager, LocalProxy, \
|
from werkzeug import Local, LocalManager, LocalProxy, \
|
||||||
Request as RequestBase, Response
|
Request as RequestBase, Response
|
||||||
@ -30,9 +32,12 @@ jinja_environment = Environment(loader=FileSystemLoader(
|
|||||||
path.join(path.dirname(__file__), 'views')))
|
path.join(path.dirname(__file__), 'views')))
|
||||||
|
|
||||||
|
|
||||||
|
_word_only = partial(re.compile(r'[^a-zA-Z0-9]').sub, '')
|
||||||
|
|
||||||
|
|
||||||
def datetimeformat(obj):
|
def datetimeformat(obj):
|
||||||
"""Helper filter for the template"""
|
"""Helper filter for the template"""
|
||||||
return obj.strftime('%Y-%m-%d %H:%M')
|
return obj.strftime('%Y-%m-%d @ %H:%M')
|
||||||
|
|
||||||
jinja_environment.filters['datetimeformat'] = datetimeformat
|
jinja_environment.filters['datetimeformat'] = datetimeformat
|
||||||
|
|
||||||
@ -42,6 +47,16 @@ def generate_user_hash():
|
|||||||
return sha1('%s|%s' % (random(), time.time())).hexdigest()
|
return sha1('%s|%s' % (random(), time.time())).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def generate_paste_hash():
|
||||||
|
"""Generates a more or less unique-truncated SHA1 hash."""
|
||||||
|
while 1:
|
||||||
|
digest = sha1('%s|%s' % (random(), time.time())).digest()
|
||||||
|
val = _word_only(digest.encode('base64').strip().splitlines()[0])[:20]
|
||||||
|
# sanity check. number only not allowed (though unlikely)
|
||||||
|
if not val.isdigit():
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
class Request(RequestBase):
|
class Request(RequestBase):
|
||||||
"""Subclass of the `Request` object. automatically creates a new
|
"""Subclass of the `Request` object. automatically creates a new
|
||||||
`user_hash` and sets `first_visit` to `True` if it's a new user.
|
`user_hash` and sets `first_visit` to `True` if it's a new user.
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<p>
|
<p>
|
||||||
Differences between the pastes
|
Differences between the pastes
|
||||||
<a href="{{ old.url|e }}">#{{ old.paste_id }}</a> ({{ old.pub_date|datetimeformat }})
|
<a href="{{ old.url|e }}">#{{ old.identifier }}</a> ({{ old.pub_date|datetimeformat }})
|
||||||
and <a href="{{ new.url|e }}">#{{ new.paste_id }}</a> ({{ new.pub_date|datetimeformat }}). Download as <a href="/unidiff/{{ old.paste_id }}/{{ new.paste_id }}/">unified diff</a>.
|
and <a href="{{ new.url|e }}">#{{ new.identifier }}</a> ({{ new.pub_date|datetimeformat }}). Download as <a href="/unidiff/{{ old.identifier }}/{{ new.identifier }}/">unified diff</a>.
|
||||||
</p>
|
</p>
|
||||||
{% if diff.chunks %}
|
{% if diff.chunks %}
|
||||||
<table class="diff">
|
<table class="diff">
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
{%- if show_captcha %}
|
{%- if show_captcha %}
|
||||||
<div class="captcha">
|
<div class="captcha">
|
||||||
<p>Please fill out the CAPTCHA to proceed:</p>
|
<p>Please fill out the CAPTCHA to proceed:</p>
|
||||||
<img src="/_captcha.png" alt="a captcha you can't see. Sorry :(">
|
<img src="{{ url_for('pastes/captcha')
|
||||||
|
}}" alt="a captcha you can't see. Sorry :(">
|
||||||
<input type="text" name="captcha" size="20">
|
<input type="text" name="captcha" size="20">
|
||||||
</div>
|
</div>
|
||||||
{%- else %}
|
{%- else %}
|
||||||
@ -19,7 +20,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- if parent %}
|
{%- if parent %}
|
||||||
<input type="hidden" name="parent" value="{{ parent.paste_id }}">
|
<input type="hidden" name="parent" value="{{ parent.identifier }}">
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<textarea name="code" rows="10" cols="80">{{ code|e }}</textarea>
|
<textarea name="code" rows="10" cols="80">{{ code|e }}</textarea>
|
||||||
<select name="language">
|
<select name="language">
|
||||||
@ -32,5 +33,7 @@
|
|||||||
<input type="submit" value="Paste!">
|
<input type="submit" value="Paste!">
|
||||||
<input type="button" value="▲" onclick="LodgeIt.resizeTextarea(-100)">
|
<input type="button" value="▲" onclick="LodgeIt.resizeTextarea(-100)">
|
||||||
<input type="button" value="▼" onclick="LodgeIt.resizeTextarea(100)">
|
<input type="button" value="▼" onclick="LodgeIt.resizeTextarea(100)">
|
||||||
|
<input type="checkbox" name="private" id="private"{% if private
|
||||||
|
%} checked{% endif %}><label for="private">make this paste private</label>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<ul class="paste_list">
|
<ul class="paste_list">
|
||||||
{% for paste in pastes %}
|
{% for paste in pastes %}
|
||||||
<li class="{{ loop.cycle('even', 'odd') }}"><p><a href="{{ paste.url|e
|
<li class="{{ loop.cycle('even', 'odd') }}"><p><a href="{{ paste.url|e
|
||||||
}}">Paste #{{ paste.paste_id }}</a>,
|
}}">Paste #{{ paste.identifier }}</a>,
|
||||||
pasted on {{ paste.pub_date|datetimeformat }}</p>
|
pasted on {{ paste.pub_date|datetimeformat }}</p>
|
||||||
{{ paste.render_preview() }}</li>
|
{{ paste.render_preview() }}</li>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% set page_title = 'Paste #%d'|format(paste.paste_id) %}
|
{% set page_title = 'Paste #' ~ paste.identifier %}
|
||||||
{% set active_page = 'all' %}
|
{% set active_page = 'all' %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="related">
|
<div class="related">
|
||||||
@ -7,26 +7,26 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<p>posted on {{ paste.pub_date|datetimeformat }}</p>
|
<p>posted on {{ paste.pub_date|datetimeformat }}</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a class="autoclose" href="/?reply_to={{ paste.paste_id }}">reply to this paste</a></li>
|
<li><a class="autoclose" href="/?reply_to={{ paste.identifier }}">reply to this paste</a></li>
|
||||||
{% if paste.parent %}
|
{% if paste.parent %}
|
||||||
<li><a class="autoclose" href="/compare/{{ paste.paste_id }}/{{
|
<li><a class="autoclose" href="/compare/{{ paste.identifier }}/{{
|
||||||
paste.parent.paste_id }}/">compare it with the parent paste</a></li>
|
paste.parent.identifier }}/">compare it with the parent paste</a></li>
|
||||||
<li><a class="autoclose" href="{{ paste.parent.url|e }}">look at the parent paste</a></li>
|
<li><a class="autoclose" href="{{ paste.parent.url|e }}">look at the parent paste</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if paste.children %}
|
{% if paste.children %}
|
||||||
<li>the following pastes replied to this paste:
|
<li>the following pastes replied to this paste:
|
||||||
{% for child in paste.children %}
|
{% for child in paste.children %}
|
||||||
<a class="autoclose" href="{{ child.url|e }}">#{{ child.paste_id }}</a>
|
<a class="autoclose" href="{{ child.url|e }}">#{{ child.identifier }}</a>
|
||||||
{%- if not loop.last %},{% endif -%}
|
{%- if not loop.last %},{% endif -%}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if paste.parent or paste.children %}
|
{% if paste.parent or paste.children %}
|
||||||
<li><a href="/tree/{{ paste.paste_id }}/">show paste tree</a></li>
|
<li><a href="/tree/{{ paste.identifier }}/">show paste tree</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a href="/raw/{{ paste.paste_id }}/">download paste</a></li>
|
<li><a href="/raw/{{ paste.identifier }}/">download paste</a></li>
|
||||||
<li>compare with paste <form action="/compare/" method="post">
|
<li>compare with paste <form action="/compare/" method="post">
|
||||||
<input type="hidden" name="old" value="{{ paste.paste_id }}">
|
<input type="hidden" name="old" value="{{ paste.identifier }}">
|
||||||
<input type="text" name="new" value="#">
|
<input type="text" name="new" value="#">
|
||||||
<input type="submit" value="compare">
|
<input type="submit" value="compare">
|
||||||
</form></li>
|
</form></li>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user