diff --git a/.gitignore b/.gitignore index 33460ab..6f9255a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ target/ # No need to store databases in the git repo **/*.sqlite +.env +aural_isle.sqlite.db diff --git a/Cargo.lock b/Cargo.lock index 9a77704..4c15c4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,59 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-write-file" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" +dependencies = [ + "nix", + "rand", +] + [[package]] name = "aural_isle" version = "0.1.0" dependencies = [ "dotenv", "rusty-money", + "serde", + "serde_json", + "sqlx", "tokio", "warp", ] @@ -60,12 +101,27 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -102,6 +158,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "cpufeatures" version = "0.2.9" @@ -111,6 +173,40 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc6598521bb5a83d491e8c1fe51db7296019d2ca3cb93cc6c2a20369a4d78a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -127,6 +223,17 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -134,7 +241,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -143,6 +252,21 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] + [[package]] name = "encoding_rs" version = "0.8.33" @@ -152,6 +276,62 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -183,6 +363,34 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + [[package]] name = "futures-sink" version = "0.3.28" @@ -202,8 +410,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-core", + "futures-io", "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -248,7 +458,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -261,6 +471,25 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "headers" version = "0.3.9" @@ -285,12 +514,54 @@ dependencies = [ "http", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.9" @@ -366,7 +637,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", ] [[package]] @@ -375,12 +665,44 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "lock_api" version = "0.4.11" @@ -397,6 +719,16 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.6.4" @@ -419,6 +751,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -436,7 +774,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -453,10 +791,69 @@ dependencies = [ "log", "memchr", "mime", - "spin", + "spin 0.9.8", "version_check", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -464,6 +861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -511,7 +909,22 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", ] [[package]] @@ -537,7 +950,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -552,6 +965,33 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -612,7 +1052,27 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", ] [[package]] @@ -641,6 +1101,19 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls-pemfile" version = "1.0.3" @@ -695,7 +1168,7 @@ checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -732,6 +1205,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -741,6 +1225,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.9" @@ -773,14 +1267,268 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.1.0", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +dependencies = [ + "atomic-write-file", + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.1", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.1", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" @@ -793,6 +1541,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.49" @@ -810,7 +1571,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -844,7 +1605,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.4", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -855,7 +1616,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -909,9 +1670,21 @@ checksum = "ee2ef2af84856a50c1d430afce2fdded0a4ec7eda868db86409b4543df0797f9" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -982,6 +1755,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "url" version = "2.4.1" @@ -993,12 +1778,24 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1051,6 +1848,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + [[package]] name = "winapi" version = "0.3.9" @@ -1079,7 +1882,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1088,13 +1900,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1103,38 +1930,106 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 07492a8..a24f3b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] +sqlx = { version = "0.7", features = [ "runtime-tokio" ] } tokio = { version = "1.2", features = ["full"] } warp = "0.3" rusty-money = "0.4.1" dotenv = "0.15.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/DEVELOP.md b/DEVELOP.md new file mode 100644 index 0000000..3e8bb7b --- /dev/null +++ b/DEVELOP.md @@ -0,0 +1,11 @@ +# Dev Notes + +To develop against this project, you will need Rust 1.70 or greater installed. + +You will want to install the `sqlx-cli` tool via Cargo: `cargo install sqlx-cli` + +You will need to initialize a sqlite database store: `touch aural_isle.sqlite.db` + +You will need to copy the example env file to .env: `cp env.example .env` + +Then you should be able to run the initial database migrations: `sqlx migrate run`. (During initial dev, if you have already run the initial migration, you will need to delete the sqlite database store and re-create it as above) \ No newline at end of file diff --git a/SCHEMA.md b/SCHEMA.md index de862ba..a143254 100644 --- a/SCHEMA.md +++ b/SCHEMA.md @@ -24,7 +24,6 @@ CREATE TABLE Persons ( deleted_at INTEGER, /* timestamp */ deleted_by TEXT(36), /* UUIDv4 */ last_seen INTEGER, /* timestamp */ - shipping_address TEXT, /* optional, should use \n between lines to keep localized format as needed */ CONSTRAINT Persons_PK PRIMARY KEY (id), CONSTRAINT Persons_FK FOREIGN KEY (modified_by) REFERENCES Persons(id), CONSTRAINT Persons_FK_1 FOREIGN KEY (deleted_by) REFERENCES Persons(id) @@ -37,6 +36,28 @@ CREATE INDEX Persons_is_blocked_IDX ON Persons (is_blocked); CREATE INDEX Persons_deleted_at_IDX ON Persons (deleted_at); ``` +# PersonShippingAddresses +The PersonShippingAddresses table will contain zero or more shipping addresses as used by a Person + +``` sql +CREATE TABLE IF NOT EXISTS PersonShippingAddresses ( + id TEXT(36), /* UUIDv4 */ + person_id TEXT(36), /* UUIDv4 */ + shipping_address TEXT, /* mandatory, should use \n between lines to keep localized format as needed */ + is_primary INTEGER DEFAULT (0), /* bool, default false */ + created_at INTEGER, /* timestamp */ + modified_at INTEGER, /* timestamp */ + modified_by TEXT(36), /* UUIDv4 */ + deleted_at INTEGER, /* timestamp */ + deleted_by TEXT(36), /* UUIDv4 */ + CONSTRAINT PersonShippingAddresses_PK PRIMARY KEY (id), + CONSTRAINT PersonShippingAddresses_FK FOREIGN KEY (person_id) REFERENCES Persons(id), + CONSTRAINT PersonShippingAddresses_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT PersonShippingAddresses_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE UNIQUE INDEX IF NOT EXISTS PersonShippingAddresses_is_primary_IDX ON PersonShippingAddresses (is_primary); +``` + # PersonEmails Table The PersonEmails table is a one-to-many lookup table relating a Person to zero or more email addresses @@ -191,6 +212,7 @@ The Artists table will contain Artists! ``` sql CREATE TABLE Artists ( id TEXT(36), + label_id TEXT(36), name TEXT, bio TEXT, website TEXT, diff --git a/env.example b/env.example index 63f1fc0..009b53d 100644 --- a/env.example +++ b/env.example @@ -7,8 +7,8 @@ # listener - configure instance for a single Person who is focused on listening (a fan, a music collector, someone who wants to share their library with others) INSTALLATION_MODE=multilabel -# DATABASE_URI represents the connection string for establishing a connection to the data store for this instance -DATABASE_URI=sqlite::memory: +# DATABASE_URL represents the connection string for establishing a connection to the data store for this instance +DATABASE_URL=sqlite://aural_isle.sqlite.db # FILESTORE takes one of the following values: # local - use local filesystem for storage @@ -16,7 +16,7 @@ DATABASE_URI=sqlite::memory: FILESTORE=local # S3_URI represents the connection string for establishing a connection to the storage system if FILESTORE=s3 -S3_URI= +#S3_URI= # SERVER_ADMIN_NAME is the name to display as the technical/administrative contact for this instance SERVER_ADMIN_NAME=DJ Sundog diff --git a/migrations/20231101134457_initial-schema.sql b/migrations/20231101134457_initial-schema.sql new file mode 100644 index 0000000..204098f --- /dev/null +++ b/migrations/20231101134457_initial-schema.sql @@ -0,0 +1,803 @@ +-- Initial SQLITE schema for Aural Isle + +--This file represents the initial schema for the various data structures to be stored in the database. + +-- The Persons table will contain data about Person entities (see MODELS.md) +CREATE TABLE IF NOT EXISTS Persons ( + id TEXT(36), /* UUIDv4 */ + remote_id TEXT, /* field to store an arbitrary remote identifier for this Person if they are not local */ + name TEXT, /* "real" name */ + handle TEXT, /* also commonly refered to as 'display_name' or 'screen_name', optional (if missing, name will be used as handle) */ + avatar TEXT, /* optional URL to Person's avatar image / profile pic */ + cover TEXT, /* optional URL to Person's cover image / header image */ + bio TEXT, /* optional biographical text provided by Person */ + is_active INTEGER DEFAULT (1), /* bool, default true */ + is_blocked INTEGER DEFAULT (0), /* bool, default false */ + created_at INTEGER, /* timestamp */ + modified_at INTEGER, /* timestamp */ + modified_by TEXT(36), /* UUIDv4 */ + deleted_at INTEGER, /* timestamp */ + deleted_by TEXT(36), /* UUIDv4 */ + last_seen INTEGER, /* timestamp */ + /*shipping_address TEXT,*/ /* optional, should use \n between lines to keep localized format as needed - UPDATE: moving to lookup table */ + CONSTRAINT Persons_PK PRIMARY KEY (id), + CONSTRAINT Persons_FK FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Persons_FK_1 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE UNIQUE INDEX IF NOT EXISTS Persons_remote_id_IDX ON Persons (remote_id); +CREATE INDEX IF NOT EXISTS Persons_name_IDX ON Persons (name); +CREATE INDEX IF NOT EXISTS Persons_handle_IDX ON Persons (handle); +CREATE INDEX IF NOT EXISTS Persons_is_active_IDX ON Persons (is_active); +CREATE INDEX IF NOT EXISTS Persons_is_blocked_IDX ON Persons (is_blocked); +CREATE INDEX IF NOT EXISTS Persons_deleted_at_IDX ON Persons (deleted_at); + +-- The PersonShippingAddresses table is a one-to-many lookup table relating a Person to zero or more shipping addresses +CREATE TABLE IF NOT EXISTS PersonShippingAddresses ( + id TEXT(36), /* UUIDv4 */ + person_id TEXT(36), /* UUIDv4 */ + shipping_address TEXT, /* mandatory, should use \n between lines to keep localized format as needed */ + is_primary INTEGER DEFAULT (0), /* bool, default false */ + created_at INTEGER, /* timestamp */ + modified_at INTEGER, /* timestamp */ + modified_by TEXT(36), /* UUIDv4 */ + deleted_at INTEGER, /* timestamp */ + deleted_by TEXT(36), /* UUIDv4 */ + CONSTRAINT PersonShippingAddresses_PK PRIMARY KEY (id), + CONSTRAINT PersonShippingAddresses_FK FOREIGN KEY (person_id) REFERENCES Persons(id), + CONSTRAINT PersonShippingAddresses_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT PersonShippingAddresses_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE UNIQUE INDEX IF NOT EXISTS PersonShippingAddresses_is_primary_IDX ON PersonShippingAddresses (is_primary); + +-- The PersonEmails table is a one-to-many lookup table relating a Person to zero or more email addresses +CREATE TABLE IF NOT EXISTS PersonEmails ( + person_id TEXT(36), + email TEXT, + is_verified INTEGER DEFAULT (0), + is_primary INTEGER DEFAULT (0), + CONSTRAINT PersonEmails_PK PRIMARY KEY (email), + CONSTRAINT PersonEmails_FK FOREIGN KEY (person_id) REFERENCES Persons(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PersonEmails_person_id_IDX ON PersonEmails (person_id); +CREATE INDEX IF NOT EXISTS PersonEmails_is_verified_IDX ON PersonEmails (is_verified); +CREATE INDEX IF NOT EXISTS PersonEmails_is_primary_IDX ON PersonEmails (is_primary); + +-- The PersonCredentialProvider table will contain configuration for different authentication providers. +CREATE TABLE IF NOT EXISTS PersonCredentialProvider ( + id TEXT(36), + name TEXT, + "type" TEXT, + config TEXT, + CONSTRAINT PersonCredentialProvider_PK PRIMARY KEY (id) +); +CREATE INDEX IF NOT EXISTS PersonCredentialProvider_name_IDX ON PersonCredentialProvider (name); +CREATE INDEX IF NOT EXISTS PersonCredentialProvider_type_IDX ON PersonCredentialProvider ("type"); + +-- The PersonCredential table will contain authentication credentials for Persons +CREATE TABLE IF NOT EXISTS PersonCredential ( + id TEXT(36), + person_id TEXT(36), + provider_id TEXT(36), + provider_user_id TEXT(36), + is_enabled INTEGER DEFAULT (1), + CONSTRAINT PersonCredential_PK PRIMARY KEY (id), + CONSTRAINT PersonCredential_FK FOREIGN KEY (person_id) REFERENCES Persons(id) ON DELETE CASCADE, + CONSTRAINT PersonCredential_FK_1 FOREIGN KEY (provider_id) REFERENCES PersonCredentialProvider(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PersonCredential_person_id_IDX ON PersonCredential (person_id); +CREATE INDEX IF NOT EXISTS PersonCredential_provider_id_IDX ON PersonCredential (provider_id); +CREATE INDEX IF NOT EXISTS PersonCredential_is_enabled_IDX ON PersonCredential (is_enabled); + +-- The PersonLocal table will contain hashed and salted passwords for users authenticating via PersonCredentialProvider.Local type provider +CREATE TABLE IF NOT EXISTS PersonLocal ( + person_id TEXT(36), + hash TEXT, + modified_at INTEGER, + modified_by TEXT(36), + CONSTRAINT PersonLocal_PK PRIMARY KEY (person_id), + CONSTRAINT PersonLocal_FK FOREIGN KEY (person_id) REFERENCES Persons(id) ON DELETE CASCADE +); + +-- The Tags table will contain tags for categorization of other entities. Tags use the originating host and the tag name as a composite key to allow for us to search for commonalities across instances (for example, "show me Albums matching *::tag::jazz" to see all the jazz albums this instance is aware of, "show me Albums matching sundog-isle.reclaim.technology::tag::jazz" to see only albums tagged as jazz on that one specific instance named in the host field). +CREATE TABLE IF NOT EXISTS Tags ( + id TEXT(36), + host TEXT, + tag TEXT, + CONSTRAINT Tags_PK PRIMARY KEY (id) +); +CREATE UNIQUE INDEX IF NOT EXISTS Tags_host_IDX ON Tags (host,tag); + +-- The Labels table will contain data about record labels/imprints that manage one or more Artists and their content. +CREATE TABLE IF NOT EXISTS Labels ( + id TEXT(36), + name TEXT, + description TEXT, + website TEXT, + is_enabled INTEGER DEFAULT (1), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + CONSTRAINT Labels_PK PRIMARY KEY (id), + CONSTRAINT Labels_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Labels_FK_1 FOREIGN KEY (modified_at) REFERENCES Persons(id), + CONSTRAINT Labels_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Labels_name_IDX ON Labels (name); +CREATE INDEX IF NOT EXISTS Labels_description_IDX ON Labels (description); +CREATE INDEX IF NOT EXISTS Labels_is_enabled_IDX ON Labels (is_enabled); +CREATE INDEX IF NOT EXISTS Labels_created_by_IDX ON Labels (created_by); +CREATE INDEX IF NOT EXISTS Labels_deleted_at_IDX ON Labels (deleted_at); + +-- The LabelContacts table will contain key-value pairs of methods to contact representatives of the Label (for example, "fediverse: sundog@toot-lab.reclaim.technology" or "email: sundog@reclaim.technology"). +CREATE TABLE IF NOT EXISTS LabelContacts ( + id TEXT(36), + label_id TEXT(36), + "method" TEXT, + address TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + sort_order INTEGER, + CONSTRAINT LabelContacts_PK PRIMARY KEY (id), + CONSTRAINT LabelContacts_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT LabelContacts_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT LabelContacts_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id), + CONSTRAINT LabelContacts_FK_3 FOREIGN KEY (label_id) REFERENCES Labels(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS LabelContacts_sort_order_IDX ON LabelContacts (sort_order); + +-- The LabelTags table will contain Tags that have been assigned to a Label. +CREATE TABLE IF NOT EXISTS LabelTags ( + label_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT LabelTags_PK PRIMARY KEY (label_id,tag_id), + CONSTRAINT LabelTags_FK FOREIGN KEY (label_id) REFERENCES Labels(id) ON DELETE CASCADE, + CONSTRAINT LabelTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS LabelTags_is_approved_IDX ON LabelTags (is_approved); +CREATE INDEX IF NOT EXISTS LabelTags_tag_id_IDX ON LabelTags (tag_id); +CREATE INDEX IF NOT EXISTS LabelTags_label_id_IDX ON LabelTags (label_id); + +-- The Artists table will contain Artists! +CREATE TABLE IF NOT EXISTS Artists ( + id TEXT(36), + label_id TEXT(36), + name TEXT, + bio TEXT, + website TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + is_enabled INTEGER DEFAULT (1), + is_public INTEGER DEFAULT (1), + CONSTRAINT Artists_PK PRIMARY KEY (id), + CONSTRAINT Artists_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Artists_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Artists_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Artists_name_IDX ON Artists (name); +CREATE INDEX IF NOT EXISTS Artists_is_enabled_IDX ON Artists (is_enabled); +CREATE INDEX IF NOT EXISTS Artists_is_public_IDX ON Artists (is_public); + +-- The ArtistContacts tablekey-value pairs of methods to contact representatives of the Artist (for example, "fediverse: sundog@toot-lab.reclaim.technology" or "email: sundog@reclaim.technology"). +CREATE TABLE IF NOT EXISTS ArtistContacts ( + id TEXT(36), + artist_id TEXT(36), + "method" TEXT, + address TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + sort_order INTEGER, + CONSTRAINT ArtistContacts_PK PRIMARY KEY (id), + CONSTRAINT ArtistContacts_FK FOREIGN KEY (artist_id) REFERENCES Artists(id) ON DELETE CASCADE + CONSTRAINT ArtistContacts_FK_1 FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT ArtistContacts_FK_2 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT ArtistContacts_FK_3 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS ArtistContacts_artist_id_IDX ON ArtistContacts (artist_id); +CREATE INDEX IF NOT EXISTS ArtistContacts_deleted_at_IDX ON ArtistContacts (deleted_at); +CREATE INDEX IF NOT EXISTS ArtistContacts_sort_order_IDX ON ArtistContacts (sort_order); + +-- The ArtistTags table will contain Tags that have been assigned to an Artist. +CREATE TABLE IF NOT EXISTS ArtistTags ( + artist_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT ArtistTags_PK PRIMARY KEY (artist_id,tag_id), + CONSTRAINT ArtistTags_FK FOREIGN KEY (artist_id) REFERENCES Artists(id) ON DELETE CASCADE, + CONSTRAINT ArtistTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS ArtistTags_is_approved_IDX ON ArtistTags (is_approved); +CREATE INDEX IF NOT EXISTS ArtistTags_artist_id_IDX ON ArtistTags (artist_id); +CREATE INDEX IF NOT EXISTS ArtistTags_tag_id_IDX ON ArtistTags (tag_id); + +-- The Tracks table will contain Tracks! +CREATE TABLE IF NOT EXISTS Tracks ( + id TEXT(36), + title TEXT, + description TEXT, + duration REAL, + is_public INTEGER, + is_available INTEGER DEFAULT (1), + preview_source TEXT, + "source" TEXT, + price INTEGER DEFAULT (0), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + lyrics TEXT, + CONSTRAINT Tracks_PK PRIMARY KEY (id), + CONSTRAINT Tracks_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Tracks_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Tracks_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Tracks_title_IDX ON Tracks (title); +CREATE INDEX IF NOT EXISTS Tracks_duration_IDX ON Tracks (duration); +CREATE INDEX IF NOT EXISTS Tracks_is_public_IDX ON Tracks (is_public); +CREATE INDEX IF NOT EXISTS Tracks_is_available_IDX ON Tracks (is_available); +CREATE INDEX IF NOT EXISTS Tracks_price_IDX ON Tracks (price); +CREATE INDEX IF NOT EXISTS Tracks_created_by_IDX ON Tracks (created_by); +CREATE INDEX IF NOT EXISTS Tracks_deleted_at_IDX ON Tracks (deleted_at); +CREATE INDEX IF NOT EXISTS Tracks_lyrics_IDX ON Tracks (lyrics); + +-- The TrackArtists table will be a one-to-many lookup table mapping Artists to a particular Track. +CREATE TABLE IF NOT EXISTS TrackArtists ( + track_id TEXT(36), + artist_id TEXT(36), + is_primary INTEGER DEFAULT (0), + CONSTRAINT TrackArtists_PK PRIMARY KEY (track_id,artist_id), + CONSTRAINT TrackArtists_FK FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE, + CONSTRAINT TrackArtists_FK_1 FOREIGN KEY (artist_id) REFERENCES Artists(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS TrackArtists_is_primary_IDX ON TrackArtists (is_primary); +CREATE INDEX IF NOT EXISTS TrackArtists_track_id_IDX ON TrackArtists (track_id); +CREATE INDEX IF NOT EXISTS TrackArtists_artist_id_IDX ON TrackArtists (artist_id); + +-- The TrackTags table will contain Tags that have been assigned to a Track. +CREATE TABLE IF NOT EXISTS TrackTags ( + track_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT TrackTags_PK PRIMARY KEY (track_id,tag_id), + CONSTRAINT TrackTags_FK FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE, + CONSTRAINT TrackTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS TrackTags_is_approved_IDX ON TrackTags (is_approved); +CREATE INDEX IF NOT EXISTS TrackTags_track_id_IDX ON TrackTags (track_id); +CREATE INDEX IF NOT EXISTS TrackTags_tag_id_IDX ON TrackTags (tag_id); + +-- The Albums table will contain Albums! +CREATE TABLE IF NOT EXISTS Albums ( + id TEXT(36), + title TEXT, + description TEXT, + is_public INTEGER DEFAULT (0), + is_available INTEGER DEFAULT (1), + preview_source TEXT, + "source" TEXT, + price INTEGER DEFAULT (0), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + CONSTRAINT Albums_PK PRIMARY KEY (id), + CONSTRAINT Albums_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Albums_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Albums_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Albums_title_IDX ON Albums (title); +CREATE INDEX IF NOT EXISTS Albums_description_IDX ON Albums (description); +CREATE INDEX IF NOT EXISTS Albums_is_public_IDX ON Albums (is_public); +CREATE INDEX IF NOT EXISTS Albums_is_available_IDX ON Albums (is_available); +CREATE INDEX IF NOT EXISTS Albums_price_IDX ON Albums (price); +CREATE INDEX IF NOT EXISTS Albums_created_by_IDX ON Albums (created_by); +CREATE INDEX IF NOT EXISTS Albums_deleted_at_IDX ON Albums (deleted_at); + +-- The AlbumArtists table will be a one-to-many lookup table mapping Artists to a particular Album. +CREATE TABLE IF NOT EXISTS AlbumArtists ( + album_id TEXT(36), + artist_id TEXT(36), + is_primary INTEGER DEFAULT (0), + CONSTRAINT AlbumArtists_PK PRIMARY KEY (album_id,artist_id), + CONSTRAINT AlbumArtists_FK FOREIGN KEY (album_id) REFERENCES Albums(id) ON DELETE CASCADE, + CONSTRAINT AlbumArtists_FK_1 FOREIGN KEY (artist_id) REFERENCES Artists(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS AlbumArtists_is_primary_IDX ON AlbumArtists (is_primary); +CREATE INDEX IF NOT EXISTS AlbumArtists_album_id_IDX ON AlbumArtists (album_id); +CREATE INDEX IF NOT EXISTS AlbumArtists_artist_id_IDX ON AlbumArtists (artist_id); + +-- The AlbumTags table will contain Tags that have been assigned to an Album. +CREATE TABLE IF NOT EXISTS AlbumTags ( + album_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT AlbumTags_PK PRIMARY KEY (album_id,tag_id), + CONSTRAINT AlbumTags_FK FOREIGN KEY (album_id) REFERENCES Albums(id) ON DELETE CASCADE, + CONSTRAINT AlbumTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS AlbumTags_is_approved_IDX ON AlbumTags (is_approved); +CREATE INDEX IF NOT EXISTS AlbumTags_album_id_IDX ON AlbumTags (album_id); +CREATE INDEX IF NOT EXISTS AlbumTags_tag_id_IDX ON AlbumTags (tag_id); + +-- The AlbumTracks table will be a many-to-many lookup table mapping Tracks to Albums +CREATE TABLE IF NOT EXISTS AlbumTracks ( + album_id TEXT(36), + track_id TEXT(36), + track_number INTEGER, + CONSTRAINT AlbumTracks_PK PRIMARY KEY (album_id,track_id), + CONSTRAINT AlbumTracks_FK FOREIGN KEY (album_id) REFERENCES Albums(id) ON DELETE CASCADE, + CONSTRAINT AlbumTracks_FK_1 FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS AlbumTracks_track_number_IDX ON AlbumTracks (track_number); +CREATE INDEX IF NOT EXISTS AlbumTracks_album_id_IDX ON AlbumTracks (album_id); +CREATE INDEX IF NOT EXISTS AlbumTracks_track_id_IDX ON AlbumTracks (track_id); + +-- The Playlists table will contain Playlists! +CREATE TABLE IF NOT EXISTS Playlists ( + id TEXT(36), + title TEXT, + description TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_at INTEGER, + deleted_at INTEGER, + is_public INTEGER DEFAULT (1), + CONSTRAINT Playlists_PK PRIMARY KEY (id), + CONSTRAINT Playlists_FK FOREIGN KEY (created_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Playlists_title_IDX ON Playlists (title); +CREATE INDEX IF NOT EXISTS Playlists_description_IDX ON Playlists (description); +CREATE INDEX IF NOT EXISTS Playlists_created_by_IDX ON Playlists (created_by); +CREATE INDEX IF NOT EXISTS Playlists_created_at_IDX ON Playlists (created_at); +CREATE INDEX IF NOT EXISTS Playlists_modified_at_IDX ON Playlists (modified_at); +CREATE INDEX IF NOT EXISTS Playlists_deleted_at_IDX ON Playlists (deleted_at); +CREATE INDEX IF NOT EXISTS Playlists_is_public_IDX ON Playlists (is_public); + +-- The PlaylistTracks table will be a many-to-many lookup table mapping Tracks to Playlists +CREATE TABLE IF NOT EXISTS PlaylistTracks ( + playlist_track_id TEXT(36), + playlist_id TEXT(36), + track_id TEXT, + track_number INTEGER, + CONSTRAINT PlaylistTracks_PK PRIMARY KEY (playlist_track_id), + CONSTRAINT PlaylistTracks_FK FOREIGN KEY (playlist_id) REFERENCES Playlists(id) ON DELETE CASCADE, + CONSTRAINT PlaylistTracks_FK_1 FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PlaylistTracks_track_number_IDX ON PlaylistTracks (track_number); +CREATE INDEX IF NOT EXISTS PlaylistTracks_playlist_id_IDX ON PlaylistTracks (playlist_id); +CREATE INDEX IF NOT EXISTS PlaylistTracks_track_id_IDX ON PlaylistTracks (track_id); + +-- The PlaylistTags table will contain Tags that have been assigned to a Playlist. +CREATE TABLE IF NOT EXISTS PlaylistTags ( + playlist_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT PlaylistTags_PK PRIMARY KEY (playlist_id,tag_id), + CONSTRAINT PlaylistTags_FK FOREIGN KEY (playlist_id) REFERENCES Playlists(id) ON DELETE CASCADE, + CONSTRAINT PlaylistTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PlaylistTags_is_approved_IDX ON PlaylistTags (is_approved); +CREATE INDEX IF NOT EXISTS PlaylistTags_playlist_id_IDX ON PlaylistTags (playlist_id); +CREATE INDEX IF NOT EXISTS PlaylistTags_tag_id_IDX ON PlaylistTags (tag_id); + +-- The Comments table will contain Comments! +CREATE TABLE IF NOT EXISTS Comments ( + id TEXT(36), + body TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + is_public INTEGER DEFAULT (1), + is_approved INTEGER DEFAULT (0), + in_reply_to TEXT(36), + CONSTRAINT Comments_PK PRIMARY KEY (id), + CONSTRAINT Comments_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Comments_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Comments_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Comments_body_IDX ON Comments (body); +CREATE INDEX IF NOT EXISTS Comments_created_at_IDX ON Comments (created_at); +CREATE INDEX IF NOT EXISTS Comments_modified_at_IDX ON Comments (modified_at); +CREATE INDEX IF NOT EXISTS Comments_deleted_at_IDX ON Comments (deleted_at); +CREATE INDEX IF NOT EXISTS Comments_is_public_IDX ON Comments (is_public); +CREATE INDEX IF NOT EXISTS Comments_is_approved_IDX ON Comments (is_approved); +CREATE INDEX IF NOT EXISTS Comments_in_reply_to_IDX ON Comments (in_reply_to); + +-- The LabelComments table will relate Comments to the Label they are about, if pertinent. +CREATE TABLE IF NOT EXISTS LabelComments ( + label_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT LabelComments_PK PRIMARY KEY (label_id,comment_id), + CONSTRAINT LabelComments_FK FOREIGN KEY (label_id) REFERENCES Labels(id) ON DELETE CASCADE, + CONSTRAINT LabelComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS LabelComments_label_id_IDX ON LabelComments (label_id); +CREATE INDEX IF NOT EXISTS LabelComments_comment_id_IDX ON LabelComments (comment_id); + +-- The ArtistComments table will relate Comments to the Artist they are about, if pertinent. +CREATE TABLE IF NOT EXISTS ArtistComments ( + artist_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT ArtistComments_PK PRIMARY KEY (artist_id,comment_id), + CONSTRAINT ArtistComments_FK FOREIGN KEY (artist_id) REFERENCES Artists(id) ON DELETE CASCADE, + CONSTRAINT ArtistComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS ArtistComments_artist_id_IDX ON ArtistComments (artist_id); +CREATE INDEX IF NOT EXISTS ArtistComments_comment_id_IDX ON ArtistComments (comment_id); + +-- The TrackComments table will relate Comments to the Track they are about, if pertinent. +CREATE TABLE IF NOT EXISTS TrackComments ( + track_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT TrackComments_PK PRIMARY KEY (track_id,comment_id), + CONSTRAINT TrackComments_FK FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE, + CONSTRAINT TrackComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS TrackComments_track_id_IDX ON TrackComments (track_id); +CREATE INDEX IF NOT EXISTS TrackComments_comment_id_IDX ON TrackComments (comment_id); + +-- The AlbumComments table will relate Comments to the Album they are about, if pertinent. +CREATE TABLE IF NOT EXISTS AlbumComments ( + album_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT AlbumComments_PK PRIMARY KEY (album_id,comment_id), + CONSTRAINT AlbumComments_FK FOREIGN KEY (album_id) REFERENCES Albums(id) ON DELETE CASCADE, + CONSTRAINT AlbumComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS AlbumComments_album_id_IDX ON AlbumComments (album_id); +CREATE INDEX IF NOT EXISTS AlbumComments_comment_id_IDX ON AlbumComments (comment_id); + +-- The PlaylistComments table will relate Comments to the Playlist they are about, if pertinent. +CREATE TABLE IF NOT EXISTS PlaylistComments ( + playlist_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT PlaylistComments_PK PRIMARY KEY (playlist_id,comment_id), + CONSTRAINT PlaylistComments_FK FOREIGN KEY (playlist_id) REFERENCES Playlists(id) ON DELETE CASCADE, + CONSTRAINT PlaylistComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PlaylistComments_playlist_id_IDX ON PlaylistComments (playlist_id); +CREATE INDEX IF NOT EXISTS PlaylistComments_comment_id_IDX ON PlaylistComments (comment_id); + +-- The Images table will contain Images! +CREATE TABLE IF NOT EXISTS Images ( + id TEXT(36), + name TEXT, + "path" TEXT, + url TEXT, + width INTEGER, + height INTEGER, + alt_text TEXT, + is_public INTEGER DEFAULT (1), + allow_hotlinking INTEGER DEFAULT (0), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + CONSTRAINT Images_PK PRIMARY KEY (id), + CONSTRAINT Images_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Images_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Images_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Images_name_IDX ON Images (name); +CREATE INDEX IF NOT EXISTS Images_path_IDX ON Images ("path"); +CREATE INDEX IF NOT EXISTS Images_url_IDX ON Images (url); +CREATE INDEX IF NOT EXISTS Images_alt_text_IDX ON Images (alt_text); +CREATE INDEX IF NOT EXISTS Images_is_public_IDX ON Images (is_public); +CREATE INDEX IF NOT EXISTS Images_allow_hotlinking_IDX ON Images (allow_hotlinking); +CREATE INDEX IF NOT EXISTS Images_created_by_IDX ON Images (created_by); +CREATE INDEX IF NOT EXISTS Images_deleted_at_IDX ON Images (deleted_at); + +-- The Videos table will contain Videos! +CREATE TABLE IF NOT EXISTS Videos ( + id TEXT(36), + name TEXT, + "path" TEXT, + url TEXT, + width INTEGER, + height INTEGER, + duration NUMERIC, + alt_text TEXT, + is_public INTEGER DEFAULT (1), + allow_hotlinking INTEGER DEFAULT (0), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + CONSTRAINT Videos_PK PRIMARY KEY (id), + CONSTRAINT Videos_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Videos_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Videos_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Videos_name_IDX ON Videos (name); +CREATE INDEX IF NOT EXISTS Videos_path_IDX ON Videos ("path"); +CREATE INDEX IF NOT EXISTS Videos_url_IDX ON Videos (url); +CREATE INDEX IF NOT EXISTS Videos_alt_text_IDX ON Videos (alt_text); +CREATE INDEX IF NOT EXISTS Videos_is_public_IDX ON Videos (is_public); +CREATE INDEX IF NOT EXISTS Videos_allow_hotlinking_IDX ON Videos (allow_hotlinking); +CREATE INDEX IF NOT EXISTS Videos_created_by_IDX ON Videos (created_by); +CREATE INDEX IF NOT EXISTS Videos_deleted_at_IDX ON Videos (deleted_at); + +-- The Articles table will contain Articles! +CREATE TABLE IF NOT EXISTS Articles ( + id TEXT(36), + title TEXT, + body TEXT, + description TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_at INTEGER, + published_at INTEGER, + deleted_at INTEGER, + is_public INTEGER DEFAULT (0), + is_draft INTEGER DEFAULT (1), + CONSTRAINT Articles_PK PRIMARY KEY (id), + CONSTRAINT Articles_FK FOREIGN KEY (created_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Articles_title_IDX ON Articles (title); +CREATE INDEX IF NOT EXISTS Articles_body_IDX ON Articles (body); +CREATE INDEX IF NOT EXISTS Articles_description_IDX ON Articles (description); +CREATE INDEX IF NOT EXISTS Articles_created_by_IDX ON Articles (created_by); +CREATE INDEX IF NOT EXISTS Articles_published_at_IDX ON Articles (published_at); +CREATE INDEX IF NOT EXISTS Articles_deleted_at_IDX ON Articles (deleted_at); +CREATE INDEX IF NOT EXISTS Articles_is_public_IDX ON Articles (is_public); +CREATE INDEX IF NOT EXISTS Articles_is_draft_IDX ON Articles (is_draft); + +-- The ArticleTags table will contain Tags that have been assigned to an Article. +CREATE TABLE IF NOT EXISTS ArticleTags ( + article_id TEXT(36), + tag_id TEXT(36), + is_approved INTEGER DEFAULT (0), + CONSTRAINT ArticleTags_PK PRIMARY KEY (article_id,tag_id), + CONSTRAINT ArticleTags_FK FOREIGN KEY (article_id) REFERENCES Articles(id) ON DELETE CASCADE, + CONSTRAINT ArticleTags_FK_1 FOREIGN KEY (tag_id) REFERENCES Tags(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS ArticleTags_is_approved_IDX ON ArticleTags (is_approved); + +-- The ArticleComments table will relate Comments to the Article they are about, if pertinent. +CREATE TABLE IF NOT EXISTS ArticleComments ( + article_id TEXT(36), + comment_id TEXT(36), + CONSTRAINT ArticleComments_PK PRIMARY KEY (article_id,comment_id), + CONSTRAINT ArticleComments_FK FOREIGN KEY (article_id) REFERENCES Articles(id) ON DELETE CASCADE, + CONSTRAINT ArticleComments_FK_1 FOREIGN KEY (comment_id) REFERENCES Comments(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS ArticleComments_article_id_IDX ON ArticleComments (article_id); +CREATE INDEX IF NOT EXISTS ArticleComments_comment_id_IDX ON ArticleComments (comment_id); + +-- The OtherProducts table will contain products for sale that are not Albums nor Tracks nor Collections. +CREATE TABLE IF NOT EXISTS OtherProducts ( + id TEXT(36), + name TEXT, + description TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + is_public INTEGER DEFAULT (0), + is_available INTEGER DEFAULT (0), + requires_shipping INTEGER DEFAULT (0), + CONSTRAINT OtherProducts_PK PRIMARY KEY (id), + CONSTRAINT OtherProducts_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT OtherProducts_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT OtherProducts_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS OtherProducts_name_IDX ON OtherProducts (name); +CREATE INDEX IF NOT EXISTS OtherProducts_description_IDX ON OtherProducts (description); +CREATE INDEX IF NOT EXISTS OtherProducts_created_by_IDX ON OtherProducts (created_by); +CREATE INDEX IF NOT EXISTS OtherProducts_created_at_IDX ON OtherProducts (created_at); +CREATE INDEX IF NOT EXISTS OtherProducts_modified_by_IDX ON OtherProducts (modified_by); +CREATE INDEX IF NOT EXISTS OtherProducts_modified_at_IDX ON OtherProducts (modified_at); +CREATE INDEX IF NOT EXISTS OtherProducts_deleted_by_IDX ON OtherProducts (deleted_by); +CREATE INDEX IF NOT EXISTS OtherProducts_deleted_at_IDX ON OtherProducts (deleted_at); +CREATE INDEX IF NOT EXISTS OtherProducts_is_public_IDX ON OtherProducts (is_public); +CREATE INDEX IF NOT EXISTS OtherProducts_is_available_IDX ON OtherProducts (is_available); +CREATE INDEX IF NOT EXISTS OtherProducts_requires_shipping_IDX ON OtherProducts (requires_shipping); + +-- The Collections table will contain Collections where each Collection is comprised of one or more Tracks, Albums, and/or OtherProducts packaged together for sale. +CREATE TABLE IF NOT EXISTS Collections ( + id TEXT(36), + name TEXT, + description TEXT, + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + is_public INTEGER DEFAULT (0), + is_available INTEGER DEFAULT (0), + CONSTRAINT Collections_PK PRIMARY KEY (id), + CONSTRAINT Collections_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT Collections_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT Collections_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Collections_name_IDX ON Collections (name); +CREATE INDEX IF NOT EXISTS Collections_description_IDX ON Collections (description); +CREATE INDEX IF NOT EXISTS Collections_created_by_IDX ON Collections (created_by); +CREATE INDEX IF NOT EXISTS Collections_created_at_IDX ON Collections (created_at); +CREATE INDEX IF NOT EXISTS Collections_modified_by_IDX ON Collections (modified_by); +CREATE INDEX IF NOT EXISTS Collections_modified_at_IDX ON Collections (modified_at); +CREATE INDEX IF NOT EXISTS Collections_deleted_by_IDX ON Collections (deleted_by); +CREATE INDEX IF NOT EXISTS Collections_deleted_at_IDX ON Collections (deleted_at); +CREATE INDEX IF NOT EXISTS Collections_is_public_IDX ON Collections (is_public); +CREATE INDEX IF NOT EXISTS Collections_is_available_IDX ON Collections (is_available); + +-- The CollectionAlbums table will relate a Collection to the Album(s) it contains. +CREATE TABLE IF NOT EXISTS CollectionAlbums ( + collection_id TEXT(36), + album_id TEXT(36), + CONSTRAINT CollectionAlbums_PK PRIMARY KEY (collection_id,album_id), + CONSTRAINT CollectionAlbums_FK FOREIGN KEY (collection_id) REFERENCES Collections(id) ON DELETE CASCADE, + CONSTRAINT CollectionAlbums_FK_1 FOREIGN KEY (album_id) REFERENCES Albums(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS CollectionAlbums_collection_id_IDX ON CollectionAlbums (collection_id); +CREATE INDEX IF NOT EXISTS CollectionAlbums_album_id_IDX ON CollectionAlbums (album_id); + +-- The CollectionTracks table will relate a Collection to the Track(s) it contains. +CREATE TABLE IF NOT EXISTS CollectionTracks ( + collection_id TEXT(36), + track_id TEXT(36), + CONSTRAINT CollectionTracks_PK PRIMARY KEY (collection_id,track_id), + CONSTRAINT CollectionTracks_FK FOREIGN KEY (collection_id) REFERENCES Collections(id) ON DELETE CASCADE, + CONSTRAINT CollectionTracks_FK_1 FOREIGN KEY (track_id) REFERENCES Tracks(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS CollectionTracks_collection_id_IDX ON CollectionTracks (collection_id); +CREATE INDEX IF NOT EXISTS CollectionTracks_track_id_IDX ON CollectionTracks (track_id); + +-- The CollectionOtherProducts table will relate a Collection to the OtherProduct(s) it contains. +CREATE TABLE IF NOT EXISTS CollectionOtherProducts ( + collection_id TEXT(36), + other_product_id TEXT(36), + CONSTRAINT CollectionOtherProducts_PK PRIMARY KEY (collection_id,other_product_id), + CONSTRAINT CollectionOtherProducts_FK FOREIGN KEY (collection_id) REFERENCES Collections(id) ON DELETE CASCADE, + CONSTRAINT CollectionOtherProducts_FK_1 FOREIGN KEY (other_product_id) REFERENCES OtherProducts(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS CollectionOtherProducts_collection_id_IDX ON CollectionOtherProducts (collection_id); +CREATE INDEX IF NOT EXISTS CollectionOtherProducts_other_product_id_IDX ON CollectionOtherProducts (other_product_id); + +-- The Skus table will contain SKUs () representing items available for Purchase through the server. +CREATE TABLE IF NOT EXISTS Skus ( + id TEXT(36), + item_type TEXT, + item_id TEXT(36), + variant TEXT, + description TEXT, + price NUMERIC DEFAULT (0.00), + requires_shipping INTEGER DEFAULT (0), + shipping_charge NUMERIC DEFAULT (0.00), + CONSTRAINT Skus_PK PRIMARY KEY (id) +); +CREATE INDEX IF NOT EXISTS Skus_item_type_IDX ON Skus (item_type); +CREATE INDEX IF NOT EXISTS Skus_item_id_IDX ON Skus (item_id); +CREATE INDEX IF NOT EXISTS Skus_variant_IDX ON Skus (variant); +CREATE INDEX IF NOT EXISTS Skus_description_IDX ON Skus (description); +CREATE INDEX IF NOT EXISTS Skus_price_IDX ON Skus (price); +CREATE INDEX IF NOT EXISTS Skus_requires_shipping_IDX ON Skus (requires_shipping); +CREATE INDEX IF NOT EXISTS Skus_shipping_charge_IDX ON Skus (shipping_charge); + +-- The LineItems table will contain individual SKUs and their associated quantites as part of a Purchase. +CREATE TABLE IF NOT EXISTS LineItems ( + id TEXT(36), + sku_id TEXT(36), + quantity INTEGER DEFAULT (1), + CONSTRAINT LineItems_PK PRIMARY KEY (id), + CONSTRAINT LineItems_FK FOREIGN KEY (sku_id) REFERENCES Skus(id) +); +CREATE INDEX IF NOT EXISTS LineItems_sku_id_IDX ON LineItems (sku_id); +CREATE INDEX IF NOT EXISTS LineItems_quantity_IDX ON LineItems (quantity); + +-- The CouponCodes table will contain coupon codes that can be redeemed for a discount, either by amount or percentage, on a Purchase. +CREATE TABLE IF NOT EXISTS CouponCodes ( + id TEXT(36), + name TEXT, + code TEXT, + uses INTEGER DEFAULT (0), + max_uses INTEGER DEFAULT (0), + expiration INTEGER, + discount_flat NUMERIC DEFAULT (0.00), + discount_percentage NUMERIC DEFAULT (0.00), + is_sku_specific INTEGER DEFAULT (0), + is_active INTEGER DEFAULT (0), + created_by TEXT(36), + created_at INTEGER, + modified_by TEXT(36), + modified_at INTEGER, + deleted_by TEXT(36), + deleted_at INTEGER, + CONSTRAINT CouponCodes_PK PRIMARY KEY (id), + CONSTRAINT CouponCodes_FK FOREIGN KEY (created_by) REFERENCES Persons(id), + CONSTRAINT CouponCodes_FK_1 FOREIGN KEY (modified_by) REFERENCES Persons(id), + CONSTRAINT CouponCodes_FK_2 FOREIGN KEY (deleted_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS CouponCodes_name_IDX ON CouponCodes (name); +CREATE UNIQUE INDEX IF NOT EXISTS CouponCodes_code_IDX ON CouponCodes (code); +CREATE INDEX IF NOT EXISTS CouponCodes_uses_IDX ON CouponCodes (uses); +CREATE INDEX IF NOT EXISTS CouponCodes_max_uses_IDX ON CouponCodes (max_uses); +CREATE INDEX IF NOT EXISTS CouponCodes_expiration_IDX ON CouponCodes (expiration); +CREATE INDEX IF NOT EXISTS CouponCodes_is_sku_specific_IDX ON CouponCodes (is_sku_specific); +CREATE INDEX IF NOT EXISTS CouponCodes_is_active_IDX ON CouponCodes (is_active); +CREATE INDEX IF NOT EXISTS CouponCodes_created_by_IDX ON CouponCodes (created_by); +CREATE INDEX IF NOT EXISTS CouponCodes_created_at_IDX ON CouponCodes (created_at); +CREATE INDEX IF NOT EXISTS CouponCodes_modified_by_IDX ON CouponCodes (modified_by); +CREATE INDEX IF NOT EXISTS CouponCodes_modified_at_IDX ON CouponCodes (modified_at); +CREATE INDEX IF NOT EXISTS CouponCodes_deleted_by_IDX ON CouponCodes (deleted_by); +CREATE INDEX IF NOT EXISTS CouponCodes_deleted_at_IDX ON CouponCodes (deleted_at); + +-- The CouponCodeSkus table will relate a CouponCode to one or more Skus the CouponCode can be applied to, if CouponCode.is_sku_specific is true. (If CouponCode.is_sku_specific is false the CouponCode can be applied to an entire Purchase regardless of the Skus being purchased.) +CREATE TABLE IF NOT EXISTS CouponCodeSkus ( + coupon_code_id TEXT(36), + sku_id TEXT(36), + CONSTRAINT CouponCodeSkus_PK PRIMARY KEY (coupon_code_id,sku_id), + CONSTRAINT CouponCodeSkus_FK FOREIGN KEY (coupon_code_id) REFERENCES CouponCodes(id), + CONSTRAINT CouponCodeSkus_FK_1 FOREIGN KEY (sku_id) REFERENCES Skus(id) +); + +-- The Purchases table will contain Purchases! +CREATE TABLE IF NOT EXISTS Purchases ( + id TEXT(36), + state TEXT, + purchased_by TEXT(36), + purchased_at INTEGER, + fulfilled_by TEXT(36), + fulfilled_at INTEGER, + total_charge NUMERIC DEFAULT (0.00), + CONSTRAINT Purchases_PK PRIMARY KEY (id), + CONSTRAINT Purchases_FK FOREIGN KEY (purchased_by) REFERENCES Persons(id), + CONSTRAINT Purchases_FK_1 FOREIGN KEY (fulfilled_by) REFERENCES Persons(id) +); +CREATE INDEX IF NOT EXISTS Purchases_state_IDX ON Purchases (state); +CREATE INDEX IF NOT EXISTS Purchases_purchased_by_IDX ON Purchases (purchased_by); +CREATE INDEX IF NOT EXISTS Purchases_purchased_at_IDX ON Purchases (purchased_at); +CREATE INDEX IF NOT EXISTS Purchases_fulfilled_by_IDX ON Purchases (fulfilled_by); +CREATE INDEX IF NOT EXISTS Purchases_fulfilled_at_IDX ON Purchases (fulfilled_at); +CREATE INDEX IF NOT EXISTS Purchases_total_charge_IDX ON Purchases (total_charge); + +-- The PurchaseLineItems table will relate a Purchase to one or more LineItems. +CREATE TABLE IF NOT EXISTS PurchaseLineItems ( + purchase_id TEXT(36), + line_item_id TEXT(36), + CONSTRAINT PurchaseLineItems_PK PRIMARY KEY (purchase_id,line_item_id), + CONSTRAINT PurchaseLineItems_FK FOREIGN KEY (purchase_id) REFERENCES Purchases(id), + CONSTRAINT PurchaseLineItems_FK_1 FOREIGN KEY (line_item_id) REFERENCES LineItems(id) ON DELETE CASCADE +); +CREATE INDEX IF NOT EXISTS PurchaseLineItems_purchase_id_IDX ON PurchaseLineItems (purchase_id); +CREATE INDEX IF NOT EXISTS PurchaseLineItems_line_item_id_IDX ON PurchaseLineItems (line_item_id); + +-- The PurchaseCouponCodes table will relate a Purchase to one or more CouponCodes successfully applied to the Purchase. +CREATE TABLE IF NOT EXISTS PurchaseCouponCodes ( + purchase_id TEXT(36), + coupon_code_id TEXT(36), + CONSTRAINT PurchaseCouponCodes_PK PRIMARY KEY (purchase_id,coupon_code_id), + CONSTRAINT PurchaseCouponCodes_FK FOREIGN KEY (purchase_id) REFERENCES Purchases(id), + CONSTRAINT PurchaseCouponCodes_FK_1 FOREIGN KEY (coupon_code_id) REFERENCES CouponCodes(id) +); +CREATE INDEX IF NOT EXISTS PurchaseCouponCodes_purchase_id_IDX ON PurchaseCouponCodes (purchase_id); +CREATE INDEX IF NOT EXISTS PurchaseCouponCodes_coupon_code_id_IDX ON PurchaseCouponCodes (coupon_code_id); diff --git a/src/main.rs b/src/main.rs index bd5795f..ef8ff1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,565 @@ -use warp::Filter; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, sync::Arc}; +use warp::{ + filters::{body::BodyDeserializeError, cors::CorsForbidden}, + http::Method, + http::StatusCode, + reject::Reject, + Filter, Rejection, Reply, +}; + +use tokio::sync::RwLock; + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Person { + id: PersonId, + remote_id: String, + name: String, + handle: Option, + avatar: Option, + cover: Option, + bio: Option, + is_active: bool, + is_blocked: bool, + created_at: usize, + modified_at: usize, + deleted_at: Option, + modified_by: PersonId, + deleted_by: Option, + last_seen: usize, + shipping_addresses: Option>, + emails: Option>, + credentials: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PersonId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct PersonShippingAddress { + id: PersonShippingAddressId, + person_id: PersonId, + shipping_address: String, + is_primary: bool, + created_at: usize, + modified_at: usize, + deleted_at: Option, + modified_by: PersonId, + deleted_by: Option, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PersonShippingAddressId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct PersonEmail { + person_id: PersonId, + email: String, + is_verified: bool, + is_primary: bool, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PersonEmailId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct PersonCredentialProvider { + id: PersonCredentialProviderId, + name: String, + r#type: String, // TODO: create a type for this + config: String, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PersonCredentialProviderId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct PersonCredential { + id: PersonCredentialId, + person_id: PersonId, + provider_user_id: String, + is_enabled: bool, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PersonCredentialId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Tag { + id: TagId, + host: String, + tag: String, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct TagId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Label { + id: LabelId, + name: String, + description: String, + website: String, + is_enabled: bool, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + contacts: Option>, + tags: Option>, + artists: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct LabelId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct LabelContact { + id: LabelContactId, + label_id: LabelId, + method: String, // TODO: create a type for this + address: String, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + sort_order: usize, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct LabelContactId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Artist { + id: ArtistId, + label_id: Option, + name: String, + bio: String, + website: String, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + is_enabled: bool, + is_public: bool, + contacts: Option>, + tags: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct ArtistId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct ArtistContact { + id: ArtistContactId, + artist_id: ArtistId, + method: String, // TODO: create a type for this + address: String, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + sort_order: usize, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct ArtistContactId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Track { + id: TrackId, + title: String, + description: String, + duration: f64, + is_public: bool, + is_available: bool, + preview_source: Option, // if preview_source == None, use source as preview + source: String, + price: usize, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + lyrics: Option, + primary_artist: Artist, + other_artists: Option>, + tags: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct TrackId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Album { + id: AlbumId, + title: String, + description: String, + tracks: Vec, + is_public: bool, + is_available: bool, + preview_source: Option, + source: String, + price: usize, + created_at: usize, + modified_at: usize, + deleted_at: Option, + created_by: PersonId, + modified_by: PersonId, + deleted_by: Option, + primary_artist: Option, + other_artists: Option>, + tags: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct AlbumId(String); + +#[derive(Deserialize, Serialize, Debug, Clone)] +struct Playlist { + id: PlaylistId, + title: String, + description: String, + created_by: PersonId, + created_at: usize, + modified_at: usize, + deleted_at: Option, + is_public: bool, + tracks: Option>, + tags: Option>, +} + +#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash)] +struct PlaylistId(String); + +#[derive(Debug)] +struct Pagination { + start: usize, + end: usize, +} + +#[derive(Clone)] +struct Datastore { + persons: Arc>>, + labels: Arc>>, + artists: Arc>>, + albums: Arc>>, + tracks: Arc>>, +} + +impl Datastore { + fn new() -> Self { + Datastore { + persons: Arc::new(RwLock::new(HashMap::new())), + labels: Arc::new(RwLock::new(HashMap::new())), + artists: Arc::new(RwLock::new(HashMap::new())), + albums: Arc::new(RwLock::new(HashMap::new())), + tracks: Arc::new(RwLock::new(HashMap::new())), + } + } +} + +#[derive(Debug)] +enum Error { + ParseError(std::num::ParseIntError), + MissingParameters, +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + Error::ParseError(ref err) => write!(f, "Cannot parse parameter: {}", err), + Error::MissingParameters => write!(f, "Missing parameter"), + } + } +} + +impl Reject for Error {} + +async fn return_error(r: Rejection) -> Result { + if let Some(error) = r.find::() { + Ok(warp::reply::with_status( + error.to_string(), + StatusCode::RANGE_NOT_SATISFIABLE, + )) + } else if let Some(error) = r.find::() { + Ok(warp::reply::with_status( + error.to_string(), + StatusCode::FORBIDDEN, + )) + } else if let Some(error) = r.find::() { + Ok(warp::reply::with_status( + error.to_string(), + StatusCode::UNPROCESSABLE_ENTITY, + )) + } else { + Ok(warp::reply::with_status( + "Route not found".to_string(), + StatusCode::NOT_FOUND, + )) + } +} + +fn extract_pagination(params: HashMap) -> Result { + if params.contains_key("start") && params.contains_key("end") { + return Ok(Pagination { + start: params + .get("start") + .unwrap() + .parse::() + .map_err(Error::ParseError)?, + end: params + .get("end") + .unwrap() + .parse::() + .map_err(Error::ParseError)?, + }); + } + + Err(Error::MissingParameters) +} + +async fn get_persons( + params: HashMap, + datastore: Datastore, +) -> Result { + if !params.is_empty() { + let pagination = extract_pagination(params)?; + let res: Vec = datastore.persons.read().await.values().cloned().collect(); + let res = &res[pagination.start..pagination.end]; + Ok(warp::reply::json(&res)) + } else { + let res: Vec = datastore.persons.read().await.values().cloned().collect(); + Ok(warp::reply::json(&res)) + } +} + +async fn get_labels( + params: HashMap, + datastore: Datastore, +) -> Result { + if !params.is_empty() { + let pagination = extract_pagination(params)?; + let res: Vec