Los archivos se guardan en la base de datos y se agregaron categorias
Si, creo que eso nada mas
This commit is contained in:
@@ -29,6 +29,9 @@ def create_app():
|
|||||||
from . import auth
|
from . import auth
|
||||||
app.register_blueprint(auth.bp)
|
app.register_blueprint(auth.bp)
|
||||||
|
|
||||||
|
from . import categories
|
||||||
|
app.register_blueprint(categories.bp)
|
||||||
|
|
||||||
from . import about
|
from . import about
|
||||||
app.register_blueprint(about.bp)
|
app.register_blueprint(about.bp)
|
||||||
app.add_url_rule('/about', endpoint='about')
|
app.add_url_rule('/about', endpoint='about')
|
||||||
@@ -37,4 +40,5 @@ def create_app():
|
|||||||
app.register_blueprint(files.bp)
|
app.register_blueprint(files.bp)
|
||||||
app.add_url_rule('/', endpoint='index')
|
app.add_url_rule('/', endpoint='index')
|
||||||
|
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|||||||
88
files/categories.py
Normal file
88
files/categories.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
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 files.auth import admin_required
|
||||||
|
from files.files import get_files_by_category
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
@bp.route('/create', methods=['GET', 'POST'])
|
||||||
|
@admin_required
|
||||||
|
def create():
|
||||||
|
if request.method == 'POST':
|
||||||
|
name = request.form['name']
|
||||||
|
error = None
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
error = "Name is required"
|
||||||
|
|
||||||
|
if error is not None:
|
||||||
|
flash(error)
|
||||||
|
else:
|
||||||
|
db = get_db()
|
||||||
|
db.execute(
|
||||||
|
'INSERT INTO categories (name)'
|
||||||
|
' VALUES (?)',
|
||||||
|
(name,)
|
||||||
|
)
|
||||||
|
db.commit()
|
||||||
|
return redirect(url_for('categories.index'))
|
||||||
|
|
||||||
|
return render_template('categories/create.html')
|
||||||
|
|
||||||
|
@bp.route('<int:id>')
|
||||||
|
def view(id):
|
||||||
|
category = get_category(id)
|
||||||
|
files = get_files_by_category(id)
|
||||||
|
return render_template('categories/view.html', category=category, files=files)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:id>/update')
|
||||||
|
@admin_required
|
||||||
|
def update():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@bp.route('/<int:id>/delete')
|
||||||
|
@admin_required
|
||||||
|
def delete():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
16
files/db.py
16
files/db.py
@@ -37,6 +37,10 @@ def generate_admin():
|
|||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
def generate_files():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@click.command('init-db')
|
@click.command('init-db')
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def init_db_command():
|
def init_db_command():
|
||||||
@@ -51,6 +55,18 @@ def generate_admin_command():
|
|||||||
generate_admin()
|
generate_admin()
|
||||||
click.echo('The admin was created')
|
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):
|
def init_app(app):
|
||||||
app.teardown_appcontext(close_db)
|
app.teardown_appcontext(close_db)
|
||||||
app.cli.add_command(init_db_command)
|
app.cli.add_command(init_db_command)
|
||||||
|
|||||||
189
files/files.py
189
files/files.py
@@ -1,12 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from flask import Flask, Blueprint, flash, request, redirect, url_for, current_app, render_template, send_from_directory
|
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.utils import secure_filename
|
||||||
from werkzeug.exceptions import abort
|
from werkzeug.exceptions import abort
|
||||||
|
|
||||||
from files.auth import admin_required
|
from files.auth import admin_required
|
||||||
|
from files.db import get_db
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint('files', __name__)
|
bp = Blueprint('files', __name__)
|
||||||
@@ -18,62 +19,194 @@ def get_extension(filename):
|
|||||||
def get_path_in_upload(filename):
|
def get_path_in_upload(filename):
|
||||||
return os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
|
return os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
db.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))
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
return new_name
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
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():
|
def index():
|
||||||
filenames = os.listdir(current_app.config['UPLOAD_FOLDER'])
|
if g.user is None:
|
||||||
return render_template('files/index.html', filenames=filenames)
|
files = get_public_files()
|
||||||
|
else:
|
||||||
|
files = get_files()
|
||||||
|
|
||||||
|
return render_template('files/index.html', files=files)
|
||||||
|
|
||||||
@bp.route('/upload', methods=['GET', 'POST'])
|
@bp.route('/upload', methods=['GET', 'POST'])
|
||||||
@admin_required
|
@admin_required
|
||||||
def upload_file():
|
def upload_file():
|
||||||
|
db = get_db()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if 'file' not in request.files:
|
if 'file' not in request.files:
|
||||||
flash('No file part')
|
flash('No file part')
|
||||||
return redirect(request.url)
|
return redirect(request.url)
|
||||||
file = request.files['file']
|
else:
|
||||||
|
file = request.files['file']
|
||||||
|
|
||||||
|
if 'private' not in request.form:
|
||||||
|
private = None
|
||||||
|
else:
|
||||||
|
private = request.form['private']
|
||||||
|
|
||||||
|
if 'category' not in request.form:
|
||||||
|
flash('No category selected')
|
||||||
|
return redirect(request.url)
|
||||||
|
else:
|
||||||
|
category = get_category(request.form['category'])
|
||||||
|
|
||||||
if file.filename == '':
|
if file.filename == '':
|
||||||
flash('No seleted file')
|
flash('No seleted file')
|
||||||
return rediret(request.url)
|
return redirect(request.url)
|
||||||
|
|
||||||
if file:
|
if file:
|
||||||
filename = secure_filename(file.filename)
|
filename = save_file(file, private, category)
|
||||||
file.save(get_path_in_upload(filename))
|
return redirect(url_for('files.index'))
|
||||||
|
|
||||||
return redirect(url_for('files.preview_file', filename=filename))
|
return render_template('files/upload.html', categories=get_categories())
|
||||||
return render_template('files/upload.html')
|
|
||||||
|
|
||||||
@bp.route('/preview/<path:filename>')
|
@bp.route('/preview/<int:id>')
|
||||||
def preview_file(filename):
|
def preview_file(id):
|
||||||
file = os.path.isfile(get_path_in_upload(filename))
|
file = get_file(id)
|
||||||
if os.path.isfile(get_path_in_upload(filename)):
|
if (file['private'] == 1 and g.user is not None) or (file['private'] == 0):
|
||||||
return render_template('files/preview.html', filename=filename)
|
return render_template('files/preview.html', file=file)
|
||||||
else:
|
else:
|
||||||
abort(404)
|
return abort(404)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/rename/<path:filename>', methods=['POST'])
|
@bp.route('/rename/<int:id>', methods=['POST'])
|
||||||
@admin_required
|
@admin_required
|
||||||
def rename_file(filename):
|
def rename_file(id):
|
||||||
if request.method == 'POST' and os.path.isfile(get_path_in_upload(filename)):
|
if request.method == 'POST':
|
||||||
|
file = get_file(id)
|
||||||
|
|
||||||
new_name = request.form['new_name'].lower()
|
new_name = request.form['new_name'].lower()
|
||||||
extension = filename.rsplit('.', 1)[1].lower()
|
extension = file['filename'].rsplit('.', 1)[1].lower()
|
||||||
|
|
||||||
if "." in new_name and get_extension(new_name):
|
if "." in new_name and get_extension(new_name):
|
||||||
new_name = new_name.rsplit('.',1)[0] + '.' + extension
|
new_name = new_name.rsplit('.',1)[0] + '.' + extension
|
||||||
else:
|
else:
|
||||||
new_name = new_name + '.' + extension
|
new_name = new_name + '.' + extension
|
||||||
|
|
||||||
new_name = secure_filename(new_name)
|
_rename_file(file, new_name)
|
||||||
os.rename(get_path_in_upload(filename), get_path_in_upload(new_name))
|
|
||||||
|
|
||||||
return redirect(url_for('files.preview_file', filename=new_name))
|
return redirect(url_for('files.preview_file', id=file['id']))
|
||||||
|
|
||||||
@bp.route('/delete/<path:filename>', methods=['POST'])
|
@bp.route('/delete/<int:id>', methods=['POST'])
|
||||||
@admin_required
|
@admin_required
|
||||||
def delete_file(filename):
|
def delete_file(id):
|
||||||
full_path = os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
|
if request.method == 'POST':
|
||||||
|
file = get_file(id)
|
||||||
if request.method == 'POST' and os.path.isfile(full_path):
|
print(file)
|
||||||
os.remove(full_path)
|
_delete_file(file)
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ input[type="button"].button-primary:focus {
|
|||||||
border-color: var(--secondary-color);
|
border-color: var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-listing{
|
.grid{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
grid-gap: 3rem 1rem;
|
grid-gap: 3rem 1rem;
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="{{ url_for('index') }}" class="nav-brand">/files</a>
|
<a href="{{ url_for('index') }}" class="nav-brand">/files</a>
|
||||||
|
<a href="{{ url_for('categories.index') }}" class="nav-link">/categories</a>
|
||||||
<a href="{{ url_for('about') }}" class="nav-link">/about</a>
|
<a href="{{ url_for('about') }}" class="nav-link">/about</a>
|
||||||
|
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<a href="{{ url_for('files.upload_file') }}" class="nav-link">/upload</a>
|
<a href="{{ url_for('files.upload_file') }}" class="nav-link">/upload</a>
|
||||||
<a href="{{ url_for('auth.logout') }}" class="nav-link">/logout</a>
|
<a href="{{ url_for('auth.logout') }}" class="nav-link">/logout</a>
|
||||||
@@ -21,6 +23,12 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section class="container">
|
<section class="container">
|
||||||
|
<ul>
|
||||||
|
{% for message in get_flashed_messages() %}
|
||||||
|
<li class="flash">{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
12
files/templates/categories/create.html
Normal file
12
files/templates/categories/create.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Categories{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h3>Create a new Category</h3>
|
||||||
|
<form method="post">
|
||||||
|
<label for="name">~/name</label>
|
||||||
|
<input type="text" class="u-full-width" name="name" id="name">
|
||||||
|
<input type="submit" class="button-primary" value="create">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
13
files/templates/categories/index.html
Normal file
13
files/templates/categories/index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}category{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="grid">
|
||||||
|
{% for category in categories %}
|
||||||
|
<a href="{{ url_for('categories.view', id=category.id) }}">{{ category.name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
13
files/templates/categories/view.html
Normal file
13
files/templates/categories/view.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}categories/view/{{ category.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h3>{{ category.name }}</h3>
|
||||||
|
<div class="grid">
|
||||||
|
{% for file in files %}
|
||||||
|
<a href="{{ url_for('files.preview_file', id=file.id) }}">{{ file.filename }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
{% block title %}{% endblock %}
|
{% block title %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="file-listing">
|
<div class="grid">
|
||||||
{% for filename in filenames %}
|
{% for file in files %}
|
||||||
<a href="{{ url_for('files.preview_file', filename=filename) }}">{{ filename }}</a>
|
<a href="{{ url_for('files.preview_file', id=file.id) }}">{{ file.filename}}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -3,21 +3,21 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<form method="post" action={{ url_for('files.delete_file', filename=filename) }}>
|
<form method="post" action={{ url_for('files.delete_file', id=file.id) }}>
|
||||||
<input type="submit" class="button-primary u-pull-right" value="delete">
|
<input type="submit" class="button-primary u-pull-right" value="delete">
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3 class="u-pull-left"><a href="{{ url_for('files.uploaded_file', filename=filename) }}">{{ filename }}</a></h3>
|
<h3 class="u-pull-left"><a href="{{ url_for('files.uploaded_file', filename=file.filename) }}">{{ file.filename }}</a></h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img src="{{ url_for('files.uploaded_file', filename=filename) }}">
|
<img src="{{ url_for('files.uploaded_file', filename=file.filename) }}">
|
||||||
|
|
||||||
{% if g.user %}
|
{% if g.user %}
|
||||||
<form action="{{ url_for('files.rename_file', filename=filename) }}" method="post">
|
<form action="{{ url_for('files.rename_file', id=file.id) }}" method="post">
|
||||||
<label for="new_name">~/rename</label>
|
<label for="new_name">~/rename</label>
|
||||||
<input type="text" class="u-full-width" id="new_name" name="new_name" value="{{ filename }}">
|
<input type="text" class="u-full-width" id="new_name" name="new_name" value="{{ file.filename }}">
|
||||||
<input type="submit" class="button-primary u-pull-right" value="rename">
|
<input type="submit" class="button-primary u-pull-right" value="rename">
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -4,7 +4,19 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
<input type="file" class="u-full-width" name="file">
|
<label for="file">~/file</label>
|
||||||
|
<input type="file" class="u-full-width" name="file" id="file">
|
||||||
|
<label for="category">~/category</label>
|
||||||
|
<select class="u-full-width" name="category" id="category">
|
||||||
|
{% for category in categories %}
|
||||||
|
<option value="{{ category.id }}">{{ category.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="private">~/private</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="private" id="private">
|
||||||
|
</label>
|
||||||
|
|
||||||
<input type="submit" class="button-primary" value="upload">
|
<input type="submit" class="button-primary" value="upload">
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user