diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
new file mode 100644
index 0000000..0a9e463
--- /dev/null
+++ b/.idea/dataSources.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$PROJECT_DIR$/instance/files.sqlite
+
+
+
+
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$PROJECT_DIR$/instance/files-test.sqlite
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..15a15b2
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/files.danielcortes.xyz.iml b/.idea/files.danielcortes.xyz.iml
new file mode 100644
index 0000000..28d3786
--- /dev/null
+++ b/.idea/files.danielcortes.xyz.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..7c8f72d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..90c7974
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/files/__init__.py b/files/__init__.py
index f2a9396..66bff24 100644
--- a/files/__init__.py
+++ b/files/__init__.py
@@ -3,42 +3,45 @@ import os
from flask import Flask, render_template
from werkzeug import SharedDataMiddleware
+
def create_app():
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
- DATABASE = os.path.join(app.instance_path, 'files.sqlite'),
- USERNAME = 'dev',
- PASSWORD = 'secret',
- SECRET_KEY = '1337',
- UPLOAD_FOLDER = 'uploads',
- ALLOWED_EXTENSIONS = set(['png', 'jpg'])
+ SQLALCHEMY_DATABASE_URI="sqlite:///{}".format(os.path.join(app.instance_path, 'files.sqlite')),
+ SQLALCHEMY_TRACK_MODIFICATIONS=False,
+ USERNAME='dev',
+ PASSWORD='secret',
+ SECRET_KEY='1337',
+ UPLOAD_FOLDER='uploads'
)
app.config.from_pyfile('config.py')
- app.wsgi_app = SharedDataMiddleware(app.wsgi_app, { '/uploads': app.config['UPLOAD_FOLDER'] })
+ app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {'/uploads': app.config['UPLOAD_FOLDER']})
try:
os.makedirs(app.instance_path)
except OSError:
pass
- from . import db
+ from files.models import db
db.init_app(app)
- from . import auth
+ from files import commands
+ commands.init_app(app)
+
+ from files import auth
app.register_blueprint(auth.bp)
- from . import categories
+ from files import categories
app.register_blueprint(categories.bp)
- from . import about
+ from files import about
app.register_blueprint(about.bp)
app.add_url_rule('/about', endpoint='about')
- from . import files
+ from files import files
app.register_blueprint(files.bp)
app.add_url_rule('/', endpoint='index')
-
return app
diff --git a/files/about.py b/files/about.py
index 3e240bb..da40fe7 100644
--- a/files/about.py
+++ b/files/about.py
@@ -1,9 +1,9 @@
-from files.db import get_db
-
from flask import Blueprint, request, render_template, redirect, url_for, flash
+from files.models import db, Message
bp = Blueprint('about', __name__, url_prefix='/about')
+
@bp.route('/', methods=('GET', 'POST'))
def about():
if request.method == 'POST':
@@ -11,7 +11,6 @@ def about():
email = request.form['email']
message = request.form['message']
- db = get_db()
error = None
if not name:
@@ -20,21 +19,18 @@ def about():
error = 'Missing email'
elif not message:
error = 'Empty message'
-
+
if error is not None:
flash(error)
else:
- db.execute(
- 'INSERT INTO messages'
- ' (name, email, message)'
- ' VALUES (?, ?, ?)',
- (name, email, message)
- )
- db.commit()
- return redirect(url_for('about.thanks'))
+ m = Message(name, email, message)
+ db.session.add(m)
+ db.session.commit()
+ return redirect(url_for('about.thanks'))
return render_template('about/about.html')
+
@bp.route('/thanks')
def thanks():
return render_template('about/thanks.html')
diff --git a/files/auth.py b/files/auth.py
index 0735d7b..d028986 100644
--- a/files/auth.py
+++ b/files/auth.py
@@ -1,47 +1,46 @@
import functools
-from files.db import get_db
+from files.models import db, User
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
-
bp = Blueprint('auth', __name__, url_prefix='/auth')
+
@bp.route('/login', methods=('GET', 'POST'))
def login():
if request.method == 'POST':
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)
return render_template('auth/login.html')
+
@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))
+
@bp.before_app_request
def load_logged_in_user():
user_id = session.get('user_id')
@@ -49,9 +48,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):
@@ -63,4 +60,3 @@ def admin_required(view):
return view(**kwargs)
return wrapped_view
-
diff --git a/files/categories.py b/files/categories.py
index b7991d8..f6c2c60 100644
--- a/files/categories.py
+++ b/files/categories.py
@@ -1,48 +1,15 @@
-from flask import Flask, Blueprint, flash, request, redirect, url_for, current_app, render_template, jsonify
-
-from werkzeug.exceptions import abort
-
-from files.db import get_db
+from flask import Flask, Blueprint, flash, request, redirect, url_for, current_app, render_template, jsonify
from files.auth import admin_required
-from files.files import get_files_by_category
+from files.models import Category, db
bp = Blueprint('categories', __name__, url_prefix='/categories')
-def get_categories():
- db = get_db()
- categories = db.execute(
- 'SELECT id, name'
- ' FROM categories'
- ' ORDER BY name DESC'
- ).fetchall()
- return categories
-
-def get_category(id):
- db = get_db()
- category = db.execute(
- 'SELECT id, name'
- ' FROM categories'
- ' WHERE id = ?'
- ' LIMIT 1',
- (id,)
- ).fetchone()
- return category
-
-def get_files_by_category(id):
- db = get_db()
- files = db.execute(
- 'SELECT id, filename, private'
- ' FROM files'
- ' WHERE category = ?'
- ' ORDER BY filename DESC',
- (id,)
- ).fetchall()
- return files
@bp.route('/')
def index():
- categories = get_categories()
- return render_template('categories/index.html', categories=categories)
+ categories = Category.query.all()
+ return render_template('categories/index.html', categories=categories)
+
@bp.route('/create', methods=['GET', 'POST'])
@admin_required
@@ -57,21 +24,18 @@ def create():
if error is not None:
flash(error)
else:
- db = get_db()
- db.execute(
- 'INSERT INTO categories (name)'
- ' VALUES (?)',
- (name,)
- )
- db.commit()
+ c = Category(name)
+ db.session.add(c)
+ db.session.commit()
return redirect(url_for('categories.index'))
return render_template('categories/create.html')
+
@bp.route('')
def view(id):
- category = get_category(id)
- files = get_files_by_category(id)
+ category = Category.query.get(id)
+ files = category.files
return render_template('categories/view.html', category=category, files=files)
@@ -80,9 +44,8 @@ def view(id):
def update():
pass
+
@bp.route('//delete')
@admin_required
def delete():
pass
-
-
diff --git a/files/commands.py b/files/commands.py
new file mode 100644
index 0000000..dbd3f5a
--- /dev/null
+++ b/files/commands.py
@@ -0,0 +1,90 @@
+import click
+import os
+
+from flask import current_app
+from flask.cli import with_appcontext
+
+from werkzeug.security import generate_password_hash
+
+from files.models import db, User, Category, File
+
+
+def init_db():
+ db.drop_all()
+ db.create_all()
+
+
+def generate_admin():
+ username = current_app.config['USERNAME']
+ password = current_app.config['PASSWORD']
+
+ u = User(username, generate_password_hash(password))
+ db.session.add(u)
+ db.session.commit()
+
+
+def add_defaults():
+ default_category = Category('Default')
+ db.session.add(default_category)
+ db.session.commit()
+
+
+def add_files():
+ existing_files = os.listdir(current_app.config['UPLOAD_FOLDER'])
+ default_category = Category.query.filter_by(name='Default').first()
+ added = 0
+
+ for f in existing_files:
+ search = File.query.filter_by(filename=f).first()
+ if search is None:
+ file = File(f, 0, default_category.id)
+ db.session.add(file)
+ added += 1
+ db.session.commit()
+
+ return added
+
+
+@click.command('init-db')
+@with_appcontext
+def init_db_command():
+ """
+ Creates the db file
+ """
+ init_db()
+
+
+@click.command("add-defaults")
+@with_appcontext
+def add_defaults_command():
+ """
+ Initializes the database with default data
+ """
+ add_defaults()
+ click.echo("Defaults added")
+
+
+@click.command('generate-admin')
+@with_appcontext
+def generate_admin_command():
+ """Creates the admin of the system"""
+ generate_admin()
+ click.echo('The admin was created')
+
+
+@click.command('add-files')
+@with_appcontext
+def add_files_command():
+ """
+ Generates the rows in the database for the files currently uploaded
+ They all will have default privacy, so, public
+ """
+ added_size= add_files()
+ click.echo(f'added {added_size} files')
+
+
+def init_app(app):
+ app.cli.add_command(init_db_command)
+ app.cli.add_command(add_defaults_command)
+ app.cli.add_command(generate_admin_command)
+ app.cli.add_command(add_files_command)
diff --git a/files/db.py b/files/db.py
deleted file mode 100644
index 66ccf47..0000000
--- a/files/db.py
+++ /dev/null
@@ -1,77 +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 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()
-
-def generate_files():
- pass
-
-
-@click.command('init-db')
-@with_appcontext
-def init_db_command():
- """Inits the database with it's schema"""
- init_db()
- click.echo('The database was initialized')
-
-@click.command('generate-admin')
-@with_appcontext
-def generate_admin_command():
- """Creates the admin of the system"""
- generate_admin()
- click.echo('The admin was created')
-
-
-@click.command('generate-files')
-@with_appcontext
-def generate_files_command():
- """
- Generates the rows in the database for the files currently uploaded
- They all will have default privacy, so, public
- """
- generate_files()
- click.echo('files generated')
-
-
-def init_app(app):
- app.teardown_appcontext(close_db)
- app.cli.add_command(init_db_command)
- app.cli.add_command(generate_admin_command)
-
-
-
-
diff --git a/files/files.py b/files/files.py
index 8a4e068..b7f248d 100644
--- a/files/files.py
+++ b/files/files.py
@@ -1,155 +1,74 @@
import os
-import random
-from flask import Flask, Blueprint, flash, request, redirect, url_for, current_app, render_template, send_from_directory, g
+from flask import Flask, Blueprint, flash, request, redirect, url_for, current_app, render_template, \
+ send_from_directory, g
from werkzeug.utils import secure_filename
from werkzeug.exceptions import abort
+from files.models import db, File, Category, User
from files.auth import admin_required
-from files.db import get_db
-
bp = Blueprint('files', __name__)
bp.add_url_rule('/uploads/', 'uploaded_file', build_only=True)
-def get_extension(filename):
- return filename.rsplit('.', 1)[1].lower()
-def get_path_in_upload(filename):
+def _get_extension(filename):
+ return filename.rsplit('.', 1)[1].lower()
+
+
+def _get_path_in_upload(filename):
return os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
-def save_file(file, private, category):
+
+def _save_file(file, private, category):
if private is None:
is_private = 0
else:
is_private = 1
- db = get_db()
-
filename = secure_filename(file.filename)
- db.execute(
- 'INSERT INTO files (filename, private, category)'
- ' VALUES (?,?,?)',
- (filename, is_private, category['id'],)
- )
- file.save(get_path_in_upload(filename))
+ file.save(_get_path_in_upload(filename))
+ f = File(filename, is_private, category.id)
- db.commit()
+ db.session.add(f)
+ db.session.commit()
- return filename
def _rename_file(file, new_name):
- db = get_db()
-
new_name = secure_filename(new_name)
- db.execute(
- 'UPDATE files'
- ' SET filename = ?'
- ' WHERE id = ?',
- (new_name, file['id'],)
- )
- os.rename(get_path_in_upload(file['filename']), get_path_in_upload(new_name))
+ os.rename(_get_path_in_upload(file.filename), _get_path_in_upload(new_name))
+ file.filename = new_name
- db.commit()
-
- return new_name
+ db.session.commit()
def _delete_file(file):
- db = get_db()
- db.execute(
- 'DELETE from files'
- ' WHERE id = ?',
- (file['id'],)
- )
-
- os.remove(get_path_in_upload(file['filename']))
- db.commit()
+ os.remove(_get_path_in_upload(file.filename))
+ db.session.delete(file)
+ db.session.commit()
-def get_files():
- db = get_db()
- files = db.execute(
- 'SELECT id, filename, private, category'
- ' FROM files'
- ' ORDER BY filename'
- ).fetchall()
- return files
-
-def get_public_files():
- db = get_db()
- files = db.execute(
- 'SELECT id, filename, private, category'
- ' FROM files'
- ' WHERE private = false'
- ' ORDER BY filename'
- ).fetchall()
-
- return files
-
-def get_files_by_category(id):
- db = get_db()
- files = db.execute(
- 'SELECT id, filename, private'
- ' FROM files'
- ' WHERE category = ?'
- ' ORDER BY filename',
- (id,)
- ).fetchall()
-
-def get_file(id):
- db = get_db()
- file = db.execute(
- 'SELECT id, filename, private, category'
- ' FROM files'
- ' WHERE id = ?'
- ' LIMIT 1',
- (id,)
- ).fetchone()
- return file
-
-def get_categories():
- db = get_db()
- categories = db.execute(
- 'SELECT id, name'
- ' FROM categories'
- ' ORDER BY name'
- ).fetchall()
- return categories
-
-def get_category(id):
- db = get_db()
- category = db.execute(
- 'SELECT id, name'
- ' FROM categories'
- ' WHERE id = ?'
- ' LIMIT 1',
- (id,)
- ).fetchone()
- return category
-
-@bp.route('/', methods=['GET', 'POST'])
+@bp.route('/', methods=['GET', 'POST'])
def index():
if g.user is None:
- files = get_public_files()
- else:
- files = get_files()
+ files = File.query.filter_by(private=0).all()
+ else:
+ files = File.query.all()
return render_template('files/index.html', files=files)
+
@bp.route('/upload', methods=['GET', 'POST'])
@admin_required
def upload_file():
- db = get_db()
-
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
- else:
+ else:
file = request.files['file']
if 'private' not in request.form:
@@ -160,23 +79,27 @@ def upload_file():
if 'category' not in request.form:
flash('No category selected')
return redirect(request.url)
- else:
- category = get_category(request.form['category'])
+
+ category = Category.query.get(request.form['category'])
+ if category is None:
+ flash('The category selected won\'t exists')
+ return redirect(request.url)
if file.filename == '':
flash('No seleted file')
return redirect(request.url)
if file:
- filename = save_file(file, private, category)
+ _save_file(file, private, category)
return redirect(url_for('files.index'))
-
- return render_template('files/upload.html', categories=get_categories())
+
+ return render_template('files/upload.html', categories=Category.query.all())
+
@bp.route('/preview/')
def preview_file(id):
- file = get_file(id)
- if (file['private'] == 1 and g.user is not None) or (file['private'] == 0):
+ file = File.query.get(id)
+ if (file.private == 1 and g.user is not None) or (file.private == 0):
return render_template('files/preview.html', file=file)
else:
return abort(404)
@@ -186,28 +109,27 @@ def preview_file(id):
@admin_required
def rename_file(id):
if request.method == 'POST':
- file = get_file(id)
+ file = File.query.get(id)
new_name = request.form['new_name'].lower()
- extension = file['filename'].rsplit('.', 1)[1].lower()
+ extension = file.filename.rsplit('.', 1)[1].lower()
- if "." in new_name and get_extension(new_name):
- new_name = new_name.rsplit('.',1)[0] + '.' + extension
+ if "." in new_name and _get_extension(new_name):
+ new_name = new_name.rsplit('.', 1)[0] + '.' + extension
else:
new_name = new_name + '.' + extension
-
+
_rename_file(file, new_name)
-
- return redirect(url_for('files.preview_file', id=file['id']))
+
+ return redirect(url_for('files.preview_file', id=file.id))
+
@bp.route('/delete/', methods=['POST'])
@admin_required
def delete_file(id):
if request.method == 'POST':
- file = get_file(id)
- print(file)
+ file = File.query.get(id)
_delete_file(file)
return redirect(url_for('index'))
else:
abort(404)
-
diff --git a/files/models.py b/files/models.py
new file mode 100644
index 0000000..a17f55d
--- /dev/null
+++ b/files/models.py
@@ -0,0 +1,64 @@
+from flask_sqlalchemy import SQLAlchemy
+from datetime import datetime
+
+db = SQLAlchemy()
+
+
+class User(db.Model):
+ __tablename__ = 'users'
+ id = db.Column(db.Integer, primary_key=True)
+ username = db.Column(db.String, unique=True, nullable=False)
+ password = db.Column(db.String, nullable=False)
+
+ def __init__(self, username=None, password=None):
+ self.username = username
+ self.password = password
+
+ def __repr__(self):
+ return f''
+
+
+class Message(db.Model):
+ __tablename__ = 'messages'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String, nullable=False)
+ email = db.Column(db.String, nullable=False)
+ message = db.Column(db.Text, nullable=False)
+ sended = db.Column(db.DateTime, default=datetime.utcnow())
+
+ def __init__(self, name=None, email=None, message=None):
+ self.name = name
+ self.email = email
+ self.message = message
+
+ def __repr__(self):
+ return f''
+
+
+class File(db.Model):
+ __tablename__ = 'files'
+ id = db.Column(db.Integer, primary_key=True)
+ filename = db.Column(db.String, nullable=False)
+ private = db.Column(db.Integer, nullable=False)
+ category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
+
+ def __init__(self, filename=None, private=None, category_id=None):
+ self.filename = filename
+ self.private = private
+ self.category_id = category_id
+
+ def __repr__(self):
+ return f''
+
+
+class Category(db.Model):
+ __tablename__ = 'categories'
+ id = db.Column(db.Integer, primary_key=True)
+ name = db.Column(db.String, nullable=False)
+ files = db.relationship('File', backref='category', lazy=True)
+
+ def __init__(self, name=None):
+ self.name = name
+
+ def __repr__(self):
+ return f''
diff --git a/files/schema.sql b/files/schema.sql
deleted file mode 100644
index fad2c20..0000000
--- a/files/schema.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-DROP TABLE IF EXISTS users;
-DROP TABLE IF EXISTS messages;
-DROP TABLE IF EXISTS files;
-DROP TABLE IF EXISTS categories;
-
-CREATE TABLE users (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- username TEXT NOT NULL,
- password TEXT NOT NULL
-);
-
-CREATE TABLE messages (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- name TEXT NOT NULL,
- email TEXT NOT NULL,
- message TEXT NOT NULL,
- sended TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-);
-
-CREATE TABLE files (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- filename TEXT NOT NULL,
- private INTEGER NOT NULL DEFAULT 0,
- category INTEGER NOT NULL,
- FOREIGN KEY(category) REFERENCES categories(id)
-);
-
-CREATE TABLE categories (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- name TEXT NOT NULL
-);
-
-