diff --git a/CMakeLists.txt b/CMakeLists.txt index f3e6a3b..3fdca91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,9 @@ SET(REDMINE_API_SOURCES include/Redmine/User.hpp src/Redmine/User.cpp + include/Redmine/IssueStatus.hpp + src/Redmine/IssueStatus.cpp + include/Redmine/API.hpp src/Redmine/API.cpp ) @@ -116,6 +119,8 @@ add_executable(redmine-cli src/Redmine-CLI/Command/Version.cpp src/Redmine-CLI/Command/MyAccount.hpp src/Redmine-CLI/Command/MyAccount.cpp + src/Redmine-CLI/Command/IssueStatus.hpp + src/Redmine-CLI/Command/IssueStatus.cpp ) target_link_libraries(redmine-cli redmine-api-cpp-static loguru CLI11) target_include_directories(redmine-cli diff --git a/include/Redmine/API.hpp b/include/Redmine/API.hpp index 97918a0..745067f 100644 --- a/include/Redmine/API.hpp +++ b/include/Redmine/API.hpp @@ -16,12 +16,14 @@ * along with this program. If not, see . */ +#include "Redmine/IssueStatus.hpp" #include "nlohmann/json_fwd.hpp" #include #include #include #include #include +#include /** * @brief The main namespace of this library for Redmine related datatypes, classes, and functions @@ -46,7 +48,9 @@ namespace Redmine /// the token to authenticate against the server in redmine called API Key std::string authToken_; - + /// cache for all issue stati + std::vector issueStatusList_; + nlohmann::json get(const std::string &path) const; void put(const std::string &path, const nlohmann::json &data) const; @@ -99,6 +103,12 @@ namespace Redmine */ void setMyAccount(const Redmine::User &user) const; + /** + * @brief Return a list of all available issue stati + * + */ + std::vector getIssueStatusList(); + /*@}*/ }; diff --git a/include/Redmine/Issue.hpp b/include/Redmine/Issue.hpp new file mode 100644 index 0000000..0692e67 --- /dev/null +++ b/include/Redmine/Issue.hpp @@ -0,0 +1,73 @@ +#pragma once +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "nlohmann/json_fwd.hpp" +#include +#include +#include +#include + +/** + * @brief The main namespace of this library for Redmine related datatypes, classes, and functions + * + */ +namespace Redmine +{ + + /** + * @brief This class represents a user within the redmine server. + * + */ + class Issue : public Redmine::Object + { + private: + /// the data store for the issue + nlohmann::json data_; + + /** + * @brief verify issue data + * + * @param data - the json object containing the issue data + */ + void _verify(const nlohmann::json &data); + + public: + explicit Issue(const nlohmann::json &issue); + + /** + * @brief set the issue object from a json object + * + * @param data + */ + void set(const nlohmann::json &data); + + /** + * @brief return a json object from the issue object + * + * @return nlohmann::json + */ + nlohmann::json get() const; + + + std::uint64_t getId() const; + + + + }; // class Issue + +}; // namespace Redmine \ No newline at end of file diff --git a/include/Redmine/IssueStatus.hpp b/include/Redmine/IssueStatus.hpp new file mode 100644 index 0000000..ed80a69 --- /dev/null +++ b/include/Redmine/IssueStatus.hpp @@ -0,0 +1,99 @@ +#pragma once +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +/** + * @brief The main namespace of this library for Redmine related datatypes, classes, and functions + * + */ +#include "Redmine/Object.hpp" +#include "nlohmann/json_fwd.hpp" +namespace Redmine +{ + + /** + * @brief Represents an IssueStatus within Redmine + * + * This can not be an enumeration as statusses can be added or deleted by an administrator + * + * The Redmine Rest API does not allow to add ad status therefore, no method to change or set + * anything. + */ + class IssueStatus : public Redmine::Object + { + private: + + /// the json object to hold all data + nlohmann::json data_; + + /// method to verify the json input + void _verify(const nlohmann::json &data); + + public: + /** + * @brief Constructor for a Status using input from a json object + * + * @param status - the status representation as a json object + */ + explicit IssueStatus(const nlohmann::json &status); + + /** + * @brief set the status from an json object + * + * @param data - the json object providing the status information + */ + void set(const nlohmann::json &data); + + /** + * @brief returns the currently set data of the object as a json object + * + * @return nlohmann::json - the json object holding all object information + */ + nlohmann::json get() const; + + /** + * @brief return the name of the status + * + * @return std::string + */ + std::string getName() const; + + /** + * @brief return the id of the status + * + * @return std::uint64_t + */ + std::uint64_t getId() const; + + /** + * @brief does the status mean the issue is closed + * + * @return true - the issue is closed + * @return false - the issue is not closed + */ + bool isClosed() const; + + /** + * @brief return a string representation of the status + * + * @return std::string + */ + std::string to_string() const; + + }; // class Status + +}; // namespace Redmine \ No newline at end of file diff --git a/include/Redmine/Priority.hpp b/include/Redmine/Priority.hpp new file mode 100644 index 0000000..e69de29 diff --git a/include/Redmine/Project.hpp b/include/Redmine/Project.hpp new file mode 100644 index 0000000..0692e67 --- /dev/null +++ b/include/Redmine/Project.hpp @@ -0,0 +1,73 @@ +#pragma once +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "nlohmann/json_fwd.hpp" +#include +#include +#include +#include + +/** + * @brief The main namespace of this library for Redmine related datatypes, classes, and functions + * + */ +namespace Redmine +{ + + /** + * @brief This class represents a user within the redmine server. + * + */ + class Issue : public Redmine::Object + { + private: + /// the data store for the issue + nlohmann::json data_; + + /** + * @brief verify issue data + * + * @param data - the json object containing the issue data + */ + void _verify(const nlohmann::json &data); + + public: + explicit Issue(const nlohmann::json &issue); + + /** + * @brief set the issue object from a json object + * + * @param data + */ + void set(const nlohmann::json &data); + + /** + * @brief return a json object from the issue object + * + * @return nlohmann::json + */ + nlohmann::json get() const; + + + std::uint64_t getId() const; + + + + }; // class Issue + +}; // namespace Redmine \ No newline at end of file diff --git a/include/Redmine/Tracker.hpp b/include/Redmine/Tracker.hpp new file mode 100644 index 0000000..e69de29 diff --git a/include/Redmine/Version.hpp b/include/Redmine/Version.hpp new file mode 100644 index 0000000..e69de29 diff --git a/src/Redmine-CLI/Command/IssueStatus.cpp b/src/Redmine-CLI/Command/IssueStatus.cpp new file mode 100644 index 0000000..c0e9da8 --- /dev/null +++ b/src/Redmine-CLI/Command/IssueStatus.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +#include "Redmine/IssueStatus.hpp" +#include +#include +#include +#include "Redmine/API.hpp" +#include "Redmine/User.hpp" +#include "nlohmann/json_fwd.hpp" +#define LOGURU_WITH_STREAMS 1 +#include + +Command::IssueStatus::IssueStatus(RedmineCLI::Redmine *r) +: +redmine_(r) +{ + + + issueStatus_ = redmine_->getCLI().add_subcommand("issuestatus", + "Request the available issue status list from the server"); + issueStatus_->callback([&](){get_();}); + +} + + +void Command::IssueStatus::get_() const +{ + + Redmine::API client{redmine_->getUrl(), redmine_->getToken()}; + + std::vector list = client.getIssueStatusList(); + + for (auto it = list.begin(); it!= list.end(); ++it) + { + std::cout << it->to_string() << std::endl; + } + +} diff --git a/src/Redmine-CLI/Command/IssueStatus.hpp b/src/Redmine-CLI/Command/IssueStatus.hpp new file mode 100644 index 0000000..22b10ca --- /dev/null +++ b/src/Redmine-CLI/Command/IssueStatus.hpp @@ -0,0 +1,75 @@ +#pragma once +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ +#include +#include +#include +#include +#include +#include +#define LOGURU_WITH_STREAMS 1 +#include +#include + + +// forward declaration +namespace RedmineCLI +{ + class Redmine; +}; + +namespace Command +{ + + /** + * @brief class for processing the CLI11 parsed command lines + * + */ + class IssueStatus + { + + private: + + /// the main redmine cli application context + RedmineCLI::Redmine *redmine_; + + /// enum for identifying supported output types + enum outputType : std::uint16_t + { + /// output is just text + TEXT, + /// output is yaml + YAML + }; + std::map outputMap{{"text", TEXT}, {"yaml", YAML}}; + + CLI::App* issueStatus_; + + /// the actual implementation of the information get + void get_() const; + + public: + /** + * @brief Construct a new CLIProcessor object + * + */ + IssueStatus(RedmineCLI::Redmine *r); + + + }; // class IssueStatus + +}; // namespace Command \ No newline at end of file diff --git a/src/Redmine-CLI/Command/MyAccount.cpp b/src/Redmine-CLI/Command/MyAccount.cpp index faae5b2..83fd9f6 100644 --- a/src/Redmine-CLI/Command/MyAccount.cpp +++ b/src/Redmine-CLI/Command/MyAccount.cpp @@ -50,7 +50,7 @@ output_(TEXT) void Command::MyAccount::set_() const { - Redmine::API client{redmine_->getUrl(), redmine_->getToken()}; + Redmine::API client{redmine_->getUrl(), redmine_->getToken()}; Redmine::User user = client.getMyAccount(); diff --git a/src/Redmine-CLI/Redmine.cpp b/src/Redmine-CLI/Redmine.cpp index 233608e..6765bdf 100644 --- a/src/Redmine-CLI/Redmine.cpp +++ b/src/Redmine-CLI/Redmine.cpp @@ -15,9 +15,13 @@ * along with this program. If not, see . */ #include +#include "Redmine-CLI/Command/IssueStatus.hpp" #include "Redmine-CLI/Command/Version.hpp" #include #include +#define LOGURU_WITH_STREAMS 1 +#include + RedmineCLI::Redmine::Redmine(CLI::App &cli) : @@ -32,7 +36,8 @@ version_(nullptr) // add all commands here - version_ = std::make_unique(this); - myAccount_ = std::make_unique(this); + version_ = std::make_unique(this); + myAccount_ = std::make_unique(this); + issueStatus_ = std::make_unique(this); } \ No newline at end of file diff --git a/src/Redmine-CLI/Redmine.hpp b/src/Redmine-CLI/Redmine.hpp index cbabe49..f652083 100644 --- a/src/Redmine-CLI/Redmine.hpp +++ b/src/Redmine-CLI/Redmine.hpp @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "Redmine-CLI/Command/IssueStatus.hpp" #include "Redmine-CLI/Command/MyAccount.hpp" #include "Redmine-CLI/Command/Version.hpp" #include @@ -56,6 +57,9 @@ namespace RedmineCLI /// pointer to the myAccount subcommand std::unique_ptr myAccount_; + /// pointer to the issues subcommand + std::unique_ptr issueStatus_; + public: /** diff --git a/src/Redmine-CLI/main.cpp b/src/Redmine-CLI/main.cpp index 89602d4..e10fc27 100644 --- a/src/Redmine-CLI/main.cpp +++ b/src/Redmine-CLI/main.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #define LOGURU_WITH_STREAMS 1 @@ -31,11 +32,16 @@ int main(int argc, char **argv) { - CLI::App app("A command line client for the redmine project management server"); - RedmineCLI::Redmine redmineCli{app}; + try { + CLI::App app("A command line client for the redmine project management server"); + RedmineCLI::Redmine redmineCli{app}; + CLI11_PARSE(app, argc, argv); + } catch (const std::exception &e) + { + return EXIT_FAILURE; + } - CLI11_PARSE(app, argc, argv); } \ No newline at end of file diff --git a/src/Redmine/API.cpp b/src/Redmine/API.cpp index 953e5ba..d6f1e0f 100644 --- a/src/Redmine/API.cpp +++ b/src/Redmine/API.cpp @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "Redmine/IssueStatus.hpp" #include "nlohmann/json_fwd.hpp" #include #include @@ -68,6 +69,12 @@ Redmine::API::API(const std::string &serverURL, const std::string &authToken) auto res = client.Get(path + ".json" , headers); + if (res == nullptr) + { + DLOG_S(ERROR) << "failed to get data from API endpoint"; + throw std::runtime_error("API request failed"); + } + if (res->status == httplib::StatusCode::Unauthorized_401) { DLOG_S(ERROR) << "authentication with API server failed (401)"; @@ -137,6 +144,22 @@ void Redmine::API::setMyAccount(const Redmine::User &user) const } +std::vector Redmine::API::getIssueStatusList() +{ + nlohmann::json statusList = get("/issue_statuses"); + issueStatusList_.clear(); + + + for (auto it=statusList["issue_statuses"].begin(); it != statusList["issue_statuses"].end(); ++it) + { + + Redmine::IssueStatus status{*it}; + + issueStatusList_.push_back(status); + } + + return issueStatusList_; +} bool Redmine::API::ready() const { diff --git a/src/Redmine/IssueStatus.cpp b/src/Redmine/IssueStatus.cpp new file mode 100644 index 0000000..4994b9c --- /dev/null +++ b/src/Redmine/IssueStatus.cpp @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ +#include +#include + +void Redmine::IssueStatus::_verify(const nlohmann::json &data) +{ + _baseVerify(data,""); + +} + + +void Redmine::IssueStatus::set(const nlohmann::json &data) +{ + _verify(data); + data_=data; +} + +Redmine::IssueStatus::IssueStatus(const nlohmann::json &status) +{ + set(status); +} + +nlohmann::json Redmine::IssueStatus::get() const +{ + return data_; +} + +std::string Redmine::IssueStatus::getName() const +{ + return data_["name"].get(); +} + +std::uint64_t Redmine::IssueStatus::getId() const +{ + return data_["id"].get(); +} + +bool Redmine::IssueStatus::isClosed() const +{ + return data_["is_closed"].get(); +} + +std::string Redmine::IssueStatus::to_string() const +{ + std::stringstream strStream; + + strStream << getName() << "( ID=" << getId() << ", closesIssue=" << isClosed() << ")"; + + return strStream.str(); +} \ No newline at end of file diff --git a/src/Redmine/Object.cpp b/src/Redmine/Object.cpp index 9a83659..958cbe5 100644 --- a/src/Redmine/Object.cpp +++ b/src/Redmine/Object.cpp @@ -26,19 +26,19 @@ void Redmine::Object::_baseVerify(const nlohmann::json &data, const std::string throw std::invalid_argument("provided data is empty"); } - if (!data.is_object()) + if (!data.is_object() && !data.is_array()) { - DLOG_S(ERROR) << "provided data is not a json object/hash"; - throw std::invalid_argument("provided data is not a json objects/hash"); + DLOG_S(ERROR) << "provided data is not a json object/hash or array"; + throw std::invalid_argument("provided data is not a json objects/hash or array"); } - if (!data.contains(objectName)) + if ( !objectName.empty() && !data.contains(objectName)) { DLOG_S(ERROR) << "provided data does not contain object information (" << objectName << ")"; throw std::invalid_argument("provided data does not contain object information (" + objectName + ")"); } - if (data[objectName].empty()) + if (!objectName.empty() && data[objectName].empty()) { DLOG_S(ERROR) << "provided object information is empty"; throw std::invalid_argument("provided object information is empty"); diff --git a/src/config.hpp b/src/config.hpp new file mode 100644 index 0000000..3e4403e --- /dev/null +++ b/src/config.hpp @@ -0,0 +1,28 @@ +#ifndef __LIBCMS_CONFIG_HPP__ +#define __LIBCMS_CONFIG_HPP__ +/* +* Copyright (C) 2024 Dominik Meyer +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + + +#define PROJECT_NAME remine-api-cpp + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 0 +#define VERSION_PATCH 1 +#define PROJECT_VERSION "0.0.1" + +#endif