~aleteoryx/muditaos

b64eb0622b6c5e59eeb2161223e793ba4164ceb9 — Pawel Olejniczak 4 years ago c476395
[EGD-5783] Exclude empty body from response message

Remove body field from response message,
if it contains null. Add 204 and 501 status codes
and use them in proper responses.
204 stands for success but no content, and 501
means endpoint is not implemented.
Additionally some minor fixes.
25 files changed, 126 insertions(+), 117 deletions(-)

M module-services/service-desktop/README.md
M module-services/service-desktop/ServiceDesktop.cpp
M module-services/service-desktop/endpoints/Context.hpp
M module-services/service-desktop/endpoints/bluetooth/README.md
M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp
M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.hpp
M module-services/service-desktop/endpoints/calllog/CalllogHelper.cpp
M module-services/service-desktop/endpoints/calllog/CalllogHelper.hpp
M module-services/service-desktop/endpoints/contacts/ContactHelper.cpp
M module-services/service-desktop/endpoints/contacts/ContactHelper.hpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp
M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp
M module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp
M module-services/service-desktop/endpoints/factoryReset/FactoryReset.hpp
M module-services/service-desktop/endpoints/messages/MessageHelper.cpp
M module-services/service-desktop/parser/HttpEnums.hpp
M module-services/service-desktop/parser/ParserUtils.hpp
M module-services/service-desktop/tests/unittest.cpp
M test/harness
M test/pytest/service-desktop/test_calendar_events.py
M test/pytest/service-desktop/test_calllog.py
M test/pytest/service-desktop/test_contacts.py
M test/pytest/service-desktop/test_messages.py
M test/pytest/service-desktop/test_templates.py
M test/pytest/service-desktop/test_threads.py
M module-services/service-desktop/README.md => module-services/service-desktop/README.md +37 -36
@@ 3,12 3,6 @@ Service Desktop

This service is handling communication between Mudita Desktop App and PurePhone.

**Note:
Service desktop is disabled by default.
To turn it on, please uncomment this line in main.cpp:**

`        ret |= sys::SystemManager::CreateService(std::make_shared<ServiceDesktop>(), sysmgr.get());
`

### Protocol description



@@ 25,11 19,8 @@ uint8_t payload[payload_length];
##### Message types
*Single printable ASCII character.*
```
enum class Type
    {
        endpoint = '#',
        rawData = '$'
    };
endpoint = '#'
rawData = '$
```
##### Payload length
*Represented by 9 printable ASCII characters.*


@@ 42,7 33,7 @@ requestPayloadJson:
     { "endpoint", endpointNumber },
     { "method", methodNumber},
     { "body", requestBodyJson },
     { "uuid", uuidString }
     { "uuid", uuidNumber }
}
```
```


@@ 51,43 42,53 @@ responsePayloadJson:
     { "endpoint", endpointNumber },
     { "status", statusCode},
     { "body", responseBodyJson },
     { "uuid", uuidString }
     { "uuid", uuidNumber }
}
```
###### Endpoint
*Each endpoint has its unique number.*

```
enum class Endpoint
{
    deviceInfo = 1,
    update
};
invalid             = 0
deviceInfo          = 1
update              = 2
filesystemUpload    = 3
backup              = 4
restore             = 5
factory             = 6
contacts            = 7
messages            = 8
calllog             = 9
calendarEvents      = 10
developerMode       = 11
bluetooth           = 12
usbSecurity         = 13
```

###### Method
*HTTP - like methods. Each has different number. Only in request message.*

```
enum class Method
{
    get = 1,
    post,
    put,
    del
};
get     = 1
post    = 2
put     = 3
del     = 4
```

###### Status
*HTTP status codes. Only in response message.*

```
enum class Code
{
    OK = 200,
    BadRequest = 400,
    InternalServerError = 500
};
OK                  = 200
Accepted            = 202
NoContent           = 204
SeeOther            = 303
BadRequest          = 400
Forbidden           = 403
NotFound            = 404
NotAcceptable       = 406
InternalServerError = 500
NotImplemented      = 501
```

###### Body


@@ 113,7 114,7 @@ get contact:
```
response:
```
#000000861{"body": [{"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 19, "numbers": ["500639802"], "priName": "Alek"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 22, "numbers": ["500453837"], "priName": "Gra<0xc5><0xbc>yna"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 20, "numbers": ["500545546"], "priName": "Zofia"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bubel", "blocked": false, "favourite": true, "id": 44, "numbers": ["500087699"], "priName": "Brian"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bubel", "blocked": false, "favourite": true, "id": 43, "numbers": ["500656981"], "priName": "Cezary"}], "endpoint": 6, "status": 200, "uuid": "3"}
#000000859{"body": [{"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 19, "numbers": ["500639802"], "priName": "Alek"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 22, "numbers": ["500453837"], "priName": "Gra<0xc5><0xbc>yna"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bolig<0xc5><0x82>owa", "blocked": false, "favourite": true, "id": 20, "numbers": ["500545546"], "priName": "Zofia"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bubel", "blocked": false, "favourite": true, "id": 44, "numbers": ["500087699"], "priName": "Brian"}, {"address": "6 Czeczota St.\n02600 Warsaw", "altName": "Bubel", "blocked": false, "favourite": true, "id": 43, "numbers": ["500656981"], "priName": "Cezary"}], "endpoint": 6, "status": 200, "uuid": 3}
```

