Skip to content

Commit f517330

Browse files
authored
Merge pull request #2 from linkartemy/features/key-service
Features/key service
2 parents 7eb34d6 + 5b630a8 commit f517330

File tree

28 files changed

+995
-106
lines changed

28 files changed

+995
-106
lines changed

CMakeLists.txt

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,39 +67,52 @@ project(vpn_manager CXX)
6767

6868
# Adding userver dependency
6969
find_package(userver COMPONENTS core postgresql REQUIRED)
70-
if(NOT userver_FOUND) # Fallback to subdirectory usage
71-
# Enable userver libraries that are needed in this project
72-
set(USERVER_FEATURE_POSTGRESQL ON CACHE BOOL "" FORCE)
73-
74-
# Compatibility mode: some systems don't support these features
75-
set(USERVER_FEATURE_CRYPTOPP_BLAKE2 OFF CACHE BOOL "" FORCE)
76-
set(USERVER_FEATURE_GRPC_CHANNELZ OFF CACHE BOOL "" FORCE)
77-
set(USERVER_FEATURE_REDIS_HI_MALLOC ON CACHE BOOL "" FORCE)
78-
79-
if (EXISTS third_party/userver)
80-
message(STATUS "Using userver framework from third_party/userver")
81-
add_subdirectory(third_party/userver)
82-
else()
83-
message(FATAL_ERROR "Either install the userver or provide a path to it")
84-
endif()
70+
if(NOT userver_FOUND) # Fallback to subdirectory usage
71+
# Enable userver libraries that are needed in this project
72+
set(USERVER_FEATURE_POSTGRESQL ON CACHE BOOL "" FORCE)
73+
74+
# Compatibility mode: some systems don't support these features
75+
set(USERVER_FEATURE_CRYPTOPP_BLAKE2 OFF CACHE BOOL "" FORCE)
76+
set(USERVER_FEATURE_GRPC_CHANNELZ OFF CACHE BOOL "" FORCE)
77+
set(USERVER_FEATURE_REDIS_HI_MALLOC ON CACHE BOOL "" FORCE)
78+
79+
if(EXISTS third_party/userver)
80+
message(STATUS "Using userver framework from third_party/userver")
81+
add_subdirectory(third_party/userver)
82+
else()
83+
message(FATAL_ERROR "Either install the userver or provide a path to it")
84+
endif()
8585
endif()
8686

8787
userver_setup_environment()
8888

8989
# Common sources
9090
add_library(${PROJECT_NAME}_objs OBJECT
91-
src/constants.hpp
92-
93-
src/models/user_dto.hpp
94-
src/models/exception.hpp
95-
96-
src/repositories/user_repository/user_repository.hpp
97-
src/repositories/user_repository/user_repository.cpp
98-
99-
src/handlers/v1/user/get-by-username/view.hpp
100-
src/handlers/v1/user/get-by-username/view.cpp
101-
src/handlers/v1/user/create-user/view.hpp
102-
src/handlers/v1/user/create-user/view.cpp
91+
src/constants.hpp
92+
93+
src/helpers/datetime_helper.hpp
94+
src/helpers/datetime_helper.cpp
95+
src/helpers/string_convertible_checker.hpp
96+
97+
src/models/user_dto.hpp
98+
src/models/response.hpp
99+
100+
src/repositories/user_repository/user_repository.hpp
101+
src/repositories/user_repository/user_repository.cpp
102+
src/repositories/key_repository/key_repository.hpp
103+
src/repositories/key_repository/key_repository.cpp
104+
105+
src/handlers/v1/user/get-by-username/view.hpp
106+
src/handlers/v1/user/get-by-username/view.cpp
107+
src/handlers/v1/user/create-user/view.hpp
108+
src/handlers/v1/user/create-user/view.cpp
109+
110+
src/handlers/v1/key/create-key/view.hpp
111+
src/handlers/v1/key/create-key/view.cpp
112+
src/handlers/v1/key/get-by-id/view.hpp
113+
src/handlers/v1/key/get-by-id/view.cpp
114+
src/handlers/v1/key/get-by-name/view.hpp
115+
src/handlers/v1/key/get-by-name/view.cpp
103116
)
104117
target_link_libraries(${PROJECT_NAME}_objs PUBLIC userver::postgresql)
105118

