From 99f6fb15a5aaa326a729e73974006d1064a5582f Mon Sep 17 00:00:00 2001 From: "B. Stack" Date: Fri, 11 Feb 2022 20:56:59 -0500 Subject: use UUID for paste id, and more js removal Using uuids means that titles need to be used for displaying "replies," "in response to," and so on. --- README-bgstack15.md | 1 - pastebin.py | 68 +++++++++++++++++++++++++++++++++++++++++------ static/pastebin.js | 47 -------------------------------- templates/layout.html | 5 ---- templates/new_paste.html | 2 +- templates/show_paste.html | 21 +++++---------- 6 files changed, 67 insertions(+), 77 deletions(-) delete mode 100644 static/pastebin.js diff --git a/README-bgstack15.md b/README-bgstack15.md index 34137f5..199b254 100644 --- a/README-bgstack15.md +++ b/README-bgstack15.md @@ -11,7 +11,6 @@ Run server. # Improvements I still need to practice these: -* Support editing the title? * Fix the private bins problem: they always return 403 * Support deleting somehow: from an admin panel, or a link on the page? * use UUIDs for link instead of sequential integers? diff --git a/pastebin.py b/pastebin.py index 4d5c231..cd67265 100644 --- a/pastebin.py +++ b/pastebin.py @@ -3,6 +3,35 @@ from itsdangerous import Signer from flask import (Flask, request, url_for, redirect, g, render_template, session, abort) from flask_sqlalchemy import SQLAlchemy +## ripped from https://stackoverflow.com/questions/183042/how-can-i-use-uuids-in-sqlalchemy/812363#812363 +from sqlalchemy import types +from sqlalchemy.dialects.mysql.base import MSBinary +from sqlalchemy.schema import Column +import uuid +class UUID(types.TypeDecorator): + impl = MSBinary + def __init__(self): + self.impl.length = 16 + types.TypeDecorator.__init__(self,length=self.impl.length) + def process_bind_param(self,value,dialect=None): + if value and isinstance(value,uuid.UUID): + return value.bytes + elif value and not isinstance(value,uuid.UUID): + raise ValueError('value %s is not a valid uuid.UUID' % value) + else: + return None + def process_result_value(self,value,dialect=None): + if value: + return uuid.UUID(bytes=value) + else: + return None + def is_mutable(self): + return False +id_column_name = "id" +def id_column(): + #import uuid + return Column(id_column_name,UUID(),primary_key=True,default=uuid.uuid4) + app = Flask(__name__) app.config.from_pyfile('config.cfg') db = SQLAlchemy(app) @@ -20,13 +49,13 @@ def check_user_status(): g.user = User.query.get(session['user_id']) class Paste(db.Model): - id = db.Column(db.Integer, primary_key=True) + id = id_column() code = db.Column(db.Text) title = db.Column(db.Text) pub_date = db.Column(db.DateTime) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) is_private = db.Column(db.Boolean) - parent_id = db.Column(db.Integer, db.ForeignKey('paste.id')) + parent_id = db.Column(UUID(), db.ForeignKey('paste.id')) parent = db.relationship('Paste', lazy=True, backref='children', uselist=False, remote_side=[id]) def __init__(self, user, code, title, parent=None, is_private=False): @@ -46,9 +75,12 @@ class User(db.Model): @app.route('/', methods=['GET', 'POST']) def new_paste(): parent = None - reply_to = request.args.get('reply_to', type=int) + reply_to = request.args.get('reply_to') if reply_to is not None: - parent = Paste.query.get(reply_to) + try: + parent = Paste.query.get(uuid.UUID(reply_to)) + except: + parent = Paste.query.get(reply_to) if request.method == 'POST' and request.form['code']: is_private = bool(request.form.get('is_private')) title = "Untitled paste" @@ -62,10 +94,13 @@ def new_paste(): return redirect(url_for('show_paste', paste_id=paste.id, s=sign)) return render_template('new_paste.html', parent=parent) -@app.route('//') -@app.route('/') +@app.route('//') +@app.route('/') def show_paste(paste_id): - paste = Paste.query.options(db.eagerload('children')).get_or_404(paste_id) + try: + paste = Paste.query.options(db.eagerload('children')).get_or_404(paste_id) + except: + paste = Paste.query.options(db.eagerload('children')).get_or_404(uuid.UUID(paste_id)) if paste.is_private: try: sign = request.args.get('s', '') @@ -73,4 +108,21 @@ def show_paste(paste_id): Signer(app.secret_key, salt='jackson').unsign(sign).decode("utf-8") except: abort(403) - return render_template('show_paste.html', paste=paste) + parent = None + if paste.parent_id: + try: + parent = Paste.query.get(uuid.UUID(paste.parent_id)) + except: + parent = Paste.query.get(paste.parent_id) + children = [] + if paste.children: + for i in paste.children: + j = None + try: + j = Paste.query.get(uuid.UUID(i.id)) + except: + j = Paste.query.get(i.id) + if j: + k = j.id, j.title + children.append(k) + return render_template('show_paste.html', paste=paste, parent=parent, children=children) diff --git a/static/pastebin.js b/static/pastebin.js deleted file mode 100644 index 4412595..0000000 --- a/static/pastebin.js +++ /dev/null @@ -1,47 +0,0 @@ -(function() { - var global = this; - - var lib = global.pastebin = { - urlRoot : '/', - - autoHideFlashes : function() { - var flashes = $('p.flash:visible').hide(); - if (flashes.length) { - flashes.slideDown('fast'); - window.setTimeout(function() { - flashes.slideUp('slow'); - }, 5000); - } - }, - - flash : function(message) { - $('

') - .append(message) - .hide() - .insertAfter('ul.nav') - .slideDown('fast'); - }, - - onNewReply : function(reply, type) { - var pasteDescription = ''; - if (type == 'user') { - pasteDescription = 'your paste #' + reply.paste_id + ''; - } else { - pasteDescription = 'this paste'; - } - var msg = $('New reply to ' + pasteDescription + ': #' + reply.reply_id + ''); - if (reply.author) - msg.append($('').text(' ' + reply.author)) - lib.flash(msg); - } - - }; - - - $(function() { - /* animate the server side flashes a bit */ - lib.autoHideFlashes(); - }); -})(); diff --git a/templates/layout.html b/templates/layout.html index 6b53bb3..bfe8b05 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -6,11 +6,6 @@ -{# - - - -#}