~aleteoryx/muditaos

b1f6d67fce033cc451f15721b3d9a51374409ef6 — Jakub Pyszczak 4 years ago f482194
[EGD-7505] Developer mode endpoint extended

Developer mode endpoint extender to support
file renaming, removal and listing dirs.
Harness requirements updated.
M module-services/service-desktop/CMakeLists.txt => module-services/service-desktop/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ set(SOURCES
    endpoints/contacts/ContactsEndpoint.cpp
    endpoints/developerMode/DeveloperModeEndpoint.cpp
    endpoints/developerMode/DeveloperModeHelper.cpp
    endpoints/developerMode/fs/FS_Helper.cpp
    endpoints/developerMode/Mode/UI_Helper.cpp
    endpoints/developerMode/event/DomRequest.cpp
    endpoints/developerMode/event/ATRequest.cpp

M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.cpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.cpp +3 -0
@@ 37,5 37,8 @@ auto DeveloperModeEndpoint::helperSwitcher(parserFSM::Context &ctx) -> parserFSM
    if (ctx.getBody()["ui"] == true) {
        return *uiHelper;
    }
    if (ctx.getBody()["fs"] == true) {
        return *fsHelper;
    }
    return *helper;
}

M module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp => module-services/service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp +4 -1
@@ 5,6 5,7 @@

#include "DeveloperModeHelper.hpp"
#include "Mode/UI_Helper.hpp"
#include "fs/FS_Helper.hpp"
#include <endpoints/Endpoint.hpp>
#include <parser/ParserUtils.hpp>



@@ 27,11 28,13 @@ class DeveloperModeEndpoint : public parserFSM::Endpoint
  private:
    const std::unique_ptr<parserFSM::DeveloperModeHelper> helper;
    const std::unique_ptr<parserFSM::UI_Helper> uiHelper;
    const std::unique_ptr<parserFSM::FS_Helper> fsHelper;

  public:
    explicit DeveloperModeEndpoint(sys::Service *_ownerServicePtr)
        : Endpoint(_ownerServicePtr), helper(std::make_unique<parserFSM::DeveloperModeHelper>(ownerServicePtr)),
          uiHelper(std::make_unique<parserFSM::UI_Helper>(ownerServicePtr))
          uiHelper(std::make_unique<parserFSM::UI_Helper>(ownerServicePtr)),
          fsHelper(std::make_unique<parserFSM::FS_Helper>(ownerServicePtr))
    {
        debugName = "DeveloperModeEndpoint";
    }

A module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.cpp => module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.cpp +93 -0
@@ 0,0 1,93 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "FS_Helper.hpp"

#include <log.hpp>
#include <service-desktop/Constants.hpp>
#include <service-desktop/DeveloperModeMessage.hpp>
#include <service-desktop/parser/MessageHandler.hpp>

#include <filesystem>
#include <system_error>

namespace parserFSM
{
    void FS_Helper::preProcess(http::Method method, Context &context)
    {
        LOG_INFO("In FS helper - requesting %d", static_cast<int>(method));
    }

    auto FS_Helper::processGet(Context &context) -> ProcessResult
    {
        const auto &body = context.getBody();
        if (body[json::fs::listDir].is_string()) {
            const auto &dir = body[json::fs::listDir].string_value();
            auto response   = requestListDir(dir);
            return {sent::no, std::move(response)};
        }
        else {
            return {sent::no, endpoint::ResponseContext{.status = http::Code::BadRequest}};
        }
    }