@@ -110,7 +123,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_objs)
110123

111124
target_include_directories(${PROJECT_NAME}
112125
PRIVATE
113-
${CMAKE_CURRENT_SOURCE_DIR}
126+
${CMAKE_CURRENT_SOURCE_DIR}
114127
)
115128

116129
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)

configs/static_config.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,19 @@ components_manager:
6464
path: /v1/users/create-user
6565
method: POST
6666
task_processor: main-task-processor
67+
68+
handler-v1-create-key:
69+
path: /v1/keys/create-key
70+
method: POST
71+
task_processor: main-task-processor
72+
handler-v1-get-key-by-id:
73+
path: /v1/keys/get-key-by-id
74+
method: POST
75+
task_processor: main-task-processor
76+
handler-v1-get-key-by-name:
77+
path: /v1/keys/get-key-by-name
78+
method: POST
79+
task_processor: main-task-processor
6780

6881
postgres-db-1:
6982
dbconnection: $dbconnection
@@ -74,6 +87,8 @@ components_manager:
7487

7588
user-repository-component:
7689
task_processor: main-task-processor
90+
key-repository-component:
91+
task_processor: main-task-processor
7792

7893
dns-client:
7994
fs-task-processor: fs-task-processor

postgresql/data/initial_data.sql

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
INSERT INTO vpn_manager.user (username, first_name, last_name, email, phone_number)
1+
INSERT INTO vpn_manager.user (id, username, first_name, last_name, email, phone_number)
22
VALUES
3-
('jdoe', 'John', 'Doe', '[email protected]', '123-456-7890'),
4-
('asmith', 'Alice', 'Smith', '[email protected]', '987-654-3210'),
5-
('bwayne', 'Bruce', 'Wayne', '[email protected]', '456-789-1234'),
6-
('cclark', 'Clark', 'Kent', '[email protected]', '789-123-4567'),
7-
('ddiana', 'Diana', 'Prince', '[email protected]', '321-654-9870');
3+
('3f47acb2-9e5d-4c3a-8f1b-2d6e5c7a9b0e', 'jdoe', 'John', 'Doe', '[email protected]', '123-456-7890'),
4+
('a1b2c3d4-e5f6-7a8b-9c0d-e1f2a3b4c5d6', 'asmith', 'Alice', 'Smith', '[email protected]', '987-654-3210'),
5+
('f7e6d5c4-b3a2-1f0e-9d8c-7b6a5f4e3d2c', 'bwayne', 'Bruce', 'Wayne', '[email protected]', '456-789-1234'),
6+
('01234567-89ab-cdef-0123-456789abcdef', 'cclark', 'Clark', 'Kent', '[email protected]', '789-123-4567'),
7+
('fedcba98-7654-3210-fedc-ba9876543210', 'ddiana', 'Diana', 'Prince', '[email protected]', '321-654-9870');
88

9-
INSERT INTO vpn_manager.key (user_id, name, key)
9+
INSERT INTO vpn_manager.key (id, user_id, name, key)
1010
VALUES
11-
((SELECT id FROM vpn_manager.user WHERE username = 'jdoe'), 'Home WiFi', 'abc123key'),
12-
((SELECT id FROM vpn_manager.user WHERE username = 'asmith'), 'Work VPN', 'xyz456key'),
13-
((SELECT id FROM vpn_manager.user WHERE username = 'bwayne'), 'Batcave VPN', 'bat789key'),
14-
((SELECT id FROM vpn_manager.user WHERE username = 'cclark'), 'Fortress VPN', 'krypton101key'),
15-
((SELECT id FROM vpn_manager.user WHERE username = 'ddiana'), 'Amazon VPN', 'wonder102key');
11+
('1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', (SELECT id FROM vpn_manager.user WHERE username = 'jdoe'), 'Home WiFi', 'abc123key'),
12+
('2b3c4d5e-6f7a-8b9c-0d1e-2f3a4b5c6d7e', (SELECT id FROM vpn_manager.user WHERE username = 'asmith'), 'Work VPN', 'xyz456key'),
13+
('3c4d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f', (SELECT id FROM vpn_manager.user WHERE username = 'bwayne'), 'Batcave VPN', 'bat789key'),
14+
('4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9f', (SELECT id FROM vpn_manager.user WHERE username = 'cclark'), 'Fortress VPN', 'krypton101key'),
15+
('5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9f0a', (SELECT id FROM vpn_manager.user WHERE username = 'ddiana'), 'Amazon VPN', 'wonder102key');

