~aleteoryx/muditaos

366b03aa3782989b2d9f43d267fdbb11cda52100 — Pawel.Paprocki 5 years ago ecfcdf0
[EGD-5560] Add pagination for Calendar EP

Implement calendar EP pagination based on PagedContext
M module-services/service-desktop/endpoints/Context.hpp => module-services/service-desktop/endpoints/Context.hpp +6 -4
@@ 85,7 85,7 @@ namespace parserFSM
        }
        virtual ~Context() noexcept = default;

        virtual auto createSimpleResponse() -> std::string
        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)},


@@ 160,10 160,10 @@ namespace parserFSM
            return pageSize;
        }

        auto createSimpleResponse() -> std::string override
        auto createSimpleResponse(const std::string &entryTitle = json::entries) -> std::string override
        {
            auto elemsCount = responseContext.body.array_items().size();
            auto newBody    = json11::Json::object{{json::entries, responseContext.body},
            auto newBody    = json11::Json::object{{entryTitle, responseContext.body},
                                                {json::totalCount, static_cast<int>(totalCount)}};
            if (requestedLimit > elemsCount) {
                std::size_t offset = requestedOffset + elemsCount;


@@ 184,6 184,7 @@ namespace parserFSM
    namespace endpoint_pageing
    {
        inline constexpr std::size_t contactsPageSize = 10;
        inline constexpr std::size_t calendarEventsPageSize = 10;
    }

    class ContextFactory


@@ 193,7 194,8 @@ namespace parserFSM
        {
            switch (static_cast<EndpointType>(js[json::endpoint].int_value())) {
            // enable for pagination in other endpoints
            // case EndpointType::calendarEvents:
            case EndpointType::calendarEvents:
                return std::make_unique<PagedContext>(js, endpoint_pageing::calendarEventsPageSize);
            // case EndpointType::calllog:
            case EndpointType::contacts:
                // case EndpointType::messages:

M module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp => module-services/service-desktop/endpoints/calendarEvents/CalendarEventsHelper.cpp +35 -40
@@ 18,6 18,7 @@
#include <queries/calendar/QueryEventsRemoveICS.hpp>
#include <queries/calendar/QueryEventsGetAllLimited.hpp>
#include <variant>
#include <utility>

namespace parserFSM
{


@@ 76,10 77,8 @@ namespace parserFSM
                constexpr inline auto iCalUid = "iCalUid";
            } // namespace provider
        }     // namespace event
        constexpr inline auto offset      = "offset";
        constexpr inline auto limit       = "limit";
        constexpr inline auto count       = "count";
        constexpr inline auto total_count = "total_count";
        constexpr inline auto offset      = "offset";

    } // namespace json::calendar
} // namespace parserFSM


@@ 232,49 231,45 @@ auto CalendarEventsHelper::eventJsonObjectFrom(EventsRecord record) const -> jso

auto CalendarEventsHelper::requestDataFromDB(Context &context) -> sys::ReturnCodes
{
    const auto obj  = context.getBody();
    uint32_t offset = obj[json::calendar::offset].int_value();
    uint32_t limit  = obj[json::calendar::limit].int_value();
    auto query      = std::make_unique<db::query::events::GetAllLimited>(offset, limit);

    auto listener = std::make_unique<db::EndpointListener>(
        [&](db::QueryResult *result, Context context) {
            if (auto EventsResult = dynamic_cast<db::query::events::GetAllLimitedResult *>(result)) {
                auto records        = EventsResult->getResult();
                uint32_t totalCount = EventsResult->getCountResult();
                auto parser         = std::make_unique<ParserICS>();
                std::vector<ICalEvent> icalEvents;
    try {
        auto &ctx          = dynamic_cast<PagedContext &>(context);
        std::size_t limit  = ctx.getBody()[json::calendar::limit].int_value();
        std::size_t offset = ctx.getBody()[json::calendar::offset].int_value();
        ctx.setRequestedLimit(limit);
        ctx.setRequestedOffset(offset);
        auto query = std::make_unique<db::query::events::GetAllLimited>(offset, std::min(ctx.getPageSize(), limit));

        auto listener = std::make_unique<db::EndpointListenerWithPages>(
            [&](db::QueryResult *result, PagedContext &context) {
                if (auto EventsResult = dynamic_cast<db::query::events::GetAllLimitedResult *>(result)) {
                    auto records        = EventsResult->getResult();
                    uint32_t totalCount = EventsResult->getCountResult();
                    auto parser         = std::make_unique<ParserICS>();
                    std::vector<ICalEvent> icalEvents;
                    context.setTotalCount(totalCount);
                    auto eventsArray = json11::Json::array();

                    for (const auto &rec : records) {
                        auto eventObject = eventJsonObjectFrom(rec);
                        eventsArray.emplace_back(eventObject);
                    }
                    context.setResponseBody(eventsArray);
                    MessageHandler::putToSendQueue(context.createSimpleResponse(json::calendar::events));

                auto eventsArray = json11::Json::array();

                for (auto rec : records) {
                    auto eventObject = eventJsonObjectFrom(rec);

                    eventsArray.emplace_back(eventObject);
                    return true;
                }
                return false;
            },
            ctx);

                auto jsonObj = json11::Json::object({{json::calendar::events, eventsArray},
                                                     {json::calendar::count, std::to_string(records.size())},
                                                     {json::calendar::total_count, std::to_string(totalCount)}});

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

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

    query->setQueryListener(std::move(listener));
    auto [ret, _] = DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));

    if (ret) {
        return sys::ReturnCodes::Success;
        query->setQueryListener(std::move(listener));
        DBServiceAPI::GetQuery(ownerServicePtr, db::Interface::Name::Events, std::move(query));
    }
    else {
    catch (const std::exception &e) {
        LOG_ERROR("%s", e.what());
        return sys::ReturnCodes::Failure;
    }
    return sys::ReturnCodes::Success;
}

auto CalendarEventsHelper::frequencyToCustomRepeat(Frequency freq) const -> uint32_t

A test/pytest/service-desktop/test_calendar_events.py => test/pytest/service-desktop/test_calendar_events.py +102 -0
@@ 0,0 1,102 @@
# Copyright (c) 2017-2020, 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
import copy
import time

@pytest.mark.service_desktop_test
def test_calendar(harness):
    # add events
    add_body = {
        "calendar_events":[
            {
                "UID":"",
                "SUMMARY":"Test1",
                "DTSTART":"20200129T123600",
                "DTEND":"20200129T124600",
                "RRULE":{
                    "COUNT":"0",
                    "FREQ":"",
                    "INTERVAL":"0"
                },
                "VALARM":{
                    "ACTION":"",
                    "TRIGGER":""
                },
                "provider":{
                    "iCalUid":"",
                    "id":"",
                    "type":""
                }
            }
        ]
    }

    UIDS = []
    ret = harness.endpoint_request("events", "put", add_body)
    assert ret["status"] == status["OK"]
    print(ret)
    UIDS.insert(0,ret["body"]["UID"])
    event_count = 15
    for new_event_counter  in range(2,event_count+1):
        new_event = copy.deepcopy(add_body)
        new_event["calendar_events"][0]["SUMMARY"] = "Test" + str(new_event_counter)
        ret = harness.endpoint_request("events", "put", new_event)
        assert ret["status"] == status["OK"]
        print(ret)
        UIDS.insert(new_event_counter-1,ret["body"]["UID"])
    print('\n')

    # get events limit < pageSize - pagination not used
    print("get events without pagination")
    limit =  2
    offset=  2
    print("limit =",limit, "offset =",offset)
    get_body = {"limit": limit, "offset": offset}
    ret = harness.endpoint_request("events", "get", get_body)
    print(ret)
    print('\n')
    assert ret["status"] == status["OK"]

    # get events limit > pageSize - pagination used - basic scenario
    print("get events with pagination")
    limit = 12
    offset=  1
    print("limit =",limit, "offset =",offset)
    get_body = {"limit": limit, "offset": offset}
    ret = harness.endpoint_request("events", "get", get_body)
    print(ret)
    print('\n')
    assert ret["status"] == status["OK"]

    # get events limit > pageSize - pagination used - get all events
    print("get all events with pagination")
    count = ret["body"]["totalCount"]
    batch_size = 10
    divider = int(count / batch_size)
    reminder = count % batch_size
    events = []
    for i in range(divider):
        body = {"limit": batch_size, "offset": batch_size*i}
        ret = harness.endpoint_request("events", "get", body)
        assert ret["status"] == status["OK"]
        events = events + ret["body"]["calendar_events"]
    body = {"limit": reminder, "offset": count-reminder}
    ret = harness.endpoint_request("events", "get", body)
    assert ret["status"] == status["OK"]
    print("status =",ret["status"])
    events = events + ret["body"]["calendar_events"]
    events_length = len(events)
    assert events_length
    assert events_length == count

    # remove all added events - clean up
    print("\n")
    print("remove all added events")
    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"]