codesmidgen/codesmidgen/views.py

149 lines
4.4 KiB
Python

# -*- coding: utf-8 -*-
"""
The views
"""
import logging
import secrets
import string
from datetime import timedelta, datetime
from quart import Blueprint, Response, redirect, request, flash, make_response, current_app, render_template
from pygments import highlight
from pygments.formatters.html import HtmlFormatter
from pygments.lexers import get_lexer_by_name, get_all_lexers
from sqlalchemy import or_
from codesmidgen.db import session
from codesmidgen.models import Smidgen
log = logging.getLogger(__name__)
views = Blueprint('views', __name__)
EXPIRY_DELTAS = {
'10min': timedelta(minutes=10),
'1d': timedelta(days=1),
'1w': timedelta(days=7),
'2w': timedelta(days=14),
'1m': timedelta(days=30)
}
def _generate_short_url() -> str:
"""
Encode the URL
"""
alphabet = string.ascii_lowercase + string.digits
short_url = ''.join(secrets.choice(alphabet) for _ in range(8))
return short_url
@views.route('/', methods=['GET'])
async def index() -> str:
"""
Add a new sticky note
"""
all_lexers = [(lexer[1][0], lexer[0]) for lexer in get_all_lexers() if len(lexer) > 1 and len(lexer[1]) > 0]
all_lexers.sort(key=lambda x: x[1].lower())
recaptcha_site_key = current_app.config.get('RECAPTCHA_SITE_KEY')
return await render_template('index.html', lexers=all_lexers, recaptcha_site_key=recaptcha_site_key)
@views.route('/notes', methods=['GET'])
async def notes() -> str:
"""
Show a list of recent notes
"""
notes = Smidgen.query\
.filter(or_(Smidgen.expiry == None, Smidgen.expiry < datetime.utcnow()))\
.filter(~Smidgen.private)\
.order_by(Smidgen.created.desc())\
.limit(10) # noqa: E711
return await render_template('notes.html', notes=notes)
@views.route('/about', methods=['GET'])
async def about() -> str:
"""
Show the about page
"""
return await render_template('about.html')
@views.route('/', methods=['POST'])
async def save() -> Response:
"""
Save a sticky note
"""
form = await request.form
if form.get('computer') and form['computer'].lower() != 'no':
return redirect('/')
# Save the note
try:
created = datetime.utcnow()
expiry = created + EXPIRY_DELTAS.get(form['expiry'], EXPIRY_DELTAS['1d'])
# Generate a short url, and check if it exists in the db
url = _generate_short_url()
while Smidgen.query.filter(Smidgen.url == url).first():
url = _generate_short_url()
# Create a new note
note = Smidgen(
title=form.get('title', ''),
source=form['source'],
lexer=form['language'],
created=created,
expiry=expiry,
private=True,
url=url
)
session.add(note)
session.commit()
return redirect('/' + note.url)
except Exception as e:
await flash(str(e), 'danger')
session.rollback()
return redirect('/')
@views.route('/<string:note_url>', methods=['GET'])
async def view(note_url: str) -> Response | str:
"""
Show a sticky note
:param note_url: The note to show
"""
note = Smidgen.query.filter(Smidgen.url == note_url).first()
if not note:
await flash('That note does not exist', 'danger')
return redirect('/')
lexer = get_lexer_by_name(note.lexer)
formatter = HtmlFormatter(linenos=True, cssclass='source')
result = highlight(note.source, lexer, formatter)
return await render_template('view.html', note=note, source=result)
@views.route('/raw/<string:note_url>', methods=['GET'])
async def raw(note_url: str) -> Response | str:
"""
Show the raw version of a sticky note
:param note_url: The note to show
"""
note = Smidgen.query.filter(Smidgen.url == note_url).scalar()
if not note:
await flash('That note does not exist', 'danger')
return redirect('/')
return await render_template('raw.html', source=note.source), 200, {'Content-Type': 'text/plain; charset=utf-8'}
@views.route('/pygments.css', methods=['GET'])
async def pygments_css() -> Response:
"""
Return the Pygments CSS to the browser
"""
response = await make_response(HtmlFormatter(style='nord').get_style_defs())
response.headers['Content-Type'] = 'text/css'
return response