update contact:


@@ 122,10 123,10 @@ update contact:
```
response:
```
#000000057{"body": "", "endpoint": 6, "status": 500, "uuid": "123"}/
#000000043{"endpoint": 6, "status": 500, "uuid": 123}/
```
```
#000000057{"body": "", "endpoint": 6, "status": 200, "uuid": "123"}
#000000043{"endpoint": 6, "status": 204, "uuid": 123}
```

add contact:


@@ 134,7 135,7 @@ add contact:
```
response:
```
#000000057{"body": "", "endpoint": 6, "status": 200, "uuid": "123"}
#000000043{"endpoint": 6, "status": 204, "uuid": 123}
```

remove contact:


@@ 143,7 144,7 @@ remove contact:
```
response:
```
#000000057{"body": "", "endpoint": 6, "status": 200, "uuid": "123"}
#000000043{"endpoint": 6, "status": 204, "uuid": 123}
```

### Service documentation

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +1 -1
@@ 158,7 158,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
        }

        if (updateOsMsg != nullptr && updateOsMsg->messageType == updateos::UpdateMessageType::UpdateNow) {
            LOG_DEBUG("ServiceDesktop::DataReceivedHandler file:%s uuuid:%" PRIu32 "",
            LOG_DEBUG("ServiceDesktop::DataReceivedHandler file:%s uuid:%" PRIu32 "",
                      updateOsMsg->updateStats.updateFile.c_str(),
                      updateOsMsg->updateStats.uuid);


M module-services/service-desktop/endpoints/Context.hpp => module-services/service-desktop/endpoints/Context.hpp +10 -4
@@ 83,10 83,16 @@ namespace parserFSM

        virtual auto createSimpleResponse(const std::string &entryTitle = json::entries) -> std::string
        {
            json11::Json responseJson = json11::Json::object{{json::endpoint, static_cast<int>(getEndpoint())},
                                                             {json::status, static_cast<int>(responseContext.status)},
                                                             {json::uuid, getUuid()},
                                                             {json::body, responseContext.body}};
            const json11::Json responseJson =
                responseContext.body.is_null()
                    ? json11::Json::object{{json::endpoint, static_cast<int>(getEndpoint())},
                                           {json::status, static_cast<int>(responseContext.status)},
                                           {json::uuid, getUuid()}}
                    : json11::Json::object{{json::endpoint, static_cast<int>(getEndpoint())},
                                           {json::status, static_cast<int>(responseContext.status)},
                                           {json::uuid, getUuid()},
                                           {json::body, responseContext.body}};

            return buildResponseStr(responseJson.dump().size(), responseJson.dump());
        }


M module-services/service-desktop/endpoints/bluetooth/README.md => module-services/service-desktop/endpoints/bluetooth/README.md +1 -1
@@ 52,7 52,7 @@ responsePayloadJson:
    { "endpoint", endpointNumber },
    { "status", statusCode},
    { "body", responseBodyJson },
    { "uuid", uuidString }
    { "uuid", uuidNumber }
}
```
The `Bluetooth` endpoint provides responses according to the following table: 

