Compare commits

..

No commits in common. "6f5031623c23b42cf901e602adbac718b2ebabfb" and "d54419fd357f5027acdf1dca2104dc3520d4a6d3" have entirely different histories.

15 changed files with 169 additions and 255 deletions

View File

@ -19,8 +19,3 @@ BASE_URL="http://localhost:5000"
# Session expiration, in days # Session expiration, in days
MAX_AGE=31 MAX_AGE=31
# Instance path ie. where are all the files + the database stored
# Keep in mind that this config option can only be loaded from default_config.py,
# as the custom config is stored in $INSTANCE_PATH/
INSTANCE_PATH="instance"

26
make.sh
View File

@ -1,27 +1,25 @@
#!/bin/bash #!/bin/bash
INSTANCE_PATH="instance"
init () { init () {
mkdir -p "$INSTANCE_PATH" mkdir -p "instance"
mkdir -p "$INSTANCE_PATH/partitions" mkdir -p "partitioncloud/partitions"
mkdir -p "$INSTANCE_PATH/attachments" mkdir -p "partitioncloud/attachments"
mkdir -p "$INSTANCE_PATH/search-partitions" mkdir -p "partitioncloud/search-partitions"
mkdir -p "$INSTANCE_PATH/static/thumbnails" mkdir -p "partitioncloud/static/thumbnails"
mkdir -p "$INSTANCE_PATH/static/search-thumbnails" mkdir -p "partitioncloud/static/search-thumbnails"
if ! test -f "$INSTANCE_PATH/config.py"; then if ! test -f "instance/config.py"; then
echo "SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex())')" > "$INSTANCE_PATH/config.py" echo "SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex())')" > instance/config.py
fi fi
if test -f "$INSTANCE_PATH/partitioncloud.sqlite"; then if test -f "instance/partitioncloud.sqlite"; then
printf "Souhaitez vous supprimer la base de données existante ? [y/n] " printf "Souhaitez vous supprimer la base de données existante ? [y/n] "
read -r CONFIRMATION read -r CONFIRMATION
[[ $CONFIRMATION == y ]] || exit 1 [[ $CONFIRMATION == y ]] || exit 1
fi fi
sqlite3 "$INSTANCE_PATH/partitioncloud.sqlite" '.read partitioncloud/schema.sql' sqlite3 "instance/partitioncloud.sqlite" '.read partitioncloud/schema.sql'
echo "Base de données créé" echo "Base de données créé"
sqlite3 "$INSTANCE_PATH/partitioncloud.sqlite" '.read partitioncloud/init.sql' sqlite3 "instance/partitioncloud.sqlite" '.read partitioncloud/init.sql'
echo "Utilisateur root:root ajouté" echo "Utilisateur root:root ajouté"
} }
@ -45,7 +43,7 @@ usage () {
if [[ $1 && $(type "$1") = *"is a"*"function"* || $(type "$1") == *"est une fonction"* ]]; then if [[ $1 && $(type "$1") = *"is a"*"function"* || $(type "$1") == *"est une fonction"* ]]; then
# Import config # Import config
source "default_config.py" source "default_config.py"
[[ ! -x" $INSTANCE_PATH/config.py" ]] && source "$INSTANCE_PATH/config.py" [[ ! -x instance/config.py ]] && source "instance/config.py"
$1 ${*:2} # Call the function $1 ${*:2} # Call the function
else else
usage usage

View File

@ -3,10 +3,8 @@
Main file Main file
""" """
import os import os
import sys
import datetime import datetime
import subprocess import subprocess
import importlib.util
from flask import Flask, g, redirect, render_template, request, send_file, flash, session, abort from flask import Flask, g, redirect, render_template, request, send_file, flash, session, abort
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
@ -18,48 +16,14 @@ from .modules.db import get_db
app = Flask(__name__) app = Flask(__name__)
app.config.from_mapping(
def load_config(): DATABASE=os.path.join(app.instance_path, f"{__name__}.sqlite"),
app.config.from_object('default_config') )
app.instance_path = os.path.abspath(app.config["INSTANCE_PATH"]) app.config.from_object('default_config')
if os.path.exists("instance/config.py"):
if not os.path.exists(app.instance_path): app.config.from_object('instance.config')
print("[ERROR] Instance path does not exist. Make sure to use an existing directory.") else:
sys.exit(1) print("[WARNING] Using default config")
if os.path.exists(f"{app.instance_path}/config.py"):
# Load module from instance_path/config.py in user_config object
spec = importlib.util.spec_from_file_location(
".",
os.path.join(app.instance_path, "config.py")
)
user_config = importlib.util.module_from_spec(spec)
spec.loader.exec_module(user_config)
app.config.from_object(user_config)
if os.path.abspath(app.config["INSTANCE_PATH"]) != app.instance_path:
print("[ERROR] Using two different instance path. \
\nPlease modify INSTANCE_PATH only in default_config.py and remove it from $INSTANCE_PATH/config.py")
sys.exit(1)
else:
print("[WARNING] Using default config")
app.config.from_mapping(
DATABASE=os.path.join(app.instance_path, f"{__name__}.sqlite"),
)
def get_version():
try:
result = subprocess.run(["git", "describe", "--tags"], stdout=subprocess.PIPE, check=True)
return result.stdout.decode('utf8')
except (FileNotFoundError, subprocess.CalledProcessError):
# In case git not found or any platform specific weird error
return "unknown"
load_config()
app.register_blueprint(auth.bp) app.register_blueprint(auth.bp)
app.register_blueprint(admin.bp) app.register_blueprint(admin.bp)
@ -67,7 +31,13 @@ app.register_blueprint(groupe.bp)
app.register_blueprint(albums.bp) app.register_blueprint(albums.bp)
app.register_blueprint(partition.bp) app.register_blueprint(partition.bp)
__version__ = get_version()
try:
result = subprocess.run(["git", "describe", "--tags"], stdout=subprocess.PIPE, check=True)
__version__ = result.stdout.decode('utf8')
except (FileNotFoundError, subprocess.CalledProcessError):
# In case git not found or any platform specific weird error
__version__ = "unknown"
@app.route("/") @app.route("/")
@ -129,7 +99,7 @@ def search_thumbnail(uuid):
f'/usr/bin/convert -thumbnail\ f'/usr/bin/convert -thumbnail\
"178^>" -background white -alpha \ "178^>" -background white -alpha \
remove -crop 178x178+0+0 \ remove -crop 178x178+0+0 \
{app.instance_path}/search-partitions/{uuid}.pdf[0] \ partitioncloud/search-partitions/{uuid}.pdf[0] \
partitioncloud/static/search-thumbnails/{uuid}.jpg' partitioncloud/static/search-thumbnails/{uuid}.jpg'
) )

