~aleteoryx/muditaos

790c746ae1362439570525dfd81f85d4e46f0f2d — Maciej Gibowicz 10 months ago 85bd217
[BH-2096] Add quote group setting

Adding a new endpoint for communication with Center;
Modification of randomization algorithm from a selected group of quotes.
21 files changed, 304 insertions(+), 40 deletions(-)

M module-services/service-db/DBServiceAPI.cpp
M module-services/service-db/agents/settings/SystemSettings.hpp
M module-services/service-db/include/service-db/DBServiceAPI.hpp
M module-services/service-db/include/service-db/QuotesMessages.hpp
M module-services/service-desktop/endpoints/include/endpoints/EndpointType.hpp
M module-services/service-desktop/endpoints/include/endpoints/JsonKeyNames.hpp
M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassicWithQuotes.cpp
M products/BellHybrid/services/db/agents/QuotesAgent.cpp
M products/BellHybrid/services/db/agents/QuotesAgent.hpp
M products/BellHybrid/services/db/agents/QuotesQueries.hpp
M products/BellHybrid/services/db/agents/ShuffleQuoteModel.cpp
M products/BellHybrid/services/db/agents/ShuffleQuoteModel.hpp
A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/.meta
A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/down.sql
A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/up.sql
M products/BellHybrid/services/desktop/endpoints/CMakeLists.txt
M products/BellHybrid/services/desktop/endpoints/EndpointFactoryBell.cpp
A products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesEndpoint.hpp
A products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesHelper.hpp
A products/BellHybrid/services/desktop/endpoints/quotes/QuotesEndpoint.cpp
A products/BellHybrid/services/desktop/endpoints/quotes/QuotesHelper.cpp
M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +7 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "service-db/DBServiceAPI.hpp"


@@ 317,6 317,12 @@ void DBServiceAPI::InformDateChanged(sys::Service *serv)
    DBServiceAPI::GetQuery(serv, db::Interface::Name::Quotes, std::move(query));
}

void DBServiceAPI::QuotesGroupChanged(sys::Service *serv, const std::string &group)
{
    auto query = std::make_unique<Quotes::Messages::InformGroupChanged>(group);
    DBServiceAPI::GetQuery(serv, db::Interface::Name::Quotes, std::move(query));
}

auto DBServiceAPI::hasContactSameNumbers(sys::Service *serv, const ContactRecord &rec) -> bool
{
    std::shared_ptr<DBContactMessage> msg =

M module-services/service-db/agents/settings/SystemSettings.hpp => module-services/service-db/agents/settings/SystemSettings.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 81,6 81,7 @@ namespace settings
    {
        inline constexpr auto randomQuotesList        = "quotes_random_list";
        inline constexpr auto randomQuoteIDUpdateTime = "quotes_random_id_update_time";
        inline constexpr auto selectedGroup           = "quotes_group";
    } // namespace Quotes

    namespace Display

M module-services/service-db/include/service-db/DBServiceAPI.hpp => module-services/service-db/include/service-db/DBServiceAPI.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 128,4 128,5 @@ class DBServiceAPI

    static void InformLanguageChanged(sys::Service *serv);
    static void InformDateChanged(sys::Service *serv);
    static void QuotesGroupChanged(sys::Service *serv, const std::string &group);
};

M module-services/service-db/include/service-db/QuotesMessages.hpp => module-services/service-db/include/service-db/QuotesMessages.hpp +27 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 337,6 337,19 @@ namespace Quotes
            }
        };

        class NotificationResult : public db::QueryResult
        {
          public:
            explicit NotificationResult(bool ret)
            {}
            bool ret;

            [[nodiscard]] auto debugInfo() const -> std::string
            {
                return "NotificationResult";
            }
        };

        class InformLanguageChangeRequest : public db::Query
        {
          public:


@@ 361,6 374,19 @@ namespace Quotes
            }
        };

        class InformGroupChanged : public db::Query
        {
          public:
            explicit InformGroupChanged(const std::string &group) : Query(Query::Type::Read), group(group)
            {}
            const std::string group;

            auto debugInfo() const -> std::string
            {
                return "InformGroupChanged";
            }
        };

        class WriteQuoteRequest : public db::Query
        {
          public:

M module-services/service-desktop/endpoints/include/endpoints/EndpointType.hpp => module-services/service-desktop/endpoints/include/endpoints/EndpointType.hpp +3 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 25,7 25,8 @@ namespace sdesktop::endpoints
        UsbSecurity,
        Outbox,
        Reboot,
        TimeSync
        TimeSync,
        Quotes
    };

    inline constexpr auto lastEndpoint = magic_enum::enum_count<EndpointType>() - 1;