postgresql/schemas/db-1.sql

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,15 @@ CREATE TABLE IF NOT EXISTS vpn_manager.user (
1717
CREATE TABLE IF NOT EXISTS vpn_manager.key (
1818
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
1919
user_id UUID REFERENCES vpn_manager.user (id) ON DELETE CASCADE,
20-
name VARCHAR(255) NOT NULL,
21-
key VARCHAR(255) NOT NULL,
20+
name VARCHAR(255) NOT NULL UNIQUE,
21+
key VARCHAR(255) NOT NULL UNIQUE,
22+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
23+
);
24+
25+
CREATE TABLE IF NOT EXISTS vpn_manager.key_subscription (
26+
id UUID DEFAULT uuid_generate_v4 () PRIMARY KEY,
27+
key_id UUID REFERENCES vpn_manager.key (id) ON DELETE CASCADE,
28+
start_date TIMESTAMP NOT NULL,
29+
end_date TIMESTAMP NOT NULL,
2230
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
2331
);
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include "view.hpp"
2+
#include "../../../../constants.hpp"
3+
#include "../../../../models/response.hpp"
4+
#include "../../../../models/user_dto.hpp"
5+
#include "../../../../repositories/key_repository/key_repository.hpp"
6+
7+
#include <fmt/format.h>
8+
#include <boost/uuid/string_generator.hpp>
9+
#include <boost/uuid/uuid.hpp>
10+
11+
#include <exception>
12+
#include <userver/components/component_config.hpp>
13+
#include <userver/components/component_context.hpp>
14+
#include <userver/formats/json/serialize.hpp>
15+
#include <userver/server/handlers/http_handler_base.hpp>
16+
#include <userver/server/http/http_status.hpp>
17+
#include <userver/storages/postgres/cluster.hpp>
18+
#include <userver/storages/postgres/component.hpp>
19+
#include <userver/storages/postgres/exceptions.hpp>
20+
#include <userver/storages/postgres/io/user_types.hpp>
21+
#include <userver/utils/assert.hpp>
22+
#include <userver/utils/boost_uuid4.hpp>
23+
#include <userver/utils/uuid4.hpp>
24+
25+
namespace vpn_manager {
26+
27+
namespace {
28+
29+
class CreateKey final : public userver::server::handlers::HttpHandlerBase {
30+
public:
31+
static constexpr std::string_view kName = "handler-v1-create-key";
32+
33+
CreateKey(const userver::components::ComponentConfig& config,
34+
const userver::components::ComponentContext& component_context)
35+
: HttpHandlerBase(config, component_context),
36+
pg_cluster_(component_context
37+
.FindComponent<userver::components::Postgres>(
38+
constants::postgres::kPostgresDBName)
39+
.GetCluster()),
40+
key_repository_(config, component_context) {}
41+
42+
std::string HandleRequestThrow(
43+
const userver::server::http::HttpRequest& request,
44+
userver::server::request::RequestContext&) const override {
45+
auto& response = request.GetHttpResponse();
46+
47+
const auto json_body =
48+
userver::formats::json::FromString(request.RequestBody());
49+
50+
if (!json_body.HasMember("name") || !json_body.HasMember("key") ||
51+
!json_body.HasMember("user_id")) {
52+
response.SetStatus(userver::server::http::HttpStatus::kBadRequest);
53+
return response::ErrorResponse(kMissingFields).ToJson();
54+
}
55+
56+
boost::uuids::uuid user_id;
57+
try {
58+
user_id = userver::utils::BoostUuidFromString(
59+
json_body["user_id"].As<std::string>());
60+
} catch (const std::exception& e) {
61+
LOG_ERROR() << "CreateKey: Invalid user_id: " << e.what();
62+
response.SetStatus(userver::server::http::HttpStatus::kBadRequest);
63+
return response::ErrorResponse(kInvalidUserId).ToJson();
64+
} catch (...) {
65+
LOG_ERROR() << "CreateKey: Invalid user_id";
66+
response.SetStatus(userver::server::http::HttpStatus::kBadRequest);
67+
return response::ErrorResponse(kInvalidUserId).ToJson();
68+
}
69+
std::string name;
70+
std::string key;
71+
try {
72+
name = json_body["name"].As<std::string>();
73+
key = json_body["key"].As<std::string>();
74+
} catch (const std::exception& e) {
75+
LOG_ERROR() << "CreateKey: Unexpected error: " << e.what();
76+
response.SetStatus(
77+
userver::server::http::HttpStatus::kInternalServerError);
78+
return response::ErrorResponse(kUnknownError).ToJson();
79+
} catch (...) {
80+
LOG_ERROR() << "CreateKey: Unexpected error";
81+
response.SetStatus(
82+
userver::server::http::HttpStatus::kInternalServerError);
83+
return response::ErrorResponse(kUnknownError).ToJson();
84+
}
85+
86+
boost::uuids::uuid key_id;
87+
try {
88+
key_id = key_repository_.CreateKey(user_id, name, key);
89+
} catch (const userver::storages::postgres::UniqueViolation& e) {
90+
LOG_ERROR() << "CreateKey: Unique constraint violation: " << e.what();
91+
response.SetStatus(userver::server::http::HttpStatus::kConflict);
92+
return response::ErrorResponse(kKeyWithSuchNameAlreadyExists).ToJson();
93+
} catch (const userver::storages::postgres::ForeignKeyViolation& e) {
94+
LOG_ERROR() << "CreateKey: Foreign key constraint violation: "
95+
<< e.what();
96+
response.SetStatus(userver::server::http::HttpStatus::kNotFound);
97+
return response::ErrorResponse(kUserDoesNotExist).ToJson();
98+
} catch (const userver::storages::postgres::ClusterError& e) {
99+
LOG_ERROR() << "CreateKey: Database error: " << e.what();
100+
response.SetStatus(
101+
userver::server::http::HttpStatus::kInternalServerError);
102+
return response::ErrorResponse(kUnknownError).ToJson();
103+
} catch (const std::exception& e) {
104+
LOG_ERROR() << "CreateKey: Unexpected error: " << e.what();
105+
response.SetStatus(
106+
userver::server::http::HttpStatus::kInternalServerError);
107+
return response::ErrorResponse(kUnknownError).ToJson();
108+
} catch (...) {
109+
LOG_ERROR() << "CreateKey: Unexpected error";
110+
response.SetStatus(
111+
userver::server::http::HttpStatus::kInternalServerError);
112+
return response::ErrorResponse(kUnknownError).ToJson();
113+
}
114+
115+
response.SetStatus(userver::server::http::HttpStatus::kOk);
116+
117+
return response::Response(fmt::format(R"({{"id": "{}"}})", key_id))
118+
.ToJson();
119+
}
120+
121+
userver::storages::postgres::ClusterPtr pg_cluster_;
122+
repositories::KeyRepositoryComponent key_repository_;
123+
124+
private:
125+
inline static constexpr std::string_view kMissingFields =
126+
"Missing required fields";
127+
inline static constexpr std::string_view kKeyWithSuchNameAlreadyExists =
128+
"Key with such name already exists";
129+
inline static constexpr std::string_view kInvalidUserId = "Invalid User ID";
130+
inline static constexpr std::string_view kUserDoesNotExist =
131+
"User does not exist";
132+
inline static constexpr std::string_view kUnknownError = "Unknown error";
133+
};
134+
135+
} // namespace
136+
137+
void AppendCreateKey(userver::components::ComponentList& component_list) {
138+
component_list.Append<CreateKey>();
139+
}
140+
141+
} // namespace vpn_manager
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <string_view>
5+
6+
#include <userver/components/component_list.hpp>
7+
#include <userver/server/handlers/http_handler_base.hpp>
8+
9+
namespace vpn_manager {
10+
11+
void AppendCreateKey(userver::components::ComponentList& component_list);
12+
13+
} // namespace vpn_manager

0 commit comments

Comments
 (0)