View File

@ -5,16 +5,14 @@ Albums module
import os import os
import shutil import shutil
from uuid import uuid4 from uuid import uuid4
from typing import TypeVar
from flask import (Blueprint, abort, flash, redirect, render_template, from flask import (Blueprint, abort, flash, redirect, render_template,
request, session, current_app) request, session, current_app)
from .auth import login_required from .auth import login_required
from .db import get_db from .db import get_db
from .utils import User, Album from .utils import User, Album, get_all_partitions, new_uuid, get_qrcode, format_uuid
from . import search, utils from . import search
bp = Blueprint("albums", __name__, url_prefix="/albums") bp = Blueprint("albums", __name__, url_prefix="/albums")
@ -42,8 +40,8 @@ def search_page():
query = request.form["query"] query = request.form["query"]
nb_queries = abs(int(request.form["nb-queries"])) nb_queries = abs(int(request.form["nb-queries"]))
search.flush_cache(current_app.instance_path) search.flush_cache()
partitions_local = search.local_search(query, utils.get_all_partitions()) partitions_local = search.local_search(query, get_all_partitions())
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
@ -52,7 +50,7 @@ def search_page():
nb_queries = min(current_app.config["MAX_ONLINE_QUERIES"], nb_queries) nb_queries = min(current_app.config["MAX_ONLINE_QUERIES"], nb_queries)
else: else:
nb_queries = min(10, nb_queries) # Query limit is 10 for an admin nb_queries = min(10, nb_queries) # Query limit is 10 for an admin
google_results = search.online_search(query, nb_queries, current_app.instance_path) google_results = search.online_search(query, nb_queries)
else: else:
google_results = [] google_results = []
@ -75,8 +73,8 @@ def get_album(uuid):
album = Album(uuid=uuid) album = Album(uuid=uuid)
except LookupError: except LookupError:
try: try:
album = Album(uuid=utils.format_uuid(uuid)) album = Album(uuid=format_uuid(uuid))
return redirect(f"/albums/{utils.format_uuid(uuid)}") return redirect(f"/albums/{format_uuid(uuid)}")
except LookupError: except LookupError:
return abort(404) return abort(404)
@ -103,12 +101,12 @@ def qr_code(uuid):
""" """
Renvoie le QR Code d'un album Renvoie le QR Code d'un album
""" """
return utils.get_qrcode(f"/albums/{uuid}") return get_qrcode(f"/albums/{uuid}")
@bp.route("/create-album", methods=["POST"]) @bp.route("/create-album", methods=["POST"])
@login_required @login_required
def create_album_req(): def create_album():
""" """
Création d'un album Création d'un album
""" """
@ -120,16 +118,31 @@ def create_album_req():
error = "Un nom est requis. L'album n'a pas été créé" error = "Un nom est requis. L'album n'a pas été créé"
if error is None: if error is None:
uuid = utils.create_album(name) while True:
album = Album(uuid=uuid) try:
db.execute( uuid = new_uuid()
"""
INSERT INTO contient_user (user_id, album_id) db.execute(
VALUES (?, ?) """
""", INSERT INTO album (uuid, name)
(session.get("user_id"), album.id), VALUES (?, ?)
) """,
db.commit() (uuid, name),
)
db.commit()
album = Album(uuid=uuid)
db.execute(
"""
INSERT INTO contient_user (user_id, album_id)
VALUES (?, ?)
""",
(session.get("user_id"), album.id),
)
db.commit()
break
except db.IntegrityError:
pass
if "response" in request.args and request.args["response"] == "json": if "response" in request.args and request.args["response"] == "json":
return { return {
@ -207,7 +220,7 @@ def delete_album(uuid):
flash(error) flash(error)
return redirect(request.referrer) return redirect(request.referrer)
album.delete(current_app.instance_path) album.delete()
flash("Album supprimé.") flash("Album supprimé.")
return redirect("/albums") return redirect("/albums")
@ -219,13 +232,6 @@ def add_partition(album_uuid):
""" """
Ajouter une partition à un album (par upload) Ajouter une partition à un album (par upload)
""" """
T = TypeVar("T")
def get_opt_string(dictionary: dict[T, str], key: T):
"""Renvoie '' si la clé n'existe pas dans le dictionnaire"""
if key in dictionary:
return dictionary[key]
return ""
db = get_db() db = get_db()
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
album = Album(uuid=album_uuid) album = Album(uuid=album_uuid)
@ -239,22 +245,23 @@ def add_partition(album_uuid):
if "name" not in request.form: if "name" not in request.form:
error = "Un titre est requis." error = "Un titre est requis."
elif "file" not in request.files and "partition-uuid" not in request.form:
error = "Aucun fichier n'a été fourni."
elif "file" not in request.files: elif "file" not in request.files:
partition_type = "uuid" if "partition-uuid" not in request.form:
search_uuid = request.form["partition-uuid"] error = "Aucun fichier n'a été fourni."
data = db.execute(
"""
SELECT * FROM search_results
WHERE uuid = ?
""",
(search_uuid,)
).fetchone()
if data is None:
error = "Les résultats de la recherche ont expiré."
else: else:
source = data["url"] partition_type = "uuid"
search_uuid = request.form["partition-uuid"]
data = db.execute(
"""
SELECT * FROM search_results
WHERE uuid = ?
""",
(search_uuid,)
).fetchone()
if data is None:
error = "Les résultats de la recherche ont expiré."
else:
source = data["url"]
else: else:
partition_type = "file" partition_type = "file"
@ -262,8 +269,14 @@ def add_partition(album_uuid):
flash(error) flash(error)
return redirect(request.referrer) return redirect(request.referrer)
author = get_opt_string(request.form, "author") if "author" in request.form:
body = get_opt_string(request.form, "body") author = request.form["author"]
else:
author = ""
if "body" in request.form:
body = request.form["body"]
else:
body = ""
while True: while True:
try: try:
@ -278,32 +291,20 @@ def add_partition(album_uuid):
) )
db.commit() db.commit()
partition_path = os.path.join(
current_app.instance_path,
"partitions",
f"{partition_uuid}.pdf"
)
if partition_type == "file": if partition_type == "file":
file = request.files["file"] file = request.files["file"]
file.save(partition_path) file.save(f"partitioncloud/partitions/{partition_uuid}.pdf")
else: else:
search_partition_path = os.path.join(
current_app.instance_path,
"search-partitions",
f"{search_uuid}.pdf"
)
shutil.copyfile( shutil.copyfile(
search_partition_path, f"partitioncloud/search-partitions/{search_uuid}.pdf",
partition_path f"partitioncloud/partitions/{partition_uuid}.pdf"
) )
os.system( os.system(
f'/usr/bin/convert -thumbnail\ f'/usr/bin/convert -thumbnail\
"178^>" -background white -alpha \ "178^>" -background white -alpha \
remove -crop 178x178+0+0 \ remove -crop 178x178+0+0 \
{partition_path}[0] \ partitioncloud/partitions/{partition_uuid}.pdf[0] \
partitioncloud/static/thumbnails/{partition_uuid}.jpg' partitioncloud/static/thumbnails/{partition_uuid}.jpg'
) )
db.commit() db.commit()

