~aleteoryx/muditaos

f5352686241a8aa5f2ab462ee97245fe5c8cbb35 — Pawel Olejniczak 5 years ago 8d79f27
[EGD-5586] Clean up messages endpoint API

Introducing changes according to new messages endpoint api
proposal doc. All request have been updated, and some new were added.
Harness tests were updated too. These changes will be followed up with
pagination implementation.
M module-db/Interface/ThreadRecord.cpp => module-db/Interface/ThreadRecord.cpp +3 -1
@@ 226,7 226,9 @@ std::unique_ptr<db::QueryResult> ThreadRecordInterface::markAsReadQuery(const st
        ret                   = Update(record);
    }

    return std::make_unique<db::query::MarkAsReadResult>(ret);
    auto response = std::make_unique<db::query::MarkAsReadResult>(ret);
    response->setRequestQuery(query);
    return response;
}

std::unique_ptr<db::QueryResult> ThreadRecordInterface::threadsGetQuery(const std::shared_ptr<db::Query> &query)

M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp +3 -5
@@ 65,7 65,7 @@ auto DeveloperModeHelper::processPutRequest(Context &context) -> sys::ReturnCode
    }
    else if (body[json::developerMode::smsCommand].is_string()) {
        if (body[json::developerMode::smsCommand].string_value() == json::developerMode::smsAdd) {
            SMSType smsType = static_cast<SMSType>(context.getBody()[json::messages::type].int_value());
            const auto smsType = static_cast<SMSType>(context.getBody()[json::messages::messageType].int_value());
            if (smsType == SMSType::DRAFT || smsType == SMSType::QUEUED || smsType == SMSType::FAILED) {
                return prepareSMS(context);
            }


@@ 212,11 212,9 @@ auto DeveloperModeHelper::smsRecordFromJson(json11::Json msgJson) -> SMSRecord
{
    auto record = SMSRecord();

    record.type = static_cast<SMSType>(msgJson[json::messages::type].int_value());
    record.type = static_cast<SMSType>(msgJson[json::messages::messageType].int_value());
    record.date = utils::time::getCurrentTimestamp().getTime();
    utils::PhoneNumber phoneNumber(msgJson[json::messages::phoneNumber].string_value());
    record.number = phoneNumber.getView();
    record.body   = UTF8(msgJson[json::messages::messageBody].string_value());
    record.body = UTF8(msgJson[json::messages::messageBody].string_value());
    return record;
}


M module-services/service-desktop/endpoints/messages/MessageHelper.cpp => module-services/service-desktop/endpoints/messages/MessageHelper.cpp +463 -337
@@ 9,16 9,13 @@

#include <BaseInterface.hpp>
#include <Common/Query.hpp>
#include <PhoneNumber.hpp>
#include <SMSRecord.hpp>
#include <SMSTemplateRecord.hpp>
#include <Service/Common.hpp>
#include <ThreadRecord.hpp>
#include <json/json11.hpp>
#include <queries/messages/sms/QuerySMSGet.hpp>
#include <queries/messages/sms/QuerySMSGetByContactID.hpp>
#include <queries/messages/sms/QuerySMSGetByID.hpp>
#include <queries/messages/sms/QuerySMSGetByText.hpp>
#include <queries/messages/sms/QuerySMSGetByThreadID.hpp>
#include <queries/messages/sms/QuerySMSGetCount.hpp>
#include <queries/messages/sms/QuerySMSRemove.hpp>


@@ 28,160 25,308 @@
#include <queries/messages/templates/QuerySMSTemplateGetCount.hpp>
#include <queries/messages/templates/QuerySMSTemplateRemove.hpp>
#include <queries/messages/templates/QuerySMSTemplateUpdate.hpp>
#include <queries/messages/threads/QueryThreadsGet.hpp>
#include <queries/messages/threads/QueryThreadMarkAsRead.hpp>
#include <service-db/DBServiceAPI.hpp>
#include <utf8/UTF8.hpp>

#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <module-db/queries/messages/sms/QuerySMSGetByText.hpp>

using namespace parserFSM;

auto MessageHelper::to_json(SMSRecord record) -> json11::Json
namespace parserFSM
{

    auto recordEntry = json11::Json::object{{json::messages::contactID, static_cast<int>(record.contactID)},
                                            {json::messages::date, static_cast<int>(record.date)},
                                            {json::messages::dateSent, static_cast<int>(record.dateSent)},
                                            {json::messages::id, static_cast<int>(record.ID)},
                                            {json::messages::messageBody, record.body.c_str()},
                                            {json::messages::type, static_cast<int>(record.type)},
                                            {json::messages::threadID, static_cast<int>(record.threadID)}};
    return recordEntry;
}

auto MessageHelper::to_json(SMSTemplateRecord record) -> json11::Json
{
    auto MessageHelper::toJson(const SMSRecord &record) -> json11::Json
    {

    auto recordEntry = json11::Json::object{{json::messages::id, static_cast<int>(record.ID)},
                                            {json::messages::templateText, record.text.c_str()}};
    return recordEntry;
}
        auto recordEntry = json11::Json::object{{json::messages::contactID, static_cast<int>(record.contactID)},
                                                {json::messages::receivedAt, static_cast<int>(record.date)},
                                                {json::messages::sentAt, static_cast<int>(record.dateSent)},
                                                {json::messages::messageID, static_cast<int>(record.ID)},
                                                {json::messages::messageBody, record.body.c_str()},
                                                {json::messages::messageType, static_cast<int>(record.type)},
                                                {json::messages::threadID, static_cast<int>(record.threadID)}};
        return recordEntry;
    }

auto MessageHelper::to_json(ThreadRecord record) -> json11::Json
{
    auto MessageHelper::toJson(const SMSTemplateRecord &record) -> json11::Json
    {

    auto recordEntry =
        json11::Json::object{{json::messages::contactID, static_cast<int>(record.contactID)},
                             {json::messages::date, static_cast<int>(record.date)},
                             {json::messages::thread::msgCount, static_cast<int>(record.msgCount)},
                             {json::messages::id, static_cast<int>(record.ID)},
                             {json::messages::thread::snippet, record.snippet.c_str()},
                             {json::messages::isUnread, record.isUnread()},
                             {json::messages::type, static_cast<int>(record.type)},
                             {json::messages::thread::unreadMsgCount, static_cast<int>(record.unreadMsgCount)}};
    return recordEntry;
}

auto MessageHelper::from_json(json11::Json msgJson) -> SMSTemplateRecord
{
    SMSTemplateRecord record;
        auto recordEntry =
            json11::Json::object{{json::messages::templateID, static_cast<int>(record.ID)},
                                 {json::messages::templateBody, record.text.c_str()},
                                 {json::messages::lastUsedAt, static_cast<int>(record.lastUsageTimestamp)}};
        return recordEntry;
    }

    record.text = UTF8(msgJson[json::messages::templateText].string_value());
    auto MessageHelper::toJson(const ThreadRecord &record) -> json11::Json
    {

    return record;
}
        auto recordEntry = json11::Json::object{{json::messages::contactID, static_cast<int>(record.contactID)},
                                                {json::messages::numberID, static_cast<int>(record.numberID)},
                                                {json::messages::lastUpdatedAt, static_cast<int>(record.date)},
                                                {json::messages::messageCount, static_cast<int>(record.msgCount)},
                                                {json::messages::threadID, static_cast<int>(record.ID)},
                                                {json::messages::messageSnippet, record.snippet.c_str()},
                                                {json::messages::isUnread, record.isUnread()},
                                                {json::messages::messageType, static_cast<int>(record.type)}};
        return recordEntry;
    }

auto MessageHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
{
    auto MessageHelper::fromJson(const json11::Json &msgJson) -> SMSTemplateRecord
    {
        SMSTemplateRecord record;

    if (context.getBody()[json::messages::msgTemplate].bool_value() == true) {
        return requestTemplate(context);
    }
    else {
        return requestSMS(context);
        record.text = UTF8(msgJson[json::messages::templateBody].string_value());

        return record;
    }
}

auto MessageHelper::requestSMS(Context &context) -> sys::ReturnCodes
{
    if (context.getBody()[json::messages::count].bool_value() == true) // get messages count
    auto MessageHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
    {
        auto query = std::make_unique<db::query::SMSGetCount>();
        if (context.getBody()[json::messages::category].string_value() == json::messages::categoryMessage) {
            return requestSMS(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryTemplate) {
            return requestTemplate(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryThread) {
            return requestThread(context);
        }
        LOG_ERROR("Category of request is missing or incorrect!");
        context.setResponseStatus(http::Code::BadRequest);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Unresolved;
    }

        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetCountResult *>(result)) {
                    auto id = SMSResult->getResults();
    auto MessageHelper::createDBEntry(Context &context) -> sys::ReturnCodes
    {
        if (context.getBody()[json::messages::category].string_value() == json::messages::categoryMessage) {
            return createSMS(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryTemplate) {
            return createTemplate(context);
        }
        LOG_ERROR("Category of request is missing or incorrect!");
        context.setResponseStatus(http::Code::BadRequest);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Unresolved;
    }

                    context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(id)}});
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);
    auto MessageHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
    {
        if (context.getBody()[json::messages::category].string_value() == json::messages::categoryTemplate) {
            return updateTemplate(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryThread) {
            return updateThread(context);
        }
        LOG_ERROR("Category of request is missing or incorrect!");
        context.setResponseStatus(http::Code::BadRequest);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Unresolved;
    }

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
    auto MessageHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
    {
        if (context.getBody()[json::messages::category].string_value() == json::messages::categoryMessage) {
            return deleteSMS(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryTemplate) {
            return deleteTemplate(context);
        }
        else if (context.getBody()[json::messages::category].string_value() == json::messages::categoryThread) {
            return deleteThread(context);
        }
        LOG_ERROR("Category of request is missing or incorrect!");
        context.setResponseStatus(http::Code::BadRequest);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Unresolved;
    }
    else if (context.getBody()[json::messages::id].int_value() != 0) { // messages search

        auto query = std::make_unique<db::query::SMSGetByID>(context.getBody()[json::messages::id].int_value());
    auto MessageHelper::requestSMS(Context &context) -> sys::ReturnCodes
    {
        if (context.getBody()[json::messages::count].bool_value()) // get messages count
        {
            auto query = std::make_unique<db::query::SMSGetCount>();

            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSGetCountResult *>(result)) {
                        auto id = smsResult->getResults();

                        context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(id)}});
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetByIDResult *>(result)) {
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
        }
        else if (context.getBody()[json::messages::messageID].int_value() != 0) { // get message by ID

                    context.setResponseBody(MessageHelper::to_json(SMSResult->getResults()));
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);
            auto query =
                std::make_unique<db::query::SMSGetByID>(context.getBody()[json::messages::messageID].int_value());

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
    }
    else if (context.getBody()[json::messages::contactID].int_value() != 0) {
            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSGetByIDResult *>(result)) {

        auto query =
            std::make_unique<db::query::SMSGetByContactID>(context.getBody()[json::messages::contactID].int_value());
                        context.setResponseBody(MessageHelper::toJson(smsResult->getResults()));
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetByContactIDResult *>(result)) {
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
        }
        else if (context.getBody()[json::messages::threadID].int_value() != 0) { // get messages by thread ID

            auto query =
                std::make_unique<db::query::SMSGetByThreadID>(context.getBody()[json::messages::threadID].int_value(),
                                                              context.getBody()[json::messages::offset].int_value(),
                                                              context.getBody()[json::messages::limit].is_number()
                                                                  ? context.getBody()[json::messages::limit].int_value()
                                                                  : defaultLimit);

            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSGetByThreadIDResult *>(result)) {

                        auto paginationInfo = json11::Json::object{
                            {json::messages::totalCount, 0},
                            {json::messages::nextPage,
                             json11::Json::object{{json::messages::offset, 0}, {json::messages::limit, 0}}}};

                        json11::Json::array smsArray;
                        for (const auto &record : smsResult->getResults()) {
                            smsArray.emplace_back(MessageHelper::toJson(record));
                        }

                        json11::Json::array responseBody;
                        responseBody.emplace_back(paginationInfo);
                        responseBody.emplace_back(json11::Json::array{{json::messages::entries, smsArray}});

                        context.setResponseBody(responseBody);
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
        }
        else if (!context.getBody()[json::messages::messageBody].string_value().empty()) // get by message body
        {
            // not adding pagination for this request, since it is just for development and testing purposes, and it's
            // not going to be used by Mudita Center
            auto query = std::make_unique<db::query::SMSGetByText>(
                context.getBody()[json::messages::messageBody].string_value());
            if (const auto filterByNumber = !context.getBody()[json::messages::phoneNumber].string_value().empty();
                filterByNumber) {
                utils::PhoneNumber number{context.getBody()[json::messages::phoneNumber].string_value()};
                query->filterByPhoneNumber(number.getView());
            }

            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSGetByTextResult *>(result)) {

                    json11::Json::array SMSarray;
                    for (auto record : SMSResult->getResults()) {
                        SMSarray.emplace_back(MessageHelper::to_json(record));
                        json11::Json::array smsArray;
                        for (const auto &record : smsResult->getResults()) {
                            smsArray.emplace_back(MessageHelper::toJson(record));
                        }

                        context.setResponseBody(smsArray);
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

                    context.setResponseBody(SMSarray);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
        }
        else // get messages
        {
            auto query = std::make_unique<db::query::SMSGet>(context.getBody()[json::messages::limit].is_number()
                                                                 ? context.getBody()[json::messages::limit].int_value()
                                                                 : defaultLimit,
                                                             context.getBody()[json::messages::offset].int_value());

            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSGetResult *>(result)) {

                        auto paginationInfo = json11::Json::object{
                            {json::messages::totalCount, 0},
                            {json::messages::nextPage,
                             json11::Json::object{{json::messages::offset, 0}, {json::messages::limit, 0}}}};

                        json11::Json::array smsArray;
                        for (const auto &record : smsResult->getRecords()) {
                            smsArray.emplace_back(MessageHelper::toJson(record));
                            LOG_DEBUG("Record found!: %" PRIu32 "\n", record.ID);
                        }

                        json11::Json::array responseBody;
                        responseBody.emplace_back(paginationInfo);
                        responseBody.emplace_back(json11::Json::array{{json::messages::entries, smsArray}});
                        context.setResponseBody(responseBody);
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
        }
        return sys::ReturnCodes::Success;
    }
    else if (context.getBody()[json::messages::threadID].int_value() != 0) {

        auto query =
            std::make_unique<db::query::SMSGetByThreadID>(context.getBody()[json::messages::threadID].int_value());
    auto MessageHelper::createSMS(Context &context) -> sys::ReturnCodes
    {
        context.setResponseStatus(http::Code::InternalServerError);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Success;
    }

    auto MessageHelper::deleteSMS(Context &context) -> sys::ReturnCodes
    {
        if (!context.getBody()[json::messages::messageID].is_number()) {
            LOG_ERROR("Bad request! messageID is incorrect or missing!");
            return sys::ReturnCodes::Unresolved;
        }
        auto id       = context.getBody()[json::messages::messageID].int_value();
        auto query    = std::make_unique<db::query::SMSRemove>(id);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetByThreadIDResult *>(result)) {

                    json11::Json::array SMSarray;
                    for (auto record : SMSResult->getResults()) {
                        SMSarray.emplace_back(MessageHelper::to_json(record));
                    }
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSRemoveResult *>(result)) {

                    context.setResponseBody(SMSarray);
                    context.setResponseStatus(smsTemplateResult->getResults() ? http::Code::OK
                                                                              : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 193,53 338,123 @@ auto MessageHelper::requestSMS(Context &context) -> sys::ReturnCodes

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));

        return sys::ReturnCodes::Success;
    }
    else if (context.getBody()[json::messages::messageBody].string_value().empty() == false) {
        auto query =
            std::make_unique<db::query::SMSGetByText>(context.getBody()[json::messages::messageBody].string_value());
        if (const auto filterByNumber = !context.getBody()[json::messages::phoneNumber].string_value().empty();
            filterByNumber) {
            utils::PhoneNumber number{context.getBody()[json::messages::phoneNumber].string_value()};
            query->filterByPhoneNumber(number.getView());

    auto MessageHelper::requestTemplate(Context &context) -> sys::ReturnCodes
    {
        if (context.getBody()[json::messages::count].bool_value()) // get templates count
        {
            auto query = std::make_unique<db::query::SMSTemplateGetCount>();

            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsResult = dynamic_cast<db::query::SMSTemplateGetCountResult *>(result)) {
                        auto id = smsResult->getResults();

                        context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(id)}});
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        }
        else if (context.getBody()[json::messages::templateID].int_value() != 0) { // get template by ID
            auto query = std::make_unique<db::query::SMSTemplateGetByID>(
                context.getBody()[json::messages::templateID].int_value());

        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetByTextResult *>(result)) {
            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateGetByIDResult *>(result)) {

                    json11::Json::array SMSarray;
                    for (auto record : SMSResult->getResults()) {
                        SMSarray.emplace_back(MessageHelper::to_json(record));
                        context.setResponseBody(MessageHelper::toJson(smsTemplateResult->getResults()));
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

                    context.setResponseBody(SMSarray);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        }
        else // get messages templates
        {
            auto query =
                std::make_unique<db::query::SMSTemplateGet>(context.getBody()[json::messages::offset].int_value(),
                                                            context.getBody()[json::messages::limit].is_number()
                                                                ? context.getBody()[json::messages::limit].int_value()
                                                                : defaultLimit);
            auto listener = std::make_unique<db::EndpointListener>(
                [=](db::QueryResult *result, Context context) {
                    if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateGetResult *>(result)) {

                        auto paginationInfo = json11::Json::object{
                            {json::messages::totalCount, 0},
                            {json::messages::nextPage,
                             json11::Json::object{{json::messages::offset, 0}, {json::messages::limit, 0}}}};

                        json11::Json::array smsTemplateArray;
                        for (const auto &record : smsTemplateResult->getResults()) {
                            smsTemplateArray.emplace_back(toJson(record));
                        }

                        json11::Json::array responseBody;
                        responseBody.emplace_back(paginationInfo);
                        responseBody.emplace_back(json11::Json::array{{json::messages::entries, smsTemplateArray}});

                        context.setResponseBody(responseBody);
                        MessageHandler::putToSendQueue(context.createSimpleResponse());
                        return true;
                    }
                    else {
                        return false;
                    }
                },
                context);

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
            query->setQueryListener(std::move(listener));
            DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        }

        return sys::ReturnCodes::Success;
    }
    else // get messages
    auto MessageHelper::updateTemplate(Context &context) -> sys::ReturnCodes
    {
        auto query = std::make_unique<db::query::SMSGet>(context.getBody()[json::messages::count].int_value(),
                                                         context.getBody()[json::messages::offset].int_value());
        if (!context.getBody()[json::messages::templateID].is_number()) {
            LOG_ERROR("Bad request! templateID is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

        if (!context.getBody()[json::messages::templateBody].is_string()) {
            LOG_ERROR("Bad request! templateBody is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

        SMSTemplateRecord record;
        record.ID   = context.getBody()[json::messages::templateID].int_value();
        record.text = context.getBody()[json::messages::templateBody].string_value();

        auto query    = std::make_unique<db::query::SMSTemplateUpdate>(record);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSGetResult *>(result)) {

                    json11::Json::array SMSarray;
                    for (auto record : SMSResult->getRecords()) {
                        SMSarray.emplace_back(MessageHelper::to_json(record));
                    }
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateUpdateResult *>(result)) {

                    context.setResponseBody(SMSarray);
                    context.setResponseStatus(smsTemplateResult->getResult() ? http::Code::OK
                                                                             : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 250,24 465,29 @@ auto MessageHelper::requestSMS(Context &context) -> sys::ReturnCodes
            context);

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));
    }
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));

    return sys::ReturnCodes::Success;
}
        return sys::ReturnCodes::Success;
    }

