Todo se fue a docker igual que el otro repo

Decidi pasar todo esto a docker igual para tener todo ahi, parece mas
ordenado y mas facil de mantener en mi servidor

de paso tambien hice el trabajo de pasar los modelos a sqlalchemy para
usar mysql :3
This commit is contained in:
Daniel Cortes
2019-03-15 03:16:59 -03:00
parent 6b34e909f2
commit c9ffcb8dca
22 changed files with 253 additions and 264 deletions

4
.gitignore vendored
View File

@@ -116,4 +116,6 @@ dmypy.json
# Personal things!
setup_env.sh
web.env
db.env
dump.sql

16
Dockerfile Normal file
View File

@@ -0,0 +1,16 @@
FROM python:alpine
RUN mkdir /app
COPY requirements.txt gunicorn.conf run.py /app/
COPY www/ /app/www
ENV FLASK_APP=www
WORKDIR /app
RUN apk add mariadb-connector-c-dev gcc musl-dev
RUN pip install --no-cache-dir -r requirements.txt
RUN apk del gcc musl-dev
ENV GUNICORN_WORKERS 2
ENV GUNICORN_BIND 0.0.0.0:8081
EXPOSE 8081
CMD ["gunicorn", "--config", "gunicorn.conf", "run:app"]

2
db.env.example Normal file
View File

@@ -0,0 +1,2 @@
MYSQL_ROOT_PASSWORD=secret
MYSQL_DATABASE=db

21
docker-compose.yml Normal file
View File

@@ -0,0 +1,21 @@
version: '3'
services:
web:
build: .
ports:
- "8081:8081"
volumes:
- ./www:/app/www
depends_on:
- db
env_file:
- web.env
command: "gunicorn --config gunicorn.conf run:app"
db:
image: mariadb
volumes:
- dbdata:/var/lib/mysql
env_file:
- db.env
volumes:
dbdata:

27
dump.sql Normal file

File diff suppressed because one or more lines are too long

6
gunicorn.conf Normal file
View File

@@ -0,0 +1,6 @@
import os
for k,v in os.environ.items():
if k.startswith("GUNICORN_"):
key = k.split('_', 1)[1].lower()
locals()[key] = v

5
requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
Flask
Flask-SQLAlchemy
mysqlclient
gunicorn
markdown

6
run.py Normal file
View File

@@ -0,0 +1,6 @@
from www import create_app
app = create_app()
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)

7
web.env.example Normal file
View File

@@ -0,0 +1,7 @@
DATABASE_URI=mysql://root:secret@db:3306/db
TRACK_MODIFICATIONS=False
USERNAME=admin
PASSWORD=secret
SECRET_KEY=1337

View File

@@ -1,6 +0,0 @@
from www import create_app
app = create_app()
if __name__ == "__main__":
app.run()

View File

@@ -5,43 +5,41 @@ from flask import redirect, url_for, render_template
def create_app():
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
DATABASE=os.path.join(app.instance_path, 'www.sqlite'),
SQLALCHEMY_DATABASE_URI=os.environ.get("DATABASE_URI"),
SQLALCHEMY_TRACK_MODIFICATIONS=os.environ.get("TRACK_MODIFICATIONS"),
USERNAME=os.environ.get("USERNAME"),
PASSWORD=os.environ.get("PASSWORD"),
SECRET_KEY=os.environ.get("SECRET_KEY")
)
app.config.from_pyfile('config.py', silent=True)
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route('/')
def index():
return redirect(url_for('blog.index'))
from . import db
from www.models import db
db.init_app(app)
from . import auth
from www import commands
commands.init_app(app)
from www import auth
app.register_blueprint(auth.bp)
from . import admin
from www import admin
app.register_blueprint(admin.bp)
from . import blog
from www import blog
app.register_blueprint(blog.bp)
from . import now
from www import now
app.register_blueprint(now.bp)
from . import recommended
from www import recommended
app.register_blueprint(recommended.bp)
from . import projects
from www import projects
app.register_blueprint(projects.bp)
return app

View File

@@ -1,6 +1,5 @@
from flask import Blueprint, flash, g, redirect, render_template, request, session, url_for
from flask import Blueprint, render_template
from www.db import get_db
from www.auth import admin_required
bp = Blueprint('admin', __name__, url_prefix='/admin')

View File

@@ -1,11 +1,12 @@
import functools
from www.db import get_db
from werkzeug.exceptions import abort
from werkzeug.security import check_password_hash
from flask import Blueprint, request, flash, render_template, session, g, redirect, url_for
from flask import Blueprint, render_template, request, session
from flask import url_for, flash, redirect, g
from www.models import User
bp = Blueprint('auth', __name__, url_prefix='/auth')
@@ -16,21 +17,18 @@ def login():
username = request.form['username']
password = request.form['password']
db = get_db()
error = None
user = db.execute(
'SELECT * FROM users WHERE username = ?', (username,)
).fetchone()
user = User.query.filter_by(username=username).first()
if user is None:
error = 'Incorrect username.'
elif not check_password_hash(user['password'], password):
elif not check_password_hash(user.password, password):
error = 'Incorrect password.'
if error is None:
session.clear()
session['user_id'] = user['id']
session['user_id'] = user.id
return redirect(url_for('index'))
flash(error)
@@ -49,9 +47,7 @@ def load_logged_in_user():
if user_id is None:
g.user = None
else:
g.user = get_db().execute(
'SELECT * FROM users WHERE id = ?', (user_id,)
).fetchone()
g.user = User.query.get(user_id)
def admin_required(view):
@functools.wraps(view)

