feat: some inital api structure

This commit is contained in:
Dominik Meyer 2024-08-05 20:54:45 +02:00
parent d64ed1fcd0
commit f205f8aa09
Signed by: byterazor
GPG Key ID: EABDA0FD5981BC97
18 changed files with 531 additions and 12 deletions

View File

@ -74,6 +74,9 @@ SET(REDMINE_API_SOURCES
include/Redmine/User.hpp include/Redmine/User.hpp
src/Redmine/User.cpp src/Redmine/User.cpp
include/Redmine/IssueStatus.hpp
src/Redmine/IssueStatus.cpp
include/Redmine/API.hpp include/Redmine/API.hpp
src/Redmine/API.cpp src/Redmine/API.cpp
) )
@ -116,6 +119,8 @@ add_executable(redmine-cli
src/Redmine-CLI/Command/Version.cpp src/Redmine-CLI/Command/Version.cpp
src/Redmine-CLI/Command/MyAccount.hpp src/Redmine-CLI/Command/MyAccount.hpp
src/Redmine-CLI/Command/MyAccount.cpp 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_link_libraries(redmine-cli redmine-api-cpp-static loguru CLI11)
target_include_directories(redmine-cli target_include_directories(redmine-cli

View File

@ -16,12 +16,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "Redmine/IssueStatus.hpp"
#include "nlohmann/json_fwd.hpp" #include "nlohmann/json_fwd.hpp"
#include <httplib.h> #include <httplib.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <Redmine/User.hpp> #include <Redmine/User.hpp>
#include <vector>
/** /**
* @brief The main namespace of this library for Redmine related datatypes, classes, and functions * @brief The main namespace of this library for Redmine related datatypes, classes, and functions
@ -46,6 +48,8 @@ namespace Redmine
/// the token to authenticate against the server in redmine called API Key /// the token to authenticate against the server in redmine called API Key
std::string authToken_; std::string authToken_;
/// cache for all issue stati
std::vector<Redmine::IssueStatus> issueStatusList_;
nlohmann::json get(const std::string &path) const; nlohmann::json get(const std::string &path) const;
void put(const std::string &path, const nlohmann::json &data) 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; void setMyAccount(const Redmine::User &user) const;
/**
* @brief Return a list of all available issue stati
*
*/
std::vector<Redmine::IssueStatus> getIssueStatusList();
/*@}*/ /*@}*/
}; };

73
include/Redmine/Issue.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "nlohmann/json_fwd.hpp"
#include <cstdint>
#include <nlohmann/json.hpp>
#include <Redmine/Object.hpp>
#include <string>
/**
* @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

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/**
* @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

View File

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "nlohmann/json_fwd.hpp"
#include <cstdint>
#include <nlohmann/json.hpp>
#include <Redmine/Object.hpp>
#include <string>
/**
* @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

View File

View File

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include "Redmine/IssueStatus.hpp"
#include <Redmine-CLI/Command/IssueStatus.hpp>
#include <Redmine-CLI/Redmine.hpp>
#include <vector>
#include "Redmine/API.hpp"
#include "Redmine/User.hpp"
#include "nlohmann/json_fwd.hpp"
#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>
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<Redmine::IssueStatus> list = client.getIssueStatusList();
for (auto it = list.begin(); it!= list.end(); ++it)
{
std::cout << it->to_string() << std::endl;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <CLI/App.hpp>
#include <Redmine/API.hpp>
#include <atomic>
#include <cstdint>
#include <memory>
#include <string>
#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>
#include <CLI/CLI.hpp>
// 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<std::string, outputType> 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

View File

@ -50,7 +50,7 @@ output_(TEXT)
void Command::MyAccount::set_() const void Command::MyAccount::set_() const
{ {
Redmine::API client{redmine_->getUrl(), redmine_->getToken()}; Redmine::API client{redmine_->getUrl(), redmine_->getToken()};
Redmine::User user = client.getMyAccount(); Redmine::User user = client.getMyAccount();

View File

@ -15,9 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <Redmine-CLI/Command/MyAccount.hpp> #include <Redmine-CLI/Command/MyAccount.hpp>
#include "Redmine-CLI/Command/IssueStatus.hpp"
#include "Redmine-CLI/Command/Version.hpp" #include "Redmine-CLI/Command/Version.hpp"
#include <Redmine-CLI/Redmine.hpp> #include <Redmine-CLI/Redmine.hpp>
#include <memory> #include <memory>
#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>
RedmineCLI::Redmine::Redmine(CLI::App &cli) RedmineCLI::Redmine::Redmine(CLI::App &cli)
: :
@ -32,7 +36,8 @@ version_(nullptr)
// add all commands here // add all commands here
version_ = std::make_unique<Command::Version>(this); version_ = std::make_unique<Command::Version>(this);
myAccount_ = std::make_unique<Command::MyAccount>(this); myAccount_ = std::make_unique<Command::MyAccount>(this);
issueStatus_ = std::make_unique<Command::IssueStatus>(this);
} }

View File

@ -15,6 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "Redmine-CLI/Command/IssueStatus.hpp"
#include "Redmine-CLI/Command/MyAccount.hpp" #include "Redmine-CLI/Command/MyAccount.hpp"
#include "Redmine-CLI/Command/Version.hpp" #include "Redmine-CLI/Command/Version.hpp"
#include <CLI/App.hpp> #include <CLI/App.hpp>
@ -56,6 +57,9 @@ namespace RedmineCLI
/// pointer to the myAccount subcommand /// pointer to the myAccount subcommand
std::unique_ptr<Command::MyAccount> myAccount_; std::unique_ptr<Command::MyAccount> myAccount_;
/// pointer to the issues subcommand
std::unique_ptr<Command::IssueStatus> issueStatus_;
public: public:
/** /**

View File

@ -22,6 +22,7 @@
#include <CLI/Option.hpp> #include <CLI/Option.hpp>
#include <Redmine/API.hpp> #include <Redmine/API.hpp>
#include <Redmine/Exception/Api.hpp> #include <Redmine/Exception/Api.hpp>
#include <cstdlib>
#include <string> #include <string>
#include <vector> #include <vector>
#define LOGURU_WITH_STREAMS 1 #define LOGURU_WITH_STREAMS 1
@ -31,11 +32,16 @@
int main(int argc, char **argv) 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);
} }

View File

@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "Redmine/IssueStatus.hpp"
#include "nlohmann/json_fwd.hpp" #include "nlohmann/json_fwd.hpp"
#include <Redmine/API.hpp> #include <Redmine/API.hpp>
#include <Redmine/Exception/Api.hpp> #include <Redmine/Exception/Api.hpp>
@ -68,6 +69,12 @@ Redmine::API::API(const std::string &serverURL, const std::string &authToken)
auto res = client.Get(path + ".json" , headers); 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) if (res->status == httplib::StatusCode::Unauthorized_401)
{ {
DLOG_S(ERROR) << "authentication with API server failed (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::IssueStatus> 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 bool Redmine::API::ready() const
{ {

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#include <Redmine/IssueStatus.hpp>
#include <sstream>
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::string>();
}
std::uint64_t Redmine::IssueStatus::getId() const
{
return data_["id"].get<std::uint64_t>();
}
bool Redmine::IssueStatus::isClosed() const
{
return data_["is_closed"].get<bool>();
}
std::string Redmine::IssueStatus::to_string() const
{
std::stringstream strStream;
strStream << getName() << "( ID=" << getId() << ", closesIssue=" << isClosed() << ")";
return strStream.str();
}

View File

@ -26,19 +26,19 @@ void Redmine::Object::_baseVerify(const nlohmann::json &data, const std::string
throw std::invalid_argument("provided data is empty"); 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"; 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"); 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 << ")"; DLOG_S(ERROR) << "provided data does not contain object information (" << objectName << ")";
throw std::invalid_argument("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"; DLOG_S(ERROR) << "provided object information is empty";
throw std::invalid_argument("provided object information is empty"); throw std::invalid_argument("provided object information is empty");

28
src/config.hpp Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#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