Compare commits
2 Commits
74d0b209b7
...
7f269901c5
Author | SHA1 | Date | |
---|---|---|---|
7f269901c5 | |||
3e508c344f |
@ -85,6 +85,12 @@ SET(REDMINE_API_SOURCES
|
|||||||
|
|
||||||
include/Redmine/API.hpp
|
include/Redmine/API.hpp
|
||||||
src/Redmine/API.cpp
|
src/Redmine/API.cpp
|
||||||
|
|
||||||
|
include/Redmine/Filter.hpp
|
||||||
|
src/Redmine/Filter.cpp
|
||||||
|
|
||||||
|
include/Redmine/Issue.hpp
|
||||||
|
src/Redmine/Issue.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(redmine-api-cpp-objlib OBJECT ${REDMINE_API_SOURCES})
|
add_library(redmine-api-cpp-objlib OBJECT ${REDMINE_API_SOURCES})
|
||||||
@ -129,6 +135,8 @@ add_executable(redmine-cli
|
|||||||
src/Redmine-CLI/Command/Project.cpp
|
src/Redmine-CLI/Command/Project.cpp
|
||||||
src/Redmine-CLI/Command/IssueStatus.hpp
|
src/Redmine-CLI/Command/IssueStatus.hpp
|
||||||
src/Redmine-CLI/Command/IssueStatus.cpp
|
src/Redmine-CLI/Command/IssueStatus.cpp
|
||||||
|
src/Redmine-CLI/Command/Issue.hpp
|
||||||
|
src/Redmine-CLI/Command/Issue.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(redmine-cli redmine-api-cpp-static loguru CLI11 tableprinter::tableprinter)
|
target_link_libraries(redmine-cli redmine-api-cpp-static loguru CLI11 tableprinter::tableprinter)
|
||||||
target_include_directories(redmine-cli
|
target_include_directories(redmine-cli
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* 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/Filter.hpp"
|
||||||
|
#include "Redmine/Issue.hpp"
|
||||||
#include "Redmine/IssueStatus.hpp"
|
#include "Redmine/IssueStatus.hpp"
|
||||||
#include "nlohmann/json_fwd.hpp"
|
#include "nlohmann/json_fwd.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -127,9 +129,19 @@ namespace Redmine
|
|||||||
*
|
*
|
||||||
* @return std::vector<Redmine::Project>
|
* @return std::vector<Redmine::Project>
|
||||||
*/
|
*/
|
||||||
std::vector<Redmine::Project> getProjects() const;
|
std::vector<Redmine::Project> getProjects(const std::uint32_t limit) const;
|
||||||
|
|
||||||
void uploadFileToProject(const std::uint64_t projectId, const std::string &filePath, const std::string &fileName, const std::string &description, const std::uint32_t version) const;
|
void uploadFileToProject(const std::uint64_t projectId, const std::string &filePath, const std::string &fileName, const std::string &description, const std::uint32_t version) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get issues with the given filters from the redmine server
|
||||||
|
*
|
||||||
|
* @param filter - the filter to apply on the issues
|
||||||
|
* @return std::vector<Redmine::Issue>
|
||||||
|
*/
|
||||||
|
std::vector<Redmine::Issue> getIssues(const Redmine::Filter& filter = {}) const;
|
||||||
|
|
||||||
|
|
||||||
/*@}*/
|
/*@}*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
64
include/Redmine/Filter.hpp
Normal file
64
include/Redmine/Filter.hpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#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 <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
namespace Redmine
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Class for filering data in a Redmine API query
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Filter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// filter the issued by project id
|
||||||
|
bool filterByProjectID_;
|
||||||
|
/// the project ID to filter
|
||||||
|
std::uint64_t projectID_;
|
||||||
|
|
||||||
|
/// possible project stati for a filter
|
||||||
|
enum class ProjectStatus {open, closed, both};
|
||||||
|
|
||||||
|
/// the project status to filter by
|
||||||
|
ProjectStatus projectStatus_;
|
||||||
|
|
||||||
|
/// whether to filter by assigned user or not
|
||||||
|
bool filterByAssignedUser_;
|
||||||
|
|
||||||
|
/// the user ID to filter by
|
||||||
|
std::uint64_t assignedUserID_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Filter();
|
||||||
|
|
||||||
|
void filterByProjectID(const std::uint64_t id);
|
||||||
|
void setProjectStatus(const ProjectStatus& status);
|
||||||
|
void filterByAssignedUserId(const std::uint64_t id);
|
||||||
|
std::string toQueryString() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Redmine
|
@ -63,10 +63,20 @@ namespace Redmine
|
|||||||
*/
|
*/
|
||||||
nlohmann::json get() const;
|
nlohmann::json get() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief return the id of the issue
|
||||||
|
*
|
||||||
|
* @return std::uint64_t
|
||||||
|
*/
|
||||||
std::uint64_t getId() const;
|
std::uint64_t getId() const;
|
||||||
|
|
||||||
|
|
||||||
|
std::string getProject() const;
|
||||||
|
std::uint64_t getProjectId() const;
|
||||||
|
std::string getStatus() const;
|
||||||
|
std::uint64_t getStatusID() const;
|
||||||
|
std::string getSubject() const;
|
||||||
|
std::string getDescription() const;
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
}; // class Issue
|
}; // class Issue
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
#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 an Issue Tracker within the redmine server.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Tracker : 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 Tracker(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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Id of the tracker
|
||||||
|
*
|
||||||
|
* @return std::uint64_t
|
||||||
|
*/
|
||||||
|
std::uint64_t getId() const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}; // class Issue
|
||||||
|
|
||||||
|
}; // namespace Redmine
|
116
src/Redmine-CLI/Command/Issue.cpp
Normal file
116
src/Redmine-CLI/Command/Issue.cpp
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* 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-CLI/Command/Issue.hpp>
|
||||||
|
#include <Redmine-CLI/Redmine.hpp>
|
||||||
|
#include "Redmine/API.hpp"
|
||||||
|
#include "Redmine/Filter.hpp"
|
||||||
|
#include "nlohmann/json_fwd.hpp"
|
||||||
|
#include <tableprinter/tableprinter.hpp>
|
||||||
|
|
||||||
|
Command::Issue::Issue(RedmineCLI::Redmine *r)
|
||||||
|
:
|
||||||
|
redmine_(r),
|
||||||
|
output_(TEXT),
|
||||||
|
projectId_(-1),
|
||||||
|
userId_(-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
CLI::App* issue = redmine_->getCLI().add_subcommand("issue",
|
||||||
|
"Api Calls on issues accessible by token owner")->require_subcommand();
|
||||||
|
|
||||||
|
|
||||||
|
list_ = issue->add_subcommand("list", "List issues accessible by the token owner");
|
||||||
|
list_->needs(redmine_->getTokenOption())->needs(redmine_->getUrlOption());
|
||||||
|
list_->callback([&](){getList_();});
|
||||||
|
list_->add_option("-o,--output", output_, "The Output Format to use. Supported: TEXT, YAML")->transform(CLI::CheckedTransformer(outputMap, CLI::ignore_case));
|
||||||
|
list_->add_option("-p,--project",projectId_,"Filter issues by project id");
|
||||||
|
list_->add_option("--userid", userId_,"Filter issues by user id");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command::Issue::printIssueListText_(const std::vector<Redmine::Issue> &issues) const
|
||||||
|
{
|
||||||
|
tableprinter::printer p
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ tableprinter::name { "ID" } , tableprinter::width { 8 } } ,
|
||||||
|
{ tableprinter::name { "Subject" } , tableprinter::width { 80 } } ,
|
||||||
|
{ tableprinter::name { "Project" } , tableprinter::width { 25 } } ,
|
||||||
|
{tableprinter::name { "Status" }, tableprinter::width { 15 }}
|
||||||
|
} ,
|
||||||
|
{ std::cout }
|
||||||
|
};
|
||||||
|
|
||||||
|
p.sanity_check();
|
||||||
|
p.print_headers();
|
||||||
|
|
||||||
|
for (auto it = issues.begin(); it!= issues.end(); ++it)
|
||||||
|
{
|
||||||
|
p.print(it->getId(), it->getSubject(), it->getProject(), it->getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command::Issue::printIssueListJson_(const std::vector<Redmine::Issue> &issues) const
|
||||||
|
{
|
||||||
|
nlohmann::json data = nlohmann::json::array();
|
||||||
|
|
||||||
|
for (auto it = issues.begin(); it!= issues.end(); ++it)
|
||||||
|
{
|
||||||
|
nlohmann::json issue;
|
||||||
|
issue["id"] = it->getId();
|
||||||
|
issue["subject"] = it->getSubject();
|
||||||
|
issue["project"] = it->getProject();
|
||||||
|
issue["project_id"] = it->getProjectId();
|
||||||
|
issue["status"] = it->getStatus();
|
||||||
|
issue["status_id"] = it->getStatusID();
|
||||||
|
|
||||||
|
data.push_back(issue);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << data.dump(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command::Issue::getList_() const
|
||||||
|
{
|
||||||
|
Redmine::API client{redmine_->getUrl(), redmine_->getToken()};
|
||||||
|
|
||||||
|
Redmine::Filter filter{};
|
||||||
|
|
||||||
|
if (projectId_ > -1)
|
||||||
|
{
|
||||||
|
filter.filterByProjectID(projectId_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userId_ > -1)
|
||||||
|
{
|
||||||
|
filter.filterByAssignedUserId(userId_);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto issues = client.getIssues(filter);
|
||||||
|
|
||||||
|
if (output_ == TEXT)
|
||||||
|
{
|
||||||
|
printIssueListText_(issues);
|
||||||
|
}
|
||||||
|
else if (output_ == JSON)
|
||||||
|
{
|
||||||
|
printIssueListJson_(issues);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
99
src/Redmine-CLI/Command/Issue.hpp
Normal file
99
src/Redmine-CLI/Command/Issue.hpp
Normal 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/>.
|
||||||
|
*/
|
||||||
|
#include "Redmine/Filter.hpp"
|
||||||
|
#include "Redmine/Project.hpp"
|
||||||
|
#include "nlohmann/json_fwd.hpp"
|
||||||
|
#include <CLI/App.hpp>
|
||||||
|
#include <Redmine/API.hpp>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#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 Issue
|
||||||
|
{
|
||||||
|
|
||||||
|
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 json
|
||||||
|
JSON
|
||||||
|
};
|
||||||
|
|
||||||
|
/// requested output type
|
||||||
|
outputType output_;
|
||||||
|
|
||||||
|
std::map<std::string, outputType> outputMap{{"text", TEXT}, {"json", JSON}};
|
||||||
|
|
||||||
|
/// vector to hold requested attribute fields
|
||||||
|
std::vector<std::string> fields_;
|
||||||
|
|
||||||
|
/// the project id to work on
|
||||||
|
std::int64_t projectId_;
|
||||||
|
|
||||||
|
/// the userid to filter on
|
||||||
|
std::uint64_t userId_;
|
||||||
|
|
||||||
|
/// the status to filter on
|
||||||
|
std::string status_;
|
||||||
|
|
||||||
|
/// pointer to the list subcommand
|
||||||
|
CLI::App* list_;
|
||||||
|
|
||||||
|
|
||||||
|
void printIssueListJson_(const std::vector<Redmine::Issue> &issues) const;
|
||||||
|
|
||||||
|
void printIssueListText_(const std::vector<Redmine::Issue> &issues) const;
|
||||||
|
|
||||||
|
/// the actual implementation of the list command
|
||||||
|
void getList_() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new CLIProcessor object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
explicit Issue(RedmineCLI::Redmine *r);
|
||||||
|
|
||||||
|
}; // class Issue
|
||||||
|
}; // namespace Command
|
@ -19,12 +19,14 @@
|
|||||||
#include <Redmine-CLI/Redmine.hpp>
|
#include <Redmine-CLI/Redmine.hpp>
|
||||||
#include "Redmine/API.hpp"
|
#include "Redmine/API.hpp"
|
||||||
#include "nlohmann/json_fwd.hpp"
|
#include "nlohmann/json_fwd.hpp"
|
||||||
|
#include <string>
|
||||||
#include <tableprinter/tableprinter.hpp>
|
#include <tableprinter/tableprinter.hpp>
|
||||||
|
|
||||||
Command::Project::Project(RedmineCLI::Redmine *r)
|
Command::Project::Project(RedmineCLI::Redmine *r)
|
||||||
:
|
:
|
||||||
redmine_(r),
|
redmine_(r),
|
||||||
output_(TEXT)
|
output_(TEXT),
|
||||||
|
limit_(100)
|
||||||
{
|
{
|
||||||
|
|
||||||
CLI::App* project = redmine_->getCLI().add_subcommand("project",
|
CLI::App* project = redmine_->getCLI().add_subcommand("project",
|
||||||
@ -36,6 +38,7 @@ output_(TEXT)
|
|||||||
list_->callback([&](){getList_();});
|
list_->callback([&](){getList_();});
|
||||||
list_->add_option("-f,--fields", fields_, "The fields of the project object to print. Supported: name, id");
|
list_->add_option("-f,--fields", fields_, "The fields of the project object to print. Supported: name, id");
|
||||||
list_->add_option("-o,--output", output_, "The Output Format to use. Supported: TEXT, YAML")->transform(CLI::CheckedTransformer(outputMap, CLI::ignore_case));
|
list_->add_option("-o,--output", output_, "The Output Format to use. Supported: TEXT, YAML")->transform(CLI::CheckedTransformer(outputMap, CLI::ignore_case));
|
||||||
|
list_->add_option("-l,--limit",limit_,"The maximum number of projects to return. (Default: " + std::to_string(limit_) +" )");
|
||||||
|
|
||||||
|
|
||||||
upload_ = project->add_subcommand("upload", "Upload a File to the Project");
|
upload_ = project->add_subcommand("upload", "Upload a File to the Project");
|
||||||
@ -81,8 +84,8 @@ void Command::Project::printProjectListText_(const std::vector<Redmine::Project>
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
{ tableprinter::name { "ID" } , tableprinter::width { 8 } } ,
|
{ tableprinter::name { "ID" } , tableprinter::width { 8 } } ,
|
||||||
{ tableprinter::name { "Identifier" } , tableprinter::width { 20 } } ,
|
{ tableprinter::name { "Identifier" } , tableprinter::width { 30 } } ,
|
||||||
{ tableprinter::name { "Name" } , tableprinter::width { 30 } } ,
|
{ tableprinter::name { "Name" } , tableprinter::width { 40 } } ,
|
||||||
} ,
|
} ,
|
||||||
{ std::cout }
|
{ std::cout }
|
||||||
};
|
};
|
||||||
@ -145,9 +148,9 @@ void Command::Project::getList_() const
|
|||||||
{
|
{
|
||||||
Redmine::API client{redmine_->getUrl(), redmine_->getToken()};
|
Redmine::API client{redmine_->getUrl(), redmine_->getToken()};
|
||||||
|
|
||||||
auto projects = client.getProjects();
|
auto projects = client.getProjects(limit_);
|
||||||
|
|
||||||
printProjectList_(projects);
|
printProjectList_(projects);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -82,12 +82,19 @@ namespace Command
|
|||||||
/// the version of the uploading files
|
/// the version of the uploading files
|
||||||
std::uint32_t fileVersion_;
|
std::uint32_t fileVersion_;
|
||||||
|
|
||||||
|
/// the maximum number of projects to list
|
||||||
|
std::uint32_t limit_;
|
||||||
|
|
||||||
/// pointer to the list subcommand
|
/// pointer to the list subcommand
|
||||||
CLI::App* list_;
|
CLI::App* list_;
|
||||||
|
|
||||||
/// pointer to the upload subcommand
|
/// pointer to the upload subcommand
|
||||||
CLI::App* upload_;
|
CLI::App* upload_;
|
||||||
|
|
||||||
|
/// point to the list issues subcommand
|
||||||
|
CLI::App* issuesList_;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief method to print the project list
|
* @brief method to print the project list
|
||||||
*
|
*
|
||||||
|
@ -40,5 +40,5 @@ version_(nullptr)
|
|||||||
myAccount_ = std::make_unique<Command::MyAccount>(this);
|
myAccount_ = std::make_unique<Command::MyAccount>(this);
|
||||||
project_ = std::make_unique<Command::Project>(this);
|
project_ = std::make_unique<Command::Project>(this);
|
||||||
issueStatus_ = std::make_unique<Command::IssueStatus>(this);
|
issueStatus_ = std::make_unique<Command::IssueStatus>(this);
|
||||||
|
issue_ = std::make_unique<Command::Issue>(this);
|
||||||
}
|
}
|
@ -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/Issue.hpp"
|
||||||
#include "Redmine-CLI/Command/IssueStatus.hpp"
|
#include "Redmine-CLI/Command/IssueStatus.hpp"
|
||||||
#include "Redmine-CLI/Command/MyAccount.hpp"
|
#include "Redmine-CLI/Command/MyAccount.hpp"
|
||||||
#include "Redmine-CLI/Command/Project.hpp"
|
#include "Redmine-CLI/Command/Project.hpp"
|
||||||
@ -63,6 +64,10 @@ namespace RedmineCLI
|
|||||||
|
|
||||||
/// pointer to the project subcommand
|
/// pointer to the project subcommand
|
||||||
std::unique_ptr<Command::Project> project_;
|
std::unique_ptr<Command::Project> project_;
|
||||||
|
|
||||||
|
/// pointer to the issue subcommand
|
||||||
|
std::unique_ptr<Command::Issue> issue_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,13 +14,16 @@
|
|||||||
* 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/Issue.hpp"
|
||||||
#include "Redmine/IssueStatus.hpp"
|
#include "Redmine/IssueStatus.hpp"
|
||||||
#include "Redmine/Project.hpp"
|
#include "Redmine/Project.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>
|
||||||
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -98,7 +101,7 @@ void Redmine::API::processGenericErrors_(httplib::Result &res) const
|
|||||||
|
|
||||||
nlohmann::json Redmine::API::get(const std::string &path) const
|
nlohmann::json Redmine::API::get(const std::string &path) const
|
||||||
{
|
{
|
||||||
DLOG_S(INFO) << "getting API endpoint " << path+".json" << " from " <<redmineApiURL_;
|
DLOG_S(INFO) << "getting API endpoint " << path << " from " <<redmineApiURL_;
|
||||||
httplib::Client client{redmineApiURL_};
|
httplib::Client client{redmineApiURL_};
|
||||||
|
|
||||||
httplib::Headers headers =
|
httplib::Headers headers =
|
||||||
@ -107,7 +110,7 @@ void Redmine::API::processGenericErrors_(httplib::Result &res) const
|
|||||||
{ "Content-Type", "application/json"}
|
{ "Content-Type", "application/json"}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto res = client.Get(path + ".json" , headers);
|
auto res = client.Get(path , headers);
|
||||||
|
|
||||||
processGenericErrors_(res);
|
processGenericErrors_(res);
|
||||||
|
|
||||||
@ -118,11 +121,11 @@ void Redmine::API::processGenericErrors_(httplib::Result &res) const
|
|||||||
|
|
||||||
void Redmine::API::put(const std::string &path, const nlohmann::json &data) const
|
void Redmine::API::put(const std::string &path, const nlohmann::json &data) const
|
||||||
{
|
{
|
||||||
DLOG_S(INFO) << "putting API endpoint " << path+".json" << " from " <<redmineApiURL_;
|
DLOG_S(INFO) << "putting API endpoint " << path << " from " <<redmineApiURL_;
|
||||||
httplib::Client client{redmineApiURL_};
|
httplib::Client client{redmineApiURL_};
|
||||||
client.set_basic_auth(authToken_, "");
|
client.set_basic_auth(authToken_, "");
|
||||||
|
|
||||||
auto res = client.Put(path + ".json", data.dump(),"application/json");
|
auto res = client.Put(path, data.dump(),"application/json");
|
||||||
|
|
||||||
processGenericErrors_(res);
|
processGenericErrors_(res);
|
||||||
|
|
||||||
@ -131,11 +134,11 @@ void Redmine::API::put(const std::string &path, const nlohmann::json &data) con
|
|||||||
|
|
||||||
void Redmine::API::post(const std::string &path, const nlohmann::json &data) const
|
void Redmine::API::post(const std::string &path, const nlohmann::json &data) const
|
||||||
{
|
{
|
||||||
DLOG_S(INFO) << "posting to API endpoint " << path+".json" << " at " <<redmineApiURL_;
|
DLOG_S(INFO) << "posting to API endpoint " << path << " at " <<redmineApiURL_;
|
||||||
httplib::Client client{redmineApiURL_};
|
httplib::Client client{redmineApiURL_};
|
||||||
client.set_basic_auth(authToken_, "");
|
client.set_basic_auth(authToken_, "");
|
||||||
|
|
||||||
auto res = client.Post(path + ".json", data.dump(),"application/json");
|
auto res = client.Post(path, data.dump(),"application/json");
|
||||||
|
|
||||||
processGenericErrors_(res);
|
processGenericErrors_(res);
|
||||||
|
|
||||||
@ -173,7 +176,7 @@ std::string Redmine::API::upload_(const std::filesystem::path &file, const std::
|
|||||||
|
|
||||||
Redmine::User Redmine::API::getMyAccount() const
|
Redmine::User Redmine::API::getMyAccount() const
|
||||||
{
|
{
|
||||||
nlohmann::json userInfo = get("/my/account");
|
nlohmann::json userInfo = get("/my/account.json");
|
||||||
|
|
||||||
return Redmine::User{userInfo};
|
return Redmine::User{userInfo};
|
||||||
}
|
}
|
||||||
@ -181,13 +184,13 @@ Redmine::User Redmine::API::getMyAccount() const
|
|||||||
void Redmine::API::setMyAccount(const Redmine::User &user) const
|
void Redmine::API::setMyAccount(const Redmine::User &user) const
|
||||||
{
|
{
|
||||||
|
|
||||||
put("/my/account", user.get());
|
put("/my/account.json", user.get());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Redmine::Project> Redmine::API::getProjects() const
|
std::vector<Redmine::Project> Redmine::API::getProjects(const std::uint32_t limit) const
|
||||||
{
|
{
|
||||||
nlohmann::json projectList = get("/projects");
|
nlohmann::json projectList = get("/projects.json?limit="+std::to_string(limit));
|
||||||
std::vector<Redmine::Project> projects;
|
std::vector<Redmine::Project> projects;
|
||||||
|
|
||||||
for (auto it = projectList["projects"].begin(); it != projectList["projects"].end(); ++it)
|
for (auto it = projectList["projects"].begin(); it != projectList["projects"].end(); ++it)
|
||||||
@ -202,7 +205,7 @@ std::vector<Redmine::Project> Redmine::API::getProjects() const
|
|||||||
|
|
||||||
std::vector<Redmine::IssueStatus> Redmine::API::getIssueStatusList()
|
std::vector<Redmine::IssueStatus> Redmine::API::getIssueStatusList()
|
||||||
{
|
{
|
||||||
nlohmann::json statusList = get("/issue_statuses");
|
nlohmann::json statusList = get("/issue_statuses.json");
|
||||||
issueStatusList_.clear();
|
issueStatusList_.clear();
|
||||||
|
|
||||||
|
|
||||||
@ -241,5 +244,18 @@ void Redmine::API::uploadFileToProject(const std::uint64_t projectId, const std:
|
|||||||
nlohmann::json upload;
|
nlohmann::json upload;
|
||||||
upload["file"] = file;
|
upload["file"] = file;
|
||||||
|
|
||||||
post("/projects/"+std::to_string(projectId)+"/files", upload);
|
post("/projects/"+std::to_string(projectId)+"/files.json", upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Redmine::Issue> Redmine::API::getIssues(const Redmine::Filter& filter) const
|
||||||
|
{
|
||||||
|
std::vector<Redmine::Issue> issues;
|
||||||
|
|
||||||
|
nlohmann::json issueList = get("/issues.json?" + filter.toQueryString());
|
||||||
|
for (auto &issue : issueList["issues"])
|
||||||
|
{
|
||||||
|
issues.push_back(Redmine::Issue(issue));
|
||||||
|
}
|
||||||
|
|
||||||
|
return issues;
|
||||||
|
}
|
75
src/Redmine/Filter.cpp
Normal file
75
src/Redmine/Filter.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* 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/Filter.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
Redmine::Filter::Filter()
|
||||||
|
:
|
||||||
|
filterByProjectID_(false),
|
||||||
|
projectStatus_(Redmine::Filter::ProjectStatus::open),
|
||||||
|
filterByAssignedUser_(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Redmine::Filter::filterByProjectID(const std::uint64_t id)
|
||||||
|
{
|
||||||
|
filterByProjectID_ = true;
|
||||||
|
projectID_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Redmine::Filter::filterByAssignedUserId(const std::uint64_t id)
|
||||||
|
{
|
||||||
|
filterByAssignedUser_ = true;
|
||||||
|
assignedUserID_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Redmine::Filter::toQueryString() const
|
||||||
|
{
|
||||||
|
std::stringstream filter;
|
||||||
|
|
||||||
|
if (filterByProjectID_)
|
||||||
|
{
|
||||||
|
filter << "project_id=" << projectID_ << "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (projectStatus_)
|
||||||
|
{
|
||||||
|
case Redmine::Filter::ProjectStatus::both:
|
||||||
|
filter << "status_id=*";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Redmine::Filter::ProjectStatus::open:
|
||||||
|
filter << "status=open";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Redmine::Filter::ProjectStatus::closed:
|
||||||
|
filter << "status=closed";
|
||||||
|
break;
|
||||||
|
}; // switch projectStatus
|
||||||
|
|
||||||
|
if (filterByAssignedUser_)
|
||||||
|
{
|
||||||
|
if (filter.rdbuf()->in_avail() > 0)
|
||||||
|
{
|
||||||
|
filter << "&";
|
||||||
|
}
|
||||||
|
filter << "assigned_to_id=" << assignedUserID_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter.str();
|
||||||
|
}
|
68
src/Redmine/Issue.cpp
Normal file
68
src/Redmine/Issue.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include <Redmine/Issue.hpp>
|
||||||
|
#define LOGURU_WITH_STREAMS 1
|
||||||
|
#include <loguru.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
Redmine::Issue::Issue(const nlohmann::json &issue) : Redmine::Object()
|
||||||
|
{
|
||||||
|
set(issue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Redmine::Issue::set(const nlohmann::json &data)
|
||||||
|
{
|
||||||
|
_verify(data);
|
||||||
|
data_=data;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json Redmine::Issue::get() const
|
||||||
|
{
|
||||||
|
return data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Redmine::Issue::_verify(const nlohmann::json &data)
|
||||||
|
{
|
||||||
|
|
||||||
|
_baseVerify(data, "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t Redmine::Issue::getId() const
|
||||||
|
{
|
||||||
|
return data_["id"].get<std::uint64_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Redmine::Issue::getProject() const
|
||||||
|
{
|
||||||
|
return data_["project"]["name"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t Redmine::Issue::getProjectId() const
|
||||||
|
{
|
||||||
|
return data_["project"]["id"].get<std::uint64_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Redmine::Issue::getStatus() const
|
||||||
|
{
|
||||||
|
return data_["status"]["name"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t Redmine::Issue::getStatusID() const
|
||||||
|
{
|
||||||
|
return data_["status"]["id"].get<std::uint64_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Redmine::Issue::getSubject() const
|
||||||
|
{
|
||||||
|
return data_["subject"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Redmine::Issue::getDescription() const
|
||||||
|
{
|
||||||
|
return data_["description"].get<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Redmine::Issue::to_string() const
|
||||||
|
{
|
||||||
|
return data_.dump(2);
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
#ifndef __LIBCMS_CONFIG_HPP__
|
#pragma once
|
||||||
#define __LIBCMS_CONFIG_HPP__
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2024 Dominik Meyer
|
* Copyright (C) 2024 Dominik Meyer
|
||||||
*
|
*
|
||||||
@ -24,5 +23,3 @@
|
|||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_PATCH 1
|
#define VERSION_PATCH 1
|
||||||
#define PROJECT_VERSION "0.0.1"
|
#define PROJECT_VERSION "0.0.1"
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user