auto MessageHelper::requestTemplate(Context &context) -> sys::ReturnCodes
{
    if (context.getBody()[json::messages::count].bool_value() == true) // get templates count
    auto MessageHelper::createTemplate(Context &context) -> sys::ReturnCodes
    {
        auto query = std::make_unique<db::query::SMSTemplateGetCount>();
        if (!context.getBody()[json::messages::templateBody].is_string()) {
            LOG_ERROR("Bad request! templateBody is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

        SMSTemplateRecord record = fromJson(context.getBody());

        auto query    = std::make_unique<db::query::SMSTemplateAdd>(record);
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSResult = dynamic_cast<db::query::SMSTemplateGetCountResult *>(result)) {
                    auto id = SMSResult->getResults();
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateAddResult *>(result)) {

                    context.setResponseBody(json11::Json::object{{json::messages::count, static_cast<int>(id)}});
                    context.setResponseStatus(smsTemplateResult->getResult() ? http::Code::OK
                                                                             : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 279,15 499,27 @@ auto MessageHelper::requestTemplate(Context &context) -> sys::ReturnCodes

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));

        return sys::ReturnCodes::Success;
    }
    else if (context.getBody()[json::messages::id].int_value() != 0) { // templates search
        auto query = std::make_unique<db::query::SMSTemplateGetByID>(context.getBody()[json::messages::id].int_value());

    auto MessageHelper::deleteTemplate(Context &context) -> sys::ReturnCodes
    {
        if (!context.getBody()[json::messages::templateID].is_number()) {
            LOG_ERROR("Bad request! templateID is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

        auto query =
            std::make_unique<db::query::SMSTemplateRemove>(context.getBody()[json::messages::templateID].int_value());
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSTemplateResult = dynamic_cast<db::query::SMSTemplateGetByIDResult *>(result)) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateRemoveResult *>(result)) {

                    context.setResponseBody(MessageHelper::to_json(SMSTemplateResult->getResults()));
                    context.setResponseStatus(smsTemplateResult->getResults() ? http::Code::OK
                                                                              : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 299,21 531,35 @@ auto MessageHelper::requestTemplate(Context &context) -> sys::ReturnCodes

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        return sys::ReturnCodes::Success;
    }
    else // get messages templates

    auto MessageHelper::requestThread(Context &context) -> sys::ReturnCodes
    {
        auto query = std::make_unique<db::query::SMSTemplateGet>(context.getBody()[json::messages::offset].int_value(),
                                                                 context.getBody()[json::messages::count].int_value());
        auto query = std::make_unique<db::query::ThreadsGet>(context.getBody()[json::messages::offset].int_value(),
                                                             context.getBody()[json::messages::limit].is_number()
                                                                 ? context.getBody()[json::messages::limit].int_value()
                                                                 : defaultLimit);

        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto SMSTemplateResult = dynamic_cast<db::query::SMSTemplateGetResult *>(result)) {
                if (auto threadsResults = dynamic_cast<db::query::ThreadsGetResults *>(result)) {

                    auto paginationInfo = json11::Json::object{
                        {json::messages::totalCount, 0},
                        {json::messages::nextPage,
                         json11::Json::object{{json::messages::offset, 0}, {json::messages::limit, 0}}}};

                    json11::Json::array SMSTemplateArray;
                    for (auto record : SMSTemplateResult->getResults()) {
                        SMSTemplateArray.emplace_back(to_json(record));
                    json11::Json::array threadsArray;
                    for (const auto &record : threadsResults->getResults()) {
                        threadsArray.emplace_back(MessageHelper::toJson(record));
                    }

                    context.setResponseBody(SMSTemplateArray);
                    json11::Json::array responseBody;
                    responseBody.emplace_back(paginationInfo);
                    responseBody.emplace_back(json11::Json::array{{json::messages::entries, threadsArray}});

                    context.setResponseBody(responseBody);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }


@@ 324,178 570,58 @@ auto MessageHelper::requestTemplate(Context &context) -> sys::ReturnCodes
            context);

        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
    }
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSThread, std::move(query));

    return sys::ReturnCodes::Success;
}

auto MessageHelper::createDBEntry(Context &context) -> sys::ReturnCodes
{

    if (context.getBody()[json::messages::msgTemplate].bool_value() == true) {
        return createTemplate(context);
        return sys::ReturnCodes::Success;
    }
    else {
        return createSMS(context);
    }
}

auto MessageHelper::createTemplate(Context &context) -> sys::ReturnCodes
{
    SMSTemplateRecord record = from_json(context.getBody());
    auto MessageHelper::updateThread(Context &context) -> sys::ReturnCodes // Set thread as read/unread
    {
        if (!context.getBody()[json::messages::threadID].is_number()) {
            LOG_ERROR("Bad request! threadID is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

    auto query    = std::make_unique<db::query::SMSTemplateAdd>(record);
    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSTemplateResult = dynamic_cast<db::query::SMSTemplateAddResult *>(result)) {
        if (!context.getBody()[json::messages::isUnread].is_bool()) {
            LOG_ERROR("Bad request! isUnread is incorrect or missing!");
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
            return sys::ReturnCodes::Unresolved;
        }

                context.setResponseStatus(SMSTemplateResult->getResult() ? http::Code::OK
                                                                         : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;
            }
            else {
                return false;
            }
        },
        context);
        auto query = std::make_unique<db::query::MarkAsRead>(context.getBody()[json::messages::threadID].int_value(),
                                                             (context.getBody()[json::messages::isUnread].bool_value()
                                                                  ? db::query::MarkAsRead::Read::False
                                                                  : db::query::MarkAsRead::Read::True));

    query->setQueryListener(std::move(listener));
    DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
        auto listener = std::make_unique<db::EndpointListener>(
            [=](db::QueryResult *result, Context context) {
                if (auto threadResult = dynamic_cast<db::query::MarkAsReadResult *>(result)) {

    return sys::ReturnCodes::Success;
}
                    context.setResponseStatus(threadResult->getResult() ? http::Code::OK
                                                                        : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;
                }
                else {
                    return false;
                }
            },
            context);

auto MessageHelper::createSMS(Context &context) -> sys::ReturnCodes
{
    return sys::ReturnCodes::Success;
}
        query->setQueryListener(std::move(listener));

auto MessageHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
{
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSThread, std::move(query));

    if (context.getBody()[json::messages::msgTemplate].bool_value() == true) {
        return deleteTemplate(context);
    }
    else {
        return deleteSMS(context);
        return sys::ReturnCodes::Success;
    }
}

auto MessageHelper::deleteSMS(Context &context) -> sys::ReturnCodes
{
    auto id       = context.getBody()[json::messages::id].int_value();
    auto query    = std::make_unique<db::query::SMSRemove>(id);
    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSTemplateResult = dynamic_cast<db::query::SMSRemoveResult *>(result)) {

                context.setResponseStatus(SMSTemplateResult->getResults() ? http::Code::OK
                                                                          : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;
            }
            else {
                return false;
            }
        },
        context);

    query->setQueryListener(std::move(listener));
    DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMS, std::move(query));

    return sys::ReturnCodes::Success;
}

auto MessageHelper::deleteTemplate(Context &context) -> sys::ReturnCodes
{
    auto id       = context.getBody()[json::messages::id].int_value();
    auto query    = std::make_unique<db::query::SMSTemplateRemove>(id);
    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSTemplateResult = dynamic_cast<db::query::SMSTemplateRemoveResult *>(result)) {

                context.setResponseStatus(SMSTemplateResult->getResults() ? http::Code::OK
                                                                          : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;
            }
            else {
                return false;
            }
        },
        context);

    query->setQueryListener(std::move(listener));
    DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));
    return sys::ReturnCodes::Success;
}