View File

@@ -1,23 +1,16 @@
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from flask import Blueprint, flash, redirect, render_template, request, url_for
from werkzeug.exceptions import abort
import markdown as md
from www.db import get_db
from www.models import db, Post
from www.auth import admin_required
bp = Blueprint('blog', __name__, url_prefix='/blog')
@bp.route('/')
def index():
db = get_db()
posts = db.execute(
'SELECT id, title, resume, created_at'
' FROM posts'
' ORDER BY created_at DESC'
).fetchall()
posts = Post.query.order_by(Post.created_at.desc()).all()
return render_template('blog/index.html', posts=posts)
@@ -38,13 +31,10 @@ def create():
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'INSERT INTO posts (title, markdown, html, resume)'
' VALUES (?, ?, ?, ?)',
(title, markdown, html, resume)
)
db.commit()
post = Post(title, markdown, html, resume)
db.session.add(post)
db.session.commit()
return redirect(url_for('blog.index'))
return render_template('blog/create.html')
@@ -52,12 +42,7 @@ def create():
@bp.route('/update/<int:id>', methods=('GET', 'POST'))
@admin_required
def update(id):
post = get_db().execute(
'SELECT id, title, markdown, resume'
' FROM posts'
' WHERE id = ?',
(id,)
).fetchone()
post = Post.query.get(id)
if post is None:
abort(404)
@@ -76,52 +61,34 @@ def update(id):
if error is not None:
flash(error)
else:
db = get_db()
db.execute(
'UPDATE posts'
' SET title = ?, markdown = ?, html = ?, resume = ?'
' WHERE id = ?',
(title, markdown, html, resume, id)
)
db.commit()
post.title = title
post.markdown = markdown
post.html = html
post.resume = resume
db.session.commit()
return redirect(url_for('blog.index'))
return render_template('blog/update.html', post=post)
@bp.route('/<int:id>')
def view(id):
post = get_db().execute(
'SELECT id, title, html'
' FROM posts'
' WHERE id = ?',
(id,)
).fetchone()
post = Post.query.get(id)
if post is None:
abort(404)
else:
return render_template('blog/view.html', post=post)
@bp.route('/delete/<int:id>', methods=('GET', 'POST',))
@bp.route('/delete/<int:id>', methods=['POST'])
@admin_required
def delete(id):
if request.method == 'GET':
abort(404)
db = get_db()
post = db.execute(
'SELECT id'
' FROM posts'
' WHERE id = ?',
(id,)
).fetchone()
print(post)
post = Post.query.get(id)
if post is None:
abort(404)
else:
db.execute('DELETE FROM posts WHERE id = ?', (id,))
db.commit()
db.session.delete(post)
db.session.commit()
return redirect(url_for('blog.index'))

46
www/commands.py Normal file
View File

@@ -0,0 +1,46 @@
import click
from flask import current_app
from flask.cli import with_appcontext
from werkzeug.security import generate_password_hash
from www.models import db, User, Now
def init_db():
db.create_all()
def generate_admin():
username = current_app.config['USERNAME']
if User.query.filter_by(username=username).first() is None:
password = current_app.config['PASSWORD']
user = User(username, generate_password_hash(password))
db.session.add(user)
db.session.commit()
def generate_base_now():
now = Now.query.first()
if now is None:
now = Now('', '')
db.session.add(now)
db.session.commit()
@click.command('init-db')
@with_appcontext
def init_db_command():
"""
Creates and initializes the db with the necesary data
If the db existed previously, it keeps it and his data
"""
init_db()
generate_admin()
generate_base_now()
def init_app(app):
app.cli.add_command(init_db_command)

View File