M module-services/service-desktop/endpoints/include/endpoints/JsonKeyNames.hpp => module-services/service-desktop/endpoints/include/endpoints/JsonKeyNames.hpp +18 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 123,4 123,21 @@ namespace sdesktop::endpoints::json
        inline constexpr auto value     = "value";
        inline constexpr auto timestamp = "timestamp";
    }

    namespace quotes
    {
        namespace settings
        {
            inline constexpr auto group    = "group";
            inline constexpr auto interval = "interval";
        } // namespace settings

        inline constexpr auto quotation = "quotation";
        namespace quotations
        {
            inline constexpr auto text   = "text";
            inline constexpr auto author = "author";
        } // namespace quotations
    }     // namespace quotes

} // namespace sdesktop::endpoints::json

M products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassicWithQuotes.cpp => products/BellHybrid/apps/common/src/layouts/HomeScreenLayoutClassicWithQuotes.cpp +4 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "layouts/HomeScreenLayoutClassicWithQuotes.hpp"


@@ 137,7 137,9 @@ namespace gui
    {
        constexpr auto dash{'-'};
        UTF8 authorWithDash = quoteAuthor;
        authorWithDash.insert(&dash, 0);
        if (!quoteAuthor.empty()) {
            authorWithDash.insert(&dash, 0);
        }
        author->setText(authorWithDash);
        quotes->setText(quoteContent);
    }

M products/BellHybrid/services/db/agents/QuotesAgent.cpp => products/BellHybrid/services/db/agents/QuotesAgent.cpp +36 -4
@@ 1,14 1,15 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "QuotesAgent.hpp"
#include "QuotesQueries.hpp"
#include <Common/Query.hpp>
#include <service-db/agents/settings/SystemSettings.hpp>

namespace Quotes
{
    QuotesAgent::QuotesAgent(Database *quotesDB, std::unique_ptr<settings::Settings> settings)
        : quotesDB(quotesDB), shuffleQuoteModel(std::move(settings), quotesDB)
        : settings(std::move(settings)), quotesDB(quotesDB), shuffleQuoteModel(*this->settings, quotesDB)
    {
        shuffleQuoteModel.updateList(ListUpdateMode::Normal);
    }


@@ 21,6 22,10 @@ namespace Quotes
        else if (typeid(*query) == typeid(Messages::InformLanguageChangeRequest) ||
                 (typeid(*query) == typeid(Messages::InformDateChanged))) {
            shuffleQuoteModel.updateList(ListUpdateMode::Forced);
            return std::make_unique<Messages::NotificationResult>(true);
        }
        else if (typeid(*query) == typeid(Messages::InformGroupChanged)) {
            return handleGroupChanged(query);
        }
        return nullptr;
    }


