mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Merge remote-tracking branch 'mvn23/api_fix_ids'
This commit is contained in:
commit
2f94089e9c
@ -82,11 +82,29 @@ def get_client_prefs():
|
|||||||
|
|
||||||
def get_entity(cls, param="id"):
|
def get_entity(cls, param="id"):
|
||||||
eid = request.values[param]
|
eid = request.values[param]
|
||||||
|
if cls == Folder:
|
||||||
|
eid = int(eid)
|
||||||
|
else:
|
||||||
eid = uuid.UUID(eid)
|
eid = uuid.UUID(eid)
|
||||||
entity = cls[eid]
|
entity = cls[eid]
|
||||||
return entity
|
return entity
|
||||||
|
|
||||||
|
|
||||||
|
def get_entity_id(cls, eid):
|
||||||
|
"""Return the entity ID as its proper type."""
|
||||||
|
if cls == Folder:
|
||||||
|
if isinstance(eid, uuid.UUID):
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
try:
|
||||||
|
return int(eid)
|
||||||
|
except ValueError:
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
try:
|
||||||
|
return uuid.UUID(eid)
|
||||||
|
except (AttributeError, ValueError):
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
|
||||||
|
|
||||||
from .errors import *
|
from .errors import *
|
||||||
|
|
||||||
from .system import *
|
from .system import *
|
||||||
|
@ -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:
|
||||||
|
@ -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,12 +32,14 @@ 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)
|
try:
|
||||||
e = cls[uid]
|
e = cls[eid]
|
||||||
|
except ObjectNotFound:
|
||||||
|
raise NotFound("{} {}".format(cls.__name__, eid))
|
||||||
|
|
||||||
starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__)
|
starred_cls = getattr(sys.modules[__name__], "Starred" + cls.__name__)
|
||||||
try:
|
try:
|
||||||
starred_cls[request.user, uid]
|
starred_cls[request.user, eid]
|
||||||
raise GenericError("{} {} already starred".format(cls.__name__, eid))
|
raise GenericError("{} {} already starred".format(cls.__name__, eid))
|
||||||
except ObjectNotFound:
|
except ObjectNotFound:
|
||||||
pass
|
pass
|
||||||
@ -52,10 +54,9 @@ 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)
|
|
||||||
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 == eid
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -68,30 +69,44 @@ def handle_star_request(func):
|
|||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
for eid in id:
|
for eid in id:
|
||||||
terr = None
|
|
||||||
ferr = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
func(Track, eid)
|
tid = get_entity_id(Track, eid)
|
||||||
except Exception as e:
|
except GenericError:
|
||||||
terr = e
|
tid = None
|
||||||
try:
|
try:
|
||||||
func(Folder, eid)
|
fid = get_entity_id(Folder, eid)
|
||||||
except Exception as e:
|
except GenericError:
|
||||||
ferr = e
|
fid = None
|
||||||
|
err = None
|
||||||
|
|
||||||
if terr and ferr:
|
if tid is None and fid is None:
|
||||||
errors += [terr, ferr]
|
raise GenericError("Invalid ID")
|
||||||
|
|
||||||
|
if tid is not None:
|
||||||
|
try:
|
||||||
|
func(Track, tid)
|
||||||
|
except Exception as e:
|
||||||
|
err = e
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
func(Folder, fid)
|
||||||
|
except Exception as e:
|
||||||
|
err = e
|
||||||
|
|
||||||
|
if err:
|
||||||
|
errors.append(err)
|
||||||
|
|
||||||
for alId in albumId:
|
for alId in albumId:
|
||||||
|
alb_id = get_entity_id(Album, alId)
|
||||||
try:
|
try:
|
||||||
func(Album, alId)
|
func(Album, alb_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errors.append(e)
|
errors.append(e)
|
||||||
|
|
||||||
for arId in artistId:
|
for arId in artistId:
|
||||||
|
art_id = get_entity_id(Artist, arId)
|
||||||
try:
|
try:
|
||||||
func(Artist, arId)
|
func(Artist, art_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
errors.append(e)
|
errors.append(e)
|
||||||
|
|
||||||
@ -115,31 +130,43 @@ def rate():
|
|||||||
id = request.values["id"]
|
id = request.values["id"]
|
||||||
rating = request.values["rating"]
|
rating = request.values["rating"]
|
||||||
|
|
||||||
uid = uuid.UUID(id)
|
try:
|
||||||
|
tid = get_entity_id(Track, id)
|
||||||
|
except GenericError:
|
||||||
|
tid = None
|
||||||
|
try:
|
||||||
|
fid = get_entity_id(Folder, id)
|
||||||
|
except GenericError:
|
||||||
|
fid = None
|
||||||
|
uid = None
|
||||||
rating = int(rating)
|
rating = int(rating)
|
||||||
|
|
||||||
|
if tid is None and fid is None:
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
|
||||||
if not 0 <= rating <= 5:
|
if not 0 <= rating <= 5:
|
||||||
raise GenericError("rating must be between 0 and 5 (inclusive)")
|
raise GenericError("rating must be between 0 and 5 (inclusive)")
|
||||||
|
|
||||||
if rating == 0:
|
if rating == 0:
|
||||||
|
if tid is not None:
|
||||||
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
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
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:
|
if tid is not None:
|
||||||
rated = Track[uid]
|
rated = Track[tid]
|
||||||
rating_cls = RatingTrack
|
rating_cls = RatingTrack
|
||||||
except ObjectNotFound:
|
uid = tid
|
||||||
try:
|
else:
|
||||||
rated = Folder[uid]
|
rated = Folder[fid]
|
||||||
rating_cls = RatingFolder
|
rating_cls = RatingFolder
|
||||||
except ObjectNotFound:
|
uid = fid
|
||||||
raise NotFound("Track or Folder")
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rating_info = rating_cls[request.user, uid]
|
rating_info = rating_cls[request.user, uid]
|
||||||
|
@ -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,7 +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:
|
||||||
mfid = uuid.UUID(musicFolderId)
|
mfid = get_entity_id(Folder, musicFolderId)
|
||||||
folder = Folder[mfid]
|
folder = Folder[mfid]
|
||||||
if not folder.root:
|
if not folder.root:
|
||||||
raise ObjectNotFound(Folder, mfid)
|
raise ObjectNotFound(Folder, mfid)
|
||||||
|
@ -35,7 +35,7 @@ from ..covers import get_embedded_cover
|
|||||||
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
|
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
|
||||||
from ..py23 import dict
|
from ..py23 import dict
|
||||||
|
|
||||||
from . import api, get_entity
|
from . import api, get_entity, get_entity_id
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
GenericError,
|
GenericError,
|
||||||
MissingParameter,
|
MissingParameter,
|
||||||
@ -190,21 +190,33 @@ 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)
|
|
||||||
|
|
||||||
try: # Track -> direct download
|
try:
|
||||||
|
uid = get_entity_id(Track, id)
|
||||||
|
except GenericError:
|
||||||
|
uid = None
|
||||||
|
try:
|
||||||
|
fid = get_entity_id(Folder, id)
|
||||||
|
except GenericError:
|
||||||
|
fid = None
|
||||||
|
|
||||||
|
if uid is None and fid is None:
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
|
||||||
|
if uid is not None:
|
||||||
|
try:
|
||||||
rv = Track[uid]
|
rv = Track[uid]
|
||||||
return send_file(rv.path, mimetype=rv.mimetype, conditional=True)
|
return send_file(rv.path, mimetype=rv.mimetype, conditional=True)
|
||||||
except ObjectNotFound:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try: # Folder -> stream zipped tracks, non recursive
|
|
||||||
rv = Folder[uid]
|
|
||||||
except ObjectNotFound:
|
except ObjectNotFound:
|
||||||
try: # Album -> stream zipped tracks
|
try: # Album -> stream zipped tracks
|
||||||
rv = Album[uid]
|
rv = Album[uid]
|
||||||
except ObjectNotFound:
|
except ObjectNotFound:
|
||||||
raise NotFound("Track, Folder or Album")
|
raise NotFound("Track or Album")
|
||||||
|
else:
|
||||||
|
try: # Folder -> stream zipped tracks, non recursive
|
||||||
|
rv = Folder[fid]
|
||||||
|
except ObjectNotFound:
|
||||||
|
raise NotFound("Folder")
|
||||||
|
|
||||||
z = ZipFile(compression=ZIP_DEFLATED)
|
z = ZipFile(compression=ZIP_DEFLATED)
|
||||||
for track in rv.tracks:
|
for track in rv.tracks:
|
||||||
@ -217,15 +229,28 @@ def download_media():
|
|||||||
@api.route("/getCoverArt.view", methods=["GET", "POST"])
|
@api.route("/getCoverArt.view", methods=["GET", "POST"])
|
||||||
def cover_art():
|
def cover_art():
|
||||||
cache = current_app.cache
|
cache = current_app.cache
|
||||||
|
|
||||||
eid = request.values["id"]
|
eid = request.values["id"]
|
||||||
if Folder.exists(id=eid):
|
try:
|
||||||
|
fid = get_entity_id(Folder, eid)
|
||||||
|
except GenericError:
|
||||||
|
fid = None
|
||||||
|
try:
|
||||||
|
tid = get_entity_id(Track, eid)
|
||||||
|
except GenericError:
|
||||||
|
tid = None
|
||||||
|
|
||||||
|
if not fid and not tid:
|
||||||
|
raise GenericError("Invalid ID")
|
||||||
|
|
||||||
|
if fid and Folder.exists(id=eid):
|
||||||
res = get_entity(Folder)
|
res = get_entity(Folder)
|
||||||
if not res.cover_art or not os.path.isfile(
|
if not res.cover_art or not os.path.isfile(
|
||||||
os.path.join(res.path, res.cover_art)
|
os.path.join(res.path, res.cover_art)
|
||||||
):
|
):
|
||||||
raise NotFound("Cover art")
|
raise NotFound("Cover art")
|
||||||
cover_path = os.path.join(res.path, res.cover_art)
|
cover_path = os.path.join(res.path, res.cover_art)
|
||||||
elif Track.exists(id=eid):
|
elif tid and Track.exists(id=eid):
|
||||||
cache_key = "{}-cover".format(eid)
|
cache_key = "{}-cover".format(eid)
|
||||||
try:
|
try:
|
||||||
cover_path = cache.get(cache_key)
|
cover_path = cache.get(cache_key)
|
||||||
|
@ -90,8 +90,13 @@ class IniConfig(DefaultConfig):
|
|||||||
lv = value.lower()
|
lv = value.lower()
|
||||||
if lv in ("yes", "true", "on"):
|
if lv in ("yes", "true", "on"):
|
||||||
return True
|
return True
|
||||||
elif lv in ("no", "false", "off"):
|
if lv in ("no", "false", "off"):
|
||||||
return False
|
return False
|
||||||
|
try:
|
||||||
|
if isinstance(value, unicode):
|
||||||
|
return str(value)
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -29,7 +29,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from urlparse import urlparse, parse_qsl
|
from urlparse import urlparse, parse_qsl
|
||||||
|
|
||||||
SCHEMA_VERSION = "20190518"
|
SCHEMA_VERSION = "20190915"
|
||||||
|
|
||||||
|
|
||||||
def now():
|
def now():
|
||||||
@ -79,7 +79,7 @@ class PathMixin(object):
|
|||||||
class Folder(PathMixin, db.Entity):
|
class Folder(PathMixin, db.Entity):
|
||||||
_table_ = "folder"
|
_table_ = "folder"
|
||||||
|
|
||||||
id = PrimaryKey(UUID, default=uuid4)
|
id = PrimaryKey(int, auto=True)
|
||||||
root = Required(bool, default=False)
|
root = Required(bool, default=False)
|
||||||
name = Required(str, autostrip=False)
|
name = Required(str, autostrip=False)
|
||||||
path = Required(str, 4096, autostrip=False) # unique
|
path = Required(str, 4096, autostrip=False) # unique
|
||||||
|
@ -21,15 +21,13 @@ from ..py23 import strtype
|
|||||||
|
|
||||||
class FolderManager:
|
class FolderManager:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(uid):
|
def get(id):
|
||||||
if isinstance(uid, strtype):
|
try:
|
||||||
uid = uuid.UUID(uid)
|
id = int(id)
|
||||||
elif isinstance(uid, uuid.UUID):
|
except ValueError:
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise ValueError("Invalid folder id")
|
raise ValueError("Invalid folder id")
|
||||||
|
|
||||||
return Folder[uid]
|
return Folder[id]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add(name, path):
|
def add(name, path):
|
||||||
@ -55,8 +53,8 @@ class FolderManager:
|
|||||||
return folder
|
return folder
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete(uid):
|
def delete(id):
|
||||||
folder = FolderManager.get(uid)
|
folder = FolderManager.get(id)
|
||||||
if not folder.root:
|
if not folder.root:
|
||||||
raise ObjectNotFound(Folder)
|
raise ObjectNotFound(Folder)
|
||||||
|
|
||||||
|
69
supysonic/schema/migration/mysql/20190915.sql
Normal file
69
supysonic/schema/migration/mysql/20190915.sql
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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,
|
||||||
|
CHANGE COLUMN int_id id INTEGER AUTO_INCREMENT,
|
||||||
|
CHANGE COLUMN int_parent_id parent_id INTEGER,
|
||||||
|
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,
|
||||||
|
CHANGE COLUMN int_root_folder_id root_folder_id INTEGER NOT NULL,
|
||||||
|
CHANGE COLUMN int_folder_id folder_id INTEGER NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
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,
|
||||||
|
CHANGE COLUMN int_starred_id starred_id INTEGER NOT NULL,
|
||||||
|
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,
|
||||||
|
CHANGE COLUMN int_rated_id rated_id INTEGER NOT NULL,
|
||||||
|
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;
|
83
supysonic/schema/migration/postgres/20190915.sql
Normal file
83
supysonic/schema/migration/postgres/20190915.sql
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE IF NOT EXISTS folder_id_to_int (
|
||||||
|
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||||
|
uid UUID NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO folder_id_to_int(uid) SELECT id FROM folder;
|
||||||
|
|
||||||
|
ALTER TABLE folder DROP CONSTRAINT folder_parent_id_fkey;
|
||||||
|
ALTER TABLE rating_folder DROP CONSTRAINT rating_folder_rated_id_fkey;
|
||||||
|
ALTER TABLE starred_folder DROP CONSTRAINT starred_folder_starred_id_fkey;
|
||||||
|
ALTER TABLE track DROP CONSTRAINT track_folder_id_fkey;
|
||||||
|
ALTER TABLE track DROP CONSTRAINT track_root_folder_id_fkey;
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE folder
|
||||||
|
ADD int_id INTEGER,
|
||||||
|
ADD int_parent_id INTEGER;
|
||||||
|
UPDATE folder SET int_id = (SELECT id FROM folder_id_to_int WHERE uid = folder.id);
|
||||||
|
UPDATE folder SET int_parent_id = (SELECT id FROM folder_id_to_int WHERE uid = folder.parent_id);
|
||||||
|
CREATE SEQUENCE folder_id_seq AS INTEGER;
|
||||||
|
SELECT setval('folder_id_seq', coalesce(max(int_id), 0) + 1, false) FROM folder;
|
||||||
|
ALTER TABLE folder
|
||||||
|
DROP CONSTRAINT folder_pkey,
|
||||||
|
DROP COLUMN id,
|
||||||
|
DROP COLUMN parent_id,
|
||||||
|
ALTER COLUMN int_id SET DEFAULT nextval('folder_id_seq'),
|
||||||
|
ADD PRIMARY KEY (int_id);
|
||||||
|
ALTER TABLE folder RENAME COLUMN int_id TO id;
|
||||||
|
ALTER TABLE folder RENAME COLUMN int_parent_id TO parent_id;
|
||||||
|
ALTER TABLE folder ADD CONSTRAINT folder_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES folder(id);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE track
|
||||||
|
ADD int_root_folder_id INTEGER,
|
||||||
|
ADD int_folder_id INTEGER;
|
||||||
|
UPDATE track SET int_root_folder_id = (SELECT id FROM folder_id_to_int WHERE uid = track.root_folder_id);
|
||||||
|
UPDATE track SET int_folder_id = (SELECT id FROM folder_id_to_int WHERE uid = track.folder_id);
|
||||||
|
ALTER TABLE track
|
||||||
|
DROP COLUMN root_folder_id,
|
||||||
|
DROP COLUMN folder_id,
|
||||||
|
ALTER COLUMN int_root_folder_id SET NOT NULL,
|
||||||
|
ALTER COLUMN int_folder_id SET NOT NULL;
|
||||||
|
ALTER TABLE track RENAME COLUMN int_root_folder_id TO root_folder_id;
|
||||||
|
ALTER TABLE track RENAME COLUMN int_folder_id TO folder_id;
|
||||||
|
ALTER TABLE track ADD CONSTRAINT track_folder_id_fkey FOREIGN KEY (folder_id) REFERENCES folder(id);
|
||||||
|
ALTER TABLE track ADD CONSTRAINT track_root_folder_id_fkey FOREIGN KEY (root_folder_id) REFERENCES folder(id);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE starred_folder ADD int_starred_id INTEGER;
|
||||||
|
UPDATE starred_folder SET int_starred_id = (SELECT id FROM folder_id_to_int WHERE uid = starred_folder.starred_id);
|
||||||
|
ALTER TABLE starred_folder
|
||||||
|
DROP CONSTRAINT starred_folder_pkey,
|
||||||
|
DROP COLUMN starred_id,
|
||||||
|
ALTER COLUMN int_starred_id SET NOT NULL,
|
||||||
|
ADD PRIMARY KEY (user_id, int_starred_id);
|
||||||
|
ALTER TABLE starred_folder RENAME COLUMN int_starred_id TO starred_id;
|
||||||
|
ALTER TABLE starred_folder ADD CONSTRAINT starred_folder_starred_id_fkey FOREIGN KEY (starred_id) REFERENCES folder(id);
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE rating_folder ADD int_rated_id INTEGER;
|
||||||
|
UPDATE rating_folder SET int_rated_id = (SELECT id FROM folder_id_to_int WHERE uid = rating_folder.rated_id);
|
||||||
|
ALTER TABLE rating_folder
|
||||||
|
DROP CONSTRAINT rating_folder_pkey,
|
||||||
|
DROP COLUMN rated_id,
|
||||||
|
ALTER COLUMN int_rated_id SET NOT NULL,
|
||||||
|
ADD PRIMARY KEY (user_id, int_rated_id);
|
||||||
|
ALTER TABLE rating_folder RENAME COLUMN int_rated_id TO rated_id;
|
||||||
|
ALTER TABLE rating_folder ADD CONSTRAINT rating_folder_rated_id_fkey FOREIGN KEY (rated_id) REFERENCES folder(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;
|
136
supysonic/schema/migration/sqlite/20190915.sql
Normal file
136
supysonic/schema/migration/sqlite/20190915.sql
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
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, NULL
|
||||||
|
FROM folder
|
||||||
|
JOIN folder_id_to_int id_int ON folder.id == id_int.uuid
|
||||||
|
WHERE folder.parent_id IS NULL;
|
||||||
|
|
||||||
|
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
|
||||||
|
WHERE folder.parent_id IS NOT NULL;
|
||||||
|
|
||||||
|
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.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;
|
@ -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;
|
||||||
|
@ -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)
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CREATE TABLE IF NOT EXISTS folder (
|
CREATE TABLE IF NOT EXISTS folder (
|
||||||
id CHAR(36) PRIMARY KEY,
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
root BOOLEAN NOT NULL,
|
root BOOLEAN NOT NULL,
|
||||||
name VARCHAR(256) NOT NULL COLLATE NOCASE,
|
name VARCHAR(256) NOT NULL COLLATE NOCASE,
|
||||||
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 CHAR(36) 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);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS index_folder_path ON folder(path_hash);
|
CREATE UNIQUE INDEX IF NOT EXISTS index_folder_path ON folder(path_hash);
|
||||||
@ -42,8 +42,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 CHAR(36) NOT NULL REFERENCES folder,
|
root_folder_id INTEGER NOT NULL REFERENCES folder,
|
||||||
folder_id CHAR(36) 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);
|
||||||
@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS client_prefs (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS starred_folder (
|
CREATE TABLE IF NOT EXISTS starred_folder (
|
||||||
user_id CHAR(36) NOT NULL REFERENCES user,
|
user_id CHAR(36) NOT NULL REFERENCES user,
|
||||||
starred_id CHAR(36) 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)
|
||||||
);
|
);
|
||||||
@ -111,7 +111,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 CHAR(36) NOT NULL REFERENCES user,
|
user_id CHAR(36) NOT NULL REFERENCES user,
|
||||||
rated_id CHAR(36) 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)
|
||||||
);
|
);
|
||||||
|
@ -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
|
||||||
|
@ -118,7 +118,7 @@ class AlbumSongsTestCase(ApiTestBase):
|
|||||||
self._make_request("getRandomSongs", {"fromYear": "year"}, error=0)
|
self._make_request("getRandomSongs", {"fromYear": "year"}, error=0)
|
||||||
self._make_request("getRandomSongs", {"toYear": "year"}, error=0)
|
self._make_request("getRandomSongs", {"toYear": "year"}, error=0)
|
||||||
self._make_request("getRandomSongs", {"musicFolderId": "idid"}, error=0)
|
self._make_request("getRandomSongs", {"musicFolderId": "idid"}, error=0)
|
||||||
self._make_request("getRandomSongs", {"musicFolderId": uuid.uuid4()}, error=70)
|
self._make_request("getRandomSongs", {"musicFolderId": 1234567890}, error=70)
|
||||||
|
|
||||||
rv, child = self._make_request(
|
rv, child = self._make_request(
|
||||||
"getRandomSongs", tag="randomSongs", skip_post=True
|
"getRandomSongs", tag="randomSongs", skip_post=True
|
||||||
|
@ -27,6 +27,10 @@ class AnnotationTestCase(ApiTestBase):
|
|||||||
artist = Artist(name="Artist")
|
artist = Artist(name="Artist")
|
||||||
album = Album(name="Album", artist=artist)
|
album = Album(name="Album", artist=artist)
|
||||||
|
|
||||||
|
# Populate folder ids
|
||||||
|
root = Folder.get(name="Root")
|
||||||
|
folder = Folder.get(name="Folder")
|
||||||
|
|
||||||
track = Track(
|
track = Track(
|
||||||
title="Track",
|
title="Track",
|
||||||
album=album,
|
album=album,
|
||||||
@ -73,7 +77,7 @@ class AnnotationTestCase(ApiTestBase):
|
|||||||
self.assertIn("starred", Folder[self.folderid].as_subsonic_child(self.user))
|
self.assertIn("starred", Folder[self.folderid].as_subsonic_child(self.user))
|
||||||
self._make_request("star", {"id": str(self.folderid)}, error=0, skip_xsd=True)
|
self._make_request("star", {"id": str(self.folderid)}, error=0, skip_xsd=True)
|
||||||
|
|
||||||
self._make_request("star", {"albumId": str(self.folderid)}, error=70)
|
self._make_request("star", {"albumId": str(self.folderid)}, error=0)
|
||||||
self._make_request("star", {"albumId": str(self.artistid)}, error=70)
|
self._make_request("star", {"albumId": str(self.artistid)}, error=70)
|
||||||
self._make_request("star", {"albumId": str(self.trackid)}, error=70)
|
self._make_request("star", {"albumId": str(self.trackid)}, error=70)
|
||||||
self._make_request("star", {"albumId": str(self.albumid)}, skip_post=True)
|
self._make_request("star", {"albumId": str(self.albumid)}, skip_post=True)
|
||||||
@ -81,7 +85,7 @@ class AnnotationTestCase(ApiTestBase):
|
|||||||
self.assertIn("starred", Album[self.albumid].as_subsonic_album(self.user))
|
self.assertIn("starred", Album[self.albumid].as_subsonic_album(self.user))
|
||||||
self._make_request("star", {"albumId": str(self.albumid)}, error=0)
|
self._make_request("star", {"albumId": str(self.albumid)}, error=0)
|
||||||
|
|
||||||
self._make_request("star", {"artistId": str(self.folderid)}, error=70)
|
self._make_request("star", {"artistId": str(self.folderid)}, error=0)
|
||||||
self._make_request("star", {"artistId": str(self.albumid)}, error=70)
|
self._make_request("star", {"artistId": str(self.albumid)}, error=70)
|
||||||
self._make_request("star", {"artistId": str(self.trackid)}, error=70)
|
self._make_request("star", {"artistId": str(self.trackid)}, error=70)
|
||||||
self._make_request("star", {"artistId": str(self.artistid)}, skip_post=True)
|
self._make_request("star", {"artistId": str(self.artistid)}, skip_post=True)
|
||||||
@ -213,7 +217,7 @@ class AnnotationTestCase(ApiTestBase):
|
|||||||
self._make_request("scrobble", error=10)
|
self._make_request("scrobble", error=10)
|
||||||
self._make_request("scrobble", {"id": "song"}, error=0)
|
self._make_request("scrobble", {"id": "song"}, error=0)
|
||||||
self._make_request("scrobble", {"id": str(uuid.uuid4())}, error=70)
|
self._make_request("scrobble", {"id": str(uuid.uuid4())}, error=70)
|
||||||
self._make_request("scrobble", {"id": str(self.folderid)}, error=70)
|
self._make_request("scrobble", {"id": str(self.folderid)}, error=0)
|
||||||
|
|
||||||
self._make_request("scrobble", {"id": str(self.trackid)})
|
self._make_request("scrobble", {"id": str(self.trackid)})
|
||||||
self._make_request("scrobble", {"id": str(self.trackid), "submission": True})
|
self._make_request("scrobble", {"id": str(self.trackid), "submission": True})
|
||||||
|
@ -82,7 +82,7 @@ class BrowseTestCase(ApiTestBase):
|
|||||||
|
|
||||||
def test_get_indexes(self):
|
def test_get_indexes(self):
|
||||||
self._make_request("getIndexes", {"musicFolderId": "abcdef"}, error=0)
|
self._make_request("getIndexes", {"musicFolderId": "abcdef"}, error=0)
|
||||||
self._make_request("getIndexes", {"musicFolderId": str(uuid.uuid4())}, error=70)
|
self._make_request("getIndexes", {"musicFolderId": 1234567890}, error=70)
|
||||||
self._make_request("getIndexes", {"ifModifiedSince": "quoi"}, error=0)
|
self._make_request("getIndexes", {"ifModifiedSince": "quoi"}, error=0)
|
||||||
|
|
||||||
rv, child = self._make_request(
|
rv, child = self._make_request(
|
||||||
@ -109,7 +109,7 @@ class BrowseTestCase(ApiTestBase):
|
|||||||
def test_get_music_directory(self):
|
def test_get_music_directory(self):
|
||||||
self._make_request("getMusicDirectory", error=10)
|
self._make_request("getMusicDirectory", error=10)
|
||||||
self._make_request("getMusicDirectory", {"id": "id"}, error=0)
|
self._make_request("getMusicDirectory", {"id": "id"}, error=0)
|
||||||
self._make_request("getMusicDirectory", {"id": str(uuid.uuid4())}, error=70)
|
self._make_request("getMusicDirectory", {"id": 1234567890}, error=70)
|
||||||
|
|
||||||
# should test with folders with both children folders and tracks. this code would break in that case
|
# should test with folders with both children folders and tracks. this code would break in that case
|
||||||
with db_session:
|
with db_session:
|
||||||
|
@ -31,6 +31,7 @@ class MediaTestCase(ApiTestBase):
|
|||||||
root=True,
|
root=True,
|
||||||
cover_art="cover.jpg",
|
cover_art="cover.jpg",
|
||||||
)
|
)
|
||||||
|
folder = Folder.get(name="Root")
|
||||||
self.folderid = folder.id
|
self.folderid = folder.id
|
||||||
|
|
||||||
artist = Artist(name="Artist")
|
artist = Artist(name="Artist")
|
||||||
@ -74,7 +75,7 @@ class MediaTestCase(ApiTestBase):
|
|||||||
self._make_request("stream", error=10)
|
self._make_request("stream", error=10)
|
||||||
self._make_request("stream", {"id": "string"}, error=0)
|
self._make_request("stream", {"id": "string"}, error=0)
|
||||||
self._make_request("stream", {"id": str(uuid.uuid4())}, error=70)
|
self._make_request("stream", {"id": str(uuid.uuid4())}, error=70)
|
||||||
self._make_request("stream", {"id": str(self.folderid)}, error=70)
|
self._make_request("stream", {"id": str(self.folderid)}, error=0)
|
||||||
self._make_request(
|
self._make_request(
|
||||||
"stream", {"id": str(self.trackid), "maxBitRate": "string"}, error=0
|
"stream", {"id": str(self.trackid), "maxBitRate": "string"}, error=0
|
||||||
)
|
)
|
||||||
|
@ -50,7 +50,12 @@ class DbTestCase(unittest.TestCase):
|
|||||||
parent=root_folder,
|
parent=root_folder,
|
||||||
)
|
)
|
||||||
|
|
||||||
return root_folder, child_folder, child_2
|
# Folder IDs don't get populated until we query the db.
|
||||||
|
return (
|
||||||
|
db.Folder.get(name="Root folder"),
|
||||||
|
db.Folder.get(name="Child folder"),
|
||||||
|
db.Folder.get(name="Child Folder (No Art)")
|
||||||
|
)
|
||||||
|
|
||||||
def create_some_tracks(self, artist=None, album=None):
|
def create_some_tracks(self, artist=None, album=None):
|
||||||
root, child, child_2 = self.create_some_folders()
|
root, child, child_2 = self.create_some_folders()
|
||||||
@ -209,7 +214,7 @@ class DbTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
root_folder, folder_art, folder_noart = self.create_some_folders()
|
root_folder, folder_art, folder_noart = self.create_some_folders()
|
||||||
track1 = self.create_track_in(
|
track1 = self.create_track_in(
|
||||||
root_folder, folder_noart, artist=artist, album=album
|
folder_noart, root_folder, artist=artist, album=album
|
||||||
)
|
)
|
||||||
|
|
||||||
album_dict = album.as_subsonic_album(user)
|
album_dict = album.as_subsonic_album(user)
|
||||||
|
@ -72,8 +72,8 @@ class FolderTestCase(FrontendTestBase):
|
|||||||
|
|
||||||
self._login("alice", "Alic3")
|
self._login("alice", "Alic3")
|
||||||
rv = self.client.get("/folder/del/string", follow_redirects=True)
|
rv = self.client.get("/folder/del/string", follow_redirects=True)
|
||||||
self.assertIn("badly formed", rv.data)
|
self.assertIn("Invalid folder id", rv.data)
|
||||||
rv = self.client.get("/folder/del/" + str(uuid.uuid4()), follow_redirects=True)
|
rv = self.client.get("/folder/del/1234567890", follow_redirects=True)
|
||||||
self.assertIn("No such folder", rv.data)
|
self.assertIn("No such folder", rv.data)
|
||||||
rv = self.client.get("/folder/del/" + str(folder.id), follow_redirects=True)
|
rv = self.client.get("/folder/del/" + str(folder.id), follow_redirects=True)
|
||||||
self.assertIn("Music folders", rv.data)
|
self.assertIn("Music folders", rv.data)
|
||||||
@ -87,8 +87,8 @@ class FolderTestCase(FrontendTestBase):
|
|||||||
self._login("alice", "Alic3")
|
self._login("alice", "Alic3")
|
||||||
|
|
||||||
rv = self.client.get("/folder/scan/string", follow_redirects=True)
|
rv = self.client.get("/folder/scan/string", follow_redirects=True)
|
||||||
self.assertIn("badly formed", rv.data)
|
self.assertIn("Invalid folder id", rv.data)
|
||||||
rv = self.client.get("/folder/scan/" + str(uuid.uuid4()), follow_redirects=True)
|
rv = self.client.get("/folder/scan/1234567890", follow_redirects=True)
|
||||||
self.assertIn("No such folder", rv.data)
|
self.assertIn("No such folder", rv.data)
|
||||||
rv = self.client.get("/folder/scan/" + str(folder.id), follow_redirects=True)
|
rv = self.client.get("/folder/scan/" + str(folder.id), follow_redirects=True)
|
||||||
self.assertIn("start", rv.data)
|
self.assertIn("start", rv.data)
|
||||||
|
@ -76,7 +76,7 @@ class FolderManagerTestCase(unittest.TestCase):
|
|||||||
self.assertRaises(ValueError, FolderManager.get, 0xDEADBEEF)
|
self.assertRaises(ValueError, FolderManager.get, 0xDEADBEEF)
|
||||||
|
|
||||||
# Non-existent folder
|
# Non-existent folder
|
||||||
self.assertRaises(ObjectNotFound, FolderManager.get, uuid.uuid4())
|
self.assertRaises(ObjectNotFound, FolderManager.get, 1234567890)
|
||||||
|
|
||||||
@db_session
|
@db_session
|
||||||
def test_add_folder(self):
|
def test_add_folder(self):
|
||||||
@ -114,12 +114,12 @@ class FolderManagerTestCase(unittest.TestCase):
|
|||||||
self.create_folders()
|
self.create_folders()
|
||||||
|
|
||||||
with db_session:
|
with db_session:
|
||||||
# Delete invalid UUID
|
# Delete invalid Folder ID
|
||||||
self.assertRaises(ValueError, FolderManager.delete, "invalid-uuid")
|
self.assertRaises(ValueError, FolderManager.delete, "invalid-uuid")
|
||||||
self.assertEqual(db.Folder.select().count(), 3)
|
self.assertEqual(db.Folder.select().count(), 3)
|
||||||
|
|
||||||
# Delete non-existent folder
|
# Delete non-existent folder
|
||||||
self.assertRaises(ObjectNotFound, FolderManager.delete, uuid.uuid4())
|
self.assertRaises(ObjectNotFound, FolderManager.delete, 1234567890)
|
||||||
self.assertEqual(db.Folder.select().count(), 3)
|
self.assertEqual(db.Folder.select().count(), 3)
|
||||||
|
|
||||||
# Delete non-root folder
|
# Delete non-root folder
|
||||||
|
Loading…
Reference in New Issue
Block a user