auto MessageHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
{

    if (context.getBody()[json::messages::msgTemplate].bool_value() == true) {
        return updateTemplate(context);
    }
    else {
        return updateSMS(context);
    auto MessageHelper::deleteThread(Context &context) -> sys::ReturnCodes
    {
        context.setResponseStatus(http::Code::InternalServerError);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Success;
    }
}

auto MessageHelper::updateSMS(Context &context) -> sys::ReturnCodes
{
    using namespace db::query;

    auto query = std::make_unique<db::query::MarkAsRead>(
        context.getBody()[json::messages::threadID].int_value(),
        (context.getBody()[json::messages::isUnread].bool_value() ? MarkAsRead::Read::False : MarkAsRead::Read::True));

    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSResult = dynamic_cast<db::query::MarkAsReadResult *>(result)) {

                context.setResponseStatus(SMSResult->getResult() ? http::Code::OK : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());

                return true;
            }
            else {
                return false;
            }
        },
        context);

    query->setQueryListener(std::move(listener));

    DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSThread, std::move(query));
    return sys::ReturnCodes::Success;
}

auto MessageHelper::updateTemplate(Context &context) -> sys::ReturnCodes
{
    SMSTemplateRecord record;
    record.ID   = context.getBody()[json::messages::id].int_value();
    record.text = context.getBody()[json::messages::templateText].string_value();

    auto query    = std::make_unique<db::query::SMSTemplateUpdate>(record);
    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto SMSTemplateResult = dynamic_cast<db::query::SMSTemplateUpdateResult *>(result)) {

                context.setResponseStatus(SMSTemplateResult->getResult() ? http::Code::OK
                                                                         : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;
            }
            else {
                return false;
            }
        },
        context);

    query->setQueryListener(std::move(listener));
    DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::SMSTemplate, std::move(query));

    return sys::ReturnCodes::Success;
}
} // namespace parserFSM