@@ 30,9 35,12 @@ namespace Quotes
        const auto request = std::dynamic_pointer_cast<Messages::ReadRandomizedQuoteRequest>(query);
        if (request) {
            const auto id = shuffleQuoteModel.getId();
            const auto quotesGroup =
                settings->getValue(settings::Quotes::selectedGroup, settings::SettingsScope::Global);
            LOG_DEBUG("Shuffle id: %d", id);
            const auto result = quotesDB->query(Queries::readQuote, id);
            if (result->getRowCount() > 0) {
            const auto readQuery = quotesGroup == customGroup ? Queries::readCustomQuote : Queries::readPredefinedQuote;
            const auto result    = quotesDB->query(readQuery, id);
            if (result && result->getRowCount() > 0) {
                const IdQuoteAuthorRecord record(result.get());
                auto response = std::make_unique<Messages::ReadRandomizedQuoteResponse>(
                    record.quote_id, record.quote, record.author);


@@ 42,4 50,28 @@ namespace Quotes
        }
        return nullptr;
    }

    auto QuotesAgent::handleGroupChanged(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>
    {
        const auto request = std::dynamic_pointer_cast<Messages::InformGroupChanged>(query);
        if (request == nullptr) {
            return std::make_unique<Messages::NotificationResult>(false);
        }
        if (request->group == customGroup) {
            const auto result = quotesDB->query(Queries::getCustomQuotesCount);
            if (result == nullptr || result->getRowCount() == 0) {
                return std::make_unique<Messages::NotificationResult>(false);
            }
            if ((*result)[0].getUInt32() == 0) {
                // if the list of custom quotes is empty, we change the group to a predefined one
                settings->setValue(settings::Quotes::selectedGroup, predefinedGroup, settings::SettingsScope::Global);
                shuffleQuoteModel.updateList(ListUpdateMode::Forced);
                return std::make_unique<Messages::NotificationResult>(true);
            }
        }

        settings->setValue(settings::Quotes::selectedGroup, request->group, settings::SettingsScope::Global);
        shuffleQuoteModel.updateList(ListUpdateMode::Forced);
        return std::make_unique<Messages::NotificationResult>(true);
    }
} // namespace Quotes

M products/BellHybrid/services/db/agents/QuotesAgent.hpp => products/BellHybrid/services/db/agents/QuotesAgent.hpp +5 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 17,7 17,7 @@ namespace Quotes
    class QuotesAgent : public RecordInterface<QuoteRecord, QuotesRecordField>
    {
      public:
        explicit QuotesAgent(Database *quotesDB, std::unique_ptr<settings::Settings> settings);
        QuotesAgent(Database *quotesDB, std::unique_ptr<settings::Settings> settings);
        ~QuotesAgent() = default;

        auto runQuery(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;


@@ 26,7 26,10 @@ namespace Quotes
        auto handleReadRandomizedQuote(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;

      private:
        std::unique_ptr<settings::Settings> settings;
        Database *quotesDB;
        ShuffleQuoteModel shuffleQuoteModel;

        auto handleGroupChanged(std::shared_ptr<db::Query> query) -> std::unique_ptr<db::QueryResult>;
    };
} // namespace Quotes

M products/BellHybrid/services/db/agents/QuotesQueries.hpp => products/BellHybrid/services/db/agents/QuotesQueries.hpp +11 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 7,9 7,17 @@

namespace Quotes::Queries
{
    inline constexpr auto getQuotes =
    inline constexpr auto getPredefinedQuotes =
        "SELECT QT.quote_id FROM quote_table as QT, quote_languages as QL WHERE QL.lang_name=" str_
        " and QT.quote_lang=QL.lang_id GROUP BY QT.quote_id;";

    inline constexpr auto readQuote = "SELECT quote_id, quote, author FROM quote_table WHERE quote_id=" u32_ ";";
    inline constexpr auto readPredefinedQuote =
        "SELECT quote_id, quote, author FROM quote_table WHERE quote_id=" u32_ ";";

    inline constexpr auto getCustomQuotes = "SELECT quote_id FROM custom_quote_table;";

    inline constexpr auto readCustomQuote =
        "SELECT quote_id, quote, author FROM custom_quote_table WHERE quote_id=" u32_ ";";

    inline constexpr auto getCustomQuotesCount = "SELECT COUNT(quote_id) FROM custom_quote_table;";
} // namespace Quotes::Queries

M products/BellHybrid/services/db/agents/ShuffleQuoteModel.cpp => products/BellHybrid/services/db/agents/ShuffleQuoteModel.cpp +17 -14
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "ShuffleQuoteModel.hpp"


@@ 32,16 32,19 @@ namespace

namespace Quotes
{
    ShuffleQuoteModel::ShuffleQuoteModel(std::unique_ptr<settings::Settings> settings, Database *quotesDB)
        : settings(std::move(settings)), quotesDB(quotesDB),
    ShuffleQuoteModel::ShuffleQuoteModel(settings::Settings &settings, Database *quotesDB)
        : settings(settings), quotesDB(quotesDB),
          serializer(std::make_unique<QuotesSettingsSerializer>()), rngEngine{std::make_unique<std::mt19937>(
                                                                        bsp::trng::getRandomValue())}
    {}

    void ShuffleQuoteModel::updateList(ListUpdateMode updateMode)
    {
        auto queryResult = quotesDB->query(Queries::getQuotes, utils::getDisplayLanguage().c_str());
        auto quotesList  = getList<IdsList, IdRecord>(zeroOffset, maxLimit, std::move(queryResult));
        const auto quotesGroup = settings.getValue(settings::Quotes::selectedGroup, settings::SettingsScope::Global);
        auto queryResult       = quotesGroup == customGroup
                                     ? quotesDB->query(Queries::getCustomQuotes)
                                     : quotesDB->query(Queries::getPredefinedQuotes, utils::getDisplayLanguage().c_str());
        auto quotesList        = getList<IdsList, IdRecord>(zeroOffset, maxLimit, std::move(queryResult));
        populateList(std::move(quotesList), updateMode);
    }



@@ 54,12 57,12 @@ namespace Quotes

        std::shuffle(std::begin(list), std::end(list), *rngEngine);
        if (updateMode == ListUpdateMode::Normal) {
            auto settingsList = settings->getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global);
            auto settingsList = settings.getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global);
            if (not settingsList.empty()) {
                return;
            }
        }
        settings->setValue(
        settings.setValue(
            settings::Quotes::randomQuotesList, serializer->serialize(list), settings::SettingsScope::Global);
        LOG_DEBUG("*** ID queue length: %zu", list.size());
    }


@@ 71,7 74,7 @@ namespace Quotes
        }

        auto list = serializer->deserialize(
            settings->getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global));
            settings.getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global));
        const auto [_, id] = list.front();
        return id;
    }