M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp +14 -13
@@ 77,14 77,14 @@ namespace parserFSM
                constexpr inline auto iCalUid = "iCalUid";
            } // namespace provider
        }     // namespace event
        constexpr inline auto limit       = "limit";
        constexpr inline auto offset      = "offset";
        constexpr inline auto limit  = "limit";
        constexpr inline auto offset = "offset";

    } // namespace json::calendar
} // namespace parserFSM
using namespace parserFSM;

auto CalendarEventsHelper::isICalEventValid(ICalEvent icalEvent) const -> bool
auto CalendarEventsHelper::isICalEventValid(const ICalEvent &icalEvent) const -> bool
{
    if (!icalEvent.event.isValid) {
        LOG_ERROR("Ical event invalid!");


@@ 197,7 197,7 @@ auto CalendarEventsHelper::icalEventFrom(const EventsRecord &record) const -> IC
    return ICalEvent{event, alarm, rrule};
}

auto CalendarEventsHelper::eventJsonObjectFrom(EventsRecord record) const -> json11::Json
auto CalendarEventsHelper::eventJsonObjectFrom(const EventsRecord &record) const -> json11::Json
{
    auto icalEvent = icalEventFrom(record);
    if (!isICalEventValid(icalEvent)) {


@@ 326,7 326,7 @@ auto CalendarEventsHelper::eventsRecordFrom(ICalEvent &icalEvent) const -> Event
    return record;
}

auto CalendarEventsHelper::ICalEventFromJson(json11::Json eventObj) const -> ICalEvent
auto CalendarEventsHelper::ICalEventFromJson(const json11::Json &eventObj) const -> ICalEvent
{
    ICalEvent icalEvent;
    icalEvent.event.setUID(eventObj[json::calendar::event::uid].string_value());


@@ 359,7 359,7 @@ auto CalendarEventsHelper::createDBEntry(Context &context) -> sys::ReturnCodes
    const auto eventsJsonObj   = context.getBody();
    const auto eventsJsonArray = eventsJsonObj[json::calendar::events].array_items();
    bool ret                   = true;
    for (auto event : eventsJsonArray) {
    for (const auto &event : eventsJsonArray) {

        auto icalEvent = ICalEventFromJson(event);



@@ 385,9 385,9 @@ auto CalendarEventsHelper::createDBEntry(Context &context) -> sys::ReturnCodes
        auto query    = std::make_unique<db::query::events::Add>(record);
        auto listener = std::make_unique<db::EndpointListener>(
            [&](db::QueryResult *result, Context context) {
                if (auto EventResult = dynamic_cast<db::query::events::AddResult *>(result)) {
                if (auto eventResult = dynamic_cast<db::query::events::AddResult *>(result)) {

                    context.setResponseStatus(EventResult->getResult() ? http::Code::OK
                    context.setResponseStatus(eventResult->getResult() ? http::Code::OK
                                                                       : http::Code::InternalServerError);

                    MessageHandler::putToSendQueue(context.createSimpleResponse());


@@ 416,7 416,7 @@ auto CalendarEventsHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
    auto eventsJsonObj = context.getBody();

    bool ret = true;
    for (auto event : eventsJsonObj[json::calendar::events].array_items()) {
    for (const auto &event : eventsJsonObj[json::calendar::events].array_items()) {

        auto icalEvent = ICalEventFromJson(event);
        if (!isICalEventValid(icalEvent) || icalEvent.event.getUID().empty()) {


@@ 429,8 429,8 @@ auto CalendarEventsHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
        auto query    = std::make_unique<db::query::events::EditICS>(record);
        auto listener = std::make_unique<db::EndpointListener>(
            [](db::QueryResult *result, Context context) {
                if (auto EventResult = dynamic_cast<db::query::events::EditICSResult *>(result)) {
                    context.setResponseStatus(EventResult->getResult() ? http::Code::OK
                if (auto eventResult = dynamic_cast<db::query::events::EditICSResult *>(result)) {
                    context.setResponseStatus(eventResult->getResult() ? http::Code::NoContent
                                                                       : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;


@@ 466,8 466,9 @@ auto CalendarEventsHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
    auto query    = std::make_unique<db::query::events::RemoveICS>(UID);
    auto listener = std::make_unique<db::EndpointListener>(
        [=](db::QueryResult *result, Context context) {
            if (auto EventResult = dynamic_cast<db::query::events::RemoveICSResult *>(result)) {
                context.setResponseStatus(EventResult->getResult() ? http::Code::OK : http::Code::InternalServerError);
            if (auto eventResult = dynamic_cast<db::query::events::RemoveICSResult *>(result)) {
                context.setResponseStatus(eventResult->getResult() ? http::Code::NoContent
                                                                   : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;
            }

M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.hpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.hpp +4 -4
@@ 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

#pragma once


@@ 29,9 29,9 @@ namespace parserFSM
        [[nodiscard]] auto repeatFrom(RecurrenceRule &rrule) const -> Repeat;
        [[nodiscard]] auto eventsRecordFrom(ICalEvent &icalEvent) const -> EventsRecord;

        [[nodiscard]] auto eventJsonObjectFrom(EventsRecord record) const -> json11::Json;
        [[nodiscard]] auto ICalEventFromJson(json11::Json eventObj) const -> ICalEvent;
        [[nodiscard]] auto isICalEventValid(ICalEvent event) const -> bool;
        [[nodiscard]] auto eventJsonObjectFrom(const EventsRecord &record) const -> json11::Json;
        [[nodiscard]] auto ICalEventFromJson(const json11::Json &eventObj) const -> ICalEvent;
        [[nodiscard]] auto isICalEventValid(const ICalEvent &event) const -> bool;

      public:
        CalendarEventsHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr)

M module-services/service-desktop/endpoints/calllog/CalllogHelper.cpp => module-services/service-desktop/endpoints/calllog/CalllogHelper.cpp +5 -5
@@ 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

#include "CalllogHelper.hpp"


@@ 47,7 47,7 @@ auto CalllogHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
                    auto recordsPtr = std::make_unique<std::vector<CalllogRecord>>(contactResult->getRecords());
                    json11::Json::array calllogArray;

                    for (auto record : *recordsPtr.get()) {
                    for (const auto &record : *recordsPtr) {
                        calllogArray.emplace_back(CalllogHelper::to_json(record));
                    }



@@ 102,7 102,7 @@ auto CalllogHelper::getCalllogByContactID(Context &context) -> sys::ReturnCodes
                auto records = calllogResult->getResults();
                json11::Json::array calllogArray;

                for (auto record : records) {
                for (const auto &record : records) {
                    calllogArray.emplace_back(CalllogHelper::to_json(record));
                }



@@ 133,7 133,7 @@ auto CalllogHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
        [](db::QueryResult *result, Context context) {
            if (auto calllogResult = dynamic_cast<db::query::CalllogRemoveResult *>(result)) {

                context.setResponseStatus(calllogResult->getResults() ? http::Code::OK
                context.setResponseStatus(calllogResult->getResults() ? http::Code::NoContent
                                                                      : http::Code::InternalServerError);
                MessageHandler::putToSendQueue(context.createSimpleResponse());
                return true;


@@ 151,7 151,7 @@ auto CalllogHelper::requestCount(Context &context) -> sys::ReturnCodes
{
    return sys::ReturnCodes::Unresolved;
}
auto CalllogHelper::to_json(CalllogRecord record) -> json11::Json
auto CalllogHelper::to_json(const CalllogRecord &record) -> json11::Json
{
    std::unique_ptr<std::stringstream> ss = std::make_unique<std::stringstream>();


M module-services/service-desktop/endpoints/calllog/CalllogHelper.hpp => module-services/service-desktop/endpoints/calllog/CalllogHelper.hpp +3 -3
@@ 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

#pragma once


@@ 27,7 27,7 @@ namespace parserFSM
    class CalllogHelper : public DBHelper
    {
      public:
        CalllogHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr){};
        explicit CalllogHelper(sys::Service *_ownerServicePtr) : DBHelper(_ownerServicePtr){};

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


@@ 35,7 35,7 @@ namespace parserFSM
        auto deleteDBEntry(Context &context) -> sys::ReturnCodes override;

        auto requestCount(Context &context) -> sys::ReturnCodes;
        static auto to_json(CalllogRecord record) -> json11::Json;
        static auto to_json(const CalllogRecord &record) -> json11::Json;
        auto getCalllogCount(Context &context) -> sys::ReturnCodes;
        auto getCalllogByContactID(Context &context) -> sys::ReturnCodes;
    };

M module-services/service-desktop/endpoints/contacts/ContactHelper.cpp => module-services/service-desktop/endpoints/contacts/ContactHelper.cpp +7 -7
@@ 31,11 31,11 @@

using namespace parserFSM;

auto ContactHelper::to_json(ContactRecord record) -> json11::Json
auto ContactHelper::to_json(const ContactRecord &record) -> json11::Json
{
    auto numberArray = json11::Json::array();

    for (auto number : record.numbers) {
    for (const auto &number : record.numbers) {
        numberArray.emplace_back(number.number.getEntered().c_str());
    }



@@ 49,7 49,7 @@ auto ContactHelper::to_json(ContactRecord record) -> json11::Json
    return recordEntry;
}

auto ContactHelper::from_json(json11::Json contactJSON) -> ContactRecord
auto ContactHelper::from_json(const json11::Json &contactJSON) -> ContactRecord
{
    auto newRecord            = ContactRecord();
    newRecord.primaryName     = UTF8(contactJSON[json::contacts::primaryName].string_value());


@@ 57,7 57,7 @@ auto ContactHelper::from_json(json11::Json contactJSON) -> ContactRecord
    newRecord.alternativeName = UTF8(contactJSON[json::contacts::alternativeName].string_value());
    newRecord.address         = UTF8(contactJSON[json::contacts::address].string_value());

    for (auto num : contactJSON[json::contacts::numbers].array_items()) {
    for (const auto &num : contactJSON[json::contacts::numbers].array_items()) {
        utils::PhoneNumber phoneNumber(num.string_value());
        auto contactNum = ContactRecord::Number(phoneNumber.get(), phoneNumber.toE164(), ContactNumberType ::CELL);
        newRecord.numbers.push_back(contactNum);


@@ 92,7 92,7 @@ auto ContactHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
                    context.setTotalCount(contactResult->getAllLength());
                    json11::Json::array contactsArray;

                    for (const auto &record : *recordsPtr.get()) {
                    for (const auto &record : *recordsPtr) {
                        contactsArray.emplace_back(ContactHelper::to_json(record));
                    }



@@ 216,7 216,7 @@ auto ContactHelper::updateDBEntry(Context &context) -> sys::ReturnCodes
        [](db::QueryResult *result, Context context) {
            if (auto contactResult = dynamic_cast<db::query::ContactUpdateResult *>(result)) {

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



@@ 243,7 243,7 @@ auto ContactHelper::deleteDBEntry(Context &context) -> sys::ReturnCodes
        [](db::QueryResult *result, Context context) {
            if (auto contactResult = dynamic_cast<db::query::ContactRemoveResult *>(result)) {

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


M module-services/service-desktop/endpoints/contacts/ContactHelper.hpp => module-services/service-desktop/endpoints/contacts/ContactHelper.hpp +2 -2
@@ 38,8 38,8 @@ namespace parserFSM

        auto requestCount(Context &context) -> sys::ReturnCodes;
        auto requestContactByID(Context &context) -> sys::ReturnCodes;
        static auto to_json(ContactRecord record) -> json11::Json;
        static auto from_json(json11::Json contactJSON) -> ContactRecord;
        static auto to_json(const ContactRecord &record) -> json11::Json;
        static auto from_json(const json11::Json &contactJSON) -> ContactRecord;
    };

    namespace json::contacts

M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.cpp +2 -2
@@ 235,7 235,7 @@ bool DeveloperModeHelper::sendKeypress(bsp::KeyCodes keyCode, gui::InputEvent::S

    gui::InputEvent event(key, state, static_cast<gui::KeyCode>(keyCode));
    LOG_INFO("Sending %s", event.str().c_str());
    auto message = std::make_shared<app::AppInputEventMessage>(std::move(event));
    auto message = std::make_shared<app::AppInputEventMessage>(event);

    return owner->bus.sendUnicast(std::move(message), service::name::evt_manager);
}


@@ 265,7 265,7 @@ bool DeveloperModeHelper::requestCellularPowerStateChange(const int cellularStat
    }
    return res;
}
auto DeveloperModeHelper::smsRecordFromJson(json11::Json msgJson) -> SMSRecord
auto DeveloperModeHelper::smsRecordFromJson(const json11::Json &msgJson) -> SMSRecord
{
    auto record = SMSRecord();


M module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeHelper.hpp +1 -1
@@ 27,7 27,7 @@ namespace parserFSM
        bool sendKeypress(bsp::KeyCodes keyCode, gui::InputEvent::State state);

        void requestSimChange(const int simSelected);
        auto smsRecordFromJson(json11::Json msgJson) -> SMSRecord;
        auto smsRecordFromJson(const json11::Json &msgJson) -> SMSRecord;
        bool requestCellularPowerStateChange(const int simSelected);
        bool requestServiceStateInfo(sys::Service *serv);
        auto prepareSMS(Context &context) -> ProcessResult;

M module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp => module-services/service-desktop/endpoints/factoryReset/FactoryReset.cpp +7 -7
@@ 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

#include "FactoryReset.hpp"


@@ 28,7 28,7 @@ namespace FactoryReset
        inline constexpr auto copy_buf = 8192 * 4;
    } // namespace

    static bool CopyFile(std::string sourcefile, std::string targetfile);
    static bool CopyFile(const std::string &sourcefile, const std::string &targetfile);

    static int recurseDepth            = 0;
    static const int max_recurse_depth = 120; /* 120 is just an arbitrary value of max number of recursive calls.


@@ 70,7 70,7 @@ namespace FactoryReset
        return true;
    }

    bool DeleteDirContent(std::string dir)
    bool DeleteDirContent(const std::string &dir)
    {
        for (auto &direntry : std::filesystem::directory_iterator(dir.c_str())) {
            if ((direntry.path().string().compare(".") != 0) && (direntry.path().string().compare("..") != 0) &&


@@ 105,7 105,7 @@ namespace FactoryReset
        return true;
    }

    bool CopyDirContent(std::string sourcedir, std::string targetdir)
    bool CopyDirContent(const std::string &sourcedir, const std::string &targetdir)
    {
        if (recurseDepth >= max_recurse_depth) {
            LOG_ERROR("FactoryReset: recurse level %d (too high), error assumed, skipping restore of dir %s",


@@ 176,7 176,7 @@ namespace FactoryReset
        return true;
    }

    static bool CopyFile(std::string sourcefile, std::string targetfile)
    static bool CopyFile(const std::string &sourcefile, const std::string &targetfile)
    {
        bool ret  = true;
        auto lamb = [](std::FILE *stream) { std::fclose(stream); };


@@ 184,10 184,10 @@ namespace FactoryReset
        std::unique_ptr<std::FILE, decltype(lamb)> sf(std::fopen(sourcefile.c_str(), "r"), lamb);
        std::unique_ptr<std::FILE, decltype(lamb)> tf(std::fopen(targetfile.c_str(), "w"), lamb);

        if ((sf.get() != nullptr) && (tf.get() != nullptr)) {
        if ((sf != nullptr) && (tf != nullptr)) {
            std::unique_ptr<unsigned char[]> buffer(new unsigned char[copy_buf]);

            if (buffer.get() != nullptr) {
            if (buffer != nullptr) {
                uint32_t loopcount = (std::filesystem::file_size(sourcefile) / copy_buf) + 1u;
                uint32_t readsize  = copy_buf;


M module-services/service-desktop/endpoints/factoryReset/FactoryReset.hpp => module-services/service-desktop/endpoints/factoryReset/FactoryReset.hpp +3 -3
@@ 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

#pragma once


@@ 15,6 15,6 @@ namespace sys
namespace FactoryReset
{
    bool Run(sys::Service *ownerService);
    bool DeleteDirContent(std::string dir);
    bool CopyDirContent(std::string sourcedir, std::string targetdir);
    bool DeleteDirContent(const std::string &dir);
    bool CopyDirContent(const std::string &sourcedir, const std::string &targetdir);
} // namespace FactoryReset

M module-services/service-desktop/endpoints/messages/MessageHelper.cpp => module-services/service-desktop/endpoints/messages/MessageHelper.cpp +9 -9
@@ 42,7 42,7 @@ namespace parserFSM

        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::createdAt, 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)},


@@ 167,7 167,7 @@ namespace parserFSM

    auto MessageHelper::createSMS(Context &context) -> sys::ReturnCodes
    {
        context.setResponseStatus(http::Code::InternalServerError);
        context.setResponseStatus(http::Code::NotImplemented);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Success;
    }


@@ 184,7 184,7 @@ namespace parserFSM
            [=](db::QueryResult *result, Context context) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSRemoveResult *>(result)) {

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


@@ 240,7 240,7 @@ namespace parserFSM
            [=](db::QueryResult *result, Context context) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateUpdateResult *>(result)) {

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


@@ 273,7 273,7 @@ namespace parserFSM
            [=](db::QueryResult *result, Context context) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateAddResult *>(result)) {

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


@@ 305,7 305,7 @@ namespace parserFSM
            [=](db::QueryResult *result, Context context) {
                if (auto smsTemplateResult = dynamic_cast<db::query::SMSTemplateRemoveResult *>(result)) {

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


@@ 339,7 339,7 @@ namespace parserFSM
                        auto theResults = threadsResults->getResults();
                        threadsArray.reserve(theResults.size());
                        for (auto &record : theResults) {
                            threadsArray.emplace_back(MessageHelper::toJson(std::move(record)));
                            threadsArray.emplace_back(MessageHelper::toJson(record));
                        }
                        context.setResponseBody(std::move(threadsArray));
                        context.setTotalCount(threadsResults->getTotalCount());


@@ 386,7 386,7 @@ namespace parserFSM
            [=](db::QueryResult *result, Context context) {
                if (auto threadResult = dynamic_cast<db::query::MarkAsReadResult *>(result)) {

                    context.setResponseStatus(threadResult->getResult() ? http::Code::OK
                    context.setResponseStatus(threadResult->getResult() ? http::Code::NoContent
                                                                        : http::Code::InternalServerError);
                    MessageHandler::putToSendQueue(context.createSimpleResponse());
                    return true;


@@ 406,7 406,7 @@ namespace parserFSM

    auto MessageHelper::deleteThread(Context &context) -> sys::ReturnCodes
    {
        context.setResponseStatus(http::Code::InternalServerError);
        context.setResponseStatus(http::Code::NotImplemented);
        MessageHandler::putToSendQueue(context.createSimpleResponse());
        return sys::ReturnCodes::Success;
    }

M module-services/service-desktop/parser/HttpEnums.hpp => module-services/service-desktop/parser/HttpEnums.hpp +3 -1
@@ 13,12 13,14 @@ namespace parserFSM::http
    {
        OK                  = 200,
        Accepted            = 202,
        NoContent           = 204,
        SeeOther            = 303,
        BadRequest          = 400,
        Forbidden           = 403,
        NotFound            = 404,
        NotAcceptable       = 406,
        InternalServerError = 500
        InternalServerError = 500,
        NotImplemented      = 501
    };

    /*! Enum class for the HTTP methods.

M module-services/service-desktop/parser/ParserUtils.hpp => module-services/service-desktop/parser/ParserUtils.hpp +1 -1
@@ 157,7 157,7 @@ namespace parserFSM
            inline constexpr auto messageType        = "messageType";
            inline constexpr auto phoneNumber        = "phoneNumber";
            inline constexpr auto receivedAt         = "receivedAt";
            inline constexpr auto sentAt             = "sentAt";
            inline constexpr auto createdAt          = "createdAt";
            inline constexpr auto lastUsedAt         = "lastUsedAt";
            inline constexpr auto lastUpdatedAt      = "lastUpdatedAt";
            inline constexpr auto isUnread           = "isUnread";

M module-services/service-desktop/tests/unittest.cpp => module-services/service-desktop/tests/unittest.cpp +3 -4
@@ 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

#include <endpoints/Endpoint.hpp>


@@ 217,7 217,7 @@ TEST_CASE("DB Helpers test - json encoding (messages)")
    REQUIRE(messageJson[json::messages::messageBody] == "test message");
    REQUIRE(messageJson[json::messages::contactID] == 1);
    REQUIRE(messageJson[json::messages::receivedAt] == 12345);
    REQUIRE(messageJson[json::messages::sentAt] == 54321);
    REQUIRE(messageJson[json::messages::createdAt] == 54321);
    REQUIRE(messageJson[json::messages::threadID] == 1);
    REQUIRE(messageJson[json::messages::messageID] == 10);



@@ 246,8 246,7 @@ TEST_CASE("Context class test")
        REQUIRE(context.getMethod() == http::Method::get);
        REQUIRE(context.getUuid() == 12345);
        REQUIRE(context.getEndpoint() == EndpointType::contacts);
        REQUIRE(context.createSimpleResponse() ==
                R"(#000000059{"body": null, "endpoint": 7, "status": 200, "uuid": 12345})");
        REQUIRE(context.createSimpleResponse() == R"(#000000045{"endpoint": 7, "status": 204, "uuid": 12345})");

        context.setResponseBody(context.getBody());
        REQUIRE(context.createSimpleResponse() ==

M test/harness => test/harness +1 -1
@@ 1,1 1,1 @@
Subproject commit 5e89897197e210f9fec418b0765d6234275d4069
Subproject commit 4315fbc4d5bb90f469b682f63e01bf703c7e43d0

M test/pytest/service-desktop/test_calendar_events.py => test/pytest/service-desktop/test_calendar_events.py +2 -2
@@ 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
from harness.interface.defs import status


@@ 91,6 91,6 @@ def test_calendar(harness):
    for ev in range(0,event_count):
        del_body = {"UID": UIDS[ev]}
        ret = harness.endpoint_request("events", "del", del_body)
        assert ret["status"] == status["OK"]
        assert ret["status"] == status["NoContent"]



M test/pytest/service-desktop/test_calllog.py => test/pytest/service-desktop/test_calllog.py +2 -2
@@ 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
from harness.interface.defs import status


@@ 41,7 41,7 @@ def test_calllog(harness):
    # remove exact call log
    body = {"id": calllog[0]["id"]}
    ret = harness.endpoint_request("calllog", "del", body)
    assert ret["status"] == status["OK"]
    assert ret["status"] == status["NoContent"]

    # getting the count again
    body = {"count": True}

M test/pytest/service-desktop/test_contacts.py => test/pytest/service-desktop/test_contacts.py +3 -3
@@ 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
from harness.interface.defs import status


@@ 93,7 93,7 @@ def test_contacts(harness):
            "priName": "Test2",
            "id": contact_id_to_update}
    ret = harness.endpoint_request("contacts", "post", body)
    assert ret["status"] == status["OK"]
    assert ret["status"] == status["NoContent"]

    # gathering updated contact
    body = {"id": contact_id_to_update}


@@ 110,7 110,7 @@ def test_contacts(harness):
    # removing added contact
    body = {"id": contact_id_to_update}
    ret = harness.endpoint_request("contacts", "del", body)
    assert ret["status"] == status["OK"]
    assert ret["status"] == status["NoContent"]

    # verifying count
    body = {"count": True}

M test/pytest/service-desktop/test_messages.py => test/pytest/service-desktop/test_messages.py +1 -1
@@ 176,7 176,7 @@ def test_remove_message(harness):
    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"]
    assert ret["status"] == status["NoContent"]

    # get messages count again
    body = {"category": "message", "count": True}

M test/pytest/service-desktop/test_templates.py => test/pytest/service-desktop/test_templates.py +3 -3
@@ 19,7 19,7 @@ class TemplatesTester:
    def __add_template(self):
        body = {"category": "template", "templateBody": self.template_body}
        ret = self.harness.endpoint_request("messages", "post", body)
        assert ret["status"] == status["OK"]
        assert ret["status"] == status["NoContent"]
        return ret

    def __get_templates(self, limit, offset):


@@ 29,7 29,7 @@ class TemplatesTester:
    def __remove_template(self, template_id):
        body = {"category": "template", "templateID": template_id}
        ret = self.harness.endpoint_request("messages", "del", body)
        assert ret["status"] == status["OK"]
        assert ret["status"] == status["NoContent"]

    def __get_all_templates(self):
        body = {"category": "template", "count": True}


@@ 100,7 100,7 @@ class TemplatesTester:
                new_template_body = "NEW TEMPLATE BODY TEST"
                body = {"category": "template", "templateID": template["templateID"], "templateBody": new_template_body}
                ret = self.harness.endpoint_request("messages", "put", body)
                assert ret["status"] == status["OK"]
                assert ret["status"] == status["NoContent"]

                # and then remove it to clean env
                self.__remove_template(template["templateID"])

M test/pytest/service-desktop/test_threads.py => test/pytest/service-desktop/test_threads.py +1 -1
@@ 27,4 27,4 @@ def test_threads(harness):
    # set thread as read
    body = {"category": "thread", "threadID": 1, "isUnread": False}
    ret = harness.endpoint_request("messages", "put", body)
    assert ret["status"] == status["OK"]
    assert ret["status"] == status["NoContent"]