View File

@ -78,7 +78,6 @@ def load_logged_in_user():
def create_user(username: str, password: str) -> Optional[str]: def create_user(username: str, password: str) -> Optional[str]:
"""Adds a new user to the database""" """Adds a new user to the database"""
error = None
if not username: if not username:
error = "Un nom d'utilisateur est requis." error = "Un nom d'utilisateur est requis."
elif not password: elif not password:
@ -97,7 +96,8 @@ def create_user(username: str, password: str) -> Optional[str]:
# commit to fail. Show a validation error. # commit to fail. Show a validation error.
error = f"Le nom d'utilisateur {username} est déjà pris." error = f"Le nom d'utilisateur {username} est déjà pris."
return error # may be None if error is not None:
return error
@bp.route("/register", methods=("GET", "POST")) @bp.route("/register", methods=("GET", "POST"))

View File

@ -4,7 +4,6 @@ Classe Album
import os import os
from ..db import get_db from ..db import get_db
from ..utils import new_uuid
from .attachment import Attachment from .attachment import Attachment
@ -82,7 +81,7 @@ class Album():
).fetchall() ).fetchall()
def delete(self, instance_path): def delete(self):
""" """
Supprimer l'album Supprimer l'album
""" """
@ -130,9 +129,9 @@ class Album():
attachments = [Attachment(data=i) for i in data] attachments = [Attachment(data=i) for i in data]
for attachment in attachments: for attachment in attachments:
attachment.delete(instance_path) attachment.delete()
os.remove(f"{instance_path}/partitions/{partition['uuid']}.pdf") os.remove(f"partitioncloud/partitions/{partition['uuid']}.pdf")
if os.path.exists(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg"): if os.path.exists(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg"):
os.remove(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg") os.remove(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg")
@ -164,26 +163,3 @@ class Album():
(partition_uuid, self.id), (partition_uuid, self.id),
) )
db.commit() db.commit()
def create(name: str) -> str:
"""Créer un nouvel album"""
db = get_db()
while True:
try:
uuid = new_uuid()
db.execute(
"""
INSERT INTO album (uuid, name)
VALUES (?, ?)
""",
(uuid, name),
)
db.commit()
break
except db.IntegrityError:
pass
return uuid

