mirror of
https://github.com/partitioncloud/partitioncloud-server.git
synced 2025-02-10 22:13:42 +01:00
Compare commits
No commits in common. "bdd9115f70fe293f0ad4980200c1463013107299" and "2de234870e1913827f7559df6c32c20b3d67610a" have entirely different histories.
bdd9115f70
...
2de234870e
3
.gitignore
vendored
3
.gitignore
vendored
@ -11,6 +11,3 @@ partitioncloud/search-partitions
|
|||||||
partitioncloud/static/thumbnails
|
partitioncloud/static/thumbnails
|
||||||
partitioncloud/static/search-thumbnails
|
partitioncloud/static/search-thumbnails
|
||||||
partitioncloud/attachments
|
partitioncloud/attachments
|
||||||
|
|
||||||
.venv
|
|
||||||
backups
|
|
@ -12,7 +12,4 @@ PORT="5000"
|
|||||||
MAX_ONLINE_QUERIES=3
|
MAX_ONLINE_QUERIES=3
|
||||||
|
|
||||||
# Disable registration of new users via /auth/register (they can still be added by root)
|
# Disable registration of new users via /auth/register (they can still be added by root)
|
||||||
DISABLE_REGISTER=False
|
DISABLE_REGISTER=False
|
||||||
|
|
||||||
# Front URL of the application (for QRCodes generation)
|
|
||||||
BASE_URL="http://localhost:5000"
|
|
@ -4,13 +4,14 @@ Albums module
|
|||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from flask import (Blueprint, abort, flash, redirect, render_template, request,
|
from flask import (Blueprint, abort, flash, redirect, render_template, request,
|
||||||
send_file, session, current_app)
|
send_file, 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, get_all_partitions, new_uuid, get_qrcode, format_uuid
|
from .utils import User, Album, get_all_partitions
|
||||||
from . import search
|
from . import search
|
||||||
|
|
||||||
bp = Blueprint("albums", __name__, url_prefix="/albums")
|
bp = Blueprint("albums", __name__, url_prefix="/albums")
|
||||||
@ -70,34 +71,25 @@ def album(uuid):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
album = Album(uuid=uuid)
|
album = Album(uuid=uuid)
|
||||||
|
album.users = [User(user_id=i["id"]) for i in album.get_users()]
|
||||||
|
user = User(user_id=session.get("user_id"))
|
||||||
|
partitions = album.get_partitions()
|
||||||
|
if user.id is None:
|
||||||
|
# On ne propose pas aux gens non connectés de rejoindre l'album
|
||||||
|
not_participant = False
|
||||||
|
else:
|
||||||
|
not_participant = not user.is_participant(album.uuid)
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"albums/album.html",
|
||||||
|
album=album,
|
||||||
|
partitions=partitions,
|
||||||
|
not_participant=not_participant,
|
||||||
|
user=user
|
||||||
|
)
|
||||||
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
try:
|
return abort(404)
|
||||||
album = Album(uuid=format_uuid(uuid))
|
|
||||||
return redirect(f"/albums/{format_uuid(uuid)}")
|
|
||||||
except LookupError:
|
|
||||||
return abort(404)
|
|
||||||
|
|
||||||
album.users = [User(user_id=i["id"]) for i in album.get_users()]
|
|
||||||
user = User(user_id=session.get("user_id"))
|
|
||||||
partitions = album.get_partitions()
|
|
||||||
if user.id is None:
|
|
||||||
# On ne propose pas aux gens non connectés de rejoindre l'album
|
|
||||||
not_participant = False
|
|
||||||
else:
|
|
||||||
not_participant = not user.is_participant(album.uuid)
|
|
||||||
|
|
||||||
return render_template(
|
|
||||||
"albums/album.html",
|
|
||||||
album=album,
|
|
||||||
partitions=partitions,
|
|
||||||
not_participant=not_participant,
|
|
||||||
user=user
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<uuid>/qr")
|
|
||||||
def qr_code(uuid):
|
|
||||||
return get_qrcode(f"/albums/{uuid}")
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/create-album", methods=["POST"])
|
@bp.route("/create-album", methods=["POST"])
|
||||||
@ -115,7 +107,7 @@ def create_album():
|
|||||||
if error is None:
|
if error is None:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
uuid = new_uuid()
|
uuid = str(uuid4())
|
||||||
|
|
||||||
db.execute(
|
db.execute(
|
||||||
"""
|
"""
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
Groupe module
|
Groupe module
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from flask import (Blueprint, abort, flash, redirect, render_template, request,
|
from flask import (Blueprint, abort, flash, redirect, render_template, request,
|
||||||
send_file, session, current_app)
|
send_file, 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, get_all_partitions, Groupe, new_uuid, get_qrcode, format_uuid
|
from .utils import User, Album, get_all_partitions, Groupe
|
||||||
from . import search
|
from . import search
|
||||||
|
|
||||||
bp = Blueprint("groupe", __name__, url_prefix="/groupe")
|
bp = Blueprint("groupe", __name__, url_prefix="/groupe")
|
||||||
@ -27,34 +28,25 @@ def groupe(uuid):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
groupe = Groupe(uuid=uuid)
|
groupe = Groupe(uuid=uuid)
|
||||||
|
groupe.users = [User(user_id=i["id"]) for i in groupe.get_users()]
|
||||||
|
groupe.get_albums()
|
||||||
|
user = User(user_id=session.get("user_id"))
|
||||||
|
|
||||||
|
if user.id is None:
|
||||||
|
# On ne propose pas aux gens non connectés de rejoindre l'album
|
||||||
|
not_participant = False
|
||||||
|
else:
|
||||||
|
not_participant = not user.id in [i.id for i in groupe.users]
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"groupe/index.html",
|
||||||
|
groupe=groupe,
|
||||||
|
not_participant=not_participant,
|
||||||
|
user=user
|
||||||
|
)
|
||||||
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
try:
|
return abort(404)
|
||||||
groupe = Groupe(uuid=format_uuid(uuid))
|
|
||||||
return redirect(f"/groupe/{format_uuid(uuid)}")
|
|
||||||
except LookupError:
|
|
||||||
return abort(404)
|
|
||||||
|
|
||||||
groupe.users = [User(user_id=i["id"]) for i in groupe.get_users()]
|
|
||||||
groupe.get_albums()
|
|
||||||
user = User(user_id=session.get("user_id"))
|
|
||||||
|
|
||||||
if user.id is None:
|
|
||||||
# On ne propose pas aux gens non connectés de rejoindre l'album
|
|
||||||
not_participant = False
|
|
||||||
else:
|
|
||||||
not_participant = not user.id in [i.id for i in groupe.users]
|
|
||||||
|
|
||||||
return render_template(
|
|
||||||
"groupe/index.html",
|
|
||||||
groupe=groupe,
|
|
||||||
not_participant=not_participant,
|
|
||||||
user=user
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<uuid>/qr")
|
|
||||||
def album_qr_code(uuid):
|
|
||||||
return get_qrcode(f"/groupe/{uuid}")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +65,7 @@ def create_groupe():
|
|||||||
if error is None:
|
if error is None:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
uuid = new_uuid()
|
uuid = str(uuid4())
|
||||||
|
|
||||||
db.execute(
|
db.execute(
|
||||||
"""
|
"""
|
||||||
@ -190,7 +182,7 @@ def create_album(groupe_uuid):
|
|||||||
if error is None:
|
if error is None:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
uuid = new_uuid()
|
uuid = str(uuid4())
|
||||||
|
|
||||||
db.execute(
|
db.execute(
|
||||||
"""
|
"""
|
||||||
@ -236,19 +228,11 @@ def album(groupe_uuid, album_uuid):
|
|||||||
try:
|
try:
|
||||||
groupe = Groupe(uuid=groupe_uuid)
|
groupe = Groupe(uuid=groupe_uuid)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
try:
|
abort(404)
|
||||||
groupe = Groupe(uuid=format_uuid(groupe_uuid))
|
|
||||||
return redirect(f"/groupe/{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]
|
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 = format_uuid(album_uuid)
|
abort(404)
|
||||||
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}")
|
|
||||||
return abort(404)
|
|
||||||
|
|
||||||
album = album_list[0]
|
album = album_list[0]
|
||||||
user = User(user_id=session.get("user_id"))
|
user = User(user_id=session.get("user_id"))
|
||||||
@ -272,9 +256,4 @@ def album(groupe_uuid, album_uuid):
|
|||||||
partitions=partitions,
|
partitions=partitions,
|
||||||
not_participant=not_participant,
|
not_participant=not_participant,
|
||||||
user=user
|
user=user
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<groupe_uuid>/<album_uuid>/qr")
|
|
||||||
def groupe_qr_code(groupe_uuid, album_uuid):
|
|
||||||
return get_qrcode(f"/groupe/{groupe_uuid}/{album_uuid}")
|
|
@ -1,29 +1,7 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
import os
|
import os
|
||||||
import io
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import qrcode
|
|
||||||
|
|
||||||
from .db import get_db
|
from .db import get_db
|
||||||
from flask import current_app, send_file
|
|
||||||
|
|
||||||
|
|
||||||
def new_uuid():
|
|
||||||
return ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(6)])
|
|
||||||
|
|
||||||
def format_uuid(uuid):
|
|
||||||
"""Format old uuid4 format"""
|
|
||||||
return uuid.upper()[:6]
|
|
||||||
|
|
||||||
def get_qrcode(location):
|
|
||||||
complete_url = current_app.config["BASE_URL"] + location
|
|
||||||
img_io = io.BytesIO()
|
|
||||||
|
|
||||||
qrcode.make(complete_url).save(img_io)
|
|
||||||
img_io.seek(0)
|
|
||||||
return send_file(img_io, mimetype="image/jpeg")
|
|
||||||
|
|
||||||
|
|
||||||
from .classes.user import User
|
from .classes.user import User
|
||||||
from .classes.album import Album
|
from .classes.album import Album
|
||||||
|
@ -28,7 +28,7 @@ CREATE TABLE partition (
|
|||||||
CREATE TABLE album (
|
CREATE TABLE album (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
uuid TEXT(6) UNIQUE NOT NULL
|
uuid TEXT(36) UNIQUE NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE contient_partition (
|
CREATE TABLE contient_partition (
|
||||||
@ -52,7 +52,7 @@ CREATE TABLE search_results (
|
|||||||
CREATE TABLE groupe (
|
CREATE TABLE groupe (
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
uuid TEXT(6) UNIQUE NOT NULL
|
uuid TEXT(36) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE groupe_contient_user (
|
CREATE TABLE groupe_contient_user (
|
||||||
|
@ -749,19 +749,4 @@ midi-player {
|
|||||||
.centered {
|
.centered {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#share-qrcode {
|
|
||||||
margin: 20px;
|
|
||||||
margin-top: 50px;
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#share-url {
|
|
||||||
background-color: var(--color-surface1);
|
|
||||||
width: fit-content;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 100px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
@ -24,15 +24,6 @@
|
|||||||
</form>
|
</form>
|
||||||
<a href="#!" class="close-dialog">Close</a>
|
<a href="#!" class="close-dialog">Close</a>
|
||||||
</dialog>
|
</dialog>
|
||||||
{% if groupe %}
|
|
||||||
{% set current_url = "/groupe/" + groupe.uuid + "/" + album.uuid %}
|
|
||||||
{% else %}
|
|
||||||
{% set current_url = "/albums/" + album.uuid %}
|
|
||||||
{% endif %}
|
|
||||||
{% with share_link=config.BASE_URL+current_url, share_qrlink=current_url + "/qr" %}
|
|
||||||
{% include 'components/share_dialog.html' %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -62,7 +53,6 @@
|
|||||||
{% elif album.users | length > 1 %}
|
{% elif album.users | length > 1 %}
|
||||||
<a href="/albums/{{ album.uuid }}/quit">Quitter</a>
|
<a href="/albums/{{ album.uuid }}/quit">Quitter</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="#share">Partager</a>
|
|
||||||
{% if g.user.access_level == 1 or (not not_participant and album.users | length == 1) %}
|
{% if g.user.access_level == 1 or (not not_participant and album.users | length == 1) %}
|
||||||
<a id="delete-album" href="#delete">Supprimer</a>
|
<a id="delete-album" href="#delete">Supprimer</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
<dialog id="share">
|
|
||||||
<center>
|
|
||||||
<img src="{{ share_qrlink }}" id="share-qrcode"><br/>
|
|
||||||
<div id="share-url" onclick='navigator.clipboard.writeText("{{ share_link }}")'>
|
|
||||||
{{ share_link }}
|
|
||||||
</div>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<a href="#!" class="close-dialog">Close</a>
|
|
||||||
</dialog>
|
|
@ -22,10 +22,6 @@
|
|||||||
</form>
|
</form>
|
||||||
<a href="#!" class="close-dialog">Close</a>
|
<a href="#!" class="close-dialog">Close</a>
|
||||||
</dialog>
|
</dialog>
|
||||||
{% set current_url = "/groupe/" + groupe.uuid %}
|
|
||||||
{% with share_link=config.BASE_URL+current_url, share_qrlink=current_url + "/qr" %}
|
|
||||||
{% include 'components/share_dialog.html' %}
|
|
||||||
{% endwith %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -48,7 +44,6 @@
|
|||||||
{% elif groupe.users | length > 1 %}
|
{% elif groupe.users | length > 1 %}
|
||||||
<a href="/groupe/{{ groupe.uuid }}/quit">Quitter</a>
|
<a href="/groupe/{{ groupe.uuid }}/quit">Quitter</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="#share">Partager</a>
|
|
||||||
{% if g.user.access_level == 1 or user.id in groupe.get_admins() %}
|
{% if g.user.access_level == 1 or user.id in groupe.get_admins() %}
|
||||||
<a href="#create-groupe-album">Ajouter un album</a>
|
<a href="#create-groupe-album">Ajouter un album</a>
|
||||||
<a id="delete-album" href="#delete">Supprimer</a>
|
<a id="delete-album" href="#delete">Supprimer</a>
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
flask
|
flask
|
||||||
google
|
google
|
||||||
colorama
|
|
||||||
qrcode
|
|
@ -1,27 +0,0 @@
|
|||||||
import random
|
|
||||||
import string
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
def run_sqlite_command(*args):
|
|
||||||
"""Run a command against the database"""
|
|
||||||
con = sqlite3.connect("instance/partitioncloud.sqlite")
|
|
||||||
cur = con.cursor()
|
|
||||||
cur.execute(*args)
|
|
||||||
con.commit()
|
|
||||||
con.close()
|
|
||||||
|
|
||||||
def get_sqlite_data(*args):
|
|
||||||
"""Get data from the db"""
|
|
||||||
con = sqlite3.connect("instance/partitioncloud.sqlite")
|
|
||||||
cur = con.cursor()
|
|
||||||
data = cur.execute(*args)
|
|
||||||
new_data = [i for i in data]
|
|
||||||
con.close()
|
|
||||||
return new_data
|
|
||||||
|
|
||||||
def new_uuid():
|
|
||||||
return ''.join([random.choice(string.ascii_uppercase + string.digits) for _ in range(6)])
|
|
||||||
|
|
||||||
def format_uuid(uuid):
|
|
||||||
"""Format old uuid4 format"""
|
|
||||||
return uuid.upper()[:6]
|
|
@ -1,136 +0,0 @@
|
|||||||
import os
|
|
||||||
import sqlite3
|
|
||||||
from hooks import utils
|
|
||||||
from colorama import Fore, Style
|
|
||||||
|
|
||||||
"""
|
|
||||||
v1.3.*
|
|
||||||
"""
|
|
||||||
def add_source():
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"ALTER TABLE partition ADD source TEXT DEFAULT 'unknown'"
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_groupes():
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""CREATE TABLE groupe (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
uuid TEXT(36) NOT NULL
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""CREATE TABLE groupe_contient_user (
|
|
||||||
groupe_id INTEGER NOT NULL,
|
|
||||||
user_id INTEGER NOT NULL,
|
|
||||||
is_admin INTEGER NOT NULL DEFAULT 0,
|
|
||||||
PRIMARY KEY (groupe_id, user_id)
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""CREATE TABLE groupe_contient_album (
|
|
||||||
groupe_id INTEGER NOT NULL,
|
|
||||||
album_id INTEGER NOT NULL,
|
|
||||||
PRIMARY KEY (groupe_id, album_id)
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
|
|
||||||
def add_attachments():
|
|
||||||
os.makedirs("partitioncloud/attachments", exist_ok=True)
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""CREATE TABLE attachments (
|
|
||||||
uuid TEXT(36) PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
filetype TEXT NOT NULL DEFAULT 'mp3',
|
|
||||||
partition_uuid INTEGER NOT NULL,
|
|
||||||
user_id INTEGER NOT NULL
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
|
|
||||||
def install_colorama():
|
|
||||||
os.system("pip install colorama -qq")
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
v1.4.*
|
|
||||||
"""
|
|
||||||
def mass_rename():
|
|
||||||
"""Rename all albums & groupes to use a shorter uuid"""
|
|
||||||
albums = utils.get_sqlite_data("SELECT * FROM album")
|
|
||||||
groupes = utils.get_sqlite_data("SELECT * FROM groupe")
|
|
||||||
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"ALTER TABLE groupe RENAME TO _groupe_old"
|
|
||||||
)
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"ALTER TABLE album RENAME TO _album_old"
|
|
||||||
)
|
|
||||||
|
|
||||||
utils.run_sqlite_command( # Add UNIQUE constraint & change uuid length
|
|
||||||
"""CREATE TABLE groupe (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
uuid TEXT(6) UNIQUE NOT NULL
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
|
|
||||||
utils.run_sqlite_command( # Change uuid length
|
|
||||||
"""CREATE TABLE album (
|
|
||||||
id INTEGER PRIMARY KEY,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
uuid TEXT(6) UNIQUE NOT NULL
|
|
||||||
);"""
|
|
||||||
)
|
|
||||||
|
|
||||||
for album in albums:
|
|
||||||
try:
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""
|
|
||||||
INSERT INTO album (id, name, uuid)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
""",
|
|
||||||
(album[0], album[1], utils.format_uuid(album[2]))
|
|
||||||
)
|
|
||||||
except sqlite3.IntegrityError:
|
|
||||||
uuid = new_uuid()
|
|
||||||
print(f"{Fore.RED}Collision on {album[1]}{Style.RESET_ALL} ({album[2][:10]} renaming to {uuid})")
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""
|
|
||||||
INSERT INTO album (id, name, uuid)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
""",
|
|
||||||
(album[0], album[1], uuid)
|
|
||||||
)
|
|
||||||
|
|
||||||
for groupe in groupes:
|
|
||||||
try:
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""
|
|
||||||
INSERT INTO groupe (id, name, uuid)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
""",
|
|
||||||
(groupe[0], groupe[1], utils.format_uuid(groupe[2]))
|
|
||||||
)
|
|
||||||
except sqlite3.IntegrityError:
|
|
||||||
uuid = new_uuid()
|
|
||||||
print(f"{Fore.RED}Collision on {groupe[1]}{Style.RESET_ALL} ({groupe[2][:10]} renaming to {uuid})")
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"""
|
|
||||||
INSERT INTO groupe (id, name, uuid)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
""",
|
|
||||||
(groupe[0], groupe[1], uuid)
|
|
||||||
)
|
|
||||||
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"DROP TABLE _groupe_old"
|
|
||||||
)
|
|
||||||
utils.run_sqlite_command(
|
|
||||||
"DROP TABLE _album_old"
|
|
||||||
)
|
|
||||||
|
|
||||||
def base_url_parameter_added():
|
|
||||||
print(f"{Style.BRIGHT}{Fore.YELLOW}The parameter BASE_URL has been added, reference your front url in it{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
def install_qrcode():
|
|
||||||
os.system("pip install qrcode -qq")
|
|
@ -1,173 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import argparse
|
|
||||||
from functools import cmp_to_key
|
|
||||||
from distutils.dir_util import copy_tree
|
|
||||||
|
|
||||||
from colorama import Fore, Style
|
|
||||||
from hooks import v1
|
|
||||||
|
|
||||||
|
|
||||||
def get_version(v: str) -> (int, int, int):
|
|
||||||
"""Returns a tuple (major, minor, patch from the string v{major}.{minor}.{patch})"""
|
|
||||||
assert (v[0] == 'v') # Check if the version is correctly formatted
|
|
||||||
return tuple(map(int, v[1:].split('.')))
|
|
||||||
|
|
||||||
|
|
||||||
def is_newer(v1: str, v2: str) -> bool:
|
|
||||||
"""Returns True if v1 > v2"""
|
|
||||||
return get_version(v1) > get_version(v2)
|
|
||||||
|
|
||||||
|
|
||||||
hooks = [
|
|
||||||
("v1.3.0", [
|
|
||||||
("add SOURCE column", v1.add_source)
|
|
||||||
]),
|
|
||||||
("v1.2.0", [
|
|
||||||
("create groupe structure", v1.add_groupes)
|
|
||||||
]),
|
|
||||||
("v1.3.0", [
|
|
||||||
("create attachment table", v1.add_attachments)
|
|
||||||
]),
|
|
||||||
("v1.3.3", [
|
|
||||||
("Install colorama", v1.install_colorama)
|
|
||||||
]),
|
|
||||||
("v1.4.0", [
|
|
||||||
("Change all albums & groupes uuids", v1.mass_rename),
|
|
||||||
("Warn new parameter", v1.base_url_parameter_added)
|
|
||||||
]),
|
|
||||||
("v1.4.1", [
|
|
||||||
("Install qrcode", v1.install_qrcode)
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_hooks(current, target):
|
|
||||||
"""Returns a list of hooks needed to migrate"""
|
|
||||||
def compare(v1: str, v2: str):
|
|
||||||
if is_newer(v2[0], v1[0]):
|
|
||||||
return -1
|
|
||||||
elif is_newer(v1[0], v2[0]):
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
applied_hooks = []
|
|
||||||
for hook in hooks:
|
|
||||||
if is_newer(hook[0], current) and (target == hook[0] or is_newer(target, hook[0])):
|
|
||||||
applied_hooks.append(hook)
|
|
||||||
|
|
||||||
return sorted(applied_hooks, key=cmp_to_key(compare))
|
|
||||||
|
|
||||||
|
|
||||||
def backup_instance(version, verbose=True):
|
|
||||||
"""Backs up current instance in backups/{version}"""
|
|
||||||
def print_verbose(*args):
|
|
||||||
if verbose:
|
|
||||||
print(*args)
|
|
||||||
|
|
||||||
print_verbose("\nBacking up current instance")
|
|
||||||
dest = os.path.join("backups", version)
|
|
||||||
|
|
||||||
if os.path.exists(dest):
|
|
||||||
print(f"{Fore.RED}Backup directory already exists{Style.RESET_ALL}")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
os.makedirs(dest)
|
|
||||||
paths = [
|
|
||||||
("instance", os.path.join(dest, "instance")),
|
|
||||||
(os.path.join("partitioncloud", "partitions"), os.path.join(dest, "partitions")),
|
|
||||||
(os.path.join("partitioncloud", "attachments"), os.path.join(dest, "attachments")),
|
|
||||||
(os.path.join("partitioncloud", "search-partitions"), os.path.join(dest, "search-partitions"))
|
|
||||||
]
|
|
||||||
for src, dst in paths:
|
|
||||||
if os.path.exists(src):
|
|
||||||
print_verbose(f"\tBacking up {src}")
|
|
||||||
copy_tree(src, dst)
|
|
||||||
|
|
||||||
|
|
||||||
def print_hooks(hooks):
|
|
||||||
for hook in hooks:
|
|
||||||
print(f"- {Fore.BLUE}{hook[0]}{Style.RESET_ALL}:")
|
|
||||||
for subhook in hook[1]:
|
|
||||||
print("\t", subhook[0])
|
|
||||||
|
|
||||||
|
|
||||||
def apply_hooks(hooks):
|
|
||||||
for hook in hooks:
|
|
||||||
print(f"Migrating to {Fore.BLUE}{hook[0]}{Style.RESET_ALL}:")
|
|
||||||
for subhook in hook[1]:
|
|
||||||
print(f"\tApplying '{subhook[0]}'")
|
|
||||||
subhook[1]()
|
|
||||||
|
|
||||||
|
|
||||||
def migrate(current, target, skip_backup=False, prog_name="scripts/migration.py"):
|
|
||||||
""""""
|
|
||||||
print(f"Trying to migrate from {args.current} to {args.target}")
|
|
||||||
|
|
||||||
assert is_newer(args.target, args.current)
|
|
||||||
|
|
||||||
applied_hooks = get_hooks(args.current, args.target)
|
|
||||||
if (len(applied_hooks) == 0):
|
|
||||||
print(f"{Fore.GREEN}No hook to apply{Style.RESET_ALL}")
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
print("The following hooks will be applied:")
|
|
||||||
print_hooks(applied_hooks)
|
|
||||||
|
|
||||||
if input("Apply these hooks ? [y/N] ") != "y":
|
|
||||||
print(f"{Fore.RED}Aborting !{Style.RESET_ALL}")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if not skip_backup:
|
|
||||||
backup_instance(current)
|
|
||||||
print(f"Instance backed up in {Style.BRIGHT}backups/{current}{Style.RESET_ALL}\n")
|
|
||||||
print(f"If something goes wrong, recover with {Style.BRIGHT}{Fore.BLUE}{prog_name} --restore {current}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print("Skipping automatic backup")
|
|
||||||
|
|
||||||
apply_hooks(applied_hooks)
|
|
||||||
print("Done !")
|
|
||||||
|
|
||||||
|
|
||||||
def restore(version):
|
|
||||||
if input("Do you really want to restore from backup ? Your current data will be deleted [y/N] ") != "y":
|
|
||||||
print(f"{Fore.RED}Aborting !{Style.RESET_ALL}")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
dest = os.path.join("backups", version)
|
|
||||||
print(f"Restoring from {dest}")
|
|
||||||
paths = [
|
|
||||||
("instance", os.path.join(dest, "instance")),
|
|
||||||
(os.path.join("partitioncloud", "partitions"), os.path.join(dest, "partitions")),
|
|
||||||
(os.path.join("partitioncloud", "attachments"), os.path.join(dest, "attachments")),
|
|
||||||
(os.path.join("partitioncloud", "search-partitions"), os.path.join(dest, "search-partitions"))
|
|
||||||
]
|
|
||||||
for src, dst in paths:
|
|
||||||
if os.path.exists(src):
|
|
||||||
shutil.rmtree(src)
|
|
||||||
|
|
||||||
if os.path.exists(dst):
|
|
||||||
print(f"\tRestoring {src}")
|
|
||||||
copy_tree(dst, src)
|
|
||||||
else:
|
|
||||||
print(f"\t{Fore.RED}No available backup for {src}, deleting current content to avoid any conflict{Style.RESET_ALL}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
prog='PartitionCloud Migration tool',
|
|
||||||
description='Helps you migrate from one version to another')
|
|
||||||
|
|
||||||
parser.add_argument('-c', '--current', help="current version (vx.y.z)")
|
|
||||||
parser.add_argument('-t', '--target', help="target version (vx.y.z)")
|
|
||||||
parser.add_argument('-s', '--skip-backup', action='store_true')
|
|
||||||
parser.add_argument('-r', '--restore', help='restore from specific version backup, will not apply any hook (vx.y.z)')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.restore is None:
|
|
||||||
migrate(args.current, args.target, skip_backup=args.skip_backup)
|
|
||||||
else:
|
|
||||||
restore(args.restore)
|
|
Loading…
x
Reference in New Issue
Block a user