Compare commits

...

2 Commits

Author SHA1 Message Date
6f5031623c Move all instance files to instance directory
Still to move: thumbnails
2024-01-16 18:50:19 +01:00
f43b1e1090 Factorise duplicated code 2024-01-15 18:53:57 +01:00
15 changed files with 255 additions and 169 deletions

View File

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

View File

@ -3,8 +3,10 @@
Main file
"""
import os
import sys
import datetime
import subprocess
import importlib.util
from flask import Flask, g, redirect, render_template, request, send_file, flash, session, abort
from werkzeug.security import generate_password_hash
@ -16,14 +18,48 @@ from .modules.db import get_db
app = Flask(__name__)
app.config.from_mapping(
DATABASE=os.path.join(app.instance_path, f"{__name__}.sqlite"),
)
app.config.from_object('default_config')
if os.path.exists("instance/config.py"):
app.config.from_object('instance.config')
else:
print("[WARNING] Using default config")
def load_config():
app.config.from_object('default_config')
app.instance_path = os.path.abspath(app.config["INSTANCE_PATH"])
if not os.path.exists(app.instance_path):
print("[ERROR] Instance path does not exist. Make sure to use an existing directory.")
sys.exit(1)
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(admin.bp)
@ -31,13 +67,7 @@ app.register_blueprint(groupe.bp)
app.register_blueprint(albums.bp)
app.register_blueprint(partition.bp)
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"
__version__ = get_version()
@app.route("/")
@ -99,7 +129,7 @@ def search_thumbnail(uuid):
f'/usr/bin/convert -thumbnail\
"178^>" -background white -alpha \
remove -crop 178x178+0+0 \
partitioncloud/search-partitions/{uuid}.pdf[0] \
{app.instance_path}/search-partitions/{uuid}.pdf[0] \
partitioncloud/static/search-thumbnails/{uuid}.jpg'
)

View File

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

View File

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

View File

@ -4,6 +4,7 @@ Classe Album
import os
from ..db import get_db
from ..utils import new_uuid
from .attachment import Attachment
@ -81,7 +82,7 @@ class Album():
).fetchall()
def delete(self):
def delete(self, instance_path):
"""
Supprimer l'album
"""
@ -129,9 +130,9 @@ class Album():
attachments = [Attachment(data=i) for i in data]
for attachment in attachments:
attachment.delete()
attachment.delete(instance_path)
os.remove(f"partitioncloud/partitions/{partition['uuid']}.pdf")
os.remove(f"{instance_path}/partitions/{partition['uuid']}.pdf")
if os.path.exists(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg"):
os.remove(f"partitioncloud/static/thumbnails/{partition['uuid']}.jpg")
@ -163,3 +164,26 @@ class Album():
(partition_uuid, self.id),
)
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.partition_uuid = data["partition_uuid"]
def delete(self):
def delete(self, instance_path):
db = get_db()
db.execute(
"""
@ -40,7 +40,7 @@ class Attachment():
)
db.commit()
os.remove(f"partitioncloud/attachments/{self.uuid}.{self.filetype}")
os.remove(f"{instance_path}/attachments/{self.uuid}.{self.filetype}")
def __repr__(self):
return f"{self.name}.{self.filetype}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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