M module-services/service-desktop/endpoints/messages/MessageHelper.hpp => module-services/service-desktop/endpoints/messages/MessageHelper.hpp +17 -41
@@ 14,9 14,6 @@
#include <ThreadRecord.hpp>
#include <json/json11.hpp>

#include <memory>
#include <string>

namespace sys
{
    class Service;


@@ 29,55 26,34 @@ namespace parserFSM
    class MessageHelper final : public DBHelper
    {
      public:
        MessageHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr){};
        explicit MessageHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr){};

        auto createDBEntry(Context &context) -> sys::ReturnCodes override;
        auto requestDataFromDB(Context &context) -> sys::ReturnCodes override;
        auto updateDBEntry(Context &context) -> sys::ReturnCodes override;
        auto deleteDBEntry(Context &context) -> sys::ReturnCodes override;

        auto createTemplate(Context &context) -> sys::ReturnCodes;
        auto requestTemplate(Context &context) -> sys::ReturnCodes;
        auto updateTemplate(Context &context) -> sys::ReturnCodes;
        auto deleteTemplate(Context &context) -> sys::ReturnCodes;
        static auto toJson(const SMSRecord &record) -> json11::Json;
        static auto toJson(const ThreadRecord &record) -> json11::Json;
        static auto toJson(const SMSTemplateRecord &record) -> json11::Json;
        static auto fromJson(const json11::Json &msgJson) -> SMSTemplateRecord;

      private:
        auto requestThread(Context &context) -> sys::ReturnCodes;
        auto updateThread(Context &context) -> sys::ReturnCodes;
        auto deleteThread(Context &context) -> sys::ReturnCodes;

        auto createSMS(Context &context) -> sys::ReturnCodes;
        auto requestSMS(Context &context) -> sys::ReturnCodes;
        auto updateSMS(Context &context) -> sys::ReturnCodes;
        auto createSMS(Context &context) -> sys::ReturnCodes;
        auto deleteSMS(Context &context) -> sys::ReturnCodes;

        // auto createSimpleResponse(Context &context) -> std::string override;

        static auto to_json(SMSRecord record) -> json11::Json;
        static auto to_json(ThreadRecord record) -> json11::Json;
        static auto to_json(SMSTemplateRecord record) -> json11::Json;
        static auto from_json(json11::Json msgJson) -> SMSTemplateRecord;
        auto requestTemplate(Context &context) -> sys::ReturnCodes;
        auto createTemplate(Context &context) -> sys::ReturnCodes;
        auto updateTemplate(Context &context) -> sys::ReturnCodes;
        auto deleteTemplate(Context &context) -> sys::ReturnCodes;

      private:
        json11::Json receivedJson;
    };

    namespace messages
    {
        inline constexpr auto id           = "id";
        inline constexpr auto count        = "count";
        inline constexpr auto offset       = "offset";
        inline constexpr auto phoneNumber  = "phoneNumber";
        inline constexpr auto isUnread     = "unread";
        inline constexpr auto contactID    = "contactID";
        inline constexpr auto date         = "date";
        inline constexpr auto dateSent     = "dateSent";
        inline constexpr auto type         = "type";
        inline constexpr auto threadID     = "threadID";
        inline constexpr auto msgTemplate  = "template";
        inline constexpr auto templateText = "text";
        namespace thread
        {
            inline constexpr auto msgCount       = "msgCount";
            inline constexpr auto snippet        = "snippet";
            inline constexpr auto unreadMsgCount = "unreadMsgCount";

        } // namespace thread

    } // namespace messages
        const int defaultLimit = 100; // will be removed after introducing pagination
    };
} // namespace parserFSM