@@ 79,7 82,7 @@ namespace Quotes
    void ShuffleQuoteModel::shiftIdList()
    {
        auto list = serializer->deserialize(
            settings->getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global));
            settings.getValue(settings::Quotes::randomQuotesList, settings::SettingsScope::Global));

        if (!list.empty()) {
            list.pop_front();


@@ 89,7 92,7 @@ namespace Quotes
            updateList(ListUpdateMode::Forced);
        }
        else {
            settings->setValue(
            settings.setValue(
                settings::Quotes::randomQuotesList, serializer->serialize(list), settings::SettingsScope::Global);
        }
    }


@@ 98,7 101,7 @@ namespace Quotes
    {
        std::time_t lastTimestamp;
        const auto lastTimestampString =
            settings->getValue(settings::Quotes::randomQuoteIDUpdateTime, settings::SettingsScope::Global);
            settings.getValue(settings::Quotes::randomQuoteIDUpdateTime, settings::SettingsScope::Global);

        try {
            lastTimestamp = std::stoll(lastTimestampString);


@@ 110,9 113,9 @@ namespace Quotes

        const auto currentTimestamp = std::time(nullptr);
        if (hasCrossedMidnight(currentTimestamp, lastTimestamp)) {
            settings->setValue(settings::Quotes::randomQuoteIDUpdateTime,
                               utils::to_string(currentTimestamp),
                               settings::SettingsScope::Global);
            settings.setValue(settings::Quotes::randomQuoteIDUpdateTime,
                              utils::to_string(currentTimestamp),
                              settings::SettingsScope::Global);
            return true;
        }
        return false;

M products/BellHybrid/services/db/agents/ShuffleQuoteModel.hpp => products/BellHybrid/services/db/agents/ShuffleQuoteModel.hpp +10 -7
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once


@@ 10,6 10,9 @@

namespace Quotes
{
    inline constexpr auto customGroup     = "Custom";
    inline constexpr auto predefinedGroup = "Predefined";

    enum class ListUpdateMode
    {
        Normal,


@@ 18,9 21,14 @@ namespace Quotes

    class ShuffleQuoteModel
    {
      public:
        ShuffleQuoteModel(settings::Settings &settings, Database *quotesDB);
        auto updateList(ListUpdateMode updateMode) -> void;
        [[nodiscard]] auto getId() -> int;

      private:
        app::ApplicationCommon *app{nullptr};
        std::unique_ptr<settings::Settings> settings;
        settings::Settings &settings;
        Database *quotesDB{nullptr};
        std::unique_ptr<QuotesSettingsSerializer> serializer;
        std::unique_ptr<std::mt19937> rngEngine;


@@ 28,11 36,6 @@ namespace Quotes
        auto populateList(std::unique_ptr<IdsList> idsList, ListUpdateMode updateMode) -> void;
        auto shiftIdList() -> void;
        auto isQuoteExpired() -> bool;

      public:
        ShuffleQuoteModel(std::unique_ptr<settings::Settings> settings, Database *quotesDB);
        auto updateList(ListUpdateMode updateMode) -> void;
        [[nodiscard]] auto getId() -> int;
    };

} // namespace Quotes

A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/.meta => products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/.meta +6 -0
@@ 0,0 1,6 @@
{
 "id": "91a948e7-4cff-4492-b25c-e219cfb4e8de",
 "date": "2025-01-27 08:55:40",
 "message": "Add quote group setting",
 "parent": 0
}
\ No newline at end of file

A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/down.sql => products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/down.sql +10 -0
@@ 0,0 1,10 @@
-- Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
-- For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

-- Message: Add quote group setting
-- Revision: 91a948e7-4cff-4492-b25c-e219cfb4e8de
-- Create Date: 2025-01-27 08:55:40

-- Insert SQL here

DELETE FROM settings_tab WHERE path = 'quotes_group';

A products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/up.sql => products/BellHybrid/services/db/databases/migration/settings_bell/current/91a948e7_Add_quote_group_setting/up.sql +11 -0
@@ 0,0 1,11 @@
-- Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
-- For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

-- Message: Add quote group setting
-- Revision: 91a948e7-4cff-4492-b25c-e219cfb4e8de
-- Create Date: 2025-01-27 08:55:40

-- Insert SQL here

INSERT OR IGNORE INTO settings_tab (path, value) VALUES
       ('quotes_group', 'Predefined');

M products/BellHybrid/services/desktop/endpoints/CMakeLists.txt => products/BellHybrid/services/desktop/endpoints/CMakeLists.txt +4 -0
@@ 6,8 6,12 @@ target_sources(
        EndpointFactoryBell.hpp
        EndpointFactoryBell.cpp
        deviceInfo/DeviceInfoEndpoint.cpp
        quotes/QuotesEndpoint.cpp
        quotes/QuotesHelper.cpp
    PUBLIC
        include/endpoints/deviceInfo/DeviceInfoEndpoint.hpp
        include/endpoints/quotes/QuotesEndpoint.hpp
        include/endpoints/quotes/QuotesHelper.hpp
)

target_include_directories(

M products/BellHybrid/services/desktop/endpoints/EndpointFactoryBell.cpp => products/BellHybrid/services/desktop/endpoints/EndpointFactoryBell.cpp +4 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "EndpointFactoryBell.hpp"


@@ 12,6 12,7 @@
#include <endpoints/update/UpdateEndpoint.hpp>
#include <endpoints/reboot/RebootEndpoint.hpp>
#include <endpoints/timeSync/TimeSyncEndpoint.hpp>
#include <endpoints/quotes/QuotesEndpoint.hpp>

namespace sdesktop::endpoints
{


@@ 34,6 35,8 @@ namespace sdesktop::endpoints
            return std::make_unique<RebootEndpoint>(ownerServicePtr);
        case EndpointType::TimeSync:
            return std::make_unique<TimeSyncEndpoint>(ownerServicePtr);
        case EndpointType::Quotes:
            return std::make_unique<QuotesEndpoint>(ownerServicePtr);
        default:
            return std::make_unique<NullEndpoint>(ownerServicePtr);
        }

A products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesEndpoint.hpp => products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesEndpoint.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once

#include "QuotesHelper.hpp"
#include <endpoints/Endpoint.hpp>

namespace sdesktop::endpoints
{
    class QuotesEndpoint : public Endpoint
    {
      public:
        explicit QuotesEndpoint(sys::Service *ownerServicePtr);
        auto handle(Context &context) -> void override;

      private:
        std::unique_ptr<QuotesHelper> helper;
    };

} // namespace sdesktop::endpoints

A products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesHelper.hpp => products/BellHybrid/services/desktop/endpoints/include/endpoints/quotes/QuotesHelper.hpp +21 -0
@@ 0,0 1,21 @@
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#pragma once

#include <endpoints/BaseHelper.hpp>

namespace sdesktop::endpoints
{
    class QuotesHelper : public BaseHelper
    {
      public:
        explicit QuotesHelper(sys::Service *p) : BaseHelper(p)
        {}

        auto processGet(Context &context) -> ProcessResult final;
        auto processPost(Context &context) -> ProcessResult final;
        auto processPut(Context &context) -> ProcessResult final;
        auto processDelete(Context &context) -> ProcessResult final;
    };
} // namespace sdesktop::endpoints

A products/BellHybrid/services/desktop/endpoints/quotes/QuotesEndpoint.cpp => products/BellHybrid/services/desktop/endpoints/quotes/QuotesEndpoint.cpp +38 -0
@@ 0,0 1,38 @@
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include <endpoints/quotes/QuotesEndpoint.hpp>
#include <endpoints/message/Sender.hpp>
#include <log/log.hpp>

namespace sdesktop::endpoints
{
    QuotesEndpoint::QuotesEndpoint(sys::Service *ownerServicePtr) : Endpoint(ownerServicePtr)
    {
        debugName = "QuotesEndpoint";
        helper    = std::make_unique<QuotesHelper>(ownerServicePtr);
    }

    auto QuotesEndpoint::handle(Context &context) -> void
    {
        const auto &[sent, response] = helper->process(context.getMethod(), context);

        if (sent == Sent::Delayed) {
            LOG_DEBUG("There is no proper delayed serving mechanism - depend on invisible context caching");
        }
        if (sent == Sent::No) {
            if (not response.has_value()) {
                LOG_ERROR("Response not sent & response not created : respond with error");
                context.setResponseStatus(http::Code::NotAcceptable);
            }
            else {
                context.setResponse(response.value());
            }

            sender::putToSendQueue(context.createSimpleResponse());
        }
        if (sent == Sent::Yes and response.has_value()) {
            LOG_ERROR("Response set when we already handled response in handler");
        }
    }
} // namespace sdesktop::endpoints

A products/BellHybrid/services/desktop/endpoints/quotes/QuotesHelper.cpp => products/BellHybrid/services/desktop/endpoints/quotes/QuotesHelper.cpp +47 -0
@@ 0,0 1,47 @@
// Copyright (c) 2017-2025, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include <endpoints/quotes/QuotesHelper.hpp>
#include <endpoints/Context.hpp>
#include <endpoints/JsonKeyNames.hpp>
#include <Service/Service.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <log/log.hpp>

namespace sdesktop::endpoints
{
    auto QuotesHelper::processGet(Context &context) -> ProcessResult
    {
        // TODO: https://appnroll.atlassian.net/browse/BH-2099
        return {Sent::No, ResponseContext{.status = http::Code::BadRequest}};
    }

    auto QuotesHelper::processPost(Context &context) -> ProcessResult
    {
        // TODO: https://appnroll.atlassian.net/browse/BH-2097
        return {Sent::No, ResponseContext{.status = http::Code::InternalServerError}};
    }

    auto QuotesHelper::processPut(Context &context) -> ProcessResult
    {
        const auto &body = context.getBody();
        if (const auto group = body[json::quotes::settings::group].string_value(); !group.empty()) {
            DBServiceAPI::QuotesGroupChanged(owner, group.c_str());
        }
        else if (const auto interval = body[json::quotes::settings::interval].string_value(); !interval.empty()) {
            // TODO: https://appnroll.atlassian.net/browse/BH-2095
        }
        else {
            return {Sent::No, ResponseContext{.status = http::Code::BadRequest}};
        }

        return {Sent::No, ResponseContext{.status = http::Code::OK}};
    }

    auto QuotesHelper::processDelete(Context &context) -> ProcessResult
    {
        // TODO: https://appnroll.atlassian.net/browse/BH-2097
        return {Sent::No, ResponseContext{.status = http::Code::InternalServerError}};
    }

} // namespace sdesktop::endpoints