1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Fix Folder ID bugs, add initial DB migration work

This commit is contained in:
mvn23 2019-09-15 11:46:32 +02:00
parent c3fd94343f
commit 99ce42c9ff
10 changed files with 246 additions and 31 deletions

View File

@ -91,6 +91,16 @@ def get_entity(cls, param="id"):
return entity return entity
def get_entity_id(cls, eid):
"""Return the entity ID as its proper type."""
if cls == Folder:
try:
return int(eid)
except ValueError:
raise ValueError("Invalid Folder ID: %s", eid)
return uuid.UUID(eid)
from .errors import * from .errors import *
from .system import * from .system import *

View File

@ -7,8 +7,6 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import uuid
from datetime import timedelta from datetime import timedelta
from flask import request from flask import request
from pony.orm import select, desc, avg, max, min, count from pony.orm import select, desc, avg, max, min, count
@ -42,7 +40,12 @@ def rand_songs():
size = int(size) if size else 10 size = int(size) if size else 10
fromYear = int(fromYear) if fromYear else None fromYear = int(fromYear) if fromYear else None
toYear = int(toYear) if toYear else None toYear = int(toYear) if toYear else None
fid = uuid.UUID(musicFolderId) if musicFolderId else None fid = None
if musicFolderId:
try:
fid = int(musicFolderId)
except ValueError:
raise ValueError("Invalid folder ID")
query = Track.select() query = Track.select()
if fromYear: if fromYear:

View File