M module-services/service-desktop/endpoints/messages/MessagesEndpoint.cpp => module-services/service-desktop/endpoints/messages/MessagesEndpoint.cpp +3 -3
@@ 14,11 14,11 @@ auto MessagesEndpoint::handle(Context &context) -> void
    case http::Method::get:
        helper->requestDataFromDB(context);
        break;
    case http::Method::post: // update entry
        helper->updateDBEntry(context);
    case http::Method::post:
        helper->createDBEntry(context);
        break;
    case http::Method::put:
        helper->createDBEntry(context);
        helper->updateDBEntry(context);
        break;
    case http::Method::del:
        helper->deleteDBEntry(context);

M module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp => module-services/service-desktop/endpoints/messages/MessagesEndpoint.hpp +1 -1
@@ 27,7 27,7 @@ class MessagesEndpoint : public parserFSM::Endpoint
    std::shared_ptr<parserFSM::MessageHelper> helper;

  public:
    MessagesEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    explicit MessagesEndpoint(sys::Service *_ownerServicePtr) : Endpoint(_ownerServicePtr)
    {
        debugName = "MessagesEndpoint";
        helper    = std::make_shared<parserFSM::MessageHelper>(ownerServicePtr);

M module-services/service-desktop/parser/ParserUtils.cpp => module-services/service-desktop/parser/ParserUtils.cpp +13 -11
@@ 5,16 5,18 @@

#include <log/log.hpp>

using namespace parserFSM;

bool http::isMethodValid(uint8_t method)
namespace parserFSM
{
    if (method == static_cast<uint8_t>(http::Method::get) || method == static_cast<uint8_t>(http::Method::post) ||
        method == static_cast<uint8_t>(http::Method::put) || method == static_cast<uint8_t>(http::Method::del)) {
        return true;
    }
    else {
        LOG_ERROR("Invalid method!");
        return false;

    bool http::isMethodValid(uint8_t method)
    {
        if (method == static_cast<uint8_t>(http::Method::get) || method == static_cast<uint8_t>(http::Method::post) ||
            method == static_cast<uint8_t>(http::Method::put) || method == static_cast<uint8_t>(http::Method::del)) {
            return true;
        }
        else {
            LOG_ERROR("Invalid method!");
            return false;
        }
    }
}
} // namespace parserFSM

M module-services/service-desktop/parser/ParserUtils.hpp => module-services/service-desktop/parser/ParserUtils.hpp +37 -27
@@ 45,7 45,7 @@ namespace parserFSM
            msg.erase(msg.begin(), msg.begin() + size_header);
        }

        inline unsigned long calcPayloadLength(const std::string header)
        inline unsigned long calcPayloadLength(const std::string &header)
        {
            try {
                return std::stol(header.substr(1, std::string::npos));


@@ 67,10 67,12 @@ namespace parserFSM
        }
        inline std::string extractPayload(std::string &msg, size_t payloadLength)
        {
            if (msg.size() > payloadLength)
            if (msg.size() > payloadLength) {
                return msg.substr(0, payloadLength);
            else
            }
            else {
                return msg;
            }
        }
    } // namespace message