@@ -1,73 +0,0 @@
import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext
from werkzeug.security import generate_password_hash
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types = sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
def fill_with_dummy():
db = get_db()
with current_app.open_resource('dummy.sql') as f:
db.executescript(f.read().decode('utf8'))
def generate_admin():
db = get_db()
username = current_app.config['USERNAME']
password = current_app.config['PASSWORD']
db.execute(
'INSERT INTO users (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
db.commit()
@click.command('init-db')
@with_appcontext
def init_db_command():
"""Initializes the schema of the database"""
init_db()
click.echo('Initialized the database')
@click.command('fill-with-dummy')
@with_appcontext
def fill_with_dummy_command():
"""Adds dummy data to the existing database"""
fill_with_dummy()
click.echo('Database filled with dummy data')
@click.command('generate-admin')
@with_appcontext
def generate_admin_command():
"""Creates the admin account to be used"""
generate_admin()
click.echo('Created admin')
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
app.cli.add_command(fill_with_dummy_command)
app.cli.add_command(generate_admin_command)

View File

@@ -1,25 +0,0 @@
INSERT INTO posts (title, markdown, html, resume) values
(
"Excepturi et debitis explicabo occaecati",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Enim unde ut eaque vero saepe ut. Iure culpa modi ipsam maxime aliquid sed officiis. Consequatur minima quaerat molestias laudantium aut. Quia voluptas sint accusantium architecto."
),
(
"Excepturi et debitis explicabo occaecati",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Enim unde ut eaque vero saepe ut. Iure culpa modi ipsam maxime aliquid sed officiis. Consequatur minima quaerat molestias laudantium aut. Quia voluptas sint accusantium architecto."
),
(
"Excepturi et debitis explicabo occaecati",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Enim unde ut eaque vero saepe ut. Iure culpa modi ipsam maxime aliquid sed officiis. Consequatur minima quaerat molestias laudantium aut. Quia voluptas sint accusantium architecto."
),
(
"Excepturi et debitis explicabo occaecati",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Sit necessitatibus quibusdam autem facere tempore quibusdam assumenda. Quo sit asperiores earum beatae unde reiciendis perspiciatis. Blanditiis natus ex similique possimus optio veritatis.",
"Enim unde ut eaque vero saepe ut. Iure culpa modi ipsam maxime aliquid sed officiis. Consequatur minima quaerat molestias laudantium aut. Quia voluptas sint accusantium architecto."
);

53
www/models.py Normal file
View File

@@ -0,0 +1,53 @@
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
def __init__(self, username=None, password=None):
self.username = username
self.password = password
def __repr__(self):
return f'User {self.username}>'
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.Text, nullable=False)
markdown = db.Column(db.Text, nullable=False)
html = db.Column(db.Text, nullable=False)
resume = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __init__(self, title=None, markdown=None, html=None, resume=None):
self.title = title
self.markdown = markdown
self.html = html
self.resume = resume
def __repr__(self):
return f'<Post {self.title} {self.created_at}>'
class Now(db.Model):
__tablename__ = 'nows'
id = db.Column(db.Integer, primary_key=True)
markdown = db.Column(db.Text, nullable=False)
html = db.Column(db.Text, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __init__(self, markdown=None, html=None):
self.markdown = markdown
self.html = html
def __repr__(self):
return f'<Now {self.created_at}>'

View File

@@ -1,25 +1,21 @@
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
import markdown as md
from www.db import get_db
from flask import Blueprint, redirect, render_template, request, url_for
from www.auth import admin_required
from www.models import db, Now
bp = Blueprint('now', __name__, url_prefix='/now')
@bp.route('/')
def index():
db = get_db()
now = db.execute(
'SELECT html'
' FROM now'
).fetchone()
now = Now.query.order_by(Now.created_at.desc()).first()
return render_template('now/now.html', now=now)
@bp.route('/update', methods=('GET', 'POST'))
@admin_required
def update():
@@ -27,19 +23,12 @@ def update():
markdown = request.form['markdown']
html = parse_markdown(markdown)
db = get_db()
db.execute(
'UPDATE now'
' SET markdown = ?, html = ?',
(markdown, html,)
)
db.commit()
now = Now(markdown, html)
db.session.add(now)
db.session.commit()
return redirect(url_for('now.index'))
now = get_db().execute(
'SELECT id, markdown'
' FROM now'
).fetchone()
now = Now.query.order_by(Now.created_at.desc()).first()
return render_template('now/update.html', now=now)
def parse_markdown(markdown):

View File

@@ -1,17 +1,7 @@
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
import markdown as md
from www.db import get_db
from www.auth import admin_required
from flask import Blueprint, render_template
bp = Blueprint('projects', __name__, url_prefix='/projects')
@bp.route('/')
def index():
return render_template('empty.html')

View File

@@ -1,17 +1,8 @@
from flask import (
Blueprint, flash, g, redirect, render_template, request, url_for
)
from flask import Blueprint, render_template
from werkzeug.exceptions import abort
import markdown as md
from www.db import get_db
from www.auth import admin_required
bp = Blueprint('recommended', __name__, url_prefix='/recommended')
@bp.route('/')
def index():
return render_template('empty.html')

View File

@@ -1,28 +0,0 @@
DROP TABLE IF EXISTS posts;
DROP TABLE IF EXISTS now;
DROP TABLE IF EXISTS users;
CREATE TABLE posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
markdown TEXT NOT NULL,
html TEXT NOT NULL,
resume TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE now (
id INTEGER PRIMARY KEY AUTOINCREMENT,
markdown TEXT NOT NULL,
html TEXT NOT NULL
);
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL
);
INSERT INTO now (markdown, html) VALUES (
"",""
);