Integrate htmx and dropzone for file Section

This commit is contained in:
kitoy 2026-01-13 01:53:13 +01:00
parent 0e79fdcb36
commit 5abbf367ab
15 changed files with 248 additions and 225 deletions

3
.gitignore vendored
View File

@ -1,5 +1,5 @@
*__pycache__/ *__pycache__/
base.db *.db
log.txt log.txt
config.py config.py
users/ users/
@ -8,3 +8,4 @@ sys
*#* *#*
.* .*
base.db.new base.db.new
public/*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
static/vendors/dropzone/dropzone.css vendored Normal file
View File

@ -0,0 +1 @@
@keyframes passing-through{0%{opacity:0;transform:translateY(40px)}30%,70%{opacity:1;transform:translateY(0px)}100%{opacity:0;transform:translateY(-40px)}}@keyframes slide-in{0%{opacity:0;transform:translateY(40px)}30%{opacity:1;transform:translateY(0px)}}@keyframes pulse{0%{transform:scale(1)}10%{transform:scale(1.1)}20%{transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:1px solid rgba(0,0,0,.8);border-radius:5px;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:3em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{transition:opacity .2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:hsla(0,0%,100%,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid rgba(0,0,0,0)}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:hsla(0,0%,100%,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{transform:scale(1.05, 1.05);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px;background:rgba(0,0,0,.8);border-radius:50%}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px;fill:#fff}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;transition:all .2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;transition:opacity .4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:20px;top:50%;margin-top:-10px;left:15%;right:15%;border:3px solid rgba(0,0,0,.8);background:rgba(0,0,0,.8);border-radius:10px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#fff;display:block;position:relative;height:100%;width:0;transition:width 300ms ease-in-out;border-radius:17px}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;transition:opacity .3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#b10606;padding:.5em 1em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:"";position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid rgba(0,0,0,0);border-right:6px solid rgba(0,0,0,0);border-bottom:6px solid #b10606}/*# sourceMappingURL=dropzone.css.map */

1
static/vendors/htmx/htmx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
<script>
window.onload = function () {
var dropzoneOptions = {
dictDefaultMessage: 'Déposez vos fichiers ici!',
paramName: "file",
maxFilesize: 1024, // MB
url: "/upload-dropzone",
chunking: true,
forceChunking: true,
chunkSize: 1000000,
autoProcessQueue: true,
init: function () {
this.on("success", function (file) {
console.log("success > " + file.name);
setTimeout(() => { this.removeFile(file); }, 2000);
});
}
};
var uploader = document.querySelector('#uploader');
var myDropzone = new Dropzone(uploader, dropzoneOptions);
console.log("Loaded");
};
</script>

4
templates/_js_htmx.html Normal file
View File

@ -0,0 +1,4 @@
<script src="{{ url_for('static', filename='vendors/htmx/htmx.min.js') }}"> </script>

View File

@ -0,0 +1,3 @@
<script src="{{ url_for('static', filename='vendors/dropzone/dropzone-min.js') }}"></script>
<link href="{{ url_for('static', filename='vendors/dropzone/dropzone.css') }}" rel="stylesheet">

View File

@ -26,83 +26,19 @@
<h5> <h5>
Vous pouvez partager des liens de vos fichiers avec les autres membres de ce serveur uniquement. Si vous partagez un lien avec une personne non inscrite elle ne pourra pas y avoir accès Vous pouvez partager des liens de vos fichiers avec les autres membres de ce serveur uniquement. Si vous partagez un lien avec une personne non inscrite elle ne pourra pas y avoir accès
</h5> </h5>
<div hx-get="/files/private/" hx-trigger="load, every 10s">
Chargement ...
</div>
{% if listFilesPrivate %}
<table class="table">
<thead>
<tr>
<th></th>
<th>Fichier(s) <span class="badge">{{ nb_pv }}</span></th>
<th>Taille (en Megaoctect)</th>
<th></th>
</tr>
</thead>
<tbody>
{% for file in listFilesPrivate %}
<tr>
<td>{{ file[0] }}</td>
<td><a href="/myfiles/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
<td>{{ file[2] }}</td>
<td>
<a href="{{ url_for('filesupload.remove_privateFile', filename=file[1]) }}">
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
</a>
<a href="{{ url_for('filesupload.move_public', filename=file[1]) }}">
<button type="button" title="Passer ce fichier en status public"><span class="icons share"></span></button>
</a>
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
<span class="icons copy-link"> </span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> Vous n'avez aucun fichier privé </p>
{% endif %}
<br /> <br />
<hr />
<br /> <br />
<h2> Fichiers publics </h2> <h2> Fichiers publics </h2>
<h5> Vous pouvez partager les liens de ces fichiers avec n'importe qui sur Internet ils y auront accès </h5> <h5> Vous pouvez partager les liens de ces fichiers avec n'importe qui sur Internet ils y auront accès </h5>
{% if listFilesPublic %}
<table class="table"> <div hx-get="/files/public/" hx-trigger="load, every 10s">
<thead> Chargement ...
<tr> </div>
<th></th>
<th>Fichier(s) <span class="badge">{{ nb_pu }}</span></th>
<th>Taille (en Megaoctets)</th>
<th></th>
</tr>
</thead>
<tbody>
{% for file in listFilesPublic %}
<tr>
<td>{{ file[0] }}</td>
<td><a href="/public/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
<td>{{ file[2] }}</td>
<td>
<a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}">
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
</a>
<a href="{{ url_for('filesupload.move_private', filename=file[1]) }}">
<button type="button" title="Passer ce fichier en status privé"><span class="icons share"></span></button>
</a>
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
<span class="icons copy-link"> </span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> Vous n'avez aucun fichier public </p>
{% endif %}
@ -110,4 +46,5 @@
{% block js %} {% block js %}
{% include '_js_dropzone.html' %} {% include '_js_dropzone.html' %}
{% include '_js_htmx.html' %}
{% endblock %} {% endblock %}

54
templates/list_files.html Normal file
View File

@ -0,0 +1,54 @@
{% if listFiles %}
<table class="table">
<thead>
<tr>
<th></th>
<th>Fichier(s) <span class="badge">{{ nb_files }}</span></th>
<th>Taille (en Megaoctect)</th>
<th></th>
</tr>
</thead>
<tbody>
{% for file in listFiles %}
<tr>
<td>{{ file[0] }}</td>
<td><a href="/myfiles/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
<td>{{ file[2] }}</td>
<td>
{% if status == "public" %}
<td>
<a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}">
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
</a>
<a href="{{ url_for('filesupload.move_private', filename=file[1]) }}">
<button type="button" title="Passer ce fichier en status privé"><span class="icons share"></span></button>
</a>
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
<span class="icons copy-link"> </span>
</button>
</td>
{% else %}
<td>
<a href="{{ url_for('filesupload.remove_privateFile', filename=file[1]) }}">
<button type="button" title="Supprimer"> <span class="icons delete"></span></button>
</a>
<a href="{{ url_for('filesupload.move_public', filename=file[1]) }}">
<button type="button" title="Passer ce fichier en status public"><span class="icons share"></span></button>
</a>
<button type="button" onclick="navigator.clipboard.writeText('{{BASE_URL}}{{ url_for('filesupload.publicfiles', username=username, filename=file[1]) }}');" title="Copier le lien du fichier">
<span class="icons copy-link"> </span>
</button>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<h5> Aucun fichier ici </h5>
{% endif %}

View File

@ -1,86 +0,0 @@
{% extends 'up_squelette.html' %}
{% block main %}
<p>Quand tu envoies des images, elles se retrouveront directement dans la <a href="/gallery/"> Gallerie</a>. </p>
<p>Ayez bien conscience que ce site est une expérience est qu'il est indispensable d'avoir
une sauvegarde de tous les fichiers qui vous mettrez ici. Nous ne pourrons, en aucun cas, être tenu responsable de la perte de vos
données. Merci de votre compréhension.
</p>
<br />
<h3>Choisissez un ou plusieurs fichiers à téléverser </h3>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" class="center" name="fic"id="fic" multiple>
<br>
<button type="submit" id="tada" class="btn btn btn-success"> Téléverser !</button>
</form>
<h2> Fichiers privés (Seul les personnes connectées et l'administrateur de l'ordinateur peuvent les voirs) </h2>
{% if listFilesPrivate %}
<table class="table">
<thead>
<tr>
<th></th>
<th>Fichier(s) <span class="badge">{{ nb_pv }}</span></th>
<th>Taille (en Megaoctect)</th>
<th></th>
</tr>
</thead>
<tbody>
{% for file in listFilesPrivate %}
<tr>
<td>{{ file[0] }}</td>
<td><a href="/myfiles/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
<td>{{ file[2] }}</td>
<td><a href="{{ url_for('filesupload.remove_privateFile', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
<td><a href="{{ url_for('filesupload.move_public', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-success"> Rendre Publique </button></a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> Vous n'avez aucun fichiers privés </p>
{% endif %}
<br />
<hr />
<br />
<h2> Fichiers publics (Tout le monde peut les voirs) </h2>
{% if listFilesPublic %}
<table class="table">
<thead>
<tr>
<th></th>
<th>Fichier(s) <span class="badge">{{ nb_pu }}</span></th>
<th>Taille (en Megaoctets)</th>
<th></th>
</tr>
</thead>
<tbody>
{% for file in listFilesPublic %}
<tr>
<td>{{ file[0] }}</td>
<td><a href="/public/{{ username }}/{{ file[1] }}">{{ file[1] }}</a></td>
<td>{{ file[2] }}</td>
<td><a href="{{ url_for('filesupload.remove_publicFile', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-danger">Supprimer</button></a></td>
<td><a href="{{ url_for('filesupload.move_private', filename=file[1]) }}"><button type="button" class="btn btn-sm btn-success"> Rendre Privée </button></a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p> Vous n'avez aucun fichiers publics </p>
{% endif %}
{% endblock %}

View File

@ -2,6 +2,7 @@
<html lang="fr"> <html lang="fr">
<head> <head>
{% include '_head.html' %} {% include '_head.html' %}
{% block css %} {% endblock %}
{% include 'css/simple_editor.html' %} {% include 'css/simple_editor.html' %}
</head> </head>

View File

@ -39,6 +39,28 @@ def append_to_log(log_line, user):
log.close() log.close()
def valid_email(mail):
valid=True
# Caractères non autorisés dans la RFC #822
invalid_char = { '(', ')', '<', '>', ',', ';', ':', '"', '[', ']', '|', 'ç', '%', '&', ' ' }
mail_cut = mail.split('@')
tld = mail_cut[-1].split('.')
for character in invalid_char:
if character in mail:
valid=False
print(tld)
if len(mail_cut) > 1 and len(tld) > 1 and valid:
if len(tld[0]) < 1 or len(tld[-1]) < 2 :
valid=False
else:
valid=False
return valid
def valid_username(username): def valid_username(username):
valid=True valid=True
# Caractères non autorisés dans la RFC #822 # Caractères non autorisés dans la RFC #822

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, flash, abort, send_file, send_from_directory from flask import Blueprint, Flask, request, flash, render_template, url_for, session, redirect, abort, make_response, flash, abort, send_file, send_from_directory
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from markupsafe import escape from markupsafe import escape
from PIL import Image from PIL import Image
@ -16,15 +17,14 @@ filesupload = Blueprint('filesupload', __name__, template_folder='templates')
app = Flask( 'pywallter' ) app = Flask( 'pywallter' )
app.config.from_pyfile('config.py') app.config.from_pyfile('config.py')
#### Variables ##################################################################################
#### Variables #################################################################################### DOSSIER_PERSO= app.config.get('DOSSIER_APP')
DOSSIER_PUBLIC= app.config.get('DOSSIER_PUBLIC')
DOSSIER_PERSO= app.config['DOSSIER_APP']+'/' extensionimg = app.config.get('EXT_IMG')
DOSSIER_PUBLIC= app.config['DOSSIER_PUBLIC']+'/' DATABASE = app.config.get('DATABASE')
BASE_URL= app.config.get('BASE_URL')
extensionimg = app.config['EXT_IMG']
DATABASE = app.config['DATABASE']
BASE_URL= app.config['BASE_URL']
################################################################################################## ##################################################################################################
@ -46,19 +46,20 @@ def upload():
files = request.files.getlist('fic') files = request.files.getlist('fic')
for f in files : for f in files :
nom = secure_filename(f.filename) nom = secure_filename(f.filename)
check_and_create(DOSSIER_PERSO+ user + '/files') check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
check_and_create(DOSSIER_PERSO+ user + '/images') check_and_create(os.path.join(DOSSIER_PERSO, user, 'images'))
if os.path.isfile(DOSSIER_PERSO + user + '/files/' + nom) or os.path.isfile(DOSSIER_PERSO + user + '/images/' + nom): if os.path.isfile(os.path.join(DOSSIER_PERSO,user, 'files', nom) or
os.path.isfile(DOSSIER_PERSO, user, 'images', nom)):
alert = "Le fichier "+str(f.filename)+" avec le même nom existe déjà, merci de spécifier un autre nom de fichier \n" alert = "Le fichier "+str(f.filename)+" avec le même nom existe déjà, merci de spécifier un autre nom de fichier \n"
flash(alert, 'error') flash(alert, 'error')
else: else:
file, ext = os.path.splitext(nom) file, ext = os.path.splitext(nom)
if ext in extensionimg : if ext in extensionimg :
f.save(DOSSIER_PERSO + user + '/images/' + nom) f.save(os.path.join(DOSSIER_PERSO, user, 'images', nom))
image = DOSSIER_PERSO + user + '/images/' + nom image = os.path.join(DOSSIER_PERSO, user, 'images', nom)
with Image.open(image) as img : with Image.open(image) as img :
img.thumbnail((300,300)) img.thumbnail((300,300))
img.save( DOSSIER_PERSO + user + '/images/thumbnails/' + nom ) img.save(os.path.join(DOSSIER_PERSO, user, 'images','thumbnails', nom ))
time_img_create=time.strftime("%A %d %B %Y %H:%M:%S") time_img_create=time.strftime("%A %d %B %Y %H:%M:%S")
IP=request.environ['REMOTE_ADDR'] IP=request.environ['REMOTE_ADDR']
client_platform=request.headers.get('User-Agent') client_platform=request.headers.get('User-Agent')
@ -68,9 +69,9 @@ def upload():
log.close() log.close()
else: else:
f.save(DOSSIER_PERSO + user + '/files/' + nom) f.save(os.path.join(DOSSIER_PERSO, user, 'files', nom))
time_file_upload=time.strftime("%A %d %B %Y %H:%M:%S") time_file_upload=time.strftime("%A %d %B %Y %H:%M:%S")
IP=request.environ['REMOTE_ADDR'] IP=request.environ.get('REMOTE_ADDR')
client_platform=request.headers.get('User-Agent') client_platform=request.headers.get('User-Agent')
log=open("log.txt", "a") # Ouvre fichier log.txt log=open("log.txt", "a") # Ouvre fichier log.txt
log.write (time_file_upload + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + nom + '\n') # Écrit dans log log.write (time_file_upload + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + nom + '\n') # Écrit dans log
@ -80,43 +81,101 @@ def upload():
return redirect(url_for('filesupload.list')) return redirect(url_for('filesupload.list'))
@filesupload.route( '/upload-dropzone', methods=['POST'])
@login_required
def drop_upload():
user = '%s'% escape(session['username'])
file = request.files['file']
check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
check_and_create(os.path.join(DOSSIER_PERSO, user, 'images' ))
filename = secure_filename(file.filename)
ext = os.path.splitext(filename)
is_image = False
print("nom du fichier :" +filename)
if ext in extensionimg :
save_path = os.path.join(DOSSIER_PERSO, user, 'images', filename )
is_image = True
else:
save_path = os.path.join(DOSSIER_PERSO, user, 'files', filename )
@filesupload.route('/view/') current_chunk = int(request.form['dzchunkindex'])
print (current_chunk)
if (os.path.isfile(save_path) or os.path.isfile( os.path.join(DOSSIER_PERSO, user, 'images', filename ))) and current_chunk == 0:
return make_response(('Un fichier avec le même nom existe déjà', 400))
try:
with open(save_path, 'ab') as f:
f.seek(int(request.form['dzchunkbyteoffset']))
f.write(file.stream.read())
except OSError:
return make_response(("Une erreur est survenue,"
" Impossible d'écrire le fichier sur le disque", 500))
total_chunks = int(request.form['dztotalchunkcount'])
if current_chunk + 1 == total_chunks:
# This was the last chunk, the file should be complete and the size we expect
if os.path.getsize(save_path) != int(request.form['dztotalfilesize']):
return make_response(('La taille du fichier source est différentes', 500))
else:
time_file_upload=time.strftime("%A %d %B %Y %H:%M:%S")
IP=request.environ['REMOTE_ADDR']
client_platform=request.headers.get('User-Agent')
log=open("log.txt", "a") # Ouvre fichier log.txt
log.write (time_file_upload + ' - ' + IP + ' - ' + user + ' - ' + client_platform + '\n' + '---> ' + filename + '\n') # Écrit dans log
log.close() # Ferme log.txt
if is_image :
with Image.open(save_path) as img :
img.thumbnail((300,300))
img.save(os.path.join(DOSSIER_PERSO, user, 'images', 'thumbnails', filename ) )
return make_response(('Chunk upload succesfull', 200))
@filesupload.route('/view/', methods=['GET'])
@login_required @login_required
def list(): def list():
user = '%s'% escape(session['username']) user = '%s'% escape(session['username'])
check_and_create(DOSSIER_PUBLIC + user + '/files/') check_and_create(os.path.join(DOSSIER_PUBLIC, user, 'files'))
check_and_create(DOSSIER_PERSO + user + '/files/') check_and_create(os.path.join(DOSSIER_PERSO, user, 'files'))
files_public = os.listdir(DOSSIER_PUBLIC + user + '/files/')
files_private = os.listdir(DOSSIER_PERSO + user + '/files/')
listFilesPublic = []
listFilesPrivate = []
nb_pv = 0
size=0
if files_private:
for fich in files_private:
nb_pv += 1
size = getFileSizeMo(DOSSIER_PERSO + user + '/files/' + fich) # size = taille des fichiers
listFilesPrivate.append([nb_pv, fich, size]) # On implémente la listeFichiers avec le num le ficier et sa taille
nb_pu = 0
if files_public:
for fich in files_public:
nb_pu += 1
size = getFileSizeMo(DOSSIER_PUBLIC + user + '/files/' + fich) # size = taille des fichiers
listFilesPublic.append([nb_pu, fich, size])
return render_template('files.html', return render_template('files.html',
section="Files", section="Files",
BASE_URL=BASE_URL, BASE_URL=BASE_URL,
username=user)
@filesupload.route('/files/<status>/', methods=['GET'])
@login_required
def list_files(status: str ):
user = '%s' % escape(session['username'])
listFiles = []
nb_files = 0
size=0
folder=""
if status == "public":
folder=DOSSIER_PUBLIC
else:
folder=DOSSIER_PERSO
files = os.listdir(os.path.join(folder, user, 'files'))
if files:
for fich in files:
nb_files += 1
size = getFileSizeMo(os.path.join(folder, user, 'files', fich)) # size = taille des fichiers
listFiles.append([nb_files, fich, size]) # On implémente la listeFichiers avec le num le ficier et sa taille
resp = "<h2> Bonjour " + user +" ça va bien putain ca marche ? </h2>"
return render_template('list_files.html',
BASE_URL=BASE_URL,
status=status,
size=size, size=size,
username=user, username=user,
nb_pv=nb_pv, nb_files=nb_files,
nb_pu=nb_pu, listFiles=listFiles)
listFilesPrivate=listFilesPrivate,
listFilesPublic=listFilesPublic)
@filesupload.route('/myfiles/<username>/<filename>') @filesupload.route('/myfiles/<username>/<filename>')
@ -130,11 +189,9 @@ def myfiles(username, filename):
@login_required @login_required
def move_public(filename): def move_public(filename):
user = '%s' % escape(session['username']) user = '%s' % escape(session['username'])
check_and_create(DOSSIER_PUBLIC + user + '/files/')
check_and_create(DOSSIER_PERSO + user + '/files/')
src = os.path.join(DOSSIER_PERSO, user, 'files', filename) src = os.path.join(DOSSIER_PERSO, user, 'files', filename)
dst = os.path.join(DOSSIER_PUBLIC, user, 'files/') dst = os.path.join(DOSSIER_PUBLIC, user, 'files')
move (src, dst) move (src, dst)
return redirect(url_for('filesupload.list', _external=True)) return redirect(url_for('filesupload.list', _external=True))
@ -142,10 +199,8 @@ def move_public(filename):
@login_required @login_required
def move_private(filename): def move_private(filename):
user = '%s' % escape(session['username']) user = '%s' % escape(session['username'])
check_and_create(DOSSIER_PUBLIC + user + '/files/')
check_and_create(DOSSIER_PERSO + user + '/files/')
src = os.path.join(DOSSIER_PUBLIC, user, 'files', filename) src = os.path.join(DOSSIER_PUBLIC, user, 'files', filename)
dst = os.path.join(DOSSIER_PERSO, user, 'files/') dst = os.path.join(DOSSIER_PERSO, user, 'files')
move (src, dst) move (src, dst)
return redirect(url_for('filesupload.list', _external=True)) return redirect(url_for('filesupload.list', _external=True))
@ -158,7 +213,7 @@ def remove_privateFile(filename):
user = '%s' % escape(session['username']) user = '%s' % escape(session['username'])
filename = secure_filename(filename) filename = secure_filename(filename)
try: try:
os.remove(DOSSIER_PERSO + user + '/files/' + filename) # on le supprime os.remove( os.path.join(DOSSIER_PERSO, user, 'files', filename)) # on le supprime
except FileNotFoundError: except FileNotFoundError:
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error') flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
return redirect(url_for('filesupload.list', _external=True)) return redirect(url_for('filesupload.list', _external=True))
@ -170,7 +225,7 @@ def remove_publicFile(filename):
user = '%s' % escape(session['username']) user = '%s' % escape(session['username'])
filename = secure_filename(filename) filename = secure_filename(filename)
try: try:
os.remove(DOSSIER_PUBLIC + user + '/files/' + filename) # on le supprime os.remove( os.path.join(DOSSIER_PUBLIC, user, 'files', filename)) # on le supprime
except FileNotFoundError: except FileNotFoundError:
flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error') flash(u'Fichier {filename} inexistant.'.format(filename=filename), 'error')
return redirect(url_for('filesupload.list', _external=True)) return redirect(url_for('filesupload.list', _external=True))
@ -179,8 +234,8 @@ def remove_publicFile(filename):
@filesupload.route('/<author>/blog.css') @filesupload.route('/<author>/blog.css')
def blog_theme(author): def blog_theme(author):
user = author user = author
if os.path.isfile(DOSSIER_PERSO+ user +'/blog.css'): if os.path.isfile(os.path.join(DOSSIER_PERSO, user,'blog.css')):
return send_file(DOSSIER_PERSO+ user +'/blog.css', mimetype='text/css') return send_file(os.path.join(DOSSIER_PERSO, user, 'blog.css'), mimetype='text/css')
else: else:
return send_file("/static/blog.css", mimetype='text/css') return send_file("/static/blog.css", mimetype='text/css')
@ -188,8 +243,8 @@ def blog_theme(author):
def theme(): def theme():
if 'username' in session: if 'username' in session:
user = '%s' % escape(session['username']) user = '%s' % escape(session['username'])
if os.path.isfile(DOSSIER_PERSO+ user +'/theme.min.css'): if os.path.isfile(os.path.join(DOSSIER_PERSO, user,'theme.min.css')):
return send_file(DOSSIER_PERSO+ user +'/theme.min.css', mimetype='text/css') return send_file(os.path.join(DOSSIER_PERSO, user,'theme.min.css'), mimetype='text/css')
return send_file("static/default.min.css", mimetype='text/css') return send_file("static/default.min.css", mimetype='text/css')

View File

@ -9,7 +9,7 @@ import subprocess
from shutil import copy from shutil import copy
from socket import gethostname from socket import gethostname
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, valid_token_register, get_user_by_token, totp_is_valid, login_required from tools.utils import email_disp, append_to_log, gen_token, valid_passwd, valid_token_register, get_user_by_token, totp_is_valid, login_required, valid_email
from pyotp import random_base32 from pyotp import random_base32
from tools.filesutils import check_and_create from tools.filesutils import check_and_create
import qrcode import qrcode
@ -73,18 +73,20 @@ def profile() :
os.path.join(DOSSIER_PERSO, user ,'theme.min.css') ) os.path.join(DOSSIER_PERSO, user ,'theme.min.css') )
if request.form['nom']: if request.form['nom']:
profil_user['nom'] = request.form['nom'] profil_user['nom'] = str(request.form['nom'])
if request.form['prenom']: if request.form['prenom']:
profil_user['prenom'] = request.form['prenom'] profil_user['prenom'] = str(request.form['prenom'])
if request.form['age']: if request.form['age']:
profil_user['age'] = request.form['age'] profil_user['age'] = str(request.form['age'])
if '@' in request.form['mail_rescue']:
if len(request.form['mail_rescue']) > 4: if request.form['mail_rescue'] :
profil_user['mail_rescue'] = request.form['mail_rescue'] new_mail_rescue = str(request.form['mail_rescue'])
if valid_email(new_mail_rescue):
profil_user['mail_rescue']=new_mail_rescue
else: else:
flash(u'Adresse de courriel invalide', 'error') flash(u'Adresse de courriel invalide', 'error')
else:
flash(u'Adresse de courriel de secour invalide', 'error')
if f: # On vérifie qu'un fichier a bien été envoyé if f: # On vérifie qu'un fichier a bien été envoyé
nom = secure_filename(f.filename) nom = secure_filename(f.filename)
f.save(os.path.join(DOSSIER_PERSO, user, 'profile', nom)) f.save(os.path.join(DOSSIER_PERSO, user, 'profile', nom))
@ -98,7 +100,6 @@ def profile() :
cursor.execute("UPDATE users SET avatar=? WHERE name=?", cursor.execute("UPDATE users SET avatar=? WHERE name=?",
(filename, user)) (filename, user))
conn.commit() conn.commit()
cursor = conn.cursor() # Création de l'objet "curseur"
conn.close() conn.close()
flash(u'Image de profil mise à jour', 'success') flash(u'Image de profil mise à jour', 'success')
@ -109,7 +110,7 @@ def profile() :
(profil_user['nom'], profil_user['prenom'], profil_user['age'], profil_user['mail_rescue'], (profil_user['nom'], profil_user['prenom'], profil_user['age'], profil_user['mail_rescue'],
user)) user))
conn.commit() conn.commit()
flash(u'Le profil a été mis à jour', 'succes') flash(u'Le profil a été mis à jour', 'success')
@ -195,7 +196,7 @@ def change_passwd() :
if not(account['totp']): if not(account['totp']):
account['totp'] = random_base32() account['totp'] = random_base32()
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+account['totp']) img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+account['totp'])
img.save(DOSSIER_PERSO + user + "/totp.png") img.save(os.path.join(DOSSIER_PERSO, user, "totp.png"))
shared_key_validate = False shared_key_validate = False
return render_template('mypassword.html', return render_template('mypassword.html',
@ -302,7 +303,7 @@ def set_totp():
cursor.execute("""UPDATE users SET totp=? WHERE name=?""", (shared_key, user,)) cursor.execute("""UPDATE users SET totp=? WHERE name=?""", (shared_key, user,))
conn.commit() conn.commit()
img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+shared_key) img = qrcode.make('otpauth://totp/'+BASE_URL+'?secret='+shared_key)
img.save(DOSSIER_PERSO + user + "/totp.png") img.save(os.path.join(DOSSIER_PERSO, user, "totp.png"))
flash(u'Votre mot de passe à usage unique est configuré et actif.', 'success') flash(u'Votre mot de passe à usage unique est configuré et actif.', 'success')
else: else:
flash(u'Le code de validation totp n\'est pas valide.', 'error') flash(u'Le code de validation totp n\'est pas valide.', 'error')