@@ 140,9 142,9 @@ namespace parserFSM
            inline constexpr auto command = "command";
            namespace commands
            {
                inline constexpr auto upload   = "upload";
                inline constexpr auto rm       = "rm";
                inline constexpr auto download = "download";
                inline constexpr auto upload    = "upload";
                inline constexpr auto rm        = "rm";
                inline constexpr auto download  = "download";
                inline constexpr auto checkFile = "checkFile";
            } // namespace commands
        }     // namespace filesystem


@@ 159,27 161,35 @@ namespace parserFSM

        namespace messages
        {
            inline constexpr auto id           = "id";
            inline constexpr auto count        = "count";
            inline constexpr auto offset       = "offset";
            inline constexpr auto phoneNumber  = "phoneNumber";
            inline constexpr auto messageBody  = "messageBody";
            inline constexpr auto isUnread     = "unread";
            inline constexpr auto contactID    = "contactID";
            inline constexpr auto date         = "date";
            inline constexpr auto dateSent     = "dateSent";
            inline constexpr auto type         = "type";
            inline constexpr auto threadID     = "threadID";
            inline constexpr auto msgTemplate  = "template";
            inline constexpr auto templateText = "text";
            namespace thread
            {
                inline constexpr auto msgCount       = "msgCount";
                inline constexpr auto snippet        = "snippet";
                inline constexpr auto unreadMsgCount = "unreadMsgCount";

            } // namespace thread

            inline constexpr auto count            = "count";
            inline constexpr auto category         = "category";
            inline constexpr auto categoryMessage  = "message";
            inline constexpr auto categoryThread   = "thread";
            inline constexpr auto categoryTemplate = "template";

            inline constexpr auto limit              = "limit";
            inline constexpr auto offset             = "offset";
            inline constexpr auto totalCount         = "totalCount";
            inline constexpr auto nextPage           = "nextPage";
            inline constexpr auto entries            = "entries";
            inline constexpr auto messageBody        = "messageBody";
            inline constexpr auto messageCount       = "messageCount";
            inline constexpr auto messageID          = "messageID";
            inline constexpr auto messageType        = "messageType";
            inline constexpr auto phoneNumber        = "phoneNumber";
            inline constexpr auto receivedAt         = "receivedAt";
            inline constexpr auto sentAt             = "sentAt";
            inline constexpr auto lastUsedAt         = "lastUsedAt";
            inline constexpr auto lastUpdatedAt      = "lastUpdatedAt";
            inline constexpr auto isUnread           = "isUnread";
            inline constexpr auto contactID          = "contactID";
            inline constexpr auto numberID           = "numberID";
            inline constexpr auto threadID           = "threadID";
            inline constexpr auto messageSnippet     = "messageSnippet";
            inline constexpr auto unreadMessageCount = "unreadMessageCount";
            inline constexpr auto messageTemplate    = "messageTemplate";
            inline constexpr auto templateBody       = "templateBody";
            inline constexpr auto templateID         = "templateID";
        } // namespace messages

    } // namespace json

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +7 -7
@@ 221,24 221,24 @@ TEST_CASE("DB Helpers test - json encoding (messages)")
    message->ID        = 10;
    message->type      = SMSType::DRAFT;

    auto messageJson = helper->to_json(*message);
    auto messageJson = helper->toJson(*message);

    REQUIRE(messageJson[json::messages::messageBody] == "test message");
    REQUIRE(messageJson[json::messages::contactID] == 1);
    REQUIRE(messageJson[json::messages::date] == 12345);
    REQUIRE(messageJson[json::messages::dateSent] == 54321);
    REQUIRE(messageJson[json::messages::receivedAt] == 12345);
    REQUIRE(messageJson[json::messages::sentAt] == 54321);
    REQUIRE(messageJson[json::messages::threadID] == 1);
    REQUIRE(messageJson[json::messages::id] == 10);
    REQUIRE(messageJson[json::messages::messageID] == 10);

    auto messageTemplate = std::make_unique<SMSTemplateRecord>();

    messageTemplate->text = "test template";
    messageTemplate->ID   = 1;

    auto messageTemplateJson = helper->to_json(*messageTemplate);
    auto messageTemplateJson = helper->toJson(*messageTemplate);

    REQUIRE(messageTemplateJson[json::messages::templateText] == "test template");
    REQUIRE(messageTemplateJson[json::messages::id] == 1);
    REQUIRE(messageTemplateJson[json::messages::templateBody] == "test template");
    REQUIRE(messageTemplateJson[json::messages::templateID] == 1);
}

