From 1a9b392a71186d2014034a32bffd3f6cd75a5ac0 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 27 Apr 2024 15:16:03 +0200 Subject: [PATCH 01/21] Upgraded alpine images --- CMakeLists.txt | 36 +------------------ Dockerfile-build-alpine | 4 +-- Dockerfile-build-arch | 2 +- Dockerfile-release | 11 +++--- INSTALL.md | 2 +- cmake/modules/FindSTB.cmake | 10 ------ cmake/modules/FindStbImage.cmake | 18 ++++++++++ src/libs/av/CMakeLists.txt | 2 +- src/libs/core/CMakeLists.txt | 3 ++ src/libs/image/CMakeLists.txt | 28 ++++++++++----- .../image/impl/graphicsmagick/JPEGImage.hpp | 4 --- .../image/impl/graphicsmagick/RawImage.hpp | 4 --- src/libs/image/impl/stb/RawImage.cpp | 14 ++++++++ src/libs/image/impl/stb/RawImage.hpp | 4 --- src/libs/metadata/CMakeLists.txt | 1 + src/libs/services/auth/CMakeLists.txt | 16 +++++++++ 16 files changed, 82 insertions(+), 77 deletions(-) delete mode 100644 cmake/modules/FindSTB.cmake create mode 100644 cmake/modules/FindStbImage.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a203733..e0727bfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,18 +17,12 @@ if(ENABLE_TESTS) find_package(GTest REQUIRED) endif() +# Common dependencies find_package(PkgConfig REQUIRED) find_package(Threads REQUIRED) find_package(Filesystem REQUIRED) find_package(Boost REQUIRED COMPONENTS system program_options iostreams) find_package(Wt REQUIRED COMPONENTS Wt Dbo DboSqlite3 HTTP) -pkg_check_modules(Taglib REQUIRED IMPORTED_TARGET taglib) -pkg_check_modules(Config++ REQUIRED IMPORTED_TARGET libconfig++) -pkg_check_modules(GraphicsMagick++ IMPORTED_TARGET GraphicsMagick++) -pkg_check_modules(LIBAV IMPORTED_TARGET libavcodec libavutil libavformat) -pkg_check_modules(Archive REQUIRED IMPORTED_TARGET libarchive) -find_package(PAM) -find_package(STB) # WT if (NOT Wt_FOUND) @@ -47,34 +41,6 @@ if (NOT TARGET Wt::HTTP) message(FATAL_ERROR "Cannot find Wt::HTTP!") endif () -# PAM -option(USE_PAM "Use the PAM backend authentication API" ON) -if (USE_PAM AND NOT PAM_FOUND) - message(WARNING "PAM library not found: disabling") - set(USE_PAM OFF) -endif () -if (USE_PAM) - message(STATUS "Using PAM authentication backend") -else () - message(STATUS "NOT using PAM authentication backend") -endif () - -# IMAGE -if (STB_FOUND) - set(IMAGE_LIBRARY STB CACHE STRING "STB library") -elseif (GraphicsMagick++_FOUND) - set(IMAGE_LIBRARY GraphicsMagick++ CACHE STRING "GraphicsMagick++") -else () - message(FATAL_ERROR "Cannot find suitable image library") -endif() -set_property(CACHE IMAGE_LIBRARY PROPERTY STRINGS GraphicsMagick++ STB) -if (IMAGE_LIBRARY STREQUAL GraphicsMagick++ AND NOT GraphicsMagick++_FOUND) - message(FATAL_ERROR "GraphicsMagick++ not found") -elseif (IMAGE_LIBRARY STREQUAL STB AND NOT STB_FOUND) - message(FATAL_ERROR "STB not found") -endif () -message(STATUS "IMAGE_LIBRARY set to ${IMAGE_LIBRARY}") - # Benchmark option(BUILD_BENCHMARKS "Build benchmarks" OFF) if (BUILD_BENCHMARKS) diff --git a/Dockerfile-build-alpine b/Dockerfile-build-alpine index 02c18010..e4a29b8b 100644 --- a/Dockerfile-build-alpine +++ b/Dockerfile-build-alpine @@ -1,5 +1,5 @@ FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx -FROM --platform=$BUILDPLATFORM alpine:3.18 +FROM --platform=$BUILDPLATFORM alpine:3.19 ARG BUILD_PACKAGES="\ clang \ @@ -36,7 +36,7 @@ ARG LMS_BUILD_TYPE="Release" RUN \ DIR=/tmp/lms/build && mkdir -p ${DIR} && cd ${DIR} && \ xx-info is-cross && export BUILD_TESTS=OFF || export BUILD_TESTS=ON && \ - PKG_CONFIG_PATH=/$(xx-info)/usr/lib/pkgconfig cmake /tmp/lms/ -DCMAKE_INCLUDE_PATH=${PREFIX}/include -DCMAKE_BUILD_TYPE=${LMS_BUILD_TYPE} $(xx-clang --print-cmake-defines) -DCMAKE_PREFIX_PATH=/$(xx-info)/usr/lib/cmake -DBUILD_TESTING=${BUILD_TESTS} -DBUILD_BENCHMARKS=ON && \ + PKG_CONFIG_PATH=/$(xx-info)/usr/lib/pkgconfig cmake /tmp/lms/ -DCMAKE_INCLUDE_PATH=/$(xx-info)/usr/include -DCMAKE_BUILD_TYPE=${LMS_BUILD_TYPE} $(xx-clang --print-cmake-defines) -DCMAKE_PREFIX_PATH=/$(xx-info)/usr/lib/cmake -DBUILD_TESTING=${BUILD_TESTS} -DBUILD_BENCHMARKS=ON && \ VERBOSE=1 make -j$(nproc) && \ xx-verify src/lms/lms && \ (xx-info is-cross || make test) diff --git a/Dockerfile-build-arch b/Dockerfile-build-arch index 82cc3ee0..b197342c 100644 --- a/Dockerfile-build-arch +++ b/Dockerfile-build-arch @@ -23,6 +23,6 @@ COPY . /tmp/lms/ ARG LMS_BUILD_TYPE="Release" RUN \ DIR=/tmp/lms/build && mkdir -p ${DIR} && cd ${DIR} && \ - cmake /tmp/lms/ -DCMAKE_BUILD_TYPE=${LMS_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_BENCHMARKS=ON && \ + cmake /tmp/lms/ -DCMAKE_BUILD_TYPE=${LMS_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=/usr -DLMS_IMAGE_BACKEND=graphicsmagick -DBUILD_BENCHMARKS=ON && \ VERBOSE=1 make -j$(nproc) && \ make test diff --git a/Dockerfile-release b/Dockerfile-release index b78366dc..a4702988 100644 --- a/Dockerfile-release +++ b/Dockerfile-release @@ -1,4 +1,4 @@ -FROM alpine:3.18 AS build +FROM alpine:3.19 AS build WORKDIR /tmp/workdir @@ -37,7 +37,7 @@ ARG BUILD_PACKAGES=" \ RUN apk add --no-cache --update ${BUILD_PACKAGES} # ffmpeg -ARG FFMPEG_VERSION=4.3.5 +ARG FFMPEG_VERSION=6.1.1 RUN \ DIR=/tmp/ffmpeg && mkdir -p ${DIR} && cd ${DIR} && \ curl -sLO https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2 && \ @@ -79,7 +79,7 @@ RUN \ make distclean # WT -ARG WT_VERSION=4.10.2 +ARG WT_VERSION=4.10.4 RUN \ DIR=/tmp/wt && mkdir -p ${DIR} && cd ${DIR} && \ curl -sLO https://github.com/emweb/wt/archive/${WT_VERSION}.tar.gz && \ @@ -92,7 +92,7 @@ RUN \ make install # STB -ARG STB_VERSION=5736b15f7ea0ffb08dd38af21067c314d6a3aae9 +ARG STB_VERSION=ae721c50eaf761660b4f90cc590453cdb0c2acd0 RUN \ DIR=/tmp/stb && mkdir -p ${DIR} && cd ${DIR} && \ curl -sLO https://github.com/nothings/stb/archive/${STB_VERSION}.tar.gz && \ @@ -134,7 +134,7 @@ RUN \ rm -rf /tmp/fakeroot/share/Wt/resources/themes ## Release Stage -FROM alpine:3.18 AS release +FROM alpine:3.19 AS release LABEL maintainer="Emeric Poupon " ARG RUNTIME_PACKAGES=" \ @@ -179,4 +179,3 @@ COPY --from=build /tmp/fakeroot/share/lms/lms.conf /etc/lms.conf EXPOSE 5082 ENTRYPOINT ["/usr/bin/lms"] - diff --git a/INSTALL.md b/INSTALL.md index 0e3d7b83..b97d2fe6 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -54,7 +54,7 @@ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ``` __Notes__: * you can customize the installation directory using `-DCMAKE_INSTALL_PREFIX=path` (defaults to `/usr/local`). -* you can customize the image library using `-DIMAGE_LIBRARY=` +* you can customize the image library using `-DLMS_IMAGE_BACKEND=` (defaults to `stb`) ```sh make ``` diff --git a/cmake/modules/FindSTB.cmake b/cmake/modules/FindSTB.cmake deleted file mode 100644 index 9da76b57..00000000 --- a/cmake/modules/FindSTB.cmake +++ /dev/null @@ -1,10 +0,0 @@ -find_path(STB_INCLUDE_DIR stb_image.h PATH_SUFFIXES stb) - -include(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS( - STB - REQUIRED_VARS STB_INCLUDE_DIR -) - - diff --git a/cmake/modules/FindStbImage.cmake b/cmake/modules/FindStbImage.cmake new file mode 100644 index 00000000..307b79fe --- /dev/null +++ b/cmake/modules/FindStbImage.cmake @@ -0,0 +1,18 @@ +find_path(STB_IMAGE_INCLUDE_DIR stb_image.h PATH_SUFFIXES stb) + +find_path(STB_IMAGE_RESIZE2_INCLUDE_DIR stb_image_resize2.h PATH_SUFFIXES stb) +if(STB_IMAGE_RESIZE2_INCLUDE_DIR) + set(STB_IMAGE_RESIZE_VERSION 2) +else() + find_path(STB_IMAGE_RESIZE_INCLUDE_DIR stb_image_resize.h PATH_SUFFIXES stb) + if(STB_IMAGE_RESIZE_INCLUDE_DIR) + set(STB_IMAGE_RESIZE_VERSION 1) + endif() +endif() + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + StbImage + REQUIRED_VARS STB_IMAGE_INCLUDE_DIR STB_IMAGE_RESIZE_VERSION +) diff --git a/src/libs/av/CMakeLists.txt b/src/libs/av/CMakeLists.txt index 3db2d5e7..be2bd834 100644 --- a/src/libs/av/CMakeLists.txt +++ b/src/libs/av/CMakeLists.txt @@ -1,3 +1,4 @@ +pkg_check_modules(LIBAV IMPORTED_TARGET libavcodec libavutil libavformat) add_library(lmsav SHARED impl/AudioFile.cpp @@ -27,4 +28,3 @@ target_link_libraries(lmsav PRIVATE ) install(TARGETS lmsav DESTINATION ${CMAKE_INSTALL_LIBDIR}) - diff --git a/src/libs/core/CMakeLists.txt b/src/libs/core/CMakeLists.txt index c8b5ff50..7e22c4be 100644 --- a/src/libs/core/CMakeLists.txt +++ b/src/libs/core/CMakeLists.txt @@ -1,3 +1,6 @@ +pkg_check_modules(Config++ REQUIRED IMPORTED_TARGET libconfig++) +pkg_check_modules(Archive REQUIRED IMPORTED_TARGET libarchive) + add_library(lmscore SHARED impl/http/Client.cpp impl/http/SendQueue.cpp diff --git a/src/libs/image/CMakeLists.txt b/src/libs/image/CMakeLists.txt index f6228210..586b038b 100644 --- a/src/libs/image/CMakeLists.txt +++ b/src/libs/image/CMakeLists.txt @@ -17,23 +17,33 @@ target_link_libraries(lmsimage PUBLIC std::filesystem ) -if (IMAGE_LIBRARY STREQUAL STB) +set(LMS_IMAGE_BACKEND "stb" CACHE STRING "Image library") +set_property(CACHE LMS_IMAGE_BACKEND PROPERTY STRINGS "stb" "graphicsmagick") + +if (${LMS_IMAGE_BACKEND} STREQUAL "stb") + find_package(StbImage REQUIRED) + message(STATUS "Using stb (resize version ${STB_IMAGE_RESIZE_VERSION})") + target_sources(lmsimage PRIVATE impl/stb/JPEGImage.cpp impl/stb/RawImage.cpp - ) - target_compile_options(lmsimage PRIVATE "-DLMS_SUPPORT_IMAGE_STB") - target_include_directories(lmsimage PRIVATE ${STB_INCLUDE_DIR}) -elseif (IMAGE_LIBRARY STREQUAL GraphicsMagick++) + ) + target_compile_options(lmsimage PRIVATE "-DSTB_IMAGE_RESIZE_VERSION=${STB_IMAGE_RESIZE_VERSION}") + target_include_directories(lmsimage PRIVATE ${STB_IMAGE_INCLUDE_DIR}) + +elseif (${LMS_IMAGE_BACKEND} STREQUAL "graphicsmagick") + pkg_check_modules(GraphicsMagick++ REQUIRED IMPORTED_TARGET GraphicsMagick++) + message(STATUS "Using graphicsmagick") + target_sources(lmsimage PRIVATE impl/graphicsmagick/JPEGImage.cpp impl/graphicsmagick/RawImage.cpp - ) - target_compile_options(lmsimage PRIVATE "-DLMS_SUPPORT_IMAGE_GM") + ) target_link_libraries(lmsimage PRIVATE PkgConfig::GraphicsMagick++) + else () - message(FATAL_ERROR "Invalid IMAGE_LIBRARY provided") -endif() + message(FATAL_ERROR "Invalid image library") +endif () install(TARGETS lmsimage DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/libs/image/impl/graphicsmagick/JPEGImage.hpp b/src/libs/image/impl/graphicsmagick/JPEGImage.hpp index cc2e6b37..934d2ed5 100644 --- a/src/libs/image/impl/graphicsmagick/JPEGImage.hpp +++ b/src/libs/image/impl/graphicsmagick/JPEGImage.hpp @@ -19,10 +19,6 @@ #pragma once -#ifndef LMS_SUPPORT_IMAGE_GM -#error "Bad configuration" -#endif - #include #include "image/IEncodedImage.hpp" diff --git a/src/libs/image/impl/graphicsmagick/RawImage.hpp b/src/libs/image/impl/graphicsmagick/RawImage.hpp index 2055f285..d65813e1 100644 --- a/src/libs/image/impl/graphicsmagick/RawImage.hpp +++ b/src/libs/image/impl/graphicsmagick/RawImage.hpp @@ -19,10 +19,6 @@ #pragma once -#ifndef LMS_SUPPORT_IMAGE_GM -#error "Bad configuration" -#endif - #include #include diff --git a/src/libs/image/impl/stb/RawImage.cpp b/src/libs/image/impl/stb/RawImage.cpp index c55164f0..28608217 100644 --- a/src/libs/image/impl/stb/RawImage.cpp +++ b/src/libs/image/impl/stb/RawImage.cpp @@ -28,7 +28,13 @@ #define STBI_FAILURE_USERMSG #include +#if STB_IMAGE_RESIZE_VERSION == 1 #include +#elif STB_IMAGE_RESIZE_VERSION == 2 +#include +#else +#error "Unhandled STB image resize version"! +#endif #include "core/ITraceLogger.hpp" #include "image/Exception.hpp" @@ -94,9 +100,17 @@ namespace lms::image::STB if (!resizedData) throw Exception{ "Cannot allocate memory for resized image!" }; +#if STB_IMAGE_RESIZE_VERSION == 1 if (::stbir_resize_uint8_srgb(reinterpret_cast(_data.get()), _width, _height, 0, reinterpret_cast(resizedData.get()), width, height, 0, 3, STBIR_ALPHA_CHANNEL_NONE, 0) == 0) +#elif STB_IMAGE_RESIZE_VERSION == 2 + if (::stbir_resize_uint8_srgb(reinterpret_cast(_data.get()), _width, _height, 0, + reinterpret_cast(resizedData.get()), width, height, 0, + STBIR_RGB) == 0) +#else + #error "Unhandled STB image resize version"! +#endif { throw Exception{ "Failed to resize image:" + std::string{ ::stbi_failure_reason() } }; } diff --git a/src/libs/image/impl/stb/RawImage.hpp b/src/libs/image/impl/stb/RawImage.hpp index 4bef16d5..d4788d4d 100644 --- a/src/libs/image/impl/stb/RawImage.hpp +++ b/src/libs/image/impl/stb/RawImage.hpp @@ -19,10 +19,6 @@ #pragma once -#ifndef LMS_SUPPORT_IMAGE_STB -#error "Bad configuration" -#endif - #include #include diff --git a/src/libs/metadata/CMakeLists.txt b/src/libs/metadata/CMakeLists.txt index 7d4b39bb..e8f84c24 100644 --- a/src/libs/metadata/CMakeLists.txt +++ b/src/libs/metadata/CMakeLists.txt @@ -1,3 +1,4 @@ +pkg_check_modules(Taglib REQUIRED IMPORTED_TARGET taglib) if(BUILD_TESTING) add_subdirectory(test) diff --git a/src/libs/services/auth/CMakeLists.txt b/src/libs/services/auth/CMakeLists.txt index 145c46fb..45c6557d 100644 --- a/src/libs/services/auth/CMakeLists.txt +++ b/src/libs/services/auth/CMakeLists.txt @@ -27,6 +27,22 @@ target_link_libraries(lmsauth PUBLIC Boost::system Wt::Wt ) + +# PAM +option(USE_PAM "Use the PAM backend authentication API" ON) +if (USE_PAM) + find_package(PAM QUIET) + if (USE_PAM AND NOT PAM_FOUND) + message(WARNING "PAM library not found: disabling") + set(USE_PAM OFF) + endif () +endif () + +if (USE_PAM) + message(STATUS "Using PAM authentication backend") +else () + message(STATUS "NOT using PAM authentication backend") +endif () if (USE_PAM) target_compile_options(lmsauth PRIVATE "-DLMS_SUPPORT_PAM") From bb70c6dbafe35c9978d6842222100c1511fb534e Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 27 Apr 2024 16:36:51 +0200 Subject: [PATCH 02/21] Added a way to visit users --- src/libs/database/impl/User.cpp | 12 +++++ src/libs/database/include/database/User.hpp | 1 + src/libs/database/test/CMakeLists.txt | 1 + src/libs/database/test/User.cpp | 53 +++++++++++++++++++++ 4 files changed, 67 insertions(+) create mode 100644 src/libs/database/test/User.cpp diff --git a/src/libs/database/impl/User.cpp b/src/libs/database/impl/User.cpp index cf5b356b..97efe9d8 100644 --- a/src/libs/database/impl/User.cpp +++ b/src/libs/database/impl/User.cpp @@ -61,6 +61,18 @@ namespace lms::db return utils::execRangeQuery(query, params.range); } + void User::find(Session& session, const FindParameters& params, const std::function& func) + { + auto query{ session.getDboSession()->find() }; + + if (params.scrobblingBackend) + query.where("scrobbling_backend = ?").bind(*params.scrobblingBackend); + if (params.feedbackBackend) + query.where("feedback_backend = ?").bind(*params.feedbackBackend); + + return utils::forEachQueryRangeResult(query, params.range, func); + } + User::pointer User::findDemoUser(Session& session) { session.checkReadTransaction(); diff --git a/src/libs/database/include/database/User.hpp b/src/libs/database/include/database/User.hpp index 9965c277..aa5e00df 100644 --- a/src/libs/database/include/database/User.hpp +++ b/src/libs/database/include/database/User.hpp @@ -72,6 +72,7 @@ namespace lms::db static pointer find(Session& session, UserId id); static pointer find(Session& session, std::string_view loginName); static RangeResults find(Session& session, const FindParameters& params); + static void find(Session& session, const FindParameters& params, const std::function& func); static pointer findDemoUser(Session& session); // accessors diff --git a/src/libs/database/test/CMakeLists.txt b/src/libs/database/test/CMakeLists.txt index 99bbf7b7..4ce77ebe 100644 --- a/src/libs/database/test/CMakeLists.txt +++ b/src/libs/database/test/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(test-database TrackBookmark.cpp TrackFeatures.cpp TrackList.cpp + User.cpp ) target_link_libraries(test-database PRIVATE diff --git a/src/libs/database/test/User.cpp b/src/libs/database/test/User.cpp new file mode 100644 index 00000000..039e485c --- /dev/null +++ b/src/libs/database/test/User.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 Emeric Poupon + * + * This file is part of LMS. + * + * LMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * LMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LMS. If not, see . + */ + +#include "Common.hpp" + +namespace lms::db::tests +{ + TEST_F(DatabaseFixture, User) + { + { + auto transaction{ session.createReadTransaction() }; + + bool visited{}; + User::find(session, User::FindParameters{}, [&](const User::pointer&) + { + visited = true; + }); + EXPECT_FALSE(visited); + } + + ScopedUser user1{ session, "MyUser1" }; + ScopedUser user2{ session, "MyUser2" }; + + { + auto transaction{ session.createReadTransaction() }; + + std::vector visitedUsers; + User::find(session, User::FindParameters{}, [&](const User::pointer& user) + { + visitedUsers.push_back(user->getId()); + }); + EXPECT_EQ(visitedUsers.size(), 2); + EXPECT_EQ(visitedUsers[0], user1->getId()); + EXPECT_EQ(visitedUsers[1], user2->getId()); + } + } +} \ No newline at end of file From fcb5b11f8193f19e6f46d04ef5a22eea4d9a5876 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 27 Apr 2024 16:43:28 +0200 Subject: [PATCH 03/21] Using visit to enumerate users --- src/lms/ui/admin/UsersView.cpp | 98 +++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/lms/ui/admin/UsersView.cpp b/src/lms/ui/admin/UsersView.cpp index 86ec57a1..c5340974 100644 --- a/src/lms/ui/admin/UsersView.cpp +++ b/src/lms/ui/admin/UsersView.cpp @@ -71,66 +71,66 @@ namespace lms::ui auto transaction{ LmsApp->getDbSession().createReadTransaction() }; - const User::IdType currentUserId{ LmsApp->getUser() }; - for (const UserId userId : User::find(LmsApp->getDbSession(), User::FindParameters{}).results) - { - const User::pointer user{ User::find(LmsApp->getDbSession(), userId) }; - - Wt::WTemplate* entry{ _container->addNew(Wt::WString::tr("Lms.Admin.Users.template.entry")) }; - - entry->bindString("name", user->getLoginName(), Wt::TextFormat::Plain); - - // Create tag - if (user->isAdmin() || user->isDemo()) + const UserId currentUserId{ LmsApp->getUserId() }; + User::find(LmsApp->getDbSession(), User::FindParameters{}, [&](const User::pointer& user) { - entry->setCondition("if-tag", true); - entry->bindString("tag", Wt::WString::tr(user->isAdmin() ? "Lms.Admin.Users.admin" : "Lms.Admin.Users.demo")); - } + const UserId userId{ user->getId() }; - // Don't edit ourself this way - if (user->getId() == currentUserId) - continue; + Wt::WTemplate* entry{ _container->addNew(Wt::WString::tr("Lms.Admin.Users.template.entry")) }; - entry->setCondition("if-edit", true); - Wt::WPushButton* editBtn = entry->bindNew("edit-btn", Wt::WString::tr("Lms.template.edit-btn"), Wt::TextFormat::XHTML); - editBtn->setToolTip(Wt::WString::tr("Lms.edit")); - editBtn->clicked().connect([=]() + entry->bindString("name", user->getLoginName(), Wt::TextFormat::Plain); + + // Create tag + if (user->isAdmin() || user->isDemo()) { - LmsApp->setInternalPath("/admin/user/" + userId.toString(), true); - }); + entry->setCondition("if-tag", true); + entry->bindString("tag", Wt::WString::tr(user->isAdmin() ? "Lms.Admin.Users.admin" : "Lms.Admin.Users.demo")); + } - Wt::WPushButton* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML); - delBtn->setToolTip(Wt::WString::tr("Lms.delete")); - delBtn->clicked().connect([this, userId, entry] - { - auto modal{ std::make_unique(Wt::WString::tr("Lms.Admin.Users.template.delete-user")) }; - modal->addFunction("tr", &Wt::WTemplate::Functions::tr); - Wt::WWidget* modalPtr{ modal.get() }; + // Don't edit ourself this way + if (user->getId() == currentUserId) + return; - auto* delBtn{ modal->bindNew("del-btn", Wt::WString::tr("Lms.delete")) }; - delBtn->clicked().connect([=, this] - { + entry->setCondition("if-edit", true); + Wt::WPushButton* editBtn = entry->bindNew("edit-btn", Wt::WString::tr("Lms.template.edit-btn"), Wt::TextFormat::XHTML); + editBtn->setToolTip(Wt::WString::tr("Lms.edit")); + editBtn->clicked().connect([userId]() + { + LmsApp->setInternalPath("/admin/user/" + userId.toString(), true); + }); + + Wt::WPushButton* delBtn = entry->bindNew("del-btn", Wt::WString::tr("Lms.template.trash-btn"), Wt::TextFormat::XHTML); + delBtn->setToolTip(Wt::WString::tr("Lms.delete")); + delBtn->clicked().connect([this, userId, entry] + { + auto modal{ std::make_unique(Wt::WString::tr("Lms.Admin.Users.template.delete-user")) }; + modal->addFunction("tr", &Wt::WTemplate::Functions::tr); + Wt::WWidget* modalPtr{ modal.get() }; + + auto* delBtn{ modal->bindNew("del-btn", Wt::WString::tr("Lms.delete")) }; + delBtn->clicked().connect([=, this] { - auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; + { + auto transaction{ LmsApp->getDbSession().createWriteTransaction() }; - User::pointer user{ User::find(LmsApp->getDbSession(), userId) }; - if (user) - user.remove(); - } + User::pointer user{ User::find(LmsApp->getDbSession(), userId) }; + if (user) + user.remove(); + } - _container->removeWidget(entry); + _container->removeWidget(entry); - LmsApp->getModalManager().dispose(modalPtr); - }); + LmsApp->getModalManager().dispose(modalPtr); + }); - auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; - cancelBtn->clicked().connect([=] - { - LmsApp->getModalManager().dispose(modalPtr); - }); + auto* cancelBtn{ modal->bindNew("cancel-btn", Wt::WString::tr("Lms.cancel")) }; + cancelBtn->clicked().connect([=] + { + LmsApp->getModalManager().dispose(modalPtr); + }); - LmsApp->getModalManager().show(std::move(modal)); - }); - } + LmsApp->getModalManager().show(std::move(modal)); + }); + }); } } // namespace lms::ui From edd407a6c948482bebec5a822108b78b47ec21e6 Mon Sep 17 00:00:00 2001 From: emeric Date: Sat, 27 Apr 2024 16:48:19 +0200 Subject: [PATCH 04/21] Cache user data in subsonic request (to simplify endpoints) --- .../services/auth/IPasswordService.hpp | 1 - src/libs/subsonic/impl/RequestContext.hpp | 5 +- src/libs/subsonic/impl/SubsonicResource.cpp | 20 +++--- src/libs/subsonic/impl/SubsonicResource.hpp | 1 + .../impl/entrypoints/AlbumSongLists.cpp | 42 ++++-------- .../subsonic/impl/entrypoints/Bookmarks.cpp | 18 ++--- .../subsonic/impl/entrypoints/Browsing.cpp | 65 +++++-------------- .../impl/entrypoints/MediaAnnotation.cpp | 19 +++--- .../impl/entrypoints/MediaRetrieval.cpp | 12 ++-- .../subsonic/impl/entrypoints/Playlists.cpp | 30 ++------- .../subsonic/impl/entrypoints/Searching.cpp | 10 +-- .../impl/entrypoints/UserManagement.cpp | 35 ++++------ 12 files changed, 87 insertions(+), 171 deletions(-) diff --git a/src/libs/services/auth/include/services/auth/IPasswordService.hpp b/src/libs/services/auth/include/services/auth/IPasswordService.hpp index d92c9386..9138e62c 100644 --- a/src/libs/services/auth/include/services/auth/IPasswordService.hpp +++ b/src/libs/services/auth/include/services/auth/IPasswordService.hpp @@ -37,7 +37,6 @@ namespace lms::db namespace lms::auth { - class IAuthTokenService; class IPasswordService diff --git a/src/libs/subsonic/impl/RequestContext.hpp b/src/libs/subsonic/impl/RequestContext.hpp index d751111c..03bf4ccc 100644 --- a/src/libs/subsonic/impl/RequestContext.hpp +++ b/src/libs/subsonic/impl/RequestContext.hpp @@ -23,13 +23,14 @@ #include -#include "database/UserId.hpp" +#include "database/Object.hpp" #include "ClientInfo.hpp" #include "ProtocolVersion.hpp" namespace lms::db { class Session; + class User; } namespace lms::api::subsonic @@ -38,7 +39,7 @@ namespace lms::api::subsonic { const Wt::Http::ParameterMap& parameters; db::Session& dbSession; - db::UserId userId; + const db::ObjectPtr user; ClientInfo clientInfo; ProtocolVersion serverProtocolVersion; bool enableOpenSubsonic{ true }; diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index b7330368..2e311628 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -135,13 +135,7 @@ namespace lms::api::subsonic void checkUserTypeIsAllowed(RequestContext& context, core::EnumSet allowedUserTypes) { - auto transaction{ context.dbSession.createReadTransaction() }; - - db::User::pointer currentUser{ db::User::find(context.dbSession, context.userId) }; - if (!currentUser) - throw RequestedDataNotFoundError{}; - - if (!allowedUserTypes.contains(currentUser->getType())) + if (!allowedUserTypes.contains(context.user->getType())) throw UserNotAuthorizedError{}; } @@ -421,7 +415,17 @@ namespace lms::api::subsonic bool enableOpenSubsonic{ _openSubsonicDisabledClients.find(clientInfo.name) == std::cend(_openSubsonicDisabledClients) }; bool enableDefaultCover{ _defaultCoverClients.find(clientInfo.name) != std::cend(_openSubsonicDisabledClients) }; - return { parameters, _db.getTLSSession(), userId, clientInfo, getServerProtocolVersion(clientInfo.name), enableOpenSubsonic, enableDefaultCover }; + db::User::pointer user; + { + db::Session& session{ _db.getTLSSession() }; + auto transaction{ session.createReadTransaction() }; + + user = db::User::find(session, userId); + if (!user) + throw UserNotAuthorizedError{}; + } + + return { parameters, _db.getTLSSession(), user, clientInfo, getServerProtocolVersion(clientInfo.name), enableOpenSubsonic, enableDefaultCover }; } db::UserId SubsonicResource::authenticateUser(const Wt::Http::Request& request, const ClientInfo& clientInfo) diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp index 67db9936..33b99054 100644 --- a/src/libs/subsonic/impl/SubsonicResource.hpp +++ b/src/libs/subsonic/impl/SubsonicResource.hpp @@ -26,6 +26,7 @@ #include #include "database/Types.hpp" +#include "database/UserId.hpp" #include "ClientInfo.hpp" #include "RequestContext.hpp" diff --git a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp index ec43f5d2..33495a61 100644 --- a/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp +++ b/src/libs/subsonic/impl/entrypoints/AlbumSongLists.cpp @@ -60,10 +60,6 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - if (type == "alphabeticalByName") { Release::FindParameters params; @@ -117,7 +113,7 @@ namespace lms::api::subsonic else if (type == "frequent") { scrobbling::IScrobblingService::FindParameters params; - params.setUser(context.userId); + params.setUser(context.user->getId()); params.setRange(range); params.setMediaLibrary(mediaLibraryId); @@ -146,7 +142,7 @@ namespace lms::api::subsonic else if (type == "recent") { scrobbling::IScrobblingService::FindParameters params; - params.setUser(context.userId); + params.setUser(context.user->getId()); params.setRange(range); params.setMediaLibrary(mediaLibraryId); @@ -155,7 +151,7 @@ namespace lms::api::subsonic else if (type == "starred") { feedback::IFeedbackService::FindParameters params; - params.setUser(context.userId); + params.setUser(context.user->getId()); params.setRange(range); params.setMediaLibrary(mediaLibraryId); @@ -172,7 +168,7 @@ namespace lms::api::subsonic for (const ReleaseId releaseId : releases.results) { const Release::pointer release{ Release::find(context.dbSession, releaseId) }; - albumListNode.addArrayChild("album", createAlbumNode(context, release, user, id3)); + albumListNode.addArrayChild("album", createAlbumNode(context, release, context.user, id3)); } return response; @@ -185,10 +181,6 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& starredNode{ response.createNode(id3 ? Response::Node::Key{ "starred2" } : Response::Node::Key{ "starred" }) }; @@ -196,29 +188,29 @@ namespace lms::api::subsonic { feedback::IFeedbackService::ArtistFindParameters artistFindParams; - artistFindParams.setUser(context.userId); + artistFindParams.setUser(context.user->getId()); artistFindParams.setSortMethod(ArtistSortMethod::SortName); for (const ArtistId artistId : feedbackService.findStarredArtists(artistFindParams).results) { if (auto artist{ Artist::find(context.dbSession, artistId) }) - starredNode.addArrayChild("artist", createArtistNode(context, artist, user, id3)); + starredNode.addArrayChild("artist", createArtistNode(context, artist, context.user, id3)); } } feedback::IFeedbackService::FindParameters findParameters; - findParameters.setUser(context.userId); + findParameters.setUser(context.user->getId()); findParameters.setMediaLibrary(mediaLibrary); for (const ReleaseId releaseId : feedbackService.findStarredReleases(findParameters).results) { if (auto release{ Release::find(context.dbSession, releaseId) }) - starredNode.addArrayChild("album", createAlbumNode(context, release, user, id3)); + starredNode.addArrayChild("album", createAlbumNode(context, release, context.user, id3)); } for (const TrackId trackId : feedbackService.findStarredTracks(findParameters).results) { if (auto track{ Track::find(context.dbSession, trackId) }) - starredNode.addArrayChild("song", createSongNode(context, track, user)); + starredNode.addArrayChild("song", createSongNode(context, track, context.user)); } return response; @@ -243,15 +235,11 @@ namespace lms::api::subsonic if (size > defaultMaxCountSize) throw ParameterValueTooHighGenericError{ "size", defaultMaxCountSize }; - auto transaction{ context.dbSession.createReadTransaction() }; - - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& randomSongsNode{ response.createNode("randomSongs") }; + auto transaction{ context.dbSession.createReadTransaction() }; + Track::FindParameters params; params.setSortMethod(TrackSortMethod::Random); params.setRange(Range{ 0, size }); @@ -259,7 +247,7 @@ namespace lms::api::subsonic Track::find(context.dbSession, params, [&](const Track::pointer& track) { - randomSongsNode.addArrayChild("song", createSongNode(context, track, user)); + randomSongsNode.addArrayChild("song", createSongNode(context, track, context.user)); }); return response; @@ -288,10 +276,6 @@ namespace lms::api::subsonic if (!cluster) throw RequestedDataNotFoundError{}; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& songsByGenreNode{ response.createNode("songsByGenre") }; @@ -302,7 +286,7 @@ namespace lms::api::subsonic Track::find(context.dbSession, params, [&](const Track::pointer& track) { - songsByGenreNode.addArrayChild("song", createSongNode(context, track, user)); + songsByGenreNode.addArrayChild("song", createSongNode(context, track, context.user)); }); return response; diff --git a/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp b/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp index 91785a0e..98f1a644 100644 --- a/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp +++ b/src/libs/subsonic/impl/entrypoints/Bookmarks.cpp @@ -36,11 +36,7 @@ namespace lms::api::subsonic { auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - - const auto bookmarkIds{ TrackBookmark::find(context.dbSession, user->getId()) }; + const auto bookmarkIds{ TrackBookmark::find(context.dbSession, context.user->getId()) }; Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& bookmarksNode{ response.createNode("bookmarks") }; @@ -49,7 +45,7 @@ namespace lms::api::subsonic { const TrackBookmark::pointer bookmark{ TrackBookmark::find(context.dbSession, bookmarkId) }; Response::Node bookmarkNode{ createBookmarkNode(bookmark) }; - bookmarkNode.addChild("entry", createSongNode(context, bookmark->getTrack(), user)); + bookmarkNode.addChild("entry", createSongNode(context, bookmark->getTrack(), context.user)); bookmarksNode.addArrayChild("bookmark", std::move(bookmarkNode)); } @@ -65,18 +61,14 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createWriteTransaction() }; - const User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - const Track::pointer track{ Track::find(context.dbSession, trackId) }; if (!track) throw RequestedDataNotFoundError{}; // Replace any existing bookmark - auto bookmark{ TrackBookmark::find(context.dbSession, user->getId(), trackId) }; + auto bookmark{ TrackBookmark::find(context.dbSession, context.user->getId(), trackId) }; if (!bookmark) - bookmark = context.dbSession.create(user, track); + bookmark = context.dbSession.create(context.user, track); bookmark.modify()->setOffset(std::chrono::milliseconds{ position }); if (comment) @@ -92,7 +84,7 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createWriteTransaction() }; - auto bookmark{ TrackBookmark::find(context.dbSession, context.userId, trackId) }; + auto bookmark{ TrackBookmark::find(context.dbSession, context.user->getId(), trackId) }; if (!bookmark) throw RequestedDataNotFoundError{}; diff --git a/src/libs/subsonic/impl/entrypoints/Browsing.cpp b/src/libs/subsonic/impl/entrypoints/Browsing.cpp index 19d4777b..a1d37584 100644 --- a/src/libs/subsonic/impl/entrypoints/Browsing.cpp +++ b/src/libs/subsonic/impl/entrypoints/Browsing.cpp @@ -75,15 +75,11 @@ namespace lms::api::subsonic { auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - for (const ArtistId similarArtistId : similarArtistsId) { const Artist::pointer similarArtist{ Artist::find(context.dbSession, similarArtistId) }; if (similarArtist) - artistInfoNode.addArrayChild("similarArtist", createArtistNode(context, similarArtist, user, id3)); + artistInfoNode.addArrayChild("similarArtist", createArtistNode(context, similarArtist, context.user, id3)); } } @@ -105,12 +101,8 @@ namespace lms::api::subsonic { auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - parameters.setSortMethod(ArtistSortMethod::SortName); - switch (user->getSubsonicArtistListMode()) + switch (context.user->getSubsonicArtistListMode()) { case SubsonicArtistListMode::AllArtists: break; @@ -165,12 +157,9 @@ namespace lms::api::subsonic for (const ArtistId artistId : artistIds) { auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; if (const Artist::pointer artist{ Artist::find(context.dbSession, artistId) }) - indexNode.addArrayChild("artist", createArtistNode(context, artist, user, id3)); + indexNode.addArrayChild("artist", createArtistNode(context, artist, context.user, id3)); } } @@ -265,16 +254,12 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& similarSongsNode{ response.createNode(id3 ? Response::Node::Key{ "similarSongs2" } : Response::Node::Key{ "similarSongs" }) }; for (const TrackId trackId : tracks) { const Track::pointer track{ Track::find(context.dbSession, trackId) }; - similarSongsNode.addArrayChild("song", createSongNode(context, track, user)); + similarSongsNode.addArrayChild("song", createSongNode(context, track, context.user)); } return response; @@ -319,10 +304,6 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - if (root) { directoryNode.setAttribute("id", idToString(RootId{})); @@ -331,7 +312,7 @@ namespace lms::api::subsonic // TODO: this does not scale when a lot of artists are present Artist::find(context.dbSession, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::SortName), [&](const Artist::pointer& artist) { - directoryNode.addArrayChild("child", createArtistNode(context, artist, user, false /* no id3 */)); + directoryNode.addArrayChild("child", createArtistNode(context, artist, context.user, false /* no id3 */)); }); } else if (artistId) @@ -346,7 +327,7 @@ namespace lms::api::subsonic Release::find(context.dbSession, Release::FindParameters{}.setArtist(*artistId), [&](const Release::pointer& release) { - directoryNode.addArrayChild("child", createAlbumNode(context, release, user, false /* no id3 */)); + directoryNode.addArrayChild("child", createAlbumNode(context, release, context.user, false /* no id3 */)); }); } else if (releaseId) @@ -361,7 +342,7 @@ namespace lms::api::subsonic Track::find(context.dbSession, Track::FindParameters{}.setRelease(*releaseId).setSortMethod(TrackSortMethod::Release), [&](const Track::pointer& track) { - directoryNode.addArrayChild("child", createSongNode(context, track, user)); + directoryNode.addArrayChild("child", createSongNode(context, track, context.user)); }); } else @@ -406,16 +387,12 @@ namespace lms::api::subsonic if (!artist) throw RequestedDataNotFoundError{}; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; - Response::Node artistNode{ createArtistNode(context, artist, user, true /* id3 */) }; + Response::Node artistNode{ createArtistNode(context, artist, context.user, true /* id3 */) }; const auto releases{ Release::find(context.dbSession, Release::FindParameters {}.setArtist(artist->getId())) }; for (const Release::pointer& release : releases.results) - artistNode.addArrayChild("album", createAlbumNode(context, release, user, true /* id3 */)); + artistNode.addArrayChild("album", createAlbumNode(context, release, context.user, true /* id3 */)); response.addNode("artist", std::move(artistNode)); @@ -433,16 +410,12 @@ namespace lms::api::subsonic if (!release) throw RequestedDataNotFoundError{}; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; - Response::Node albumNode{ createAlbumNode(context, release, user, true /* id3 */) }; + Response::Node albumNode{ createAlbumNode(context, release, context.user, true /* id3 */) }; - const auto tracks{ Track::find(context.dbSession, Track::FindParameters {}.setRelease(id).setSortMethod(TrackSortMethod::Release)) }; + const auto tracks{ Track::find(context.dbSession, Track::FindParameters{}.setRelease(id).setSortMethod(TrackSortMethod::Release)) }; for (const Track::pointer& track : tracks.results) - albumNode.addArrayChild("song", createSongNode(context, track, user)); + albumNode.addArrayChild("song", createSongNode(context, track, context.user)); response.addNode("album", std::move(albumNode)); @@ -460,12 +433,8 @@ namespace lms::api::subsonic if (!track) throw RequestedDataNotFoundError{}; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; - response.addNode("song", createSongNode(context, track, user)); + response.addNode("song", createSongNode(context, track, context.user)); return response; } @@ -504,15 +473,11 @@ namespace lms::api::subsonic if (artists.size() != 1) throw RequestedDataNotFoundError{}; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& topSongs{ response.createNode("topSongs") }; scrobbling::IScrobblingService::FindParameters params; - params.setUser(context.userId); + params.setUser(context.user->getId()); params.setRange(db::Range{ 0, count }); params.setArtist(artists.front()->getId()); @@ -520,7 +485,7 @@ namespace lms::api::subsonic for (const TrackId trackId : trackIds.results) { if (Track::pointer track{ Track::find(context.dbSession, trackId) }) - topSongs.addArrayChild("song", createSongNode(context, track, user)); + topSongs.addArrayChild("song", createSongNode(context, track, context.user)); } return response; diff --git a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp index 17924076..27a537c1 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp +++ b/src/libs/subsonic/impl/entrypoints/MediaAnnotation.cpp @@ -24,6 +24,7 @@ #include "database/ArtistId.hpp" #include "database/ReleaseId.hpp" #include "database/TrackId.hpp" +#include "database/User.hpp" #include "services/feedback/IFeedbackService.hpp" #include "services/scrobbling/IScrobblingService.hpp" #include "core/Service.hpp" @@ -61,13 +62,13 @@ namespace lms::api::subsonic StarParameters params{ getStarParameters(context.parameters) }; for (const ArtistId id : params.artistIds) - core::Service::get()->star(context.userId, id); + core::Service::get()->star(context.user->getId(), id); for (const ReleaseId id : params.releaseIds) - core::Service::get()->star(context.userId, id); + core::Service::get()->star(context.user->getId(), id); for (const TrackId id : params.trackIds) - core::Service::get()->star(context.userId, id); + core::Service::get()->star(context.user->getId(), id); return Response::createOkResponse(context.serverProtocolVersion); } @@ -77,13 +78,13 @@ namespace lms::api::subsonic StarParameters params{ getStarParameters(context.parameters) }; for (const ArtistId id : params.artistIds) - core::Service::get()->unstar(context.userId, id); + core::Service::get()->unstar(context.user->getId(), id); for (const ReleaseId id : params.releaseIds) - core::Service::get()->unstar(context.userId, id); + core::Service::get()->unstar(context.user->getId(), id); for (const TrackId id : params.trackIds) - core::Service::get()->unstar(context.userId, id); + core::Service::get()->unstar(context.user->getId(), id); return Response::createOkResponse(context.serverProtocolVersion); } @@ -104,13 +105,13 @@ namespace lms::api::subsonic if (!submission) { - core::Service::get()->listenStarted({ context.userId, ids.front() }); + core::Service::get()->listenStarted({ context.user->getId(), ids.front() }); } else { if (times.empty()) { - core::Service::get()->listenFinished({ context.userId, ids.front() }); + core::Service::get()->listenFinished({ context.user->getId(), ids.front() }); } else { @@ -118,7 +119,7 @@ namespace lms::api::subsonic { const TrackId trackId{ ids[i] }; const unsigned long time{ times[i] }; - core::Service::get()->addTimedListen({ {context.userId, trackId}, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) }); + core::Service::get()->addTimedListen({ {context.user->getId(), trackId}, Wt::WDateTime::fromTime_t(static_cast(time / 1000)) }); } } } diff --git a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp index b0f9b5d3..843cbd0c 100644 --- a/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp +++ b/src/libs/subsonic/impl/entrypoints/MediaRetrieval.cpp @@ -129,10 +129,6 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - const User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - const auto track{ Track::find(context.dbSession, id) }; if (!track) throw RequestedDataNotFoundError{}; @@ -147,8 +143,8 @@ namespace lms::api::subsonic std::optional requestedFormat{ subsonicStreamFormatToAvOutputFormat(format) }; if (!requestedFormat) { - if (user->getSubsonicEnableTranscodingByDefault()) - requestedFormat = userTranscodeFormatToAvFormat(user->getSubsonicDefaultTranscodingOutputFormat()); + if (context.user->getSubsonicEnableTranscodingByDefault()) + requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat()); } if (!requestedFormat && (maxBitRate == 0 || track->getBitrate() <= maxBitRate )) @@ -172,9 +168,9 @@ namespace lms::api::subsonic } if (!requestedFormat) - requestedFormat = userTranscodeFormatToAvFormat(user->getSubsonicDefaultTranscodingOutputFormat()); + requestedFormat = userTranscodeFormatToAvFormat(context.user->getSubsonicDefaultTranscodingOutputFormat()); if (!bitrate) - bitrate = std::min(user->getSubsonicDefaultTranscodingOutputBitrate(), maxBitRate); + bitrate = std::min(context.user->getSubsonicDefaultTranscodingOutputBitrate(), maxBitRate); av::transcoding::OutputParameters& outputParameters{ parameters.outputParameters.emplace() }; diff --git a/src/libs/subsonic/impl/entrypoints/Playlists.cpp b/src/libs/subsonic/impl/entrypoints/Playlists.cpp index d27e7be3..520e2d9e 100644 --- a/src/libs/subsonic/impl/entrypoints/Playlists.cpp +++ b/src/libs/subsonic/impl/entrypoints/Playlists.cpp @@ -40,7 +40,7 @@ namespace lms::api::subsonic Response::Node& playlistsNode{ response.createNode("playlists") }; TrackList::FindParameters params; - params.setUser(context.userId); + params.setUser(context.user->getId()); params.setType(TrackListType::Playlist); auto tracklistIds{ TrackList::find(context.dbSession, params) }; @@ -60,10 +60,6 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - TrackList::pointer tracklist{ TrackList::find(context.dbSession, trackListId) }; if (!tracklist) throw RequestedDataNotFoundError{}; @@ -73,7 +69,7 @@ namespace lms::api::subsonic auto entries{ tracklist->getEntries() }; for (const TrackListEntry::pointer& entry : entries.results) - playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user)); + playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.user)); response.addNode("playlist", std::move(playlistNode)); @@ -93,16 +89,12 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createWriteTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - TrackList::pointer tracklist; if (id) { tracklist = TrackList::find(context.dbSession, *id); if (!tracklist - || tracklist->getUser() != user + || tracklist->getUser() != context.user || tracklist->getType() != TrackListType::Playlist) { throw RequestedDataNotFoundError{}; @@ -113,7 +105,7 @@ namespace lms::api::subsonic } else { - tracklist = context.dbSession.create(*name, TrackListType::Playlist, false, user); + tracklist = context.dbSession.create(*name, TrackListType::Playlist, false, context.user); } for (const TrackId trackId : trackIds) @@ -130,7 +122,7 @@ namespace lms::api::subsonic auto entries{ tracklist->getEntries() }; for (const TrackListEntry::pointer& entry : entries.results) - playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), user)); + playlistNode.addArrayChild("entry", createSongNode(context, entry->getTrack(), context.user)); response.addNode("playlist", std::move(playlistNode)); @@ -151,13 +143,9 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createWriteTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - TrackList::pointer tracklist{ TrackList::find(context.dbSession, id) }; if (!tracklist - || tracklist->getUser() != user + || tracklist->getUser() != context.user || tracklist->getType() != TrackListType::Playlist) { throw RequestedDataNotFoundError{}; @@ -200,13 +188,9 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createWriteTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - TrackList::pointer tracklist{ TrackList::find(context.dbSession, id) }; if (!tracklist - || tracklist->getUser() != user + || tracklist->getUser() != context.user || tracklist->getType() != TrackListType::Playlist) { throw RequestedDataNotFoundError{}; diff --git a/src/libs/subsonic/impl/entrypoints/Searching.cpp b/src/libs/subsonic/impl/entrypoints/Searching.cpp index 6d672428..743be7ed 100644 --- a/src/libs/subsonic/impl/entrypoints/Searching.cpp +++ b/src/libs/subsonic/impl/entrypoints/Searching.cpp @@ -334,13 +334,9 @@ namespace lms::api::subsonic auto transaction{ context.dbSession.createReadTransaction() }; - User::pointer user{ User::find(context.dbSession, context.userId) }; - if (!user) - throw UserNotAuthorizedError{}; - - findRequestedArtists(context, id3, keywords, mediaLibrary, user, searchResultNode); - findRequestedAlbums(context, id3, keywords, mediaLibrary, user, searchResultNode); - findRequestedTracks(context, keywords, mediaLibrary, user, searchResultNode); + findRequestedArtists(context, id3, keywords, mediaLibrary, context.user, searchResultNode); + findRequestedAlbums(context, id3, keywords, mediaLibrary, context.user, searchResultNode); + findRequestedTracks(context, keywords, mediaLibrary, context.user, searchResultNode); return response; } diff --git a/src/libs/subsonic/impl/entrypoints/UserManagement.cpp b/src/libs/subsonic/impl/entrypoints/UserManagement.cpp index fb079ce4..e9576a78 100644 --- a/src/libs/subsonic/impl/entrypoints/UserManagement.cpp +++ b/src/libs/subsonic/impl/entrypoints/UserManagement.cpp @@ -15,11 +15,7 @@ namespace lms::api::subsonic namespace { void checkUserIsMySelfOrAdmin(RequestContext& context, const std::string& username) { - User::pointer currentUser{ User::find(context.dbSession, context.userId) }; - if (!currentUser) - throw RequestedDataNotFoundError{}; - - if (currentUser->getLoginName() != username && !currentUser->isAdmin()) + if (context.user->getLoginName() != username && !context.user->isAdmin()) throw UserNotAuthorizedError{}; } } @@ -44,17 +40,14 @@ namespace lms::api::subsonic Response handleGetUsersRequest(RequestContext& context) { - auto transaction{ context.dbSession.createReadTransaction() }; - Response response{ Response::createOkResponse(context.serverProtocolVersion) }; Response::Node& usersNode{ response.createNode("users") }; - const auto userIds{ User::find(context.dbSession, User::FindParameters {}) }; - for (const UserId userId : userIds.results) - { - const User::pointer user{ User::find(context.dbSession, userId) }; - usersNode.addArrayChild("user", createUserNode(user)); - } + auto transaction{ context.dbSession.createReadTransaction() }; + User::find(context.dbSession, User::FindParameters{}, [&](const User::pointer& user) + { + usersNode.addArrayChild("user", createUserNode(user)); + }); return response; } @@ -77,13 +70,13 @@ namespace lms::api::subsonic userId = user->getId(); } - auto removeCreatedUser{ [&]() - { - auto transaction {context.dbSession.createWriteTransaction()}; - User::pointer user {User::find(context.dbSession, userId)}; - if (user) - user.remove(); - } }; + auto removeCreatedUser{ [&] + { + auto transaction {context.dbSession.createWriteTransaction()}; + User::pointer user{ User::find(context.dbSession, userId) }; + if (user) + user.remove(); + } }; try { @@ -119,7 +112,7 @@ namespace lms::api::subsonic throw RequestedDataNotFoundError{}; // cannot delete ourself - if (user->getId() == context.userId) + if (user->getId() == context.user->getId()) throw UserNotAuthorizedError{}; user.remove(); From 83c71ee90cda0dfa50586992c1452070ab0271e1 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 28 Apr 2024 23:07:36 +0200 Subject: [PATCH 05/21] UI: restored margin around notification toasts --- approot/notifications.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/approot/notifications.xml b/approot/notifications.xml index a353b77f..38686090 100644 --- a/approot/notifications.xml +++ b/approot/notifications.xml @@ -2,7 +2,7 @@ -