@ -21,7 +21,7 @@ from ..db import RatingTrack, RatingFolder
from ..lastfm import LastFm from ..lastfm import LastFm
from ..py23 import dict from ..py23 import dict
from . import api, get_entity from . import api, get_entity, get_entity_id
from .exceptions import AggregateException, GenericError, MissingParameter, NotFound from .exceptions import AggregateException, GenericError, MissingParameter, NotFound
@ -32,7 +32,7 @@ def star_single(cls, eid):
:param eid: id of the entity to star :param eid: id of the entity to star
""" """
uid = uuid.UUID(eid) uid = get_entity_id(cls, eid)
e = cls[uid] e = cls[uid]
starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__) starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__)
@ -52,7 +52,7 @@ def unstar_single(cls, eid):
:param eid: id of the entity to unstar :param eid: id of the entity to unstar
""" """
uid = uuid.UUID(eid) uid = get_entity_id(cls, eid)
starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__) starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__)
delete( delete(
s for s in starred_cls if s.user.id == request.user.id and s.starred.id == uid s for s in starred_cls if s.user.id == request.user.id and s.starred.id == uid
@ -115,7 +115,9 @@ def rate():
id = request.values["id"] id = request.values["id"]
rating = request.values["rating"] rating = request.values["rating"]
uid = uuid.UUID(id) tid = get_entity_id(Track, id)
fid = get_entity_id(Folder, id)
uid = None
rating = int(rating) rating = int(rating)
if not 0 <= rating <= 5: if not 0 <= rating <= 5:
@ -123,21 +125,23 @@ def rate():
if rating == 0: if rating == 0:
delete( delete(
r for r in RatingTrack if r.user.id == request.user.id and r.rated.id == uid r for r in RatingTrack if r.user.id == request.user.id and r.rated.id == tid
) )
delete( delete(
r r
for r in RatingFolder for r in RatingFolder
if r.user.id == request.user.id and r.rated.id == uid if r.user.id == request.user.id and r.rated.id == fid
) )
else: else:
try: try:
rated = Track[uid] rated = Track[tid]
rating_cls = RatingTrack rating_cls = RatingTrack
uid = tid
except ObjectNotFound: except ObjectNotFound:
try: try:
rated = Folder[uid] rated = Folder[fid]
rating_cls = RatingFolder rating_cls = RatingFolder
uid = fid
except ObjectNotFound: except ObjectNotFound:
raise NotFound("Track or Folder") raise NotFound("Track or Folder")

View File

@ -16,7 +16,7 @@ from pony.orm import ObjectNotFound, select
from ..db import Folder, Artist, Album, Track from ..db import Folder, Artist, Album, Track
from ..py23 import dict from ..py23 import dict
from . import api, get_entity from . import api, get_entity, get_entity_id
@api.route("/getMusicFolders.view", methods=["GET", "POST"]) @api.route("/getMusicFolders.view", methods=["GET", "POST"])
@ -42,10 +42,7 @@ def list_indexes():
if musicFolderId is None: if musicFolderId is None:
folders = Folder.select(lambda f: f.root)[:] folders = Folder.select(lambda f: f.root)[:]
else: else:
try: mfid = get_entity_id(Folder, musicFolderId)
mfid = int(musicFolderId)
except ValueError:
raise ValueError("Invalid folder ID")
folder = Folder[mfid] folder = Folder[mfid]
if not folder.root: if not folder.root:
raise ObjectNotFound(Folder, mfid) raise ObjectNotFound(Folder, mfid)

View File

@ -187,7 +187,8 @@ def stream_media():
@api.route("/download.view", methods=["GET", "POST"]) @api.route("/download.view", methods=["GET", "POST"])
def download_media(): def download_media():
id = request.values["id"] id = request.values["id"]
uid = uuid.UUID(id) uid = get_entity_id(Track, id)
fid = get_entity_id(Folder, id)
try: # Track -> direct download try: # Track -> direct download
rv = Track[uid] rv = Track[uid]
@ -196,7 +197,7 @@ def download_media():
pass pass
try: # Folder -> stream zipped tracks, non recursive try: # Folder -> stream zipped tracks, non recursive
rv = Folder[uid] rv = Folder[fid]
except ObjectNotFound: except ObjectNotFound:
try: # Album -> stream zipped tracks try: # Album -> stream zipped tracks
rv = Album[uid] rv = Album[uid]

View File

@ -0,0 +1,70 @@
START TRANSACTION;
CREATE TEMPORARY TABLE IF NOT EXISTS folder_id_to_int (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
uuid BINARY(16) NOT NULL
);
INSERT INTO folder_id_to_int(uuid) SELECT id FROM folder;
DROP INDEX index_folder_parent_id_fk ON folder;
DROP INDEX index_track_folder_id_fk ON track;
DROP INDEX index_track_root_folder_id_fk ON track;
DROP INDEX index_starred_folder_starred_id_fk ON starred_folder;
DROP INDEX index_rating_folder_rated_id_fk ON rating_folder;
ALTER TABLE folder
ADD int_id INTEGER AFTER id,
ADD int_parent_id INTEGER REFERENCES folder AFTER parent_id;
UPDATE folder SET int_id = (SELECT id FROM folder_id_to_int WHERE uuid == folder.id);
UPDATE folder SET int_parent_id = (SELECT id FROM folder_id_to_int WHERE uuid == folder.parent_id);
ALTER TABLE folder
DROP PRIMARY KEY,
DROP COLUMN id,
DROP COLUMN parent_id,
RENAME COLUMN int_id TO id,
RENAME COLUMN int_parent_id TO parent_id,
MODIFY id INTEGER AUTO_INCREMENT,
ADD PRIMARY KEY (id);
ALTER TABLE track
ADD int_root_folder_id INTEGER NOT NULL REFERENCES folder AFTER root_folder_id,
ADD int_folder_id INTEGER NOT NULL REFERENCES folder AFTER folder_id;
UPDATE track SET int_root_folder_id = (SELECT id FROM folder_id_to_int WHERE uuid == track.root_folder_id);
UPDATE track SET int_folder_id = (SELECT id FROM folder_id_to_int WHERE uuid == track.folder_id);
ALTER TABLE track
DROP COLUMN root_folder_id,
DROP COLUMN folder_id,
RENAME COLUMN int_root_folder_id TO root_folder_id,
RENAME COLUMN int_folder_id TO folder_id,
ALTER TABLE starred_folder ADD int_starred_id INTEGER NOT NULL REFERENCES folder AFTER starred_id;
UPDATE starred_folder SET int_starred_id = (SELECT id FROM folder_id_to_int WHERE uuid == starred_folder.starred_id);
ALTER TABLE starred_folder
DROP PRIMARY KEY,
DROP COLUMN starred_id,
RENAME COLUMN int_starred_id TO starred_id,
ADD PRIMARY KEY (user_id, starred_id);
ALTER TABLE rating_folder ADD int_rated_id INTEGER NOT NULL REFERENCES folder AFTER rated_id;
UPDATE rating_folder SET int_rated_id = (SELECT id FROM folder_id_to_int WHERE uuid == rating_folder.rated_id);
ALTER TABLE rating_folder
DROP PRIMARY KEY,
DROP COLUMN rated_id,
RENAME COLUMN int_rated_id TO rated_id,
ADD PRIMARY KEY (user_id, rated_id);
CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder(parent_id);
CREATE INDEX IF NOT EXISTS index_track_folder_id_fk ON track(folder_id);
CREATE INDEX IF NOT EXISTS index_track_root_folder_id_fk ON track(root_folder_id);
CREATE INDEX IF NOT EXISTS index_starred_folder_starred_id_fk ON starred_folder(starred_id);
CREATE INDEX IF NOT EXISTS index_rating_folder_rated_id_fk ON rating_folder(rated_id);
DROP TABLE folder_id_to_int;
COMMIT;

View File

@ -0,0 +1,129 @@
COMMIT;
PRAGMA foreign_keys = OFF;
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE IF NOT EXISTS folder_id_to_int (
id INTEGER NOT NULL PRIMARY KEY,
uuid CHAR(36) NOT NULL
);
INSERT INTO folder_id_to_int(uuid) SELECT id FROM folder;
DROP INDEX index_folder_parent_id_fk;
DROP INDEX index_folder_path;
CREATE TABLE IF NOT EXISTS folder_new (
id INTEGER NOT NULL PRIMARY KEY,
root BOOLEAN NOT NULL,
name VARCHAR(256) NOT NULL COLLATE NOCASE,
path VARCHAR(4096) NOT NULL,
path_hash BLOB NOT NULL,
created DATETIME NOT NULL,
cover_art VARCHAR(256),
last_scan INTEGER NOT NULL,
parent_id INTEGER REFERENCES folder
);
CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder_new(parent_id);
CREATE UNIQUE INDEX IF NOT EXISTS index_folder_path ON folder_new(path_hash);
INSERT INTO folder_new(id, root, name, path, path_hash, created, cover_art, last_scan, parent_id)
SELECT id_int.id, root, name, path, path_hash, created, cover_art, last_scan, parent_id_int.id
FROM folder
JOIN folder_id_to_int id_int ON folder.id == id_int.uuid
JOIN folder_id_to_int parent_id_int ON folder.parent_id == parent_id_int.uuid;
DROP TABLE folder;
ALTER TABLE folder_new RENAME TO folder;
DROP INDEX index_track_album_id_fk;
DROP INDEX index_track_artist_id_fk;
DROP INDEX index_track_folder_id_fk;
DROP INDEX index_track_root_folder_id_fk;
DROP INDEX index_track_path;
CREATE TABLE IF NOT EXISTS track_new (
id CHAR(36) PRIMARY KEY,
disc INTEGER NOT NULL,
number INTEGER NOT NULL,
title VARCHAR(256) NOT NULL COLLATE NOCASE,
year INTEGER,
genre VARCHAR(256),
duration INTEGER NOT NULL,
has_art BOOLEAN NOT NULL DEFAULT false,
album_id CHAR(36) NOT NULL REFERENCES album,
artist_id CHAR(36) NOT NULL REFERENCES artist,
bitrate INTEGER NOT NULL,
path VARCHAR(4096) NOT NULL,
path_hash BLOB NOT NULL,
created DATETIME NOT NULL,
last_modification INTEGER NOT NULL,
play_count INTEGER NOT NULL,
last_play DATETIME,
root_folder_id INTEGER NOT NULL REFERENCES folder,
folder_id INTEGER NOT NULL REFERENCES folder
);
CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track_new(album_id);
CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track_new(artist_id);
CREATE INDEX IF NOT EXISTS index_track_folder_id_fk ON track_new(folder_id);
CREATE INDEX IF NOT EXISTS index_track_root_folder_id_fk ON track_new(root_folder_id);
CREATE UNIQUE INDEX IF NOT EXISTS index_track_path ON track_new(path_hash);
INSERT INTO track_new(id, disc, number, title, year, genre, duration, has_art, album_id, artist_id, bitrate, path, path_hash, created, last_modification, play_count, last_play, root_folder_id, folder_id)
SELECT track.id, disc, number, title, year, genre, duration, has_art, album_id, artist_id, bitrate, path, path_hash, created, last_modification, play_count, last_play, root_id_int.id, folder_id_int.id
FROM track
JOIN folder_id_to_int root_id_int ON track.root_folder_id == root_id_int.uuid
JOIN folder_id_to_int folder_id_int ON track.folder_id == folder_id_int.uuid;
DROP TABLE track;
ALTER TABLE track_new RENAME TO track;
DROP INDEX index_starred_folder_user_id_fk;
DROP INDEX index_starred_folder_starred_id_fk;
CREATE TABLE IF NOT EXISTS starred_folder_new (
user_id CHAR(36) NOT NULL REFERENCES user,
starred_id INTEGER NOT NULL REFERENCES folder,
date DATETIME NOT NULL,
PRIMARY KEY (user_id, starred_id)
);
CREATE INDEX IF NOT EXISTS index_starred_folder_user_id_fk ON starred_folder_new(user_id);
CREATE INDEX IF NOT EXISTS index_starred_folder_starred_id_fk ON starred_folder_new(starred_id);
INSERT INTO starred_folder_new(user_id, starred_id, date)
SELECT user_id, id_int.id, date
FROM starred_folder
JOIN folder_id_to_int id_int ON starred_folder_new.starred_id == id_int.uuid;
DROP TABLE starred_folder;
ALTER TABLE starred_folder_new RENAME TO starred_folder;
DROP INDEX index_rating_folder_user_id_fk;
DROP INDEX index_rating_folder_rated_id_fk;
CREATE TABLE IF NOT EXISTS rating_folder_new (
user_id CHAR(36) NOT NULL REFERENCES user,
rated_id INTEGER NOT NULL REFERENCES folder,
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
PRIMARY KEY (user_id, rated_id)
);
CREATE INDEX IF NOT EXISTS index_rating_folder_user_id_fk ON rating_folder_new(user_id);
CREATE INDEX IF NOT EXISTS index_rating_folder_rated_id_fk ON rating_folder_new(rated_id);
INSERT INTO rating_folder_new(user_id, rated_id, rating)
SELECT user_id, id_int.id, rating
FROM rating_folder
JOIN folder_id_to_int id_int ON rating_folder.rated_id == id_int.uuid;
DROP TABLE rating_folder;
ALTER TABLE rating_folder_new RENAME TO rating_folder;
DROP TABLE folder_id_to_int;
COMMIT;
VACUUM;
PRAGMA foreign_keys = ON;
BEGIN TRANSACTION;

View File

@ -1,5 +1,5 @@
CREATE TABLE IF NOT EXISTS folder ( CREATE TABLE IF NOT EXISTS folder (
id BINARY(16) PRIMARY KEY, id INTEGER PRIMARY KEY AUTO_INCREMENT,
root BOOLEAN NOT NULL, root BOOLEAN NOT NULL,
name VARCHAR(256) NOT NULL, name VARCHAR(256) NOT NULL,
path VARCHAR(4096) NOT NULL, path VARCHAR(4096) NOT NULL,
@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS folder (
created DATETIME NOT NULL, created DATETIME NOT NULL,
cover_art VARCHAR(256), cover_art VARCHAR(256),
last_scan INTEGER NOT NULL, last_scan INTEGER NOT NULL,
parent_id BINARY(16) REFERENCES folder parent_id INTEGER REFERENCES folder
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder(parent_id); CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder(parent_id);
@ -41,8 +41,8 @@ CREATE TABLE IF NOT EXISTS track (
last_modification INTEGER NOT NULL, last_modification INTEGER NOT NULL,
play_count INTEGER NOT NULL, play_count INTEGER NOT NULL,
last_play DATETIME, last_play DATETIME,
root_folder_id BINARY(16) NOT NULL REFERENCES folder, root_folder_id INTEGER NOT NULL REFERENCES folder,
folder_id BINARY(16) NOT NULL REFERENCES folder folder_id INTEGER NOT NULL REFERENCES folder
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track(album_id); CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track(album_id);
CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track(artist_id); CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track(artist_id);
@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS client_prefs (
CREATE TABLE IF NOT EXISTS starred_folder ( CREATE TABLE IF NOT EXISTS starred_folder (
user_id BINARY(16) NOT NULL REFERENCES user, user_id BINARY(16) NOT NULL REFERENCES user,
starred_id BINARY(16) NOT NULL REFERENCES folder, starred_id INTEGER NOT NULL REFERENCES folder,
date DATETIME NOT NULL, date DATETIME NOT NULL,
PRIMARY KEY (user_id, starred_id) PRIMARY KEY (user_id, starred_id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
@ -109,7 +109,7 @@ CREATE INDEX IF NOT EXISTS index_starred_track_starred_id_fk ON starred_track(st
CREATE TABLE IF NOT EXISTS rating_folder ( CREATE TABLE IF NOT EXISTS rating_folder (
user_id BINARY(16) NOT NULL REFERENCES user, user_id BINARY(16) NOT NULL REFERENCES user,
rated_id BINARY(16) NOT NULL REFERENCES folder, rated_id INTEGER NOT NULL REFERENCES folder,
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5), rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
PRIMARY KEY (user_id, rated_id) PRIMARY KEY (user_id, rated_id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

View File

@ -1,5 +1,5 @@
CREATE TABLE IF NOT EXISTS folder ( CREATE TABLE IF NOT EXISTS folder (
id UUID PRIMARY KEY, id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
root BOOLEAN NOT NULL, root BOOLEAN NOT NULL,
name CITEXT NOT NULL, name CITEXT NOT NULL,
path VARCHAR(4096) NOT NULL, path VARCHAR(4096) NOT NULL,
@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS folder (
created TIMESTAMP NOT NULL, created TIMESTAMP NOT NULL,
cover_art VARCHAR(256), cover_art VARCHAR(256),
last_scan INTEGER NOT NULL, last_scan INTEGER NOT NULL,
parent_id UUID REFERENCES folder parent_id INTEGER REFERENCES folder
); );
CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder(parent_id); CREATE INDEX IF NOT EXISTS index_folder_parent_id_fk ON folder(parent_id);
@ -41,8 +41,8 @@ CREATE TABLE IF NOT EXISTS track (
last_modification INTEGER NOT NULL, last_modification INTEGER NOT NULL,
play_count INTEGER NOT NULL, play_count INTEGER NOT NULL,
last_play TIMESTAMP, last_play TIMESTAMP,
root_folder_id UUID NOT NULL REFERENCES folder, root_folder_id INTEGER NOT NULL REFERENCES folder,
folder_id UUID NOT NULL REFERENCES folder folder_id INTEGER NOT NULL REFERENCES folder
); );
CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track(album_id); CREATE INDEX IF NOT EXISTS index_track_album_id_fk ON track(album_id);
CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track(artist_id); CREATE INDEX IF NOT EXISTS index_track_artist_id_fk ON track(artist_id);
@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS client_prefs (
CREATE TABLE IF NOT EXISTS starred_folder ( CREATE TABLE IF NOT EXISTS starred_folder (
user_id UUID NOT NULL REFERENCES "user", user_id UUID NOT NULL REFERENCES "user",
starred_id UUID NOT NULL REFERENCES folder, starred_id INTEGER NOT NULL REFERENCES folder,
date TIMESTAMP NOT NULL, date TIMESTAMP NOT NULL,
PRIMARY KEY (user_id, starred_id) PRIMARY KEY (user_id, starred_id)
); );
@ -109,7 +109,7 @@ CREATE INDEX IF NOT EXISTS index_starred_track_starred_id_fk ON starred_track(st
CREATE TABLE IF NOT EXISTS rating_folder ( CREATE TABLE IF NOT EXISTS rating_folder (
user_id UUID NOT NULL REFERENCES "user", user_id UUID NOT NULL REFERENCES "user",
rated_id UUID NOT NULL REFERENCES folder, rated_id INTEGER NOT NULL REFERENCES folder,
rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5), rating INTEGER NOT NULL CHECK(rating BETWEEN 1 AND 5),
PRIMARY KEY (user_id, rated_id) PRIMARY KEY (user_id, rated_id)
); );

View File

@ -6,12 +6,13 @@
# Copyright (C) 2019 Alban 'spl0k' Féron # Copyright (C) 2019 Alban 'spl0k' Féron
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import uuid
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from os import urandom from os import urandom
from pony.orm import db_session, commit, ObjectNotFound from pony.orm import db_session, commit, ObjectNotFound
from supysonic.db import Meta from supysonic.db import Folder, Meta
@db_session @db_session