Skip to content

Commit

Permalink
refactor: cleanup public API
Browse files Browse the repository at this point in the history
- Separated messages into separate structs
- Refactored controllers to use reflection and shared error creation functions
- Adapted frontend to API changes
- Unified API paths
- Updated OpenAPI spec
  • Loading branch information
LordTermor committed May 24, 2024
1 parent c952ce2 commit e7ba67a
Show file tree
Hide file tree
Showing 27 changed files with 689 additions and 651 deletions.
5 changes: 5 additions & 0 deletions daemon/core/application/dtos/PackageSectionDTO.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,8 @@ template<> struct std::hash<PackageSectionDTO> {
return seed;
}
};

template<> inline std::string bxt::to_string(const PackageSectionDTO& dto) {
return fmt::format("{}/{}/{}", dto.branch, dto.repository,
dto.architecture);
}
2 changes: 1 addition & 1 deletion daemon/core/domain/enums/LogEntryType.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

namespace bxt::Core::Domain {

enum LogEntryType { Add, Remove, Update };
enum struct LogEntryType { Add, Remove, Update };

} // namespace bxt::Core::Domain
16 changes: 16 additions & 0 deletions daemon/presentation/messages/AuthMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include <string>

namespace bxt::Presentation {
struct AuthRequest {
std::string name;
std::string password;
};
} // namespace bxt::Presentation
27 changes: 27 additions & 0 deletions daemon/presentation/messages/CompareMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include "core/application/dtos/PackageSectionDTO.h"
#include "presentation/messages/SectionMessages.h"

#include <string>
#include <unordered_map>
#include <vector>

namespace bxt::Presentation {

using CompareRequest = std::vector<SectionRequest>;

using LocationMap = std::unordered_map<std::string, std::string>;
using SectionMap = std::unordered_map<std::string, LocationMap>;

struct CompareResponse {
std::vector<Core::Application::PackageSectionDTO> sections;
std::unordered_map<std::string, SectionMap> compare_table;
};
} // namespace bxt::Presentation
24 changes: 24 additions & 0 deletions daemon/presentation/messages/LogMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include "core/domain/enums/LogEntryType.h"
#include "presentation/messages/PackageMessages.h"

#include <string>

namespace bxt::Presentation {

struct LogEntryReponse {
std::string id;
uint64_t time;
Core::Domain::LogEntryType type;
PackageResponse package;
};

using LogResponse = std::vector<LogEntryReponse>;
} // namespace bxt::Presentation
33 changes: 33 additions & 0 deletions daemon/presentation/messages/PackageMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include "core/application/dtos/PackageSectionDTO.h"
#include "presentation/messages/SectionMessages.h"

#include <string>
#include <unordered_map>

namespace bxt::Presentation {

struct SnapRequest {
SectionRequest source;
SectionRequest target;
};

struct PoolEntryResponse {
std::string version;
bool has_signature;
};

struct PackageResponse {
std::string name;
Core::Application::PackageSectionDTO section;
std::unordered_map<std::string, PoolEntryResponse> pool_entries;
std::string preferred_location;
};
} // namespace bxt::Presentation
17 changes: 17 additions & 0 deletions daemon/presentation/messages/SectionMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include "core/application/dtos/PackageSectionDTO.h"

namespace bxt::Presentation {

using SectionRequest = Core::Application::PackageSectionDTO;

using SectionReponse = Core::Application::PackageSectionDTO;

} // namespace bxt::Presentation
34 changes: 34 additions & 0 deletions daemon/presentation/messages/UserMessages.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#pragma once

#include <optional>
#include <set>
#include <string>

namespace bxt::Presentation {
struct AddUserRequest {
std::string name;
std::string password;
std::optional<std::set<std::string>> permissions;
};

struct UpdateUserRequest {
std::string name;
std::optional<std::string> password;
std::optional<std::set<std::string>> permissions;
};

struct RemoveUserRequest {
std::string name;
};

struct UserResponse {
std::string name;
std::set<std::string> permissions;
};
} // namespace bxt::Presentation
36 changes: 14 additions & 22 deletions daemon/presentation/web-controllers/AuthController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "AuthController.h"

#include "drogon/HttpTypes.h"
#include "presentation/messages/AuthMessages.h"
#include "utilities/drogon/Helpers.h"