TEST_CASE("Context class test")

M test/pytest/service-desktop/test_messages.py => test/pytest/service-desktop/test_messages.py +25 -24
@@ 1,4 1,4 @@
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

import pytest


@@ 8,50 8,51 @@ from harness.interface.defs import status
@pytest.mark.service_desktop_test
def test_messages(harness):
    # getting the messages count
    body = {"count": True}
    body = {"category": "message", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    count = ret["body"]["count"]
    if count == 0:
        pytest.skip("No contacts entries, skipping")
        pytest.skip("No messages entries, skipping")

    # getting all the messages
    body = {"count": count}
    body = {"category": "message", "limit": count, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    messages = ret["body"]
    messages = ret["body"][1][1]  # getting entries
    messages_count = len(messages)
    assert messages_count == count

    # remove message
    sms_to_remove = messages[0]
    body = {"id": sms_to_remove["id"]}
    ret = harness.endpoint_request("messages", "del", body)
    assert ret["status"] == status["OK"]

    # getting the messages count again
    body = {"count": True}
    # getting a number of messages
    number_of_requested_messages = 3
    body = {"category": "message", "limit": number_of_requested_messages, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    assert ret["body"]["count"] == count - 1
    messages = ret["body"][1][1]  # getting entries
    messages_count = len(messages)
    assert messages_count == number_of_requested_messages

    # getting messages binded to contactID
    contact_id = 2  # in test dataset this one has some messages
    body = {"contactID": contact_id}
    # getting messages binded to threadID
    thread_id = 1
    body = {"category": "message", "threadID": thread_id, "limit": 10, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    for message in ret["body"]:
        assert message["contactID"] == contact_id
    for message in ret["body"][1][1]:
        assert message["threadID"] == thread_id

    # getting messages binded to threadID
    thread_id = 1
    body = {"threadID": thread_id, "count": 10}
    # remove message
    sms_to_remove = messages[0]
    body = {"category": "message", "messageID": sms_to_remove["messageID"]}
    ret = harness.endpoint_request("messages", "del", body)
    assert ret["status"] == status["OK"]

    # getting the messages count again
    body = {"category": "message", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    for message in ret["body"]:
        assert message["threadID"] == thread_id
    assert ret["body"]["count"] == count - 1

M test/pytest/service-desktop/test_templates.py => test/pytest/service-desktop/test_templates.py +33 -17
@@ 1,62 1,78 @@
# Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
import pytest
from harness.interface.defs import status


@pytest.mark.service_desktop_test
def test_messages(harness):
def test_templates(harness):
    # getting the templates count
    body = {"template": True, "count": True}
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    count = ret["body"]["count"]

    if count == 0:
        body = {"template": True, "text": "first template"}
        ret = harness.endpoint_request("messages", "put", body)
        body = {"category": "template", "templateBody": "first template"}
        ret = harness.endpoint_request("messages", "post", body)
        assert ret["status"] == status["OK"]

        body = {"template": True, "count": True}
        body = {"category": "template", "count": True}
        ret = harness.endpoint_request("messages", "get", body)
        assert ret["status"] == status["OK"]
        count = ret["body"]["count"]
        assert count

    # getting all templates
    body = {"template": True, "count": count}
    body = {"category": "template", "limit": count}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert len(ret["body"][1][1]) == count

    # getting a number of templates
    number_of_requested_templates = 3
    body = {"category": "template", "limit": number_of_requested_templates, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    templates = ret["body"][1][1]  # getting entries
    templates_count = len(templates)
    assert templates_count == number_of_requested_templates

    # getting template by ID
    body = {"category": "template", "templateID": 1}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert len(ret["body"]) == count

    # adding new template
    body = {"template": True, "text": "test template"}
    ret = harness.endpoint_request("messages", "put", body)
    body = {"category": "template", "templateBody": "test template"}
    ret = harness.endpoint_request("messages", "post", body)
    assert ret["status"] == status["OK"]

    # getting the templates count again
    body = {"template": True, "count": True}
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert ret["body"]["count"] == count + 1

    # getting template to remove
    body = {"template": True, "count": count + 1}
    body = {"category": "template", "limit": count + 1}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    for template in ret["body"]:
        if template["text"] == "test template":
            id = template["id"]
    templateid = 0
    for template in ret["body"][1][1]:
        if template["templateBody"] == "test template":
            templateid = template["templateID"]
            break

    # removing template
    body = {"template": True, "id": id}
    body = {"category": "template", "templateID": templateid}
    ret = harness.endpoint_request("messages", "del", body)
    assert ret["status"] == status["OK"]

    # getting the templates count again
    body = {"template": True, "count": True}
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert ret["body"]["count"] == count

A test/pytest/service-desktop/test_threads.py => test/pytest/service-desktop/test_threads.py +27 -0
@@ 0,0 1,27 @@
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
import pytest
from harness.interface.defs import status


@pytest.mark.service_desktop_test
def test_threads(harness):
    # getting all threads
    body = {"category": "thread"}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    # getting a number of threads
    number_of_requested_threads = 3
    body = {"category": "thread", "limit": number_of_requested_threads, "offset": 0}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]

    threads = ret["body"][1][1]  # getting entries
    threads_count = len(threads)
    assert threads_count == number_of_requested_threads

    # set thread as read
    body = {"category": "thread", "threadID": 1, "isUnread": False}
    ret = harness.endpoint_request("messages", "put", body)
    assert ret["status"] == status["OK"]

M test/pytest/test_search_sms.py => test/pytest/test_search_sms.py +2 -1
@@ 5,9 5,10 @@ import pytest

from harness.interface.defs import key_codes


@pytest.mark.rt1051
@pytest.mark.usefixtures("phone_unlocked")
def test_search_sms(harness, sms_text, phone_number):
    body = {"messageBody": sms_text, "phoneNumber": str(phone_number)}
    body = {"category": "message", "messageBody": sms_text, "phoneNumber": str(phone_number)}
    messages = harness.endpoint_request("messages", "get", body)["body"]
    assert len(messages) != 0

M test/pytest/test_send_message.py => test/pytest/test_send_message.py +10 -10
@@ 9,27 9,27 @@ from harness.interface.CDCSerial import Keytype

def erase_all_templates(harness):
    # getting the templates count
    body = {"template": True, "count": True}
    body = {"category": "template", "count": True}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    count = ret["body"]["count"]

    # getting all templates
    body = {"template": True, "count": count}
    body = {"category": "template", "limit": count}
    ret = harness.endpoint_request("messages", "get", body)
    assert ret["status"] == status["OK"]
    assert len(ret["body"]) == count
    assert len(ret["body"][1][1]) == count

    for template in ret["body"]:
        body = {"template": True, "id": template["id"]}
    for template in ret["body"][1][1]:
        body = {"category": "template", "templateID": template["templateID"]}
        del_res = harness.endpoint_request("messages", "del", body)
        assert del_res["status"] == status["OK"]


def add_new_template(harness, template_text: str):
    # adding new template
    body = {"template": True, "text": template_text}
    ret = harness.endpoint_request("messages", "put", body)
    body = {"category": "template", "templateBody": template_text}
    ret = harness.endpoint_request("messages", "post", body)
    assert ret["status"] == status["OK"]




@@ 72,19 72,19 @@ def erase_contacts_by_name(harness, name):


def get_message_by_text(harness, message: str, phone_number: str):
    body = {"messageBody": message, "phoneNumber": phone_number}
    body = {"category": "message", "messageBody": message, "phoneNumber": phone_number}
    return harness.endpoint_request("messages", "get", body)["body"]


# default sms type is draft
def prepare_sms(harness, message: str, phone_number: str, sms_type: int = 1):
    body = {"smsCommand": "smsAdd", "messageBody": message, "phoneNumber": phone_number, "type": sms_type}
    return harness.endpoint_request("developerMode", "put", body)
    return harness.endpoint_request("developerMode", "post", body)


def prepare_sms_template(harness, message: str, phone_number: str):
    body = {"template": True, "messageBody": message, "phoneNumber": phone_number}
    return harness.endpoint_request("developerMode", "put", body)
    return harness.endpoint_request("developerMode", "post", body)


def compare_messages(old_messages, new_messages, sms_type: SMSType = SMSType.OUTBOX):

M test/search_sms.py => test/search_sms.py +1 -2
@@ 14,7 14,7 @@ from harness.interface.error import TestError, Error
def search_sms(harness, message: str, phone_number: str):
    @harness.with_phone_unlocked
    def do_it(connection):
        body = {"messageBody": message, "phoneNumber": phone_number}
        body = {"category": "message", "messageBody": message, "phoneNumber": phone_number}
        messages = harness.endpoint_request("messages", "get", body)["body"]
        print(f'Found {len(messages)} messages')



@@ 49,4 49,3 @@ if __name__ == "__main__":
    except TestError as err:
        log.error(err)
        exit(err.get_error_code())