View File

@ -29,7 +29,7 @@ class Attachment():
self.filetype = data["filetype"] self.filetype = data["filetype"]
self.partition_uuid = data["partition_uuid"] self.partition_uuid = data["partition_uuid"]
def delete(self, instance_path): def delete(self):
db = get_db() db = get_db()
db.execute( db.execute(
""" """
@ -40,7 +40,7 @@ class Attachment():
) )
db.commit() db.commit()
os.remove(f"{instance_path}/attachments/{self.uuid}.{self.filetype}") os.remove(f"partitioncloud/attachments/{self.uuid}.{self.filetype}")
def __repr__(self): def __repr__(self):
return f"{self.name}.{self.filetype}" return f"{self.name}.{self.filetype}"

View File

@ -21,7 +21,7 @@ class Groupe():
self.albums = None self.albums = None
self.admins = None self.admins = None
def delete(self, instance_path): def delete(self):
""" """
Supprime le groupe, et les albums laissés orphelins (sans utilisateur) Supprime le groupe, et les albums laissés orphelins (sans utilisateur)
""" """
@ -63,7 +63,7 @@ class Groupe():
for i in data: for i in data:
album = Album(id=i["id"]) album = Album(id=i["id"])
album.delete(instance_path) album.delete()
def get_users(self): def get_users(self):

