diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ef8c8dd --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# Example environment variable file +# Copy this to .env or manually set the environment variables + +# Redis URL -- Used for storing session data +REDIS_URL=redis://localhost:6379 + +# PostgreSQL URL -- Used for storing data +# Option 1: Specify the URL directly +DATABASE_URL=postgresql://libretunes:password@localhost:5432/libretunes + +# Option 2: Specify the individual components +# Must specify at least POSTGRES_HOST +# POSTGRES_USER=libretunes +# POSTGRES_PASSWORD=password +# POSTGRES_HOST=localhost +# POSTGRES_PORT=5432 +# POSTGRES_DB=libretunes diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c74cbba..4954a4c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,17 +2,25 @@ build: needs: [] image: $CI_REGISTRY/libretunes/ops/docker-leptos:latest + variables: + RUSTFLAGS: "-D warnings" script: - cargo-leptos build +.docker: + image: docker:latest + services: + - docker:dind + tags: + - docker + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + # Build the docker image and push it to the registry docker-build: needs: ["build"] - image: docker:latest + extends: .docker script: - - /usr/local/bin/dockerd-entrypoint.sh & - - while ! docker info; do echo "Waiting for Docker to become available..."; sleep 1; done - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . # If running on the default branch, tag as latest - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then docker tag @@ -44,35 +52,50 @@ cargo-doc: paths: - target/doc -.argocd: - image: argoproj/argocd:v2.6.15 - before_script: - - argocd login ${ARGOCD_SERVER} --username ${ARGOCD_USERNAME} --password ${ARGOCD_PASSWORD} --grpc-web - # Start the review environment start-review: - extends: .argocd + extends: .docker rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: manual script: - - argocd app sync argocd/libretunes-review-${CI_COMMIT_SHORT_SHA} - - argocd app wait argocd/libretunes-review-${CI_COMMIT_SHORT_SHA} + - apk add curl openssl + - cd cicd + - echo "$CLOUDFLARE_TUNNEL_AUTH_JSON" > tunnel-auth.json + - ./add-dns.sh $CLOUDFLARE_ZONE_ID review-$CI_COMMIT_SHORT_SHA libretunes-auto-review $CLOUDFLARE_API_TOKEN $CLOUDFLARE_TUNNEL_ID + - ./create-tunnel-config.sh http://libretunes:3000 review-$CI_COMMIT_SHORT_SHA.libretunes.xyz $CLOUDFLARE_TUNNEL_ID + - export COMPOSE_PROJECT_NAME=review-$CI_COMMIT_SHORT_SHA + - export POSTGRES_PASSWORD=$(openssl rand -hex 16) + - export LIBRETUNES_VERSION=$CI_COMMIT_SHORT_SHA + - docker compose --file docker-compose-cicd.yml pull + - docker compose --file docker-compose-cicd.yml create + - export CONFIG_VOL_NAME=review-${CI_COMMIT_SHORT_SHA}_cloudflared-config + - export TMP_CONTAINER_NAME=$(docker run --rm -d -v $CONFIG_VOL_NAME:/data busybox sh -c "sleep infinity") + - docker cp tunnel-auth.json $TMP_CONTAINER_NAME:/data/auth.json + - docker cp cloudflared-tunnel-config.yml $TMP_CONTAINER_NAME:/data/config.yml + - docker stop $TMP_CONTAINER_NAME + - docker compose --file docker-compose-cicd.yml up -d environment: name: review/$CI_COMMIT_SHORT_SHA - url: https://review-$CI_COMMIT_SHORT_SHA.libretunes.mregirouard.com + url: https://review-$CI_COMMIT_SHORT_SHA.libretunes.xyz on_stop: stop-review + auto_stop_in: 1 week # Stop the review environment stop-review: needs: ["start-review"] - extends: .argocd + extends: .docker rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" when: manual allow_failure: true script: - - argocd app delete argocd/libretunes-review-${CI_COMMIT_SHORT_SHA} --cascade + - apk add jq curl + - ./cicd/remove-dns.sh $CLOUDFLARE_ZONE_ID review-$CI_COMMIT_SHORT_SHA.libretunes.xyz libretunes-auto-review $CLOUDFLARE_API_TOKEN + - export COMPOSE_PROJECT_NAME=review-$CI_COMMIT_SHORT_SHA + - export LIBRETUNES_VERSION=$CI_COMMIT_SHORT_SHA + - docker compose --file cicd/docker-compose-cicd.yml down + - docker compose --file cicd/docker-compose-cicd.yml rm -f -v environment: name: review/$CI_COMMIT_SHORT_SHA action: stop diff --git a/Cargo.lock b/Cargo.lock index 9126602..28a9dfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -760,6 +760,19 @@ dependencies = [ "toml 0.5.11", ] +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "lazy_static", + "nom", + "pathdiff", + "serde", + "toml 0.8.12", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -923,6 +936,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "deranged" version = "0.3.10" @@ -1231,7 +1257,28 @@ dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.2.0", + "http 0.2.11", "js-sys", "pin-project", "serde", @@ -1255,6 +1302,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "h2" version = "0.3.22" @@ -1450,65 +1510,195 @@ dependencies = [ [[package]] name = "icondata" -version = "0.0.8" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41f2deec9249d16ef6b1a8442fbe16013f67053797052aa0b7d2f5ebd0f0098" +checksum = "e38f18389f3cd0e664bd42f1dfe0aba4acda0a44036fb720eb07e8ba3a09640c" dependencies = [ "icondata_ai", + "icondata_bi", "icondata_bs", "icondata_cg", + "icondata_ch", "icondata_core", + "icondata_fa", + "icondata_fi", + "icondata_hi", + "icondata_im", "icondata_io", + "icondata_lu", + "icondata_oc", "icondata_ri", + "icondata_si", + "icondata_tb", + "icondata_ti", + "icondata_vs", + "icondata_wi", ] [[package]] name = "icondata_ai" -version = "0.0.8" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8fe5fa2eed7715d5388e046d97f09d3baddd155b487454eb9cda3168c79d4b" +checksum = "9bf3a9c196a6a169f790639ecc8fdd4396660b1d53b905230bf0b364776a56fc" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_bi" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ce125f0d203e66444b02982af9b15631f2385573ad7992af79d4d4babc638d" dependencies = [ "icondata_core", ] [[package]] name = "icondata_bs" -version = "0.0.8" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1eeaedae6788b08308e1b050eeddaffa62dd5f2368469ef980c8e0e75837e3" +checksum = "67940e592b0b8df8d7adc055c8542d135ce1d7d6ad01d8fb8de9405ebfc21c2e" dependencies = [ "icondata_core", ] [[package]] name = "icondata_cg" -version = "0.0.8" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90cda35aa524761219a8dbd006513734e08a4cf92ee05820b01749e76435462" +checksum = "a0eba691ca17a43ffc8ebbcf200cd3ea54ad75837f210a6a6ace87a491be8314" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_ch" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2870b3c4ebf013b7e27af71d4c55f10b97ea448831e9a156cb53fec0f262dc20" dependencies = [ "icondata_core", ] [[package]] name = "icondata_core" -version = "0.0.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1640a4c1d5ddd08ab1d9854ffa7a2fa3dc52339492676b6d3031e77ca579f434" +checksum = "6c97be924215abd5e630d84e95a47c710138a6559b4c55039f4f33aa897fa859" + +[[package]] +name = "icondata_fa" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7fee576096efe5567a7216a6fb8154db8eae9ae108e5a4706805204208c2af" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_fi" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a4e81557c205a12ac051046595bb616f388537468987f7ee8960f897cdc538" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_hi" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3435d50de04c61799613995e753e613dc4f2771aa08eb94a7318289a5ea9d784" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_im" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce4bd1d64bb67bb080f605e3e600271894b67c4aaa18965179586ef5990a2297" +dependencies = [ + "icondata_core", +] [[package]] name = "icondata_io" -version = "0.0.8" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d9fb91cdd0e7ac971199e2c8c8eb917a975faeeee54b227a0068c4f70c886" +checksum = "35b9d681c936a6e087940beb4766159cddc080d7f1fd5ef0ef3ab9f50a11f3f6" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_lu" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d552c45cc3ab1d1bf88cc0201004eb92418141e5454e9e0e46c4b4a4faf66248" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_oc" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be19499912a05d5db89ccb88dbe3c459ca4100bda3dbcbddff69f2dcf71d305" dependencies = [ "icondata_core", ] [[package]] name = "icondata_ri" -version = "0.0.8" +version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d3adc5b64b22d10ab23a7b1a005f4cb52f3d08909f578fbaa09af9f9c0b7b" +checksum = "114a85cc95d1bfaee8dc5bf8a07dd043fc9e75499dc2ff4ac5e066193c594930" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_si" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc30cb2dbc2ac53f23dddbcb0ad73720970b24c0ed13935df8082b74fb627860" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_tb" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2b8d8e2047546285805795e6d3cb6e820a52bb008e15942e11353c7ba659f2" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_ti" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f85074d4bf10960d0f2b01ce3d9cfa2b2434a170d0738336411bb61e83227e4" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_vs" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a82bb4a8b1523200fc7c3b588bb80858db16708067093110ee8614db63b8913" +dependencies = [ + "icondata_core", +] + +[[package]] +name = "icondata_wi" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2c65b534aa9d7ccb107d892200e8fef2d1849acad160af067e9e20ced3619b" dependencies = [ "icondata_core", ] @@ -1593,6 +1783,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1636,12 +1835,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d02b78d6e38acf8199426058a0d8c4030835d84a4ee16147df25be7fed707e0" dependencies = [ "cfg-if", - "leptos_config", - "leptos_dom", - "leptos_macro", - "leptos_reactive", - "leptos_server", - "server_fn", + "leptos_config 0.5.4", + "leptos_dom 0.5.4", + "leptos_macro 0.5.4", + "leptos_reactive 0.5.4", + "leptos_server 0.5.4", + "server_fn 0.5.4", + "tracing", + "typed-builder", + "typed-builder-macro", + "web-sys", +] + +[[package]] +name = "leptos" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d079555ff18158a1ed28d2a8ac529b4cb5904490384064346eb2d321addde6" +dependencies = [ + "cfg-if", + "leptos_config 0.6.9", + "leptos_dom 0.6.9", + "leptos_macro 0.6.9", + "leptos_reactive 0.6.9", + "leptos_server 0.6.9", + "server_fn 0.6.9", "tracing", "typed-builder", "typed-builder-macro", @@ -1651,20 +1869,22 @@ dependencies = [ [[package]] name = "leptos_actix" -version = "0.5.4" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b2b118a031de24b39be9ef2dcfa03e7e255e98d06a8aa2c53f220155424cf1" +checksum = "9edb4789a15864a26d695038f42dcdf1d1c32d3a1f537751ce177c97f4f5e3dd" dependencies = [ "actix-http", "actix-web", "futures", - "leptos", - "leptos_integration_utils", - "leptos_meta", - "leptos_router", + "leptos 0.6.9", + "leptos_integration_utils 0.6.9", + "leptos_macro 0.6.9", + "leptos_meta 0.6.9", + "leptos_router 0.6.9", "parking_lot", "regex", "serde_json", + "server_fn 0.6.9", "tokio", "tracing", ] @@ -1680,10 +1900,10 @@ dependencies = [ "futures", "http 0.2.11", "hyper", - "leptos", - "leptos_integration_utils", - "leptos_meta", - "leptos_router", + "leptos 0.5.4", + "leptos_integration_utils 0.5.4", + "leptos_meta 0.5.4", + "leptos_router 0.5.4", "once_cell", "parking_lot", "serde_json", @@ -1698,7 +1918,20 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afcaa5db5b22b794b624e14ffe2aefae215b2d21c60a230ae2d06fe21ae5da64" dependencies = [ - "config", + "config 0.13.4", + "regex", + "serde", + "thiserror", + "typed-builder", +] + +[[package]] +name = "leptos_config" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d80b4ed5f0447996b9a28879002f995d3770687630f568be41307f362f84cb7" +dependencies = [ + "config 0.14.0", "regex", "serde", "thiserror", @@ -1720,14 +1953,44 @@ dependencies = [ "indexmap", "itertools 0.10.5", "js-sys", - "leptos_reactive", + "leptos_reactive 0.5.4", "once_cell", "pad-adapter", "paste", "rustc-hash", "serde", "serde_json", - "server_fn", + "server_fn 0.5.4", + "smallvec", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_dom" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4b4da3cb6a4dde22e68717482a4b926fb5dd182c12461b27efa37764b29d9a" +dependencies = [ + "async-recursion", + "cfg-if", + "drain_filter_polyfill", + "futures", + "getrandom", + "html-escape", + "indexmap", + "itertools 0.12.1", + "js-sys", + "leptos_reactive 0.6.9", + "once_cell", + "pad-adapter", + "paste", + "rustc-hash", + "serde", + "serde_json", + "server_fn 0.6.9", "smallvec", "tracing", "wasm-bindgen", @@ -1754,14 +2017,36 @@ dependencies = [ ] [[package]] -name = "leptos_icons" -version = "0.1.0" +name = "leptos_hot_reload" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3fad7820b18b983d49ff4262df88de94dc8fd993278937979cc0dd188868e5" +checksum = "fb051c7b3bce8368ee30fb57e7b14cdcd573019ea6cd1858b9c697a3519ea099" dependencies = [ - "icondata", - "leptos", - "tracing", + "anyhow", + "camino", + "indexmap", + "parking_lot", + "proc-macro2", + "quote", + "rstml", + "serde", + "syn 2.0.48", + "walkdir", +] + +[[package]] +name = "leptos_icons" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "584bccafed73138f4d700f936e6a82268efec2df9a2f9d74e1ee80985653413e" +dependencies = [ + "bytes", + "encoding_rs", + "icondata_core", + "lazy_static", + "leptos 0.6.9", + "log", + "paste", ] [[package]] @@ -1771,10 +2056,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2dbbd7d721bcdd9aa7b20987063de41314c836a3ac67e263ca489857e337dec" dependencies = [ "futures", - "leptos", - "leptos_config", - "leptos_hot_reload", - "leptos_meta", + "leptos 0.5.4", + "leptos_config 0.5.4", + "leptos_hot_reload 0.5.4", + "leptos_meta 0.5.4", + "tracing", +] + +[[package]] +name = "leptos_integration_utils" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff00799857159434d31b6bd1898e21c63f69f39289621da5a554fcab1c3e7300" +dependencies = [ + "futures", + "leptos 0.6.9", + "leptos_config 0.6.9", + "leptos_hot_reload 0.6.9", + "leptos_meta 0.6.9", "tracing", ] @@ -1789,13 +2088,36 @@ dependencies = [ "convert_case 0.6.0", "html-escape", "itertools 0.11.0", - "leptos_hot_reload", + "leptos_hot_reload 0.5.4", "prettyplease", "proc-macro-error", "proc-macro2", "quote", "rstml", - "server_fn_macro", + "server_fn_macro 0.5.4", + "syn 2.0.48", + "tracing", + "uuid", +] + +[[package]] +name = "leptos_macro" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e82c33c8baa07a36c1f0d6149af821be885e6863779bcb24954bf865ad8402b4" +dependencies = [ + "attribute-derive", + "cfg-if", + "convert_case 0.6.0", + "html-escape", + "itertools 0.12.1", + "leptos_hot_reload 0.6.9", + "prettyplease", + "proc-macro-error", + "proc-macro2", + "quote", + "rstml", + "server_fn_macro 0.6.9", "syn 2.0.48", "tracing", "uuid", @@ -1809,7 +2131,21 @@ checksum = "983bbf829598d275b01e96bd9fca71e4739dd7b9fdf69cb8898b30ebfb124332" dependencies = [ "cfg-if", "indexmap", - "leptos", + "leptos 0.5.4", + "tracing", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "leptos_meta" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b9dac59a2f88f5235dbe17cfa81b738a6f47238a64e4f23b921f1a90a9bf11" +dependencies = [ + "cfg-if", + "indexmap", + "leptos 0.6.9", "tracing", "wasm-bindgen", "web-sys", @@ -1820,6 +2156,30 @@ name = "leptos_reactive" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22207568e096ac153ba8da68635e3136c1ec614ea9012736fa861c05bfb2eeff" +dependencies = [ + "base64 0.21.7", + "cfg-if", + "futures", + "indexmap", + "paste", + "pin-project", + "rustc-hash", + "self_cell", + "serde", + "serde-wasm-bindgen 0.5.0", + "serde_json", + "slotmap", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "leptos_reactive" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93bdcebc9822cc22a72cc9528dd794e1396152c75749ee09959f8272a8c99657" dependencies = [ "base64 0.21.7", "cfg-if", @@ -1832,7 +2192,7 @@ dependencies = [ "rustc-hash", "self_cell", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.6.5", "serde_json", "slotmap", "thiserror", @@ -1851,13 +2211,13 @@ checksum = "c1a2ff8b8e8ae8b17efd8be2a407f7f83ed57c5243f70f2d03e6635f9ff61848" dependencies = [ "cached", "cfg-if", - "gloo-net", + "gloo-net 0.2.6", "itertools 0.11.0", "js-sys", "lazy_static", - "leptos", - "leptos_integration_utils", - "leptos_meta", + "leptos 0.5.4", + "leptos_integration_utils 0.5.4", + "leptos_meta 0.5.4", "linear-map", "lru", "once_cell", @@ -1874,6 +2234,38 @@ dependencies = [ "web-sys", ] +[[package]] +name = "leptos_router" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9460a5dc184fa05d8eb635b687ad3220d02d2d23d6f49c3bf146aa71e427f423" +dependencies = [ + "cached", + "cfg-if", + "gloo-net 0.2.6", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "leptos 0.6.9", + "leptos_integration_utils 0.6.9", + "leptos_meta 0.6.9", + "linear-map", + "lru", + "once_cell", + "percent-encoding", + "regex", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "thiserror", + "tracing", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "leptos_server" version = "0.5.4" @@ -1882,10 +2274,26 @@ checksum = "272d018a5adf33d10ee57e6f0f83dccc305c68613cd207e8a653aeebd4cd5b4f" dependencies = [ "inventory", "lazy_static", - "leptos_macro", - "leptos_reactive", + "leptos_macro 0.5.4", + "leptos_reactive 0.5.4", "serde", - "server_fn", + "server_fn 0.5.4", + "thiserror", + "tracing", +] + +[[package]] +name = "leptos_server" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654b6ff6a24e79977641b5214452373b1e12fdf4c8a563fadf656c139694b4b9" +dependencies = [ + "inventory", + "lazy_static", + "leptos_macro 0.6.9", + "leptos_reactive 0.6.9", + "serde", + "server_fn 0.6.9", "thiserror", "tracing", ] @@ -1912,13 +2320,14 @@ dependencies = [ "dotenv", "futures", "http 0.2.11", + "icondata", "lazy_static", - "leptos", + "leptos 0.6.9", "leptos_actix", "leptos_axum", "leptos_icons", - "leptos_meta", - "leptos_router", + "leptos_meta 0.6.9", + "leptos_router 0.6.9", "openssl", "pbkdf2", "serde", @@ -2696,6 +3105,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + [[package]] name = "serde" version = "1.0.195" @@ -2716,6 +3134,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_derive" version = "1.0.195" @@ -2797,7 +3226,7 @@ checksum = "cfed18dfcc8d9004579c40482c3419c07f60ffb9c5b250542edca99f508b0ce9" dependencies = [ "ciborium", "const_format", - "gloo-net", + "gloo-net 0.2.6", "inventory", "js-sys", "lazy_static", @@ -2808,12 +3237,43 @@ dependencies = [ "serde", "serde_json", "serde_qs", - "server_fn_macro_default", + "server_fn_macro_default 0.5.4", "syn 2.0.48", "thiserror", "xxhash-rust", ] +[[package]] +name = "server_fn" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2955da1dc5fcd970c182ebf1089af6c5f19051e1f286a21f7b96490a49b7a531" +dependencies = [ + "actix-web", + "bytes", + "ciborium", + "const_format", + "dashmap", + "futures", + "gloo-net 0.5.0", + "http 1.0.0", + "inventory", + "js-sys", + "once_cell", + "send_wrapper", + "serde", + "serde_json", + "serde_qs", + "server_fn_macro_default 0.6.9", + "thiserror", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "xxhash-rust", +] + [[package]] name = "server_fn_macro" version = "0.5.4" @@ -2829,13 +3289,37 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "server_fn_macro" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfdd051ef905fdb3da20942b0c52d536158d7489a724e14cc2fd47323e7ca91" +dependencies = [ + "const_format", + "convert_case 0.6.0", + "proc-macro2", + "quote", + "syn 2.0.48", + "xxhash-rust", +] + [[package]] name = "server_fn_macro_default" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7256ba61dfadb220598db418376e7bc2a34b96df36c4dc48f24ffe161810fc0b" dependencies = [ - "server_fn_macro", + "server_fn_macro 0.5.4", + "syn 2.0.48", +] + +[[package]] +name = "server_fn_macro_default" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060af1def72353a779fcc184c53e1965d3055a38b9e827f2259b2bff2d9c371e" +dependencies = [ + "server_fn_macro 0.6.9", "syn 2.0.48", ] @@ -3131,7 +3615,19 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.9", ] [[package]] @@ -3153,7 +3649,20 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.37", +] + +[[package]] +name = "toml_edit" +version = "0.22.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.5", ] [[package]] @@ -3508,6 +4017,19 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.66" @@ -3624,6 +4146,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index 115a22d..ce1a54f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,23 +13,14 @@ actix-web = { version = "4", optional = true, features = ["macros"] } console_error_panic_hook = "0.1" cfg-if = "1" http = "0.2" -leptos = { version = "0.5", features = ["nightly"] } -leptos_meta = { version = "0.5", features = ["nightly"] } -leptos_actix = { version = "0.5", optional = true } +leptos = { version = "0.6", features = ["nightly"] } +leptos_meta = { version = "0.6", features = ["nightly"] } +leptos_actix = { version = "0.6", optional = true } leptos_axum = { version = "0.5", optional = true } -leptos_router = { version = "0.5", features = ["nightly"] } +leptos_router = { version = "0.6", features = ["nightly"] } wasm-bindgen = "=0.2.89" -leptos_icons = { version = "0.1.0", default_features = false, features = [ - "BsPlayFill", - "BsPauseFill", - "BsSkipStartFill", - "BsSkipEndFill", - "RiPlayListMediaFill", - "CgTrash", - "IoReturnUpBackSharp", - "AiEyeFilled", - "AiEyeInvisibleFilled" -] } +leptos_icons = { version = "0.3.0" } +icondata = { version = "0.3.0" } dotenv = { version = "0.15.0", optional = true } diesel = { version = "2.1.4", features = ["postgres", "r2d2", "time"], optional = true } lazy_static = { version = "1.4.0", optional = true } @@ -84,7 +75,7 @@ panic = "abort" [package.metadata.leptos] # The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name -output-name = "leptos_start" +output-name = "libretunes" # The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup. site-root = "target/site" # The site-root relative folder where all compiled output (JS, WASM and CSS) is written diff --git a/LICENSE b/LICENSE index e869ce3..43bb24e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 henrik +Copyright (c) 2023-2024 The LibreTunes Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/assets/favicon.ico b/assets/favicon.ico index 2ba8527..1294ab1 100644 Binary files a/assets/favicon.ico and b/assets/favicon.ico differ diff --git a/cicd/add-dns.sh b/cicd/add-dns.sh new file mode 100755 index 0000000..7247314 --- /dev/null +++ b/cicd/add-dns.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +ZONE_ID=$1 +RECORD_NAME=$2 +RECORD_COMMENT=$3 +API_TOKEN=$4 +TUNNEL_ID=$5 + +curl --request POST --silent \ + --url https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records \ + --header 'Content-Type: application/json' \ + --header "Authorization: Bearer $API_TOKEN" \ + --data '{ + "content": "'$TUNNEL_ID'.cfargotunnel.com", + "name": "'$RECORD_NAME'", + "comment": "'$RECORD_COMMENT'", + "proxied": true, + "type": "CNAME", + "ttl": 1 +}' \ diff --git a/cicd/create-tunnel-config.sh b/cicd/create-tunnel-config.sh new file mode 100755 index 0000000..11fb59a --- /dev/null +++ b/cicd/create-tunnel-config.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e + +SERVICE=$1 +HOSTNAME=$2 +TUNNEL_ID=$3 + +echo "Creating tunnel config for $HOSTNAME" + +cat < cloudflared-tunnel-config.yml +tunnel: $TUNNEL_ID +credentials-file: /etc/cloudflared/auth.json + +ingress: + - hostname: $HOSTNAME + service: $SERVICE + - service: http_status:404 +EOF diff --git a/cicd/docker-compose-cicd.yml b/cicd/docker-compose-cicd.yml new file mode 100644 index 0000000..723ca41 --- /dev/null +++ b/cicd/docker-compose-cicd.yml @@ -0,0 +1,55 @@ +version: '3' + +services: + cloudflare: + image: cloudflare/cloudflared:latest + command: tunnel run + volumes: + - cloudflared-config:/etc/cloudflared:ro + + libretunes: + image: registry.mregirouard.com/libretunes/libretunes:${LIBRETUNES_VERSION} + environment: + REDIS_URL: redis://redis:6379 + POSTGRES_HOST: postgres + POSTGRES_USER: libretunes + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: libretunes + volumes: + - libretunes-audio:/site/audio + depends_on: + - redis + - postgres + restart: always + + redis: + image: redis:latest + volumes: + - libretunes-redis:/data + restart: always + healthcheck: + test: ["CMD-SHELL", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + postgres: + image: postgres:latest + environment: + POSTGRES_USER: libretunes + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: libretunes + volumes: + - libretunes-postgres:/var/lib/postgresql/data + restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready -U libretunes"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + cloudflared-config: + libretunes-audio: + libretunes-redis: + libretunes-postgres: diff --git a/cicd/remove-dns.sh b/cicd/remove-dns.sh new file mode 100755 index 0000000..3a80869 --- /dev/null +++ b/cicd/remove-dns.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +ZONE_ID=$1 +RECORD_NAME=$2 +RECORD_COMMENT=$3 +API_TOKEN=$4 + +RECORD_ID=$( +curl --request GET --silent \ + --url "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?name=$RECORD_NAME&comment=$RECORD_COMMENT" \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $API_TOKEN" \ +| jq -r '.result[0].id') + +echo "Deleting DNS record ID $RECORD_ID" + +curl --request DELETE --silent \ + --url "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" \ + --header "Content-Type: application/json" \ + --header "Authorization: Bearer $API_TOKEN" diff --git a/src/app.rs b/src/app.rs index dd0e0d2..762e28b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -16,7 +16,7 @@ pub fn App() -> impl IntoView { view! { // injects a stylesheet into the document // id=leptos means cargo-leptos will hot-reload this stylesheet - + // sets the document title @@ -44,7 +44,7 @@ pub fn App() -> impl IntoView { /// Renders the home page of your application. #[component] fn HomePage() -> impl IntoView { - let mut play_status = PlayStatus::default(); + let play_status = PlayStatus::default(); let play_status = create_rw_signal(play_status); view! { diff --git a/src/auth.rs b/src/auth.rs index 1995deb..63d107a 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,4 +1,5 @@ use leptos::*; + use crate::models::User; /// Create a new user and log them in @@ -11,6 +12,7 @@ pub async fn signup(new_user: User) -> Result<(), ServerFnError> { use leptos_actix::extract; use actix_web::{HttpMessage, HttpRequest}; use actix_identity::Identity; + use leptos::server_fn::error::NoCustomError; // Ensure the user has no id let new_user = User { @@ -19,13 +21,17 @@ pub async fn signup(new_user: User) -> Result<(), ServerFnError> { }; create_user(&new_user).await - .map_err(|e| ServerFnError::ServerError(format!("Error creating user: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error creating user: {}", e)))?; - extract(|request: HttpRequest| async move { - Identity::login(&request.extensions(), new_user.username.clone()) - }).await??; - - Ok(()) + match extract::<HttpRequest>().await { + Ok(request) => { + match Identity::login(&request.extensions(), new_user.username.clone()) { + Ok(_) => Ok(()), + Err(e) => Err(ServerFnError::<NoCustomError>::ServerError(format!("Error logging in user: {}", e))), + } + }, + Err(e) => Err(ServerFnError::<NoCustomError>::ServerError(format!("Error getting request: {}", e))), + } } /// Log a user in @@ -37,20 +43,25 @@ pub async fn login(username_or_email: String, password: String) -> Result<bool, use actix_web::{HttpMessage, HttpRequest}; use actix_identity::Identity; use leptos_actix::extract; + use leptos::server_fn::error::NoCustomError; let possible_user = validate_user(username_or_email, password).await - .map_err(|e| ServerFnError::ServerError(format!("Error validating user: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error validating user: {}", e)))?; let user = match possible_user { Some(user) => user, None => return Ok(false) }; - extract(|request: HttpRequest| async move { - Identity::login(&request.extensions(), user.username.clone()) - }).await??; - - Ok(true) + match extract::<HttpRequest>().await { + Ok(request) => { + match Identity::login(&request.extensions(), user.username.clone()) { + Ok(_) => Ok(true), + Err(e) => Err(ServerFnError::<NoCustomError>::ServerError(format!("Error logging in user: {}", e))), + } + } + Err(e) => Err(ServerFnError::<NoCustomError>::ServerError(format!("Error getting request: {}", e))), + } } /// Log a user out @@ -59,12 +70,13 @@ pub async fn login(username_or_email: String, password: String) -> Result<bool, pub async fn logout() -> Result<(), ServerFnError> { use leptos_actix::extract; use actix_identity::Identity; + use leptos::server_fn::error::NoCustomError; - extract(|user: Option<Identity>| async move { - if let Some(user) = user { - user.logout(); - } - }).await?; + match extract::<Option<Identity>>().await { + Ok(Some(user)) => user.logout(), + Ok(None) => {}, + Err(e) => return Err(ServerFnError::<NoCustomError>::ServerError(format!("Error getting user: {}", e))), + }; Ok(()) } diff --git a/src/database.rs b/src/database.rs index cb1bee1..6ec58cc 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,8 +1,8 @@ use cfg_if::cfg_if; -use leptos::logging::log; cfg_if! { if #[cfg(feature = "ssr")] { +use leptos::logging::log; use lazy_static::lazy_static; use std::env; diff --git a/src/lib.rs b/src/lib.rs index be30f52..eba864d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,6 @@ if #[cfg(feature = "hydrate")] { #[wasm_bindgen] pub fn hydrate() { use app::*; - use leptos::*; console_error_panic_hook::set_once(); diff --git a/src/models.rs b/src/models.rs index 7ad0cda..15a6d12 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,4 @@ use std::time::SystemTime; -use std::error::Error; use time::Date; use serde::{Deserialize, Serialize}; @@ -9,6 +8,7 @@ cfg_if! { if #[cfg(feature = "ssr")] { use diesel::prelude::*; use crate::database::PgPooledConn; + use std::error::Error; } } diff --git a/src/pages/login.rs b/src/pages/login.rs index 0d55a26..253399c 100644 --- a/src/pages/login.rs +++ b/src/pages/login.rs @@ -1,9 +1,8 @@ use crate::auth::login; use leptos::leptos_dom::*; use leptos::*; -use leptos_icons::AiIcon::*; -use leptos_icons::IoIcon::*; use leptos_icons::*; +use icondata; #[component] pub fn Login() -> impl IntoView { @@ -42,7 +41,7 @@ pub fn Login() -> impl IntoView { view! { <div class="auth-page-container"> <div class="login-container"> - <a class="return" href="/"><Icon icon=Icon::from(IoReturnUpBackSharp) /></a> + <a class="return" href="/"><Icon icon=icondata::IoReturnUpBackSharp /></a> <div class="header"> <h1>LibreTunes</h1> </div> @@ -70,11 +69,11 @@ pub fn Login() -> impl IntoView { <Show when=move || {show_password() == false} fallback=move || view!{ <button on:click=toggle_password class="login-password-visibility"> - <Icon icon=Icon::from(AiEyeInvisibleFilled) /> + <Icon icon=icondata::AiEyeInvisibleFilled /> </button> /> } > <button on:click=toggle_password class="login-password-visibility"> - <Icon icon=Icon::from(AiEyeFilled) /> + <Icon icon=icondata::AiEyeFilled /> </button> </Show> diff --git a/src/pages/signup.rs b/src/pages/signup.rs index c2de8f8..d02d7c5 100644 --- a/src/pages/signup.rs +++ b/src/pages/signup.rs @@ -1,11 +1,9 @@ use crate::auth::signup; use crate::models::User; -use leptos::ev::input; use leptos::leptos_dom::*; use leptos::*; -use leptos_icons::AiIcon::*; -use leptos_icons::IoIcon::*; use leptos_icons::*; +use icondata; #[component] pub fn Signup() -> impl IntoView { @@ -15,8 +13,6 @@ pub fn Signup() -> impl IntoView { let (show_password, set_show_password) = create_signal(false); - let navigate = leptos_router::use_navigate(); - let toggle_password = move |_| { set_show_password.update(|show_password| *show_password = !*show_password); log!("showing password"); @@ -49,7 +45,7 @@ pub fn Signup() -> impl IntoView { view! { <div class="auth-page-container"> <div class="signup-container"> - <a class="return" href="/"><Icon icon=Icon::from(IoReturnUpBackSharp) /></a> + <a class="return" href="/"><Icon icon=icondata::IoReturnUpBackSharp /></a> <div class="header"> <h1>LibreTunes</h1> </div> @@ -86,10 +82,10 @@ pub fn Signup() -> impl IntoView { <i></i> <Show when=move || {show_password() == false} - fallback=move || view!{ <button on:click=toggle_password class="password-visibility"> <Icon icon=Icon::from(AiEyeInvisibleFilled) /></button> /> } + fallback=move || view!{ <button on:click=toggle_password class="password-visibility"> <Icon icon=icondata::AiEyeInvisibleFilled /></button> /> } > <button on:click=toggle_password class="password-visibility"> - <Icon icon=Icon::from(AiEyeFilled) /> + <Icon icon=icondata::AiEyeFilled /> </button> </Show> </div> diff --git a/src/playbar.rs b/src/playbar.rs index fcab9a7..7bfc1b0 100644 --- a/src/playbar.rs +++ b/src/playbar.rs @@ -1,12 +1,8 @@ -use std::time::Duration; - use crate::playstatus::PlayStatus; use leptos::ev::MouseEvent; use leptos::html::{Audio, Div}; use leptos::leptos_dom::*; use leptos::*; -use leptos_icons::BsIcon::*; -use leptos_icons::RiIcon::*; use leptos_icons::*; /// Width and height of the forward/backward skip buttons @@ -195,9 +191,9 @@ fn PlayControls(status: RwSignal<PlayStatus>) -> impl IntoView { let icon = Signal::derive(move || { status.with(|status| { if status.playing { - Icon::from(BsPauseFill) + icondata::BsPauseFill } else { - Icon::from(BsPlayFill) + icondata::BsPlayFill } }) }); @@ -206,7 +202,7 @@ fn PlayControls(status: RwSignal<PlayStatus>) -> impl IntoView { <div class="playcontrols" align="center"> <button on:click=skip_back on:mousedown=prevent_focus> - <Icon class="controlbtn" width=SKIP_BTN_SIZE height=SKIP_BTN_SIZE icon=Icon::from(BsSkipStartFill) /> + <Icon class="controlbtn" width=SKIP_BTN_SIZE height=SKIP_BTN_SIZE icon=icondata::BsSkipStartFill /> </button> <button on:click=toggle_play on:mousedown=prevent_focus> @@ -214,7 +210,7 @@ fn PlayControls(status: RwSignal<PlayStatus>) -> impl IntoView { </button> <button on:click=skip_forward on:mousedown=prevent_focus> - <Icon class="controlbtn" width=SKIP_BTN_SIZE height=SKIP_BTN_SIZE icon=Icon::from(BsSkipEndFill) /> + <Icon class="controlbtn" width=SKIP_BTN_SIZE height=SKIP_BTN_SIZE icon=icondata::BsSkipEndFill /> </button> </div> @@ -339,7 +335,7 @@ fn QueueToggle(status: RwSignal<PlayStatus>) -> impl IntoView { view! { <div class="queue-toggle"> <button on:click=update_queue on:mousedown=prevent_focus> - <Icon class="controlbtn" width=QUEUE_BTN_SIZE height=QUEUE_BTN_SIZE icon=Icon::from(RiPlayListMediaFill) /> + <Icon class="controlbtn" width=QUEUE_BTN_SIZE height=QUEUE_BTN_SIZE icon=icondata::RiPlayListMediaFill /> </button> </div> } diff --git a/src/queue.rs b/src/queue.rs index fc786b9..39f0ee0 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -4,7 +4,6 @@ use leptos::ev::MouseEvent; use leptos::leptos_dom::*; use leptos::*; use leptos_icons::*; -use leptos_icons::CgIcon::*; use leptos::ev::DragEvent; const RM_BTN_SIZE: &str = "2.5rem"; @@ -106,7 +105,7 @@ pub fn Queue(status: RwSignal<PlayStatus>) -> impl IntoView { <p>Playing</p> }> <button on:click=move |_| remove_song(index) on:mousedown=prevent_focus> - <Icon class="remove-song" width=RM_BTN_SIZE height=RM_BTN_SIZE icon=Icon::from(CgTrash) /> + <Icon class="remove-song" width=RM_BTN_SIZE height=RM_BTN_SIZE icon=icondata::CgTrash /> </button> </Show> </div> diff --git a/src/users.rs b/src/users.rs index 7d81b31..51fecdc 100644 --- a/src/users.rs +++ b/src/users.rs @@ -21,12 +21,13 @@ use crate::models::User; #[cfg(feature = "ssr")] pub async fn find_user(username_or_email: String) -> Result<Option<User>, ServerFnError> { use crate::schema::users::dsl::*; + use leptos::server_fn::error::NoCustomError; // Look for either a username or email that matches the input, and return an option with None if no user is found let db_con = &mut get_db_conn(); let user = users.filter(username.eq(username_or_email.clone())).or_filter(email.eq(username_or_email)) .first::<User>(db_con).optional() - .map_err(|e| ServerFnError::ServerError(format!("Error getting user from database: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error getting user from database: {}", e)))?; Ok(user) } @@ -36,13 +37,14 @@ pub async fn find_user(username_or_email: String) -> Result<Option<User>, Server #[cfg(feature = "ssr")] pub async fn create_user(new_user: &User) -> Result<(), ServerFnError> { use crate::schema::users::dsl::*; + use leptos::server_fn::error::NoCustomError; let new_password = new_user.password.clone() - .ok_or(ServerFnError::ServerError(format!("No password provided for user {}", new_user.username)))?; + .ok_or(ServerFnError::<NoCustomError>::ServerError(format!("No password provided for user {}", new_user.username)))?; let salt = SaltString::generate(&mut OsRng); let password_hash = Pbkdf2.hash_password(new_password.as_bytes(), &salt) - .map_err(|_| ServerFnError::ServerError("Error hashing password".to_string()))?.to_string(); + .map_err(|_| ServerFnError::<NoCustomError>::ServerError("Error hashing password".to_string()))?.to_string(); let new_user = User { password: Some(password_hash), @@ -52,7 +54,7 @@ pub async fn create_user(new_user: &User) -> Result<(), ServerFnError> { let db_con = &mut get_db_conn(); diesel::insert_into(users).values(&new_user).execute(db_con) - .map_err(|e| ServerFnError::ServerError(format!("Error creating user: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error creating user: {}", e)))?; Ok(()) } @@ -61,8 +63,10 @@ pub async fn create_user(new_user: &User) -> Result<(), ServerFnError> { /// Returns a Result with the user if the credentials are valid, None if not valid, or an error if there was a problem #[cfg(feature = "ssr")] pub async fn validate_user(username_or_email: String, password: String) -> Result<Option<User>, ServerFnError> { + use leptos::server_fn::error::NoCustomError; + let db_user = find_user(username_or_email.clone()).await - .map_err(|e| ServerFnError::ServerError(format!("Error getting user from database: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error getting user from database: {}", e)))?; // If the user is not found, return None let db_user = match db_user { @@ -71,10 +75,10 @@ pub async fn validate_user(username_or_email: String, password: String) -> Resul }; let db_password = db_user.password.clone() - .ok_or(ServerFnError::ServerError(format!("No password found for user {}", db_user.username)))?; + .ok_or(ServerFnError::<NoCustomError>::ServerError(format!("No password found for user {}", db_user.username)))?; let password_hash = PasswordHash::new(&db_password) - .map_err(|e| ServerFnError::ServerError(format!("Error hashing supplied password: {}", e)))?; + .map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error hashing supplied password: {}", e)))?; match Pbkdf2.verify_password(password.as_bytes(), &password_hash) { Ok(()) => {}, @@ -82,7 +86,7 @@ pub async fn validate_user(username_or_email: String, password: String) -> Resul return Ok(None); }, Err(e) => { - return Err(ServerFnError::ServerError(format!("Error verifying password: {}", e))); + return Err(ServerFnError::<NoCustomError>::ServerError(format!("Error verifying password: {}", e))); } }