    auto FS_Helper::processPut(Context &context) -> ProcessResult
    {
        auto body = context.getBody();
        auto code = http::Code::BadRequest;
        if (body[json::fs::removeFile].is_string()) {
            const auto &fileName = body[json::fs::removeFile].string_value();
            try {
                code = requestFileRemoval(fileName) ? http::Code::NoContent : http::Code::NotFound;
            }
            catch (const std::filesystem::filesystem_error &) {
                LOG_WARN("Can't remove requested file");
                code = http::Code::InternalServerError;
            }
        }
        else if (body[json::fs::renameFile].is_string()) {
            const auto &fileName = body[json::fs::renameFile].string_value();
            if (body[json::fs::destFileName].is_string()) {
                const auto &destFileName = body[json::fs::destFileName].string_value();
                code = requestFileRename(fileName, destFileName) ? http::Code::NoContent : http::Code::NotFound;
            }
            else {
                code = http::Code::NotFound;
            }
        }
        else {
            context.setResponseStatus(http::Code::BadRequest);
            MessageHandler::putToSendQueue(context.createSimpleResponse());
        }

        return {sent::no, endpoint::ResponseContext{.status = code}};
    }

    bool FS_Helper::requestFileRemoval(const std::string &fileName)
    {
        return std::filesystem::remove(fileName);
    }

    bool FS_Helper::requestFileRename(const std::string &fileName, const std::string &destFileName) noexcept
    {
        std::error_code ec;
        std::filesystem::rename(fileName, destFileName, ec);
        return (!ec) ? true : false;
    }

    endpoint::ResponseContext FS_Helper::requestListDir(const std::string &directory)
    {
        std::vector<std::string> filesInDir;
        for (const auto &entry : std::filesystem::directory_iterator{directory}) {
            filesInDir.push_back(entry.path());
        }
        json11::Json::array jsonArr;
        jsonArr.reserve(filesInDir.size());
        for (const auto &path : filesInDir) {
            jsonArr.push_back(json11::Json::object{{json::fs::path, path}});
        }
        json11::Json::object response({{directory, jsonArr}});
        return endpoint::ResponseContext{.status = http::Code::OK, .body = response};
    }

} // namespace parserFSM

A module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.hpp => module-services/service-desktop/endpoints/developerMode/fs/FS_Helper.hpp +37 -0
@@ 0,0 1,37 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <endpoints/Context.hpp>
#include <Service/Common.hpp>
#include <endpoints/BaseHelper.hpp>

namespace parserFSM
{

    class FS_Helper : public BaseHelper
    {
      public:
        explicit FS_Helper(sys::Service *p) : BaseHelper(p)
        {}

      private:
        auto processGet(Context &context) -> ProcessResult final;
        auto processPut(Context &context) -> ProcessResult final;
        void preProcess(http::Method method, Context &context) final;

        bool requestFileRemoval(const std::string &fileName);
        bool requestFileRename(const std::string &fileName, const std::string &destFileName) noexcept;
        endpoint::ResponseContext requestListDir(const std::string &directory);
    };

    namespace json::fs
    {
        inline constexpr auto removeFile   = "removeFile";
        inline constexpr auto renameFile   = "renameFile";
        inline constexpr auto destFileName = "destfilename";
        inline constexpr auto listDir      = "listDir";
        inline constexpr auto path         = "path";
    } // namespace json::fs
} // namespace parserFSM

A test/pytest/test_file_indexer.py => test/pytest/test_file_indexer.py +25 -0
@@ 0,0 1,25 @@
# Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
# For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
from harness.harness import Harness
import pytest
import eyed3
from harness.api.filesystem import put_file

def remove_file(harness, filename):
    body = {"fs": True, "removeFile": filename}
    return harness.endpoint_request("developerMode", "put", body)

def rename_file(harness, filename, destfilename):
    body = {"fs": True, "renameFile": filename, "destfilename": destfilename}
    return harness.endpoint_request("developerMode", "put", body)

def list_files(harness, directory):
    body = {"fs": True, "listDir": directory}
    return harness.endpoint_request("developerMode", "get", body)["body"][directory]

def add_tags(filename, title, artist, album):
    audioFile = eyed3.load(filename)
    audioFile.tag.title = title
    audioFile.tag.artist = artist
    audioFile.tag.album = album
    audioFile.tag.save()

M test/requirements.txt => test/requirements.txt +3 -0
@@ 9,4 9,7 @@ pytest==6.1.2
six==1.15.0
toml==0.10.2
inotify==0.2.10
dataclasses==0.6
dataclasses_json==0.5.4
tqdm=4.62.2
eyed3=0.9.6