Author: Pedro Lucas Porcellis <porcellis@eletrotupi.com>
Rename from core to rascunho for better packaging
app.py | 4 ++-- | 0 | 8 ++++---- | 4 ++-- | 4 ++-- | 0 | 4 ++-- | 0 | 0 | 0 | 0 | 0 | 0 | 2 +-
diff --git a/app.py b/app.py index e9b5046d9e4bc0e6ec0b2d601613823a5a76db5e..785bbe0945b4502d3613ff1d9473913f4d8dde6d 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,5 @@ -from core.app import app -from core.config import env +from rascunho.app import app +from rascunho.config import env if __name__ == '__main__': debug = False diff --git a/core/__init__.py b/core/__init__.py deleted file mode 100644 index c07c45996e3bd354c2448c09f07c6f2cfe45d922..0000000000000000000000000000000000000000 --- a/core/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .app import app diff --git a/core/app.py b/core/app.py deleted file mode 100644 index 1b3d402484864cf17f7f021a3aa94768a2486270..0000000000000000000000000000000000000000 --- a/core/app.py +++ /dev/null @@ -1,84 +0,0 @@ -from flask import Flask, abort, render_template, request -from jinja2 import Markup -import locale -from core.config import read_from_config, env -from core.database import db, init_database -import mistune -import humanize -from datetime import datetime, timedelta -from pytz import timezone - -class Rascunho(Flask): - def __init__(self, *args, **kwargs): - super().__init__(__name__, *args, **kwargs) - - init_database() - - try: - # TODO: Use the locale config, from my local package it doesn't - # work as the package is out-of-date on Arch's Community Repository - humanize.i18n.activate("pt_BR") - locale.setlocale(locale.LC_ALL, read_from_config("locale")) - locale.setlocale(locale.LC_TIME, read_from_config("locale")) - except: - pass - - - from core.blueprints.basic import basic - from core.blueprints.api import api - - self.register_blueprint(basic) - self.register_blueprint(api) - - @self.template_filter() - def human_date(d): - if not d: - return 'Nunca' - - local_tz = timezone(str(read_from_config("timezone"))) - d = d.replace(tzinfo=timezone('UTC')) - local_date = d.astimezone(local_tz) - - if isinstance(d, timedelta): - return Markup('<span title="{}">{}</span>'.format( - f'{d.seconds} segundos', humanize.naturaldelta(d))) - - return Markup('<span title="{}">{}</span>'.format( - d.strftime('%Y-%m-%d %H:%M:%S UTC'), - humanize.naturaltime( - datetime.now().astimezone(local_tz) - local_date - ))) - - @self.template_filter() - def md(text): - return mistune.markdown(text) - - @self.errorhandler(422) - def handle_unprocessable_entity(e): - if request.path.startswith("/api"): - return { "errors": [ { "reason": "422 Unprocessable Entity" } ] }, 422 - - return render_template("unprocessable_entity.html", 422) - - @self.errorhandler(500) - def handle_internal_server_error(e): - if request.path.startswith("/api"): - return { "errors": [ { "reason": "500 Internal Server Error" } ] }, 500 - - return render_template("internal_error.html", 500) - - @self.errorhandler(404) - def handle_not_found(e): - if request.path.startswith("/api"): - return { "errors": [ { "reason": "404 Not Found" } ] }, 404 - - return render_template("not_found.html"), 404 - - @self.context_processor - def inject(): - return { - "env": env - } - - -app = Rascunho() diff --git a/core/blueprints/__init__.py b/core/blueprints/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 Binary files a/core/blueprints/__init__.py and /dev/null differ diff --git a/core/blueprints/api.py b/core/blueprints/api.py deleted file mode 100644 index 3d49d78c2e7615844a93c6c3c6ef46bb9b991b8b..0000000000000000000000000000000000000000 --- a/core/blueprints/api.py +++ /dev/null @@ -1,46 +0,0 @@ -from flask import Blueprint, abort, request -from hashlib import sha1 -from core.types.document import Document -from core.database import db -import json - -api = Blueprint("apiv1", __name__) - -@api.route('/api/v1', methods = ['POST']) -def create(): - params = json.loads(request.data.decode('utf-8')) - - doc = None - content = params.get('text') - - if not content: - abort(422) - - sha = sha1() - sha.update(content.encode()) - sha.update(request.remote_addr.encode()) - - existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none() - - if existing_doc: - doc = existing_doc - else: - doc = Document() - - doc.sha = sha.hexdigest() - doc.content = content - - db.add(doc) - db.commit() - db.flush() - - return doc.to_dict(), 201 - -@api.route('/api/v1/<sha>', methods = ['GET']) -def show(sha): - doc = Document.query.filter(Document.sha == sha).one_or_none() - - if not doc: - abort(404) - - return doc.to_dict(), 200 diff --git a/core/blueprints/basic.py b/core/blueprints/basic.py deleted file mode 100644 index 37a0fa7cbe2a94e2ec52846c1fee74ef54204688..0000000000000000000000000000000000000000 --- a/core/blueprints/basic.py +++ /dev/null @@ -1,59 +0,0 @@ -from flask import Blueprint, render_template, request, abort, Response, redirect, url_for -from core.database import db -from core.types.document import Document -from hashlib import sha1 - -basic = Blueprint('basic', __name__) - -@basic.route("/", methods = ['GET', 'POST']) -def index(): - if request.method == "GET": - doc = Document.query.order_by(Document.created_at.asc()).first() - return render_template('index.html', doc = doc) - else: - return create(request.form) - -@basic.route("/<sha>", methods = ['GET']) -def show(sha): - doc = Document.query.filter(Document.sha == sha).one_or_none() - - if not doc: - abort(404) - - return render_template('preview.html', doc = doc) - -@basic.route("/<sha>/raw", methods = ['GET']) -def raw(sha): - doc = Document.query.filter(Document.sha == sha).one_or_none() - - if not doc: - abort(404) - - return Response(doc.content, mimetype="text/plain") - -def create(params): - doc = None - content = params['text'] - - if not content: - abort(422) - - sha = sha1() - sha.update(content.encode()) - sha.update(request.remote_addr.encode()) - - existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none() - - if existing_doc: - doc = existing_doc - else: - doc = Document() - - doc.sha = sha.hexdigest() - doc.content = content - - db.add(doc) - db.commit() - db.flush() - - return redirect(url_for('basic.show', sha = doc.sha)) diff --git a/core/config.py b/core/config.py deleted file mode 100644 index 30c507fa0d04934468781a4121749e2a81f8793f..0000000000000000000000000000000000000000 --- a/core/config.py +++ /dev/null @@ -1,8 +0,0 @@ -from configparser import ConfigParser - -config = ConfigParser() -config.read_file(open('config.ini')) - -env = config['meta']['env'] - -read_from_config = lambda key: config.get(env, key) diff --git a/core/database.py b/core/database.py deleted file mode 100644 index 1c68f5788eadcf97c0c3f878188d8ba70aaca780..0000000000000000000000000000000000000000 --- a/core/database.py +++ /dev/null @@ -1,33 +0,0 @@ -from sqlalchemy import create_engine, event -from sqlalchemy.orm import sessionmaker, scoped_session -from sqlalchemy.ext.declarative import declarative_base - -from datetime import datetime - -from core.config import read_from_config - -engine = create_engine(read_from_config('connection-string'), echo=True) -db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) - -Base = declarative_base() -Base.query = db.query_property() - -def init_database(): - @event.listens_for(Base, 'before_insert', propagate=True) - def before_insert(mapper, connection, target): - if hasattr(target, '_no_autoupdate'): - return - if hasattr(target, 'created_at'): - target.created_at = datetime.utcnow() - if hasattr(target, 'updated_at'): - target.updated_at = datetime.utcnow() - - @event.listens_for(Base, 'before_update', propagate=True) - def before_insert(mapper, connection, target): - if hasattr(target, '_no_autoupdate'): - return - if hasattr(target, 'updated_at'): - target.updated_at = datetime.utcnow() - - import core.types - Base.metadata.create_all(bind=engine) diff --git a/core/static/rascunho.css b/core/static/rascunho.css deleted file mode 100644 index 2fe65ac733b7c1f3f6d369e47398e7095cb512dc..0000000000000000000000000000000000000000 --- a/core/static/rascunho.css +++ /dev/null @@ -1,70 +0,0 @@ -.py { - margin-top: 1rem; - margin-bottom: 1rem; -} - -.box { - border: 2px dashed #ccc; - padding: 0.5rem; -} - -details > summary { - cursor: pointer; -} - -.text-muted { - color: #ccc; -} - -.public-box > textarea { - width: 100%; - border: 0; - resize: none; -} - -button { - background-color: #444; - border-color: transparent; - border-width: 1px; - color: white; - cursor: pointer; - justify-content: center; - padding-bottom: calc(0.5em - 1px); - padding-left: 1em; - padding-right: 1em; - padding-top: calc(0.5em - 1px); - text-align: center; - white-space: nowrap -} - -button:hover { - background-color: #3e3e3e; - border-color: transparent; - color: #fff; -} - -/* - * Markdown to HTML specific styles - */ - -blockquote { - background-color: #efefef; - margin: 0; - padding: 2px 1em; -} - -blockquote > p { - margin-left: 1em; - color: gray; -} - -pre { - padding: 5px; - background-color: #efefef; - white-space: pre-wrap; -} - -code { - background-color: #efefef; - padding: 0px 5px; -} diff --git a/core/static/umbo.min.css b/core/static/umbo.min.css deleted file mode 100644 index 383623170d0ade7431eb41575f04ea77ff66e026..0000000000000000000000000000000000000000 --- a/core/static/umbo.min.css +++ /dev/null @@ -1 +0,0 @@ -html {line-height: 1.15;-webkit-text-size-adjust: 100%;}body {margin: 0;}main {display: block;}h1 {font-size: 2em;margin: 0.67em 0;}hr {box-sizing: content-box;height: 0;overflow: visible;}pre {font-family: monospace, monospace;font-size: 1em;}a {background-color: transparent;}abbr[title] {border-bottom: none;text-decoration: underline;text-decoration: underline dotted;}b,strong {font-weight: bolder;}code,kbd,samp {font-family: monospace, monospace;font-size: 1em;}small {font-size: 80%;}sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}img {border-style: none;}button,input,optgroup,select,textarea {font-family: inherit;font-size: 100%;line-height: 1.15;margin: 0;}button,input {overflow: visible;}button,select {text-transform: none;}button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}fieldset {padding: 0.35em 0.75em 0.625em;}legend {box-sizing: border-box;color: inherit;display: table;max-width: 100%;padding: 0;white-space: normal;}progress {vertical-align: baseline;}textarea {overflow: auto;}[type="checkbox"],[type="radio"] {box-sizing: border-box;padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}[type="search"] {-webkit-appearance: textfield;outline-offset: -2px;}[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}::-webkit-file-upload-button {-webkit-appearance: button;font: inherit;}details {display: block;}summary {display: list-item;}template {display: none;}[hidden] {display: none;}*, ::after, ::before {box-sizing: border-box;}body {font-family: Roboto, "Helvetica Neue", "San Francisco", "Open Sans", Arial, sans-serif;font-size: 1.1875rem;text-rendering: optimizeLegibility;line-height: 1.31579;}h1, .heading-xl {font-size: 3rem;}h2, .heading-l {font-size: 2.25rem;}h3, .heading-m {font-size: 1.5rem;}h4, .heading-s {font-size: 1.1875rem;}a {color: #1d70b8;}a:hover {color: #003078;}a:active {color: #336752;outline: 3px solid transparent;background-color: #33fe96;text-decoration: none;box-shadow: 0 -2px #33fe96,0 4px #0b0c0c;}ul, ol {font-size: 1.1875rem;line-height: 1.31579;}.umbo-table {width: 100%;border-spacing: 0;border-collapse: collapse;}.umbo-caption {font-weight: 700;display: table-caption;text-align: left;}.umbo-table-header, .umbo-table-cell {padding: 10px 20px 10px 0;border-bottom: 1px solid #b1b4b6;text-align: left;vertical-align: top;}.umbo-table-header-numeric, .umbo-table-cell-numeric {text-align: right;}.umbo-table-header {font-weight: 700;}.umbo-table-cell-numeric {font-feature-settings: normal;font-variant-numeric: tabular-nums;}.container {box-sizing: border-box;margin-left: auto;margin-right: auto;padding-right: 8px;padding-left: 8px;}.container-fluid {padding-right: 16px;padding-left: 16px;}@media only screen and (min-width: 576px) {.container {width: 560px;max-width: 100%;}}@media only screen and (min-width: 768px) {.container {width: 752px;max-width: 100%;}}@media only screen and (min-width: 992px) {.container {width: 976px;max-width: 100%;}}@media only screen and (min-width: 1200px) {.container {width: 1184px;max-width: 100%;}}.row {box-sizing: border-box;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-flex: 0;-ms-flex: 0 1 auto;flex: 0 1 auto;-webkit-box-orient: horizontal;-webkit-box-direction: normal;-ms-flex-direction: row;flex-direction: row;-ms-flex-wrap: wrap;flex-wrap: wrap;margin-right: -8px;margin-left: -8px;}.row.reverse {-webkit-box-orient: horizontal;-webkit-box-direction: reverse;-ms-flex-direction: row-reverse;flex-direction: row-reverse;}.col.reverse {-webkit-box-orient: vertical;-webkit-box-direction: reverse;-ms-flex-direction: column-reverse;flex-direction: column-reverse;}.col-xs,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-offset-0,.col-xs-offset-1,.col-xs-offset-2,.col-xs-offset-3,.col-xs-offset-4,.col-xs-offset-5,.col-xs-offset-6,.col-xs-offset-7,.col-xs-offset-8,.col-xs-offset-9,.col-xs-offset-10,.col-xs-offset-11,.col-xs-offset-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-offset-0,.col-sm-offset-1,.col-sm-offset-2,.col-sm-offset-3,.col-sm-offset-4,.col-sm-offset-5,.col-sm-offset-6,.col-sm-offset-7,.col-sm-offset-8,.col-sm-offset-9,.col-sm-offset-10,.col-sm-offset-11,.col-sm-offset-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;-ms-flex-preferred-size: 100%;flex-basis: 100%;padding-right: 8px;padding-left: 8px;max-width: 100%;}.col-xs {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xs-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xs-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xs-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xs-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xs-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xs-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xs-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xs-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xs-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xs-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xs-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xs-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xs-offset-0 {margin-left: 0;}.col-xs-offset-1 {margin-left: 8.33333333%;}.col-xs-offset-2 {margin-left: 16.66666667%;}.col-xs-offset-3 {margin-left: 25%;}.col-xs-offset-4 {margin-left: 33.33333333%;}.col-xs-offset-5 {margin-left: 41.66666667%;}.col-xs-offset-6 {margin-left: 50%;}.col-xs-offset-7 {margin-left: 58.33333333%;}.col-xs-offset-8 {margin-left: 66.66666667%;}.col-xs-offset-9 {margin-left: 75%;}.col-xs-offset-10 {margin-left: 83.33333333%;}.col-xs-offset-11 {margin-left: 91.66666667%;}.start-xs {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xs {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xs {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xs {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xs {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xs {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xs {-ms-flex-pack: distribute;justify-content: space-around;}.between-xs {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xs {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xs {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xs {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}@media only screen and (min-width: 576px) {.col-sm {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-sm-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-sm-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-sm-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-sm-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-sm-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-sm-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-sm-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-sm-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-sm-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-sm-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-sm-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-sm-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-sm-offset-0 {margin-left: 0;}.col-sm-offset-1 {margin-left: 8.33333333%;}.col-sm-offset-2 {margin-left: 16.66666667%;}.col-sm-offset-3 {margin-left: 25%;}.col-sm-offset-4 {margin-left: 33.33333333%;}.col-sm-offset-5 {margin-left: 41.66666667%;}.col-sm-offset-6 {margin-left: 50%;}.col-sm-offset-7 {margin-left: 58.33333333%;}.col-sm-offset-8 {margin-left: 66.66666667%;}.col-sm-offset-9 {margin-left: 75%;}.col-sm-offset-10 {margin-left: 83.33333333%;}.col-sm-offset-11 {margin-left: 91.66666667%;}.start-sm {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-sm {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-sm {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-sm {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-sm {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-sm {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-sm {-ms-flex-pack: distribute;justify-content: space-around;}.between-sm {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-sm {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-sm {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-sm {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 768px) {.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-md {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-md-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-md-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-md-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-md-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-md-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-md-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-md-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-md-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-md-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-md-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-md-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-md-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-md-offset-0 {margin-left: 0;}.col-md-offset-1 {margin-left: 8.33333333%;}.col-md-offset-2 {margin-left: 16.66666667%;}.col-md-offset-3 {margin-left: 25%;}.col-md-offset-4 {margin-left: 33.33333333%;}.col-md-offset-5 {margin-left: 41.66666667%;}.col-md-offset-6 {margin-left: 50%;}.col-md-offset-7 {margin-left: 58.33333333%;}.col-md-offset-8 {margin-left: 66.66666667%;}.col-md-offset-9 {margin-left: 75%;}.col-md-offset-10 {margin-left: 83.33333333%;}.col-md-offset-11 {margin-left: 91.66666667%;}.start-md {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-md {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-md {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-md {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-md {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-md {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-md {-ms-flex-pack: distribute;justify-content: space-around;}.between-md {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-md {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-md {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-md {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 992px) {.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-lg {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-lg-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-lg-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-lg-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-lg-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-lg-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-lg-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-lg-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-lg-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-lg-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-lg-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-lg-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-lg-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-lg-offset-0 {margin-left: 0;}.col-lg-offset-1 {margin-left: 8.33333333%;}.col-lg-offset-2 {margin-left: 16.66666667%;}.col-lg-offset-3 {margin-left: 25%;}.col-lg-offset-4 {margin-left: 33.33333333%;}.col-lg-offset-5 {margin-left: 41.66666667%;}.col-lg-offset-6 {margin-left: 50%;}.col-lg-offset-7 {margin-left: 58.33333333%;}.col-lg-offset-8 {margin-left: 66.66666667%;}.col-lg-offset-9 {margin-left: 75%;}.col-lg-offset-10 {margin-left: 83.33333333%;}.col-lg-offset-11 {margin-left: 91.66666667%;}.start-lg {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-lg {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-lg {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-lg {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-lg {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-lg {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-lg {-ms-flex-pack: distribute;justify-content: space-around;}.between-lg {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-lg {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-lg {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-lg {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 1200px) {.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-xl {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xl-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xl-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xl-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xl-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xl-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xl-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xl-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xl-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xl-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xl-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xl-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xl-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xl-offset-0 {margin-left: 0;}.col-xl-offset-1 {margin-left: 8.33333333%;}.col-xl-offset-2 {margin-left: 16.66666667%;}.col-xl-offset-3 {margin-left: 25%;}.col-xl-offset-4 {margin-left: 33.33333333%;}.col-xl-offset-5 {margin-left: 41.66666667%;}.col-xl-offset-6 {margin-left: 50%;}.col-xl-offset-7 {margin-left: 58.33333333%;}.col-xl-offset-8 {margin-left: 66.66666667%;}.col-xl-offset-9 {margin-left: 75%;}.col-xl-offset-10 {margin-left: 83.33333333%;}.col-xl-offset-11 {margin-left: 91.66666667%;}.start-xl {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xl {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xl {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xl {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xl {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xl {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xl {-ms-flex-pack: distribute;justify-content: space-around;}.between-xl {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xl {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xl {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xl {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (max-width: 575px) {.hidden-xs {display: none;}}@media only screen and (min-width: 576px) and (max-width: 767px) {.hidden-sm {display: none;}}@media only screen and (min-width: 768px) and (max-width: 991px) {.hidden-md {display: none;}}@media only screen and (min-width: 992px) and (max-width: 1199px) {.hidden-lg {display: none;}}@media only screen and (min-width: 1200px) {.hidden-xl {display: none;}}.umbo-fieldset {min-width: 0;margin: 0;padding: 0;border: 0;}.umbo-fieldset-legend {margin-bottom: 5px;}.umbo-form-group {display: block;margin-bottom: 30px;}.umbo-label {display: block;font-size: 1rem;font-weight: 400;margin-bottom: 5px;}.umbo-input {font-size: 1rem;line-height: 1.5;padding: .25rem .375rem;height: 2.5rem;border-color: #888;}.umbo-input:focus {outline: 3px solid #33fe96;outline-offset: 0;border: 1px solid #0b0c0c;box-shadow: inset 0px 0px 0px 2px;}.umbo-form-actions {display: inline-block;}.umbo-input-full-width {width: 100%;}.umbo-input-large {width: 75%;}.umbo-input-medium {width: 50%;}.umbo-input-small {width: 25%;}.umbo-input-xsmall {width: 10%;} \ No newline at end of file diff --git a/core/templates/index.html b/core/templates/index.html deleted file mode 100644 index 58f7a3d1d3ccc6a082e675d35ecbbdf7ca6ddf54..0000000000000000000000000000000000000000 --- a/core/templates/index.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends 'layout.html' %} - -{% block body %} - <div class="row"> - <div class="col-xs"> - {{ doc.content | md | safe }} - </div> - </div> - - <div class="row box"> - <div class="col-xs"> - <form method="POST" action="/" class="public-box"> - <textarea name="text" cols="72" rows="30" placeholder="Escreva aqui"></textarea> - <br /> - <button type="submit">Enviar</button> - </form> - </div> - </div> -{% endblock %} diff --git a/core/templates/internal_server.html b/core/templates/internal_server.html deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 Binary files a/core/templates/internal_server.html and /dev/null differ diff --git a/core/templates/layout.html b/core/templates/layout.html deleted file mode 100644 index 3503a71a1648076a7de6ef7334a9b59df0a30ed4..0000000000000000000000000000000000000000 --- a/core/templates/layout.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <title>Rascunho - Prévia de Markdown</title> - <meta name="viewport" content="width=device-width, initial-scale=1" /> - <link href="/static/umbo.min.css" rel="stylesheet" /> - <link href="/static/rascunho.css" rel="stylesheet" /> - </head> - - <body> - <div class="container py"> - {% block body %} - {% endblock %} - </div> - </body> -</html> - diff --git a/core/templates/not_found.html b/core/templates/not_found.html deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 Binary files a/core/templates/not_found.html and /dev/null differ diff --git a/core/templates/preview.html b/core/templates/preview.html deleted file mode 100644 index 207bf8599bb51a2c03f1da875f558ad92afbefd8..0000000000000000000000000000000000000000 --- a/core/templates/preview.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends 'layout.html' %} - -{% block body %} - <div class="row"> - <div class="col-xs"> - {{ doc.content | md | safe }} - </div> - </div> - - <div class="row"> - <div class="col-xs"> - <details> - <summary>Informações sobre este rascunho</summary> - <div class="box text-muted"> - <ul> - <li> - Identificador: {{ doc.sha }} - </li> - <li> - Criado há: {{ doc.created_at | human_date | safe }} - </li> - <li> - <a href="/{{doc.sha}}/raw">Ver arquivo puro</a> - </li> - </ul> - </div> - </details> - </div> - </div> - -{% endblock %} diff --git a/core/templates/unprocessable_entity.html b/core/templates/unprocessable_entity.html deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 Binary files a/core/templates/unprocessable_entity.html and /dev/null differ diff --git a/core/types/__init__.py b/core/types/__init__.py deleted file mode 100644 index 9c01ea2470e408389a5b947f4247f87ecd21a81d..0000000000000000000000000000000000000000 --- a/core/types/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import document diff --git a/core/types/document.py b/core/types/document.py deleted file mode 100644 index 9f6cf83adf823e11b6bb9fb671eb7a8528fd00d9..0000000000000000000000000000000000000000 --- a/core/types/document.py +++ /dev/null @@ -1,20 +0,0 @@ -import sqlalchemy as sa -from core.database import Base - -class Document(Base): - __tablename__ = 'documents' - - id = sa.Column(sa.Integer, primary_key=True) - sha = sa.Column(sa.String(40), nullable=False, index=True) - content = sa.Column(sa.Unicode, nullable=False) - - created_at = sa.Column(sa.DateTime, nullable=False) - updated_at = sa.Column(sa.DateTime, nullable=False) - - def to_dict(self): - return { - "sha": self.sha, - "content": self.content, - "created_at": self.created_at, - "updated_at": self.updated_at - } diff --git a/rascunho/__init__.py b/rascunho/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c07c45996e3bd354c2448c09f07c6f2cfe45d922 --- /dev/null +++ b/rascunho/__init__.py @@ -0,0 +1 @@ +from .app import app diff --git a/rascunho/app.py b/rascunho/app.py new file mode 100644 index 0000000000000000000000000000000000000000..19d288e2c2c290d6a4304be25fd780d0cfcf6dd7 --- /dev/null +++ b/rascunho/app.py @@ -0,0 +1,84 @@ +from flask import Flask, abort, render_template, request +from jinja2 import Markup +import locale +from rascunho.config import read_from_config, env +from rascunho.database import db, init_database +import mistune +import humanize +from datetime import datetime, timedelta +from pytz import timezone + +class Rascunho(Flask): + def __init__(self, *args, **kwargs): + super().__init__(__name__, *args, **kwargs) + + init_database() + + try: + # TODO: Use the locale config, from my local package it doesn't + # work as the package is out-of-date on Arch's Community Repository + humanize.i18n.activate("pt_BR") + locale.setlocale(locale.LC_ALL, read_from_config("locale")) + locale.setlocale(locale.LC_TIME, read_from_config("locale")) + except: + pass + + + from rascunho.blueprints.basic import basic + from rascunho.blueprints.api import api + + self.register_blueprint(basic) + self.register_blueprint(api) + + @self.template_filter() + def human_date(d): + if not d: + return 'Nunca' + + local_tz = timezone(str(read_from_config("timezone"))) + d = d.replace(tzinfo=timezone('UTC')) + local_date = d.astimezone(local_tz) + + if isinstance(d, timedelta): + return Markup('<span title="{}">{}</span>'.format( + f'{d.seconds} segundos', humanize.naturaldelta(d))) + + return Markup('<span title="{}">{}</span>'.format( + d.strftime('%Y-%m-%d %H:%M:%S UTC'), + humanize.naturaltime( + datetime.now().astimezone(local_tz) - local_date + ))) + + @self.template_filter() + def md(text): + return mistune.markdown(text) + + @self.errorhandler(422) + def handle_unprocessable_entity(e): + if request.path.startswith("/api"): + return { "errors": [ { "reason": "422 Unprocessable Entity" } ] }, 422 + + return render_template("unprocessable_entity.html", 422) + + @self.errorhandler(500) + def handle_internal_server_error(e): + if request.path.startswith("/api"): + return { "errors": [ { "reason": "500 Internal Server Error" } ] }, 500 + + return render_template("internal_error.html", 500) + + @self.errorhandler(404) + def handle_not_found(e): + if request.path.startswith("/api"): + return { "errors": [ { "reason": "404 Not Found" } ] }, 404 + + return render_template("not_found.html"), 404 + + @self.context_processor + def inject(): + return { + "env": env + } + + +app = Rascunho() diff --git a/rascunho/blueprints/__init__.py b/rascunho/blueprints/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files /dev/null and b/rascunho/blueprints/__init__.py differ diff --git a/rascunho/blueprints/api.py b/rascunho/blueprints/api.py new file mode 100644 index 0000000000000000000000000000000000000000..1edecc9851c5358d76068bda4eec292465a6c3c6 --- /dev/null +++ b/rascunho/blueprints/api.py @@ -0,0 +1,46 @@ +from flask import Blueprint, abort, request +from hashlib import sha1 +from rascunho.types.document import Document +from rascunho.database import db +import json + +api = Blueprint("apiv1", __name__) + +@api.route('/api/v1', methods = ['POST']) +def create(): + params = json.loads(request.data.decode('utf-8')) + + doc = None + content = params.get('text') + + if not content: + abort(422) + + sha = sha1() + sha.update(content.encode()) + sha.update(request.remote_addr.encode()) + + existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none() + + if existing_doc: + doc = existing_doc + else: + doc = Document() + + doc.sha = sha.hexdigest() + doc.content = content + + db.add(doc) + db.commit() + db.flush() + + return doc.to_dict(), 201 + +@api.route('/api/v1/<sha>', methods = ['GET']) +def show(sha): + doc = Document.query.filter(Document.sha == sha).one_or_none() + + if not doc: + abort(404) + + return doc.to_dict(), 200 diff --git a/rascunho/blueprints/basic.py b/rascunho/blueprints/basic.py new file mode 100644 index 0000000000000000000000000000000000000000..ab074db00e5eceb37736539029ed458b80a053c8 --- /dev/null +++ b/rascunho/blueprints/basic.py @@ -0,0 +1,59 @@ +from flask import Blueprint, render_template, request, abort, Response, redirect, url_for +from rascunho.database import db +from rascunho.types.document import Document +from hashlib import sha1 + +basic = Blueprint('basic', __name__) + +@basic.route("/", methods = ['GET', 'POST']) +def index(): + if request.method == "GET": + doc = Document.query.order_by(Document.created_at.asc()).first() + return render_template('index.html', doc = doc) + else: + return create(request.form) + +@basic.route("/<sha>", methods = ['GET']) +def show(sha): + doc = Document.query.filter(Document.sha == sha).one_or_none() + + if not doc: + abort(404) + + return render_template('preview.html', doc = doc) + +@basic.route("/<sha>/raw", methods = ['GET']) +def raw(sha): + doc = Document.query.filter(Document.sha == sha).one_or_none() + + if not doc: + abort(404) + + return Response(doc.content, mimetype="text/plain") + +def create(params): + doc = None + content = params['text'] + + if not content: + abort(422) + + sha = sha1() + sha.update(content.encode()) + sha.update(request.remote_addr.encode()) + + existing_doc = Document.query.filter(Document.sha == sha.hexdigest()).one_or_none() + + if existing_doc: + doc = existing_doc + else: + doc = Document() + + doc.sha = sha.hexdigest() + doc.content = content + + db.add(doc) + db.commit() + db.flush() + + return redirect(url_for('basic.show', sha = doc.sha)) diff --git a/rascunho/config.py b/rascunho/config.py new file mode 100644 index 0000000000000000000000000000000000000000..30c507fa0d04934468781a4121749e2a81f8793f --- /dev/null +++ b/rascunho/config.py @@ -0,0 +1,8 @@ +from configparser import ConfigParser + +config = ConfigParser() +config.read_file(open('config.ini')) + +env = config['meta']['env'] + +read_from_config = lambda key: config.get(env, key) diff --git a/rascunho/database.py b/rascunho/database.py new file mode 100644 index 0000000000000000000000000000000000000000..9998ba7434ea4caf35c2aa547233fc154c572421 --- /dev/null +++ b/rascunho/database.py @@ -0,0 +1,33 @@ +from sqlalchemy import create_engine, event +from sqlalchemy.orm import sessionmaker, scoped_session +from sqlalchemy.ext.declarative import declarative_base + +from datetime import datetime + +from rascunho.config import read_from_config + +engine = create_engine(read_from_config('connection-string'), echo=True) +db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) + +Base = declarative_base() +Base.query = db.query_property() + +def init_database(): + @event.listens_for(Base, 'before_insert', propagate=True) + def before_insert(mapper, connection, target): + if hasattr(target, '_no_autoupdate'): + return + if hasattr(target, 'created_at'): + target.created_at = datetime.utcnow() + if hasattr(target, 'updated_at'): + target.updated_at = datetime.utcnow() + + @event.listens_for(Base, 'before_update', propagate=True) + def before_insert(mapper, connection, target): + if hasattr(target, '_no_autoupdate'): + return + if hasattr(target, 'updated_at'): + target.updated_at = datetime.utcnow() + + import rascunho.types + Base.metadata.create_all(bind=engine) diff --git a/rascunho/static/rascunho.css b/rascunho/static/rascunho.css new file mode 100644 index 0000000000000000000000000000000000000000..2fe65ac733b7c1f3f6d369e47398e7095cb512dc --- /dev/null +++ b/rascunho/static/rascunho.css @@ -0,0 +1,70 @@ +.py { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.box { + border: 2px dashed #ccc; + padding: 0.5rem; +} + +details > summary { + cursor: pointer; +} + +.text-muted { + color: #ccc; +} + +.public-box > textarea { + width: 100%; + border: 0; + resize: none; +} + +button { + background-color: #444; + border-color: transparent; + border-width: 1px; + color: white; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.5em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.5em - 1px); + text-align: center; + white-space: nowrap +} + +button:hover { + background-color: #3e3e3e; + border-color: transparent; + color: #fff; +} + +/* + * Markdown to HTML specific styles + */ + +blockquote { + background-color: #efefef; + margin: 0; + padding: 2px 1em; +} + +blockquote > p { + margin-left: 1em; + color: gray; +} + +pre { + padding: 5px; + background-color: #efefef; + white-space: pre-wrap; +} + +code { + background-color: #efefef; + padding: 0px 5px; +} diff --git a/rascunho/static/umbo.min.css b/rascunho/static/umbo.min.css new file mode 100644 index 0000000000000000000000000000000000000000..383623170d0ade7431eb41575f04ea77ff66e026 --- /dev/null +++ b/rascunho/static/umbo.min.css @@ -0,0 +1 @@ +html {line-height: 1.15;-webkit-text-size-adjust: 100%;}body {margin: 0;}main {display: block;}h1 {font-size: 2em;margin: 0.67em 0;}hr {box-sizing: content-box;height: 0;overflow: visible;}pre {font-family: monospace, monospace;font-size: 1em;}a {background-color: transparent;}abbr[title] {border-bottom: none;text-decoration: underline;text-decoration: underline dotted;}b,strong {font-weight: bolder;}code,kbd,samp {font-family: monospace, monospace;font-size: 1em;}small {font-size: 80%;}sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}img {border-style: none;}button,input,optgroup,select,textarea {font-family: inherit;font-size: 100%;line-height: 1.15;margin: 0;}button,input {overflow: visible;}button,select {text-transform: none;}button,[type="button"],[type="reset"],[type="submit"] {-webkit-appearance: button;}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner {border-style: none;padding: 0;}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring {outline: 1px dotted ButtonText;}fieldset {padding: 0.35em 0.75em 0.625em;}legend {box-sizing: border-box;color: inherit;display: table;max-width: 100%;padding: 0;white-space: normal;}progress {vertical-align: baseline;}textarea {overflow: auto;}[type="checkbox"],[type="radio"] {box-sizing: border-box;padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}[type="search"] {-webkit-appearance: textfield;outline-offset: -2px;}[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}::-webkit-file-upload-button {-webkit-appearance: button;font: inherit;}details {display: block;}summary {display: list-item;}template {display: none;}[hidden] {display: none;}*, ::after, ::before {box-sizing: border-box;}body {font-family: Roboto, "Helvetica Neue", "San Francisco", "Open Sans", Arial, sans-serif;font-size: 1.1875rem;text-rendering: optimizeLegibility;line-height: 1.31579;}h1, .heading-xl {font-size: 3rem;}h2, .heading-l {font-size: 2.25rem;}h3, .heading-m {font-size: 1.5rem;}h4, .heading-s {font-size: 1.1875rem;}a {color: #1d70b8;}a:hover {color: #003078;}a:active {color: #336752;outline: 3px solid transparent;background-color: #33fe96;text-decoration: none;box-shadow: 0 -2px #33fe96,0 4px #0b0c0c;}ul, ol {font-size: 1.1875rem;line-height: 1.31579;}.umbo-table {width: 100%;border-spacing: 0;border-collapse: collapse;}.umbo-caption {font-weight: 700;display: table-caption;text-align: left;}.umbo-table-header, .umbo-table-cell {padding: 10px 20px 10px 0;border-bottom: 1px solid #b1b4b6;text-align: left;vertical-align: top;}.umbo-table-header-numeric, .umbo-table-cell-numeric {text-align: right;}.umbo-table-header {font-weight: 700;}.umbo-table-cell-numeric {font-feature-settings: normal;font-variant-numeric: tabular-nums;}.container {box-sizing: border-box;margin-left: auto;margin-right: auto;padding-right: 8px;padding-left: 8px;}.container-fluid {padding-right: 16px;padding-left: 16px;}@media only screen and (min-width: 576px) {.container {width: 560px;max-width: 100%;}}@media only screen and (min-width: 768px) {.container {width: 752px;max-width: 100%;}}@media only screen and (min-width: 992px) {.container {width: 976px;max-width: 100%;}}@media only screen and (min-width: 1200px) {.container {width: 1184px;max-width: 100%;}}.row {box-sizing: border-box;display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-flex: 0;-ms-flex: 0 1 auto;flex: 0 1 auto;-webkit-box-orient: horizontal;-webkit-box-direction: normal;-ms-flex-direction: row;flex-direction: row;-ms-flex-wrap: wrap;flex-wrap: wrap;margin-right: -8px;margin-left: -8px;}.row.reverse {-webkit-box-orient: horizontal;-webkit-box-direction: reverse;-ms-flex-direction: row-reverse;flex-direction: row-reverse;}.col.reverse {-webkit-box-orient: vertical;-webkit-box-direction: reverse;-ms-flex-direction: column-reverse;flex-direction: column-reverse;}.col-xs,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-offset-0,.col-xs-offset-1,.col-xs-offset-2,.col-xs-offset-3,.col-xs-offset-4,.col-xs-offset-5,.col-xs-offset-6,.col-xs-offset-7,.col-xs-offset-8,.col-xs-offset-9,.col-xs-offset-10,.col-xs-offset-11,.col-xs-offset-12,.col-sm,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-offset-0,.col-sm-offset-1,.col-sm-offset-2,.col-sm-offset-3,.col-sm-offset-4,.col-sm-offset-5,.col-sm-offset-6,.col-sm-offset-7,.col-sm-offset-8,.col-sm-offset-9,.col-sm-offset-10,.col-sm-offset-11,.col-sm-offset-12,.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12,.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12,.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;-ms-flex-preferred-size: 100%;flex-basis: 100%;padding-right: 8px;padding-left: 8px;max-width: 100%;}.col-xs {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xs-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xs-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xs-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xs-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xs-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xs-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xs-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xs-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xs-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xs-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xs-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xs-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xs-offset-0 {margin-left: 0;}.col-xs-offset-1 {margin-left: 8.33333333%;}.col-xs-offset-2 {margin-left: 16.66666667%;}.col-xs-offset-3 {margin-left: 25%;}.col-xs-offset-4 {margin-left: 33.33333333%;}.col-xs-offset-5 {margin-left: 41.66666667%;}.col-xs-offset-6 {margin-left: 50%;}.col-xs-offset-7 {margin-left: 58.33333333%;}.col-xs-offset-8 {margin-left: 66.66666667%;}.col-xs-offset-9 {margin-left: 75%;}.col-xs-offset-10 {margin-left: 83.33333333%;}.col-xs-offset-11 {margin-left: 91.66666667%;}.start-xs {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xs {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xs {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xs {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xs {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xs {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xs {-ms-flex-pack: distribute;justify-content: space-around;}.between-xs {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xs {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xs {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xs {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}@media only screen and (min-width: 576px) {.col-sm {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-sm-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-sm-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-sm-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-sm-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-sm-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-sm-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-sm-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-sm-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-sm-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-sm-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-sm-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-sm-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-sm-offset-0 {margin-left: 0;}.col-sm-offset-1 {margin-left: 8.33333333%;}.col-sm-offset-2 {margin-left: 16.66666667%;}.col-sm-offset-3 {margin-left: 25%;}.col-sm-offset-4 {margin-left: 33.33333333%;}.col-sm-offset-5 {margin-left: 41.66666667%;}.col-sm-offset-6 {margin-left: 50%;}.col-sm-offset-7 {margin-left: 58.33333333%;}.col-sm-offset-8 {margin-left: 66.66666667%;}.col-sm-offset-9 {margin-left: 75%;}.col-sm-offset-10 {margin-left: 83.33333333%;}.col-sm-offset-11 {margin-left: 91.66666667%;}.start-sm {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-sm {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-sm {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-sm {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-sm {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-sm {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-sm {-ms-flex-pack: distribute;justify-content: space-around;}.between-sm {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-sm {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-sm {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-sm {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 768px) {.col-md,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-md-offset-0,.col-md-offset-1,.col-md-offset-2,.col-md-offset-3,.col-md-offset-4,.col-md-offset-5,.col-md-offset-6,.col-md-offset-7,.col-md-offset-8,.col-md-offset-9,.col-md-offset-10,.col-md-offset-11,.col-md-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-md {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-md-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-md-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-md-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-md-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-md-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-md-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-md-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-md-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-md-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-md-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-md-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-md-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-md-offset-0 {margin-left: 0;}.col-md-offset-1 {margin-left: 8.33333333%;}.col-md-offset-2 {margin-left: 16.66666667%;}.col-md-offset-3 {margin-left: 25%;}.col-md-offset-4 {margin-left: 33.33333333%;}.col-md-offset-5 {margin-left: 41.66666667%;}.col-md-offset-6 {margin-left: 50%;}.col-md-offset-7 {margin-left: 58.33333333%;}.col-md-offset-8 {margin-left: 66.66666667%;}.col-md-offset-9 {margin-left: 75%;}.col-md-offset-10 {margin-left: 83.33333333%;}.col-md-offset-11 {margin-left: 91.66666667%;}.start-md {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-md {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-md {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-md {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-md {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-md {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-md {-ms-flex-pack: distribute;justify-content: space-around;}.between-md {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-md {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-md {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-md {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 992px) {.col-lg,.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-offset-0,.col-lg-offset-1,.col-lg-offset-2,.col-lg-offset-3,.col-lg-offset-4,.col-lg-offset-5,.col-lg-offset-6,.col-lg-offset-7,.col-lg-offset-8,.col-lg-offset-9,.col-lg-offset-10,.col-lg-offset-11,.col-lg-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-lg {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-lg-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-lg-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-lg-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-lg-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-lg-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-lg-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-lg-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-lg-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-lg-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-lg-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-lg-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-lg-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-lg-offset-0 {margin-left: 0;}.col-lg-offset-1 {margin-left: 8.33333333%;}.col-lg-offset-2 {margin-left: 16.66666667%;}.col-lg-offset-3 {margin-left: 25%;}.col-lg-offset-4 {margin-left: 33.33333333%;}.col-lg-offset-5 {margin-left: 41.66666667%;}.col-lg-offset-6 {margin-left: 50%;}.col-lg-offset-7 {margin-left: 58.33333333%;}.col-lg-offset-8 {margin-left: 66.66666667%;}.col-lg-offset-9 {margin-left: 75%;}.col-lg-offset-10 {margin-left: 83.33333333%;}.col-lg-offset-11 {margin-left: 91.66666667%;}.start-lg {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-lg {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-lg {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-lg {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-lg {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-lg {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-lg {-ms-flex-pack: distribute;justify-content: space-around;}.between-lg {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-lg {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-lg {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-lg {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (min-width: 1200px) {.col-xl,.col-xl-1,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-offset-0,.col-xl-offset-1,.col-xl-offset-2,.col-xl-offset-3,.col-xl-offset-4,.col-xl-offset-5,.col-xl-offset-6,.col-xl-offset-7,.col-xl-offset-8,.col-xl-offset-9,.col-xl-offset-10,.col-xl-offset-11,.col-xl-offset-12 {box-sizing: border-box;-webkit-box-flex: 0;-ms-flex: 0 0 auto;flex: 0 0 auto;padding-right: 8px;padding-left: 8px;}.col-xl {-webkit-box-flex: 1;-ms-flex-positive: 1;flex-grow: 1;-ms-flex-preferred-size: 0;flex-basis: 0;max-width: 100%;}.col-xl-1 {-ms-flex-preferred-size: 8.33333333%;flex-basis: 8.33333333%;max-width: 8.33333333%;}.col-xl-2 {-ms-flex-preferred-size: 16.66666667%;flex-basis: 16.66666667%;max-width: 16.66666667%;}.col-xl-3 {-ms-flex-preferred-size: 25%;flex-basis: 25%;max-width: 25%;}.col-xl-4 {-ms-flex-preferred-size: 33.33333333%;flex-basis: 33.33333333%;max-width: 33.33333333%;}.col-xl-5 {-ms-flex-preferred-size: 41.66666667%;flex-basis: 41.66666667%;max-width: 41.66666667%;}.col-xl-6 {-ms-flex-preferred-size: 50%;flex-basis: 50%;max-width: 50%;}.col-xl-7 {-ms-flex-preferred-size: 58.33333333%;flex-basis: 58.33333333%;max-width: 58.33333333%;}.col-xl-8 {-ms-flex-preferred-size: 66.66666667%;flex-basis: 66.66666667%;max-width: 66.66666667%;}.col-xl-9 {-ms-flex-preferred-size: 75%;flex-basis: 75%;max-width: 75%;}.col-xl-10 {-ms-flex-preferred-size: 83.33333333%;flex-basis: 83.33333333%;max-width: 83.33333333%;}.col-xl-11 {-ms-flex-preferred-size: 91.66666667%;flex-basis: 91.66666667%;max-width: 91.66666667%;}.col-xl-12 {-ms-flex-preferred-size: 100%;flex-basis: 100%;max-width: 100%;}.col-xl-offset-0 {margin-left: 0;}.col-xl-offset-1 {margin-left: 8.33333333%;}.col-xl-offset-2 {margin-left: 16.66666667%;}.col-xl-offset-3 {margin-left: 25%;}.col-xl-offset-4 {margin-left: 33.33333333%;}.col-xl-offset-5 {margin-left: 41.66666667%;}.col-xl-offset-6 {margin-left: 50%;}.col-xl-offset-7 {margin-left: 58.33333333%;}.col-xl-offset-8 {margin-left: 66.66666667%;}.col-xl-offset-9 {margin-left: 75%;}.col-xl-offset-10 {margin-left: 83.33333333%;}.col-xl-offset-11 {margin-left: 91.66666667%;}.start-xl {-webkit-box-pack: start;-ms-flex-pack: start;justify-content: flex-start;text-align: start;}.center-xl {-webkit-box-pack: center;-ms-flex-pack: center;justify-content: center;text-align: center;}.end-xl {-webkit-box-pack: end;-ms-flex-pack: end;justify-content: flex-end;text-align: end;}.top-xl {-webkit-box-align: start;-ms-flex-align: start;align-items: flex-start;}.middle-xl {-webkit-box-align: center;-ms-flex-align: center;align-items: center;}.bottom-xl {-webkit-box-align: end;-ms-flex-align: end;align-items: flex-end;}.around-xl {-ms-flex-pack: distribute;justify-content: space-around;}.between-xl {-webkit-box-pack: justify;-ms-flex-pack: justify;justify-content: space-between;}.first-xl {-webkit-box-ordinal-group: 0;-ms-flex-order: -1;order: -1;}.last-xl {-webkit-box-ordinal-group: 2;-ms-flex-order: 1;order: 1;}.initial-order-xl {-webkit-box-ordinal-group: NaN;-ms-flex-order: initial;order: initial;}}@media only screen and (max-width: 575px) {.hidden-xs {display: none;}}@media only screen and (min-width: 576px) and (max-width: 767px) {.hidden-sm {display: none;}}@media only screen and (min-width: 768px) and (max-width: 991px) {.hidden-md {display: none;}}@media only screen and (min-width: 992px) and (max-width: 1199px) {.hidden-lg {display: none;}}@media only screen and (min-width: 1200px) {.hidden-xl {display: none;}}.umbo-fieldset {min-width: 0;margin: 0;padding: 0;border: 0;}.umbo-fieldset-legend {margin-bottom: 5px;}.umbo-form-group {display: block;margin-bottom: 30px;}.umbo-label {display: block;font-size: 1rem;font-weight: 400;margin-bottom: 5px;}.umbo-input {font-size: 1rem;line-height: 1.5;padding: .25rem .375rem;height: 2.5rem;border-color: #888;}.umbo-input:focus {outline: 3px solid #33fe96;outline-offset: 0;border: 1px solid #0b0c0c;box-shadow: inset 0px 0px 0px 2px;}.umbo-form-actions {display: inline-block;}.umbo-input-full-width {width: 100%;}.umbo-input-large {width: 75%;}.umbo-input-medium {width: 50%;}.umbo-input-small {width: 25%;}.umbo-input-xsmall {width: 10%;} \ No newline at end of file diff --git a/rascunho/templates/index.html b/rascunho/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..58f7a3d1d3ccc6a082e675d35ecbbdf7ca6ddf54 --- /dev/null +++ b/rascunho/templates/index.html @@ -0,0 +1,19 @@ +{% extends 'layout.html' %} + +{% block body %} + <div class="row"> + <div class="col-xs"> + {{ doc.content | md | safe }} + </div> + </div> + + <div class="row box"> + <div class="col-xs"> + <form method="POST" action="/" class="public-box"> + <textarea name="text" cols="72" rows="30" placeholder="Escreva aqui"></textarea> + <br /> + <button type="submit">Enviar</button> + </form> + </div> + </div> +{% endblock %} diff --git a/rascunho/templates/internal_server.html b/rascunho/templates/internal_server.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files /dev/null and b/rascunho/templates/internal_server.html differ diff --git a/rascunho/templates/layout.html b/rascunho/templates/layout.html new file mode 100644 index 0000000000000000000000000000000000000000..3503a71a1648076a7de6ef7334a9b59df0a30ed4 --- /dev/null +++ b/rascunho/templates/layout.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <title>Rascunho - Prévia de Markdown</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link href="/static/umbo.min.css" rel="stylesheet" /> + <link href="/static/rascunho.css" rel="stylesheet" /> + </head> + + <body> + <div class="container py"> + {% block body %} + {% endblock %} + </div> + </body> +</html> + diff --git a/rascunho/templates/not_found.html b/rascunho/templates/not_found.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files /dev/null and b/rascunho/templates/not_found.html differ diff --git a/rascunho/templates/preview.html b/rascunho/templates/preview.html new file mode 100644 index 0000000000000000000000000000000000000000..207bf8599bb51a2c03f1da875f558ad92afbefd8 --- /dev/null +++ b/rascunho/templates/preview.html @@ -0,0 +1,31 @@ +{% extends 'layout.html' %} + +{% block body %} + <div class="row"> + <div class="col-xs"> + {{ doc.content | md | safe }} + </div> + </div> + + <div class="row"> + <div class="col-xs"> + <details> + <summary>Informações sobre este rascunho</summary> + <div class="box text-muted"> + <ul> + <li> + Identificador: {{ doc.sha }} + </li> + <li> + Criado há: {{ doc.created_at | human_date | safe }} + </li> + <li> + <a href="/{{doc.sha}}/raw">Ver arquivo puro</a> + </li> + </ul> + </div> + </details> + </div> + </div> + +{% endblock %} diff --git a/rascunho/templates/unprocessable_entity.html b/rascunho/templates/unprocessable_entity.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 Binary files /dev/null and b/rascunho/templates/unprocessable_entity.html differ diff --git a/rascunho/types/__init__.py b/rascunho/types/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..9c01ea2470e408389a5b947f4247f87ecd21a81d --- /dev/null +++ b/rascunho/types/__init__.py @@ -0,0 +1 @@ +from . import document diff --git a/rascunho/types/document.py b/rascunho/types/document.py new file mode 100644 index 0000000000000000000000000000000000000000..51556c2fc4a6ef93a0220f4709b79b740b09346d --- /dev/null +++ b/rascunho/types/document.py @@ -0,0 +1,20 @@ +import sqlalchemy as sa +from rascunho.database import Base + +class Document(Base): + __tablename__ = 'documents' + + id = sa.Column(sa.Integer, primary_key=True) + sha = sa.Column(sa.String(40), nullable=False, index=True) + content = sa.Column(sa.Unicode, nullable=False) + + created_at = sa.Column(sa.DateTime, nullable=False) + updated_at = sa.Column(sa.DateTime, nullable=False) + + def to_dict(self): + return { + "sha": self.sha, + "content": self.content, + "created_at": self.created_at, + "updated_at": self.updated_at + }