#include <boost/json.hpp>
Expand All @@ -18,43 +19,34 @@ namespace bxt::Presentation {

drogon::Task<drogon::HttpResponsePtr>
AuthController::auth(drogon::HttpRequestPtr req) {
if (!req->getJsonObject() || !req->getJsonObject()->isObject()) {
auto error_resp = drogon::HttpResponse::newHttpResponse();
error_resp->setStatusCode(drogon::k400BadRequest);
co_return error_resp;
const auto auth_request =
drogon_helpers::get_request_json<AuthRequest>(req);

if (!auth_request) {
co_return drogon_helpers::make_error_response(
fmt::format("Invalid request: {}", auth_request.error()->what()));
}

auto json = *req->getJsonObject();
const auto& [name, password] = *auth_request;

const auto name_json = json["name"];
const auto password_json = json["password"];
const auto check_ok = co_await m_service.auth(name, password);

if (name_json.isNull() || password_json.isNull()) {
auto error_resp = drogon::HttpResponse::newHttpResponse();
error_resp->setStatusCode(drogon::k400BadRequest);
co_return error_resp;
if (!check_ok.has_value()) {
co_return drogon_helpers::make_error_response(check_ok.error().what(),
drogon::k401Unauthorized);
}

const std::string name = name_json.asString();
const std::string password = password_json.asString();

if (!co_await m_service.auth(name, password)) {
auto error_resp = drogon::HttpResponse::newHttpResponse();
error_resp->setStatusCode(drogon::k401Unauthorized);
co_return error_resp;
}
const auto token = jwt::create()
.set_payload_claim("username", name)
.set_issuer("auth0")
.set_type("JWS")
.sign(jwt::algorithm::hs256 {m_options.secret});

auto response = drogon::HttpResponse::newHttpResponse();
drogon::Cookie jwt_cookie("token", token);

jwt_cookie.setHttpOnly(true);

auto response = drogon::HttpResponse::newHttpResponse();
response->addCookie(jwt_cookie);

co_return response;
}

Expand Down
74 changes: 26 additions & 48 deletions daemon/presentation/web-controllers/CompareController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,86 +7,64 @@
#include "CompareController.h"

#include "core/application/dtos/PackageSectionDTO.h"
#include "core/domain/enums/PoolLocation.h"
#include "drogon/HttpResponse.h"
#include "drogon/HttpTypes.h"
#include "presentation/messages/CompareMessages.h"
#include "utilities/drogon/Helpers.h"
#include "utilities/drogon/Macro.h"
#include "utilities/to_string.h"

#include "json/value.h"
#include <rfl/as.hpp>
#include <rfl/json/read.hpp>
#include <string>
#include <unordered_map>
#include <vector>
namespace bxt::Presentation {
drogon::Task<drogon::HttpResponsePtr>
CompareController::compare(drogon::HttpRequestPtr req) {
Json::Value result;
const auto available_sections = co_await m_section_service.get_sections();

if (!available_sections.has_value()) {
result["error"] = "No sections available in the Box";
result["status"] = "error";

auto response = drogon::HttpResponse::newHttpJsonResponse(result);
response->setStatusCode(drogon::k400BadRequest);

co_return response;
}

for (const auto& [branch, repository, architecture] : *available_sections) {
BXT_JWT_CHECK_PERMISSIONS(fmt::format("packages.compare.{}.{}.{}",
branch, repository, architecture),
req)
}

const auto sections_json = *req->getJsonObject();

if (sections_json.empty()) {
result["error"] = "No sections to compare provided";
result["status"] = "error";
if (!available_sections.has_value()) {
co_return drogon_helpers::make_error_response("No sections available");
}

auto response = drogon::HttpResponse::newHttpJsonResponse(result);
response->setStatusCode(drogon::k400BadRequest);
const auto sections_request =
drogon_helpers::get_request_json<CompareRequest>(req);

co_return response;
if (!sections_request) {
co_return drogon_helpers::make_error_response(fmt::format(
"Invalid request: {}", sections_request.error()->what()));
}

std::vector<PackageSectionDTO> sections;

for (const auto& section_json : sections_json) {
sections.emplace_back(PackageSectionDTO {
.branch = section_json["branch"].asString(),
.repository = section_json["repository"].asString(),
.architecture = section_json["architecture"].asString()});
if ((*sections_request).empty()) {
co_return drogon_helpers::make_error_response(
"No sections to compare were provided");
}

const auto compare_result = co_await m_compare_service.compare(sections);
const auto compare_result =
co_await m_compare_service.compare(*sections_request);

if (compare_result->sections.empty()
|| compare_result->compare_table.empty()) {
result["error"] = "No compare data found (all sections are empty)";
result["status"] = "error";

auto response = drogon::HttpResponse::newHttpJsonResponse(result);
response->setStatusCode(drogon::k400BadRequest);

co_return response;
co_return drogon_helpers::make_error_response(
"No compare data found (all sections are empty)");
}

for (const auto& section : compare_result->sections) {
Json::Value section_json;

section_json["branch"] = section.branch;
section_json["repository"] = section.repository;
section_json["architecture"] = section.architecture;

result["sections"].append(section_json);
}
CompareResponse result {compare_result->sections};

for (const auto& [index, version] : compare_result->compare_table) {
auto&& [name, section, location] = index;
result["compare_table"][name][std::string(section)]
[bxt::to_string(location)] = version;

result.compare_table[name][bxt::to_string(section)]
[bxt::to_string(location)] = version;
}

co_return drogon::HttpResponse::newHttpJsonResponse(result);
co_return drogon_helpers::make_json_response(result);
}
} // namespace bxt::Presentation
Loading

0 comments on commit e7ba67a

Please sign in to comment.