View File

@ -29,7 +29,7 @@ class Partition():
else: else:
raise LookupError raise LookupError
def delete(self, instance_path): def delete(self):
self.load_attachments() self.load_attachments()
db = get_db() db = get_db()
@ -42,7 +42,7 @@ class Partition():
) )
db.commit() db.commit()
os.remove(f"{instance_path}/partitions/{self.uuid}.pdf") os.remove(f"partitioncloud/partitions/{self.uuid}.pdf")
if os.path.exists(f"partitioncloud/static/thumbnails/{self.uuid}.jpg"): if os.path.exists(f"partitioncloud/static/thumbnails/{self.uuid}.jpg"):
os.remove(f"partitioncloud/static/thumbnails/{self.uuid}.jpg") os.remove(f"partitioncloud/static/thumbnails/{self.uuid}.jpg")
@ -56,7 +56,7 @@ class Partition():
db.commit() db.commit()
for attachment in self.attachments: for attachment in self.attachments:
attachment.delete(instance_path) attachment.delete()
def update(self, name=None, author="", body=""): def update(self, name=None, author="", body=""):
if name is None: if name is None:

View File

@ -3,12 +3,11 @@
Groupe module Groupe module
""" """
from flask import (Blueprint, abort, flash, redirect, render_template, from flask import (Blueprint, abort, flash, redirect, render_template,
request, session, current_app) request, session)
from .auth import login_required from .auth import login_required
from .db import get_db from .db import get_db
from .utils import User, Album, Groupe from .utils import User, Album, Groupe, new_uuid, get_qrcode, format_uuid
from . import utils
bp = Blueprint("groupe", __name__, url_prefix="/groupe") bp = Blueprint("groupe", __name__, url_prefix="/groupe")
@ -27,8 +26,8 @@ def get_groupe(uuid):
groupe = Groupe(uuid=uuid) groupe = Groupe(uuid=uuid)
except LookupError: except LookupError:
try: try:
groupe = Groupe(uuid=utils.format_uuid(uuid)) groupe = Groupe(uuid=format_uuid(uuid))
return redirect(f"/groupe/{utils.format_uuid(uuid)}") return redirect(f"/groupe/{format_uuid(uuid)}")
except LookupError: except LookupError:
return abort(404) return abort(404)
@ -52,7 +51,7 @@ def get_groupe(uuid):
@bp.route("/<uuid>/qr") @bp.route("/<uuid>/qr")
def album_qr_code(uuid): def album_qr_code(uuid):
return utils.get_qrcode(f"/groupe/{uuid}") return get_qrcode(f"/groupe/{uuid}")
@ -69,7 +68,7 @@ def create_groupe():
if error is None: if error is None:
while True: while True:
try: try:
uuid = utils.new_uuid() uuid = new_uuid()
db.execute( db.execute(
""" """
@ -155,7 +154,7 @@ def delete_groupe(uuid):
flash(error) flash(error)
return redirect(request.referrer) return redirect(request.referrer)
groupe.delete(current_app.instance_path) groupe.delete()
flash("Groupe supprimé.") flash("Groupe supprimé.")
return redirect("/albums") return redirect("/albums")
@ -163,7 +162,7 @@ def delete_groupe(uuid):
@bp.route("/<groupe_uuid>/create-album", methods=["POST"]) @bp.route("/<groupe_uuid>/create-album", methods=["POST"])
@login_required @login_required
def create_album_req(groupe_uuid): def create_album(groupe_uuid):
try: try:
groupe = Groupe(uuid=groupe_uuid) groupe = Groupe(uuid=groupe_uuid)
except LookupError: except LookupError:
@ -182,17 +181,32 @@ def create_album_req(groupe_uuid):
error ="Vous n'êtes pas administrateur de ce groupe" error ="Vous n'êtes pas administrateur de ce groupe"
if error is None: if error is None:
uuid = utils.create_album(name) while True:
album = Album(uuid=uuid) try:
uuid = new_uuid()
db.execute( db.execute(
""" """
INSERT INTO groupe_contient_album (groupe_id, album_id) INSERT INTO album (uuid, name)
VALUES (?, ?) VALUES (?, ?)
""", """,
(groupe.id, album.id) (uuid, name),
) )
db.commit() db.commit()
album = Album(uuid=uuid)
db.execute(
"""
INSERT INTO groupe_contient_album (groupe_id, album_id)
VALUES (?, ?)
""",
(groupe.id, album.id)
)
db.commit()
break
except db.IntegrityError:
pass
if "response" in request.args and request.args["response"] == "json": if "response" in request.args and request.args["response"] == "json":
return { return {
@ -215,14 +229,14 @@ def get_album(groupe_uuid, album_uuid):
groupe = Groupe(uuid=groupe_uuid) groupe = Groupe(uuid=groupe_uuid)
except LookupError: except LookupError:
try: try:
groupe = Groupe(uuid=utils.format_uuid(groupe_uuid)) groupe = Groupe(uuid=format_uuid(groupe_uuid))
return redirect(f"/groupe/{utils.format_uuid(groupe_uuid)}/{album_uuid}") return redirect(f"/groupe/{format_uuid(groupe_uuid)}/{album_uuid}")
except LookupError: except LookupError:
return abort(404) return abort(404)
album_list = [a for a in groupe.get_albums() if a.uuid == album_uuid] album_list = [a for a in groupe.get_albums() if a.uuid == album_uuid]
if len(album_list) == 0: if len(album_list) == 0:
album_uuid = utils.format_uuid(album_uuid) album_uuid = format_uuid(album_uuid)
album_list = [a for a in groupe.get_albums() if a.uuid == album_uuid] album_list = [a for a in groupe.get_albums() if a.uuid == album_uuid]
if len(album_list) != 0: if len(album_list) != 0:
return redirect(f"/groupe/{groupe_uuid}/{album_uuid}") return redirect(f"/groupe/{groupe_uuid}/{album_uuid}")
@ -255,4 +269,4 @@ def get_album(groupe_uuid, album_uuid):
@bp.route("/<groupe_uuid>/<album_uuid>/qr") @bp.route("/<groupe_uuid>/<album_uuid>/qr")
def groupe_qr_code(groupe_uuid, album_uuid): def groupe_qr_code(groupe_uuid, album_uuid):
return utils.get_qrcode(f"/groupe/{groupe_uuid}/{album_uuid}") return get_qrcode(f"/groupe/{groupe_uuid}/{album_uuid}")

View File

@ -4,8 +4,7 @@ Partition module
""" """
import os import os
from uuid import uuid4 from uuid import uuid4
from flask import (Blueprint, abort, send_file, render_template, from flask import Blueprint, abort, send_file, render_template, request, redirect, flash, session
request, redirect, flash, session, current_app)
from .db import get_db from .db import get_db
from .auth import login_required, admin_required from .auth import login_required, admin_required
@ -22,11 +21,9 @@ def get_partition(uuid):
abort(404) abort(404)
return send_file(os.path.join( return send_file(
current_app.instance_path, os.path.join("partitions", f"{uuid}.pdf"),
"partitions", download_name = f"{partition.name}.pdf"
f"{uuid}.pdf"
), download_name = f"{partition.name}.pdf"
) )
@bp.route("/<uuid>/attachments") @bp.route("/<uuid>/attachments")
@ -47,6 +44,7 @@ def attachments(uuid):
@bp.route("/<uuid>/add-attachment", methods=["POST"]) @bp.route("/<uuid>/add-attachment", methods=["POST"])
@login_required @login_required
def add_attachment(uuid): def add_attachment(uuid):
db = get_db()
try: try:
partition = Partition(uuid=uuid) partition = Partition(uuid=uuid)
except LookupError: except LookupError:
@ -54,7 +52,7 @@ def add_attachment(uuid):
user = User(user_id=session.get("user_id")) user = User(user_id=session.get("user_id"))
if user.id != partition.user_id and user.access_level != 1: if user.id != partition.user_id and user.access_level != 1:
flash("Cette partition ne vous current_appartient pas") flash("Cette partition ne vous appartient pas")
return redirect(request.referrer) return redirect(request.referrer)
error = None # À mettre au propre error = None # À mettre au propre
@ -68,6 +66,7 @@ def add_attachment(uuid):
if name == "": if name == "":
error = "Pas de nom de fichier" error = "Pas de nom de fichier"
else: else:
filename = request.files["file"].filename filename = request.files["file"].filename
ext = filename.split(".")[-1] ext = filename.split(".")[-1]
@ -82,7 +81,6 @@ def add_attachment(uuid):
try: try:
attachment_uuid = str(uuid4()) attachment_uuid = str(uuid4())
db = get_db()
db.execute( db.execute(
""" """
INSERT INTO attachments (uuid, name, filetype, partition_uuid, user_id) INSERT INTO attachments (uuid, name, filetype, partition_uuid, user_id)
@ -93,11 +91,7 @@ def add_attachment(uuid):
db.commit() db.commit()
file = request.files["file"] file = request.files["file"]
file.save(os.path.join( file.save(f"partitioncloud/attachments/{attachment_uuid}.{ext}")
current_app.instance_path,
"attachments",
f"{attachment_uuid}.{ext}"
))
break break
except db.IntegrityError: except db.IntegrityError:
@ -121,11 +115,9 @@ def get_attachment(uuid, filetype):
assert filetype == attachment.filetype assert filetype == attachment.filetype
return send_file(os.path.join( return send_file(
current_app.instance_path, os.path.join("attachments", f"{uuid}.{attachment.filetype}"),
"attachments", download_name = f"{attachment.name}.{attachment.filetype}"
f"{uuid}.{attachment.filetype}"
), download_name = f"{attachment.name}.{attachment.filetype}"
) )
@ -232,7 +224,7 @@ def delete(uuid):
if request.method == "GET": if request.method == "GET":
return render_template("partition/delete.html", partition=partition, user=user) return render_template("partition/delete.html", partition=partition, user=user)
partition.delete(current_app.instance_path) partition.delete()
flash("Partition supprimée.") flash("Partition supprimée.")
return redirect("/albums") return redirect("/albums")
@ -254,13 +246,7 @@ def partition_search(uuid):
abort(404) abort(404)
if request.args.get("redirect") == "true" and partition["url"] is not None: if request.args.get("redirect") == "true" and partition["url"] is not None:
return redirect(partition["url"]) return redirect(partition["url"])
return send_file(os.path.join("search-partitions", f"{uuid}.pdf"))
return send_file(os.path.join(
current_app.instance_path,
"search-partitions",
f"{uuid}.pdf"
)
)
@bp.route("/") @bp.route("/")

View File

@ -49,19 +49,19 @@ def local_search(query, partitions):
return selection return selection
def download_search_result(element, instance_path): def download_search_result(element):
uuid = element["uuid"] uuid = element["uuid"]
url = element["url"] url = element["url"]
try: try:
urllib.request.urlretrieve(url, f"{instance_path}/search-partitions/{uuid}.pdf") urllib.request.urlretrieve(url, f"partitioncloud/search-partitions/{uuid}.pdf")
except (urllib.error.HTTPError, urllib.error.URLError): except (urllib.error.HTTPError, urllib.error.URLError):
with open(f"{instance_path}/search-partitions/{uuid}.pdf", 'a', encoding="utf8") as _: with open(f"partitioncloud/search-partitions/{uuid}.pdf", 'a', encoding="utf8") as _:
pass # Create empty file pass # Create empty file
def online_search(query, num_queries, instance_path): def online_search(query, num_queries):
""" """
Renvoie les 3 résultats les plus pertinents depuis google Renvoie les 3 résultats les plus pertinents depuis google
""" """
@ -103,12 +103,7 @@ def online_search(query, num_queries, instance_path):
except urllib.error.URLError: # Unable to access network except urllib.error.URLError: # Unable to access network
return [] return []
threads = [ threads = [threading.Thread(target=download_search_result, args=(elem,)) for elem in partitions]
threading.Thread(
target=download_search_result,
args=(elem, instance_path)
) for elem in partitions
]
for thread in threads: for thread in threads:
thread.start() thread.start()
@ -116,10 +111,10 @@ def online_search(query, num_queries, instance_path):
for thread in threads: for thread in threads:
thread.join() thread.join()
for element in partitions.copy(): for element in partitions:
uuid = element["uuid"] uuid = element["uuid"]
url = element["url"] url = element["url"]
if os.stat(f"{instance_path}/search-partitions/{uuid}.pdf").st_size == 0: if os.stat(f"partitioncloud/search-partitions/{uuid}.pdf").st_size == 0:
print("An error occured", url) print("An error occured", url)
db.execute( db.execute(
""" """
@ -130,14 +125,14 @@ def online_search(query, num_queries, instance_path):
) )
db.commit() db.commit()
os.remove(f"{instance_path}/search-partitions/{uuid}.pdf") os.remove(f"partitioncloud/search-partitions/{uuid}.pdf")
partitions.remove(element) partitions.remove(element)
return partitions return partitions
def flush_cache(instance_path): def flush_cache():
""" """
Supprimer les résultats de recherche datant de plus de 15 minutes Supprimer les résultats de recherche datant de plus de 15 minutes
""" """
@ -151,7 +146,7 @@ def flush_cache(instance_path):
for element in expired_cache: for element in expired_cache:
uuid = element["uuid"] uuid = element["uuid"]
try: try:
os.remove(f"{instance_path}/search-partitions/{uuid}.pdf") os.remove(f"partitioncloud/search-partitions/{uuid}.pdf")
except FileNotFoundError: except FileNotFoundError:
pass pass
try: try:

View File

@ -29,7 +29,6 @@ from .classes.album import Album
from .classes.groupe import Groupe from .classes.groupe import Groupe
from .classes.partition import Partition from .classes.partition import Partition
from .classes.attachment import Attachment from .classes.attachment import Attachment
from .classes.album import create as create_album
def get_all_partitions(): def get_all_partitions():

View File

@ -1,5 +1,4 @@
import os import os
import shutil
import sqlite3 import sqlite3
from hooks import utils from hooks import utils
from colorama import Fore, Style from colorama import Fore, Style
@ -143,21 +142,3 @@ def base_url_parameter_added():
def install_qrcode(): def install_qrcode():
os.system("pip install qrcode -qq") os.system("pip install qrcode -qq")
"""
v1.5.*
"""
def move_instance():
paths = [
"attachments",
"partitions",
"search-partitions"
]
for path in paths:
shutil.move(
os.path.join("partitioncloud", path),
os.path.join("instance", path)
)

View File

@ -33,7 +33,6 @@ hooks = [
], ],
), ),
("v1.4.1", [("Install qrcode", v1_hooks.install_qrcode)]), ("v1.4.1", [("Install qrcode", v1_hooks.install_qrcode)]),
("v1.5.0", [("Move to instance directory", v1_hooks.move_instance)])
] ]
@ -87,10 +86,10 @@ def backup_instance(version, verbose=True):
os.path.join(dest, "search-partitions"), os.path.join(dest, "search-partitions"),
), ),
] ]
for src, dst in paths: # Only the first one exists after v1.5.0 for src, dst in paths:
if os.path.exists(src): if os.path.exists(src):
print_verbose(f"\tBacking up {src}") print_verbose(f"\tBacking up {src}")
shutil.copytree(src, dst) shutil.copy_tree(src, dst)
def print_hooks(hooks_list): def print_hooks(hooks_list):
@ -109,7 +108,7 @@ def apply_hooks(hooks_list):
def migrate(current, target, skip_backup=False, prog_name="scripts/migration.py"): def migrate(current, target, skip_backup=False, prog_name="scripts/migration.py"):
"""Migrate from one version to another""" """"""
print(f"Trying to migrate from {current} to {target}") print(f"Trying to migrate from {current} to {target}")
assert is_newer(target, current) assert is_newer(target, current)
@ -133,7 +132,7 @@ def migrate(current, target, skip_backup=False, prog_name="scripts/migration.py"
) )
print( print(
f"If something goes wrong, recover with {Style.BRIGHT}{Fore.BLUE}{prog_name}\ f"If something goes wrong, recover with {Style.BRIGHT}{Fore.BLUE}{prog_name}\
--restore {current}{Style.RESET_ALL}" --restore {current}{Style.RESET_ALL}"
) )
else: else:
print("Skipping automatic backup") print("Skipping automatic backup")
@ -169,13 +168,13 @@ def restore(version):
os.path.join(dest, "search-partitions"), os.path.join(dest, "search-partitions"),
), ),
] ]
for src, dst in paths: # Only the first one exists after v1.5.0 for src, dst in paths:
if os.path.exists(src): if os.path.exists(src):
shutil.rmtree(src) shutil.rmtree(src)
if os.path.exists(dst): if os.path.exists(dst):
print(f"\tRestoring {src}") print(f"\tRestoring {src}")
shutil.copytree(dst, src) shutil.copy_tree(dst, src)
else: else:
print( print(
f"\t{Fore.RED}No available backup for {src}, \ f"\t{Fore.RED}No available backup for {src}, \