diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ff541d..cf3da1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,8 @@ -name: CI +name: urealmedium CI 'on': + schedule: + - cron: '30 5 * * 1' # Every Monday at 5:30 pull_request: push: branches: @@ -42,16 +44,15 @@ jobs: - name: Install packages run: | + (cd third_party && git clone -b develop --single-branch --depth 1 https://github.com/userver-framework/userver.git) sudo apt update - sudo apt install --allow-downgrades -y postgresql $(cat third_party/userver/scripts/docs/en/deps/${{matrix.os}}.md | tr '\n' ' ') - sudo apt install --allow-downgrades -y pep8 $(cat third_party/userver/scripts/docs/en/deps/${{matrix.os}}.md | tr '\n' ' ') + sudo apt install --allow-downgrades -y pycodestyle postgresql $(cat third_party/userver/scripts/docs/en/deps/${{matrix.os}}.md | tr '\n' ' ') - name: Reinstall postgres 14 run: | sudo apt purge libpq5 libpq-dev postgresql-* sudo apt install -y postgresql-14 postgresql-client-14 postgresql-server-dev-14 - - name: Setup ccache run: | ccache -M 2.0GB @@ -81,11 +82,11 @@ jobs: - name: Test run after install if: matrix.make == 'test-release' - run: >- - ./local_installation/bin/realmedium_sample - --config=./local_installation/etc/realmedium_sample/static_config.yaml - --config_vars=./local_installation/etc/realmedium_sample/config_vars.yaml - & + run: | + ./local_installation/bin/realmedium_sample \ + --config=./local_installation/etc/realmedium_sample/config.yaml \ + --config_vars=./local_installation/etc/realmedium_sample/config_vars.yaml \ + & - name: Check work run service if: matrix.make == 'test-release' diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 9201371..9cea2a6 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -1,6 +1,8 @@ -name: Docker build +name: urealmedium Docker build 'on': + schedule: + - cron: '30 5 * * 1' # Every Monday at 5:30 pull_request: push: branches: @@ -15,12 +17,12 @@ jobs: tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Reuse ccache directory - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: .ccache key: 'ccache-dir-${{github.ref}}_run-${{github.run_number}}' diff --git a/.github/workflows/update-submodules.yaml b/.github/workflows/update-submodules.yaml deleted file mode 100644 index 9603da8..0000000 --- a/.github/workflows/update-submodules.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Update submodules - -on: - workflow_dispatch: - -jobs: - update: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Update submodules - run: | - git submodule update --init - - - name: Commit & push changes - run: | - git config user.email "actions@github.com" - git config user.name "GitHub Actions - update submodules" - git commit -am "Update submodules" - git push diff --git a/.gitmodules b/.gitmodules index 3e830eb..74a5834 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "third_party/userver"] - path = third_party/userver - url = https://github.com/userver-framework/userver.git [submodule "third_party/cpp-jwt"] path = third_party/cpp-jwt url = https://github.com/arun11299/cpp-jwt diff --git a/CMakeLists.txt b/CMakeLists.txt index 46ee7d8..d0165c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,8 @@ add_library(${PROJECT_NAME}_objs OBJECT src/cache/articles_cache.cpp src/cache/comments_cache.cpp src/cache/comments_cache.hpp + src/handlers/common.cpp + src/handlers/common.hpp src/handlers/profiles/profiles.cpp src/handlers/profiles/profiles.hpp src/handlers/users/users.cpp @@ -80,7 +82,6 @@ add_library(${PROJECT_NAME}_objs OBJECT src/dto/comment.hpp src/dto/comment.cpp src/db/sql.hpp - src/db/types.hpp src/models/user.hpp src/models/user.cpp src/models/comment.hpp @@ -88,7 +89,6 @@ add_library(${PROJECT_NAME}_objs OBJECT src/models/article.hpp src/models/article.cpp src/models/profile.hpp - src/models/profile.cpp src/validators/user_validators.hpp src/validators/user_validators.cpp src/validators/length_validator.hpp @@ -118,10 +118,8 @@ target_link_libraries(${PROJECT_NAME}_objs PUBLIC userver::core userver::postgre file(GLOB_RECURSE SCHEMAS ${CMAKE_CURRENT_SOURCE_DIR}/docs/*.yaml) userver_target_generate_chaotic(${PROJECT_NAME}-chgen - ARGS - -n "/components/schemas/([^/]*)/=real_medium::handlers::{0}" - -f "(.*)={0}" - --generate-serializers + LAYOUT "/components/schemas/([^/]*)/=real_medium::handlers::{0}" + GENERATE_SERIALIZERS OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/src SCHEMAS @@ -153,7 +151,9 @@ target_link_libraries(${PROJECT_NAME}_unittest PRIVATE ${PROJECT_NAME}_objs user add_google_tests(${PROJECT_NAME}_unittest) # Functional Tests -add_subdirectory(tests) +userver_testsuite_add_simple( + REQUIREMENTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/requirements.txt +) # Install include(GNUInstallDirs) diff --git a/Makefile b/Makefile index 46d804b..bc57019 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CMAKE_COMMON_FLAGS ?= -DUSERVER_OPEN_SOURCE_BUILD=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +CMAKE_COMMON_FLAGS ?= -DCMAKE_EXPORT_COMPILE_COMMANDS=ON CMAKE_DEBUG_FLAGS ?= -DUSERVER_SANITIZE='addr ub' CMAKE_RELEASE_FLAGS ?= CMAKE_OS_FLAGS ?= -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 -DUSERVER_FEATURE_REDIS_HI_MALLOC=1 diff --git a/Makefile.local b/Makefile.local deleted file mode 100644 index 5e40df6..0000000 --- a/Makefile.local +++ /dev/null @@ -1 +0,0 @@ -CMAKE_COMMON_FLAGS += -DUSERVER_FEATURE_CRYPTOPP_BLAKE=0 -DUSERVER_FEATURE_GRPC_CHANNELZ=0 diff --git a/README.md b/README.md index e70cfa1..8c6dc4d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,19 @@ # RealMedium -## THIS SAMPLE IS NOT READY! COME BACK LATER +[![urealmedium CI](https://github.com/userver-framework/realmedium_sample/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/userver-framework/realmedium_sample/actions/workflows/ci.yml) +[![urealmedium Docker build](https://github.com/userver-framework/realmedium_sample/actions/workflows/docker.yaml/badge.svg?branch=develop)](https://github.com/userver-framework/realmedium_sample/actions/workflows/docker.yaml) This is project created in summer school Yandex. This codebase was created to demonstrate a fully fledged backend application built with **[userver framework](https://userver.tech/)** +### Prerequisites + +[Install the userver](https://userver.tech/de/dab/md_en_2userver_2build_2build.html#ways_to_get_userver) into the system +or +* check it out `git clone --depth 1 https://github.com/userver-framework/userver.git /path/to/userver` +* install all of its dependencies +* `ln -s /path/to/userver /path/to/realmedioum_sample/third_party/userver` + ### Docker-compose ``` # Clone submodules @@ -13,16 +22,20 @@ git submodule update --init # Run service make docker-start-service-release ``` + ### Local ``` make service-start-release ``` + ## Tests Run unit and functional tests in docker or local. + ### Docker-compose ``` make docker-test-release ``` + ### Local ``` make test-release diff --git a/configs/static_config.yaml b/configs/config.yaml similarity index 100% rename from configs/static_config.yaml rename to configs/config.yaml diff --git a/configs/config_vars_testing.yaml b/configs/config_vars.testsuite.yaml similarity index 100% rename from configs/config_vars_testing.yaml rename to configs/config_vars.testsuite.yaml diff --git a/docker-compose.yml b/docker-compose.yml index 1b7182a..8fc4f50 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -37,7 +37,6 @@ services: - CMAKE_OPTIONS volumes: - .:/realmedium:rw - - ./third_party/userver/tools/docker:/tools:ro - ${TC_CORES_DIR:-./.cores}:/cores:rw ports: - 8080:8080 diff --git a/src/cache/articles_cache.cpp b/src/cache/articles_cache.cpp index 01d20e7..9efb1fb 100644 --- a/src/cache/articles_cache.cpp +++ b/src/cache/articles_cache.cpp @@ -1,5 +1,7 @@ #include "articles_cache.hpp" +#include + namespace real_medium::cache::articles_cache { userver::storages::postgres::Query ArticlesCachePolicy::kQuery = @@ -41,7 +43,10 @@ ArticlesCacheContainer::getRecent( std::vector articles; int offset = 0; for (const auto& it : recentArticles_) { - if (filter.limit && articles.size() >= filter.limit) break; + if (filter.limit && + articles.size() >= + userver::utils::numeric_cast(filter.limit)) + break; const auto& tags = it.second->tags; if (filter.tag && it.second->tags.find(filter.tag.value()) == tags.end()) @@ -77,7 +82,10 @@ std::vector ArticlesCacheContainer::getFeed( ; int offset = 0; for (const auto& it : followedArticlesOrdered) { - if (filter.limit && articles.size() >= filter.limit) break; + if (filter.limit && + articles.size() >= + userver::utils::numeric_cast(filter.limit)) + break; if (filter.offset && offset < filter.offset) { ++offset; continue; diff --git a/src/cache/articles_cache.hpp b/src/cache/articles_cache.hpp index d8df3cd..9f17e22 100644 --- a/src/cache/articles_cache.hpp +++ b/src/cache/articles_cache.hpp @@ -1,9 +1,9 @@ #pragma once +#include #include #include #include #include -#include #include "../db/sql.hpp" #include "../dto/filter.hpp" #include "../models/article.hpp" @@ -26,7 +26,8 @@ class ArticlesCacheContainer { std::vector getRecent( real_medium::handlers::ArticleFilterDTO& filter_) const; std::vector getFeed( - real_medium::handlers::FeedArticleFilterDTO& filter_, UserId authId_) const; + real_medium::handlers::FeedArticleFilterDTO& filter_, + UserId authId_) const; private: struct TimepointedArticle { diff --git a/src/db/types.hpp b/src/db/types.hpp deleted file mode 100644 index a6e1bd7..0000000 --- a/src/db/types.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -namespace real_medium::sql::types { - -inline constexpr std::string_view kProfile{"real_medium.profile"}; -inline constexpr std::string_view kUser{"real_medium.user"}; -inline constexpr std::string_view kComment{"real_medium.comment"}; -inline constexpr std::string_view kFullArticleInfo{ - "real_medium.full_article_info"}; -inline constexpr std::string_view kTaggedArticleWithProfile{ - "real_medium.tagged_article_with_author_profile"}; - -} // namespace real_medium::sql::types diff --git a/src/dto/article.hpp b/src/dto/article.hpp index da5c631..30c98f4 100644 --- a/src/dto/article.hpp +++ b/src/dto/article.hpp @@ -1,10 +1,10 @@ #pragma once +#include #include #include #include #include -#include #include #include "models/article.hpp" diff --git a/src/dto/filter.cpp b/src/dto/filter.cpp index 871fd09..7d9c006 100644 --- a/src/dto/filter.cpp +++ b/src/dto/filter.cpp @@ -5,7 +5,8 @@ namespace real_medium::dto { template <> -handlers::FeedArticleFilterDTO Parse(const userver::server::http::HttpRequest& request) { +handlers::FeedArticleFilterDTO Parse( + const userver::server::http::HttpRequest& request) { handlers::FeedArticleFilterDTO filter; if (request.HasArg("limit")) { filter.limit = boost::lexical_cast(request.GetArg("limit")); @@ -19,7 +20,8 @@ handlers::FeedArticleFilterDTO Parse(const userver::server::http::HttpRequest& r } template <> -handlers::ArticleFilterDTO Parse(const userver::server::http::HttpRequest& request) { +handlers::ArticleFilterDTO Parse( + const userver::server::http::HttpRequest& request) { handlers::ArticleFilterDTO filter; if (request.HasArg("tag")) { filter.tag = request.GetArg("tag"); diff --git a/src/handlers/articles/articles_favorite.cpp b/src/handlers/articles/articles_favorite.cpp index 1f46443..4674cbd 100644 --- a/src/handlers/articles/articles_favorite.cpp +++ b/src/handlers/articles/articles_favorite.cpp @@ -1,17 +1,12 @@ #include "articles_favorite.hpp" + +#include + #include "db/sql.hpp" #include "dto/article.hpp" namespace real_medium::handlers::articles_favorite::post { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, @@ -20,9 +15,9 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( auto& slug = request.GetPathArg("slug"); auto transaction = - pg_cluster_->Begin("favorite_article_transaction", - userver::storages::postgres::ClusterHostType::kMaster, - userver::storages::postgres::Transaction::RW); + GetPg().Begin("favorite_article_transaction", + userver::storages::postgres::ClusterHostType::kMaster, + userver::storages::postgres::Transaction::RW); auto res = transaction.Execute(sql::kInsertFavoritePair.data(), user_id, slug); @@ -34,7 +29,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( transaction.Commit(); } - const auto get_article_res = pg_cluster_->Execute( + const auto get_article_res = GetPg().Execute( userver::storages::postgres::ClusterHostType::kSlave, real_medium::sql::kGetArticleWithAuthorProfileBySlug.data(), slug, user_id); diff --git a/src/handlers/articles/articles_favorite.hpp b/src/handlers/articles/articles_favorite.hpp index 5928511..d304aff 100644 --- a/src/handlers/articles/articles_favorite.hpp +++ b/src/handlers/articles/articles_favorite.hpp @@ -1,28 +1,22 @@ #pragma once -#include "userver/components/component.hpp" -#include "userver/components/component_list.hpp" -#include "userver/formats/json/serialize_container.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" +#include +#include + +#include "handlers/common.hpp" namespace real_medium::handlers::articles_favorite::post { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-articles-favorite-post"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, userver::server::request::RequestContext& context) const override; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace real_medium::handlers::articles_favorite::post diff --git a/src/handlers/articles/articles_get.cpp b/src/handlers/articles/articles_get.cpp index 1dd6828..25fa710 100644 --- a/src/handlers/articles/articles_get.cpp +++ b/src/handlers/articles/articles_get.cpp @@ -1,6 +1,6 @@ #include "articles_get.hpp" -#include #include +#include #include "db/sql.hpp" #include "dto/article.hpp" #include "dto/filter.hpp" @@ -9,19 +9,9 @@ namespace real_medium::handlers::articles::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()), - cache_(component_context.FindComponent< - real_medium::cache::articles_cache::ArticlesCache>()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value& request_json, + const userver::formats::json::Value& /*request_json*/, userver::server::request::RequestContext& context) const { handlers::ArticleFilterDTO filter; @@ -34,7 +24,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( } auto user_id = context.GetData>("id"); - auto data = cache_.Get(); + auto data = GetArticlesCache().Get(); auto recentArticles = data->getRecent(filter); userver::formats::json::ValueBuilder builder; builder["articles"] = userver::formats::common::Type::kArray; diff --git a/src/handlers/articles/articles_get.hpp b/src/handlers/articles/articles_get.hpp index bbc17ad..24cd837 100644 --- a/src/handlers/articles/articles_get.hpp +++ b/src/handlers/articles/articles_get.hpp @@ -1,35 +1,19 @@ #pragma once -#include -#include +#include -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "../../cache/articles_cache.hpp" -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::articles::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-get-articles"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; - const real_medium::cache::articles_cache::ArticlesCache& cache_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::articles::get diff --git a/src/handlers/articles/articles_post.cpp b/src/handlers/articles/articles_post.cpp index 3ab487e..1a98c25 100644 --- a/src/handlers/articles/articles_post.cpp +++ b/src/handlers/articles/articles_post.cpp @@ -1,28 +1,21 @@ #include "articles_post.hpp" -#include #include +#include #include "../../db/sql.hpp" #include "../../models/article.hpp" #include "../../utils/errors.hpp" #include "../../utils/slugify.hpp" #include "validators/validators.hpp" -namespace real_medium::handlers::articles::post { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) - : HttpHandlerJsonBase(config, context), - pg_cluster_(context - .FindComponent( - "realmedium-database") - .GetCluster()) {} +namespace real_medium::handlers::articles::post { userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, userver::server::request::RequestContext& context) const { handlers::CreateArticleRequest createArticleRequest = - request_json["article"].As(); + request_json["article"].As(); try { validator::validate(createArticleRequest); } catch (const real_medium::utils::error::ValidationException& ex) { @@ -41,7 +34,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( const auto slug = real_medium::utils::slug::Slugify(createArticleRequest.title.value()); - const auto res = pg_cluster_->Execute( + const auto res = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, real_medium::sql::kCreateArticle.data(), createArticleRequest.title, slug, createArticleRequest.body, createArticleRequest.description, @@ -58,7 +51,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( throw; } - const auto res = pg_cluster_->Execute( + const auto res = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, real_medium::sql::kGetArticleWithAuthorProfile.data(), articleId, userId); diff --git a/src/handlers/articles/articles_post.hpp b/src/handlers/articles/articles_post.hpp index d1e57c7..44d56f4 100644 --- a/src/handlers/articles/articles_post.hpp +++ b/src/handlers/articles/articles_post.hpp @@ -1,28 +1,21 @@ #pragma once -#include -#include -#include -#include #include -#include -#include + +#include "handlers/common.hpp" namespace real_medium::handlers::articles::post { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + +class Handler final : public Common { public: static constexpr std::string_view kName{"handler-create-article"}; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, - userver::server::request::RequestContext& request_context) - const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& request_context) const override; }; + } // namespace real_medium::handlers::articles::post diff --git a/src/handlers/articles/articles_slug_delete.cpp b/src/handlers/articles/articles_slug_delete.cpp index ae3e90c..a76c3bf 100644 --- a/src/handlers/articles/articles_slug_delete.cpp +++ b/src/handlers/articles/articles_slug_delete.cpp @@ -5,13 +5,6 @@ #include "../../utils/slugify.hpp" namespace real_medium::handlers::articles_slug::del { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) - : HttpHandlerJsonBase(config, context), - pg_cluster_(context - .FindComponent( - "realmedium-database") - .GetCluster()) {} userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -19,16 +12,16 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( userver::server::request::RequestContext& context) const { const auto& slug = request.GetPathArg("slug"); const auto userId = context.GetData>("id"); - auto res = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - real_medium::sql::kGetArticleIdBySlug.data(), slug); + auto res = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + real_medium::sql::kGetArticleIdBySlug.data(), slug); if (res.IsEmpty()) { request.SetResponseStatus(userver::server::http::HttpStatus::kNotFound); return {}; } - res = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - real_medium::sql::kDeleteArticleBySlug.data(), slug, userId); + res = GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + real_medium::sql::kDeleteArticleBySlug.data(), slug, + userId); if (res.IsEmpty()) { request.SetResponseStatus(userver::server::http::HttpStatus::kForbidden); diff --git a/src/handlers/articles/articles_slug_delete.hpp b/src/handlers/articles/articles_slug_delete.hpp index 9424220..4f27f9a 100644 --- a/src/handlers/articles/articles_slug_delete.hpp +++ b/src/handlers/articles/articles_slug_delete.hpp @@ -3,32 +3,23 @@ #include #include -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - #include "userver/storages/postgres/cluster.hpp" #include "userver/storages/postgres/component.hpp" -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::articles_slug::del { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + +class Handler final : public Common { public: static constexpr std::string_view kName{"handler-delete-article"}; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, - userver::server::request::RequestContext& request_context) - const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& request_context) const override; }; } // namespace real_medium::handlers::articles_slug::del diff --git a/src/handlers/articles/articles_slug_get.cpp b/src/handlers/articles/articles_slug_get.cpp index 79ff2e8..19f9456 100644 --- a/src/handlers/articles/articles_slug_get.cpp +++ b/src/handlers/articles/articles_slug_get.cpp @@ -4,15 +4,6 @@ #include "../../models/article.hpp" namespace real_medium::handlers::articles_slug::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()), - cache_(component_context.FindComponent< - real_medium::cache::articles_cache::ArticlesCache>()) {} userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -21,7 +12,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( const auto& slug = request.GetPathArg("slug"); const std::optional userId = context.GetData>("id"); - auto data = cache_.Get(); + auto data = GetArticlesCache().Get(); auto article = data->findArticleBySlug(slug); if (article == nullptr) { request.SetResponseStatus(userver::server::http::HttpStatus::kNotFound); diff --git a/src/handlers/articles/articles_slug_get.hpp b/src/handlers/articles/articles_slug_get.hpp index 9f96c24..8024831 100644 --- a/src/handlers/articles/articles_slug_get.hpp +++ b/src/handlers/articles/articles_slug_get.hpp @@ -1,30 +1,21 @@ #pragma once -#include -#include -#include -#include -#include #include -#include -#include -#include "../../cache/articles_cache.hpp" + +#include "handlers/common.hpp" namespace real_medium::handlers::articles_slug::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + +class Handler final : public Common { public: static constexpr std::string_view kName{"handler-get-article"}; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; - const real_medium::cache::articles_cache::ArticlesCache& cache_; + userver::server::request::RequestContext& context) const override; }; + } // namespace real_medium::handlers::articles_slug::get diff --git a/src/handlers/articles/articles_slug_put.cpp b/src/handlers/articles/articles_slug_put.cpp index ae77267..c101808 100644 --- a/src/handlers/articles/articles_slug_put.cpp +++ b/src/handlers/articles/articles_slug_put.cpp @@ -8,13 +8,6 @@ #include "validators/validators.hpp" namespace real_medium::handlers::articles_slug::put { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) - : HttpHandlerJsonBase(config, context), - pg_cluster_(context - .FindComponent( - "realmedium-database") - .GetCluster()) {} userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -22,9 +15,9 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( userver::server::request::RequestContext& context) const { auto slug = request.GetPathArg("slug"); handlers::UpdateArticleRequest updateRequest = - request_json["article"].As(); + request_json["article"].As(); try { - validator::validate(updateRequest); + validator::validate(updateRequest); } catch (const real_medium::utils::error::ValidationException& ex) { request.SetResponseStatus( userver::server::http::HttpStatus::kUnprocessableEntity); @@ -39,11 +32,11 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( ? std::make_optional( real_medium::utils::slug::Slugify(*updateRequest.title)) : std::nullopt; - const auto res = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - real_medium::sql::kUpdateArticleBySlug.data(), slug, userId, - updateRequest.title, newSlug, updateRequest.description, - updateRequest.body); + const auto res = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + real_medium::sql::kUpdateArticleBySlug.data(), slug, + userId, updateRequest.title, newSlug, + updateRequest.description, updateRequest.body); if (res.IsEmpty()) { request.SetResponseStatus(userver::server::http::HttpStatus::kNotFound); return {}; @@ -58,7 +51,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( } throw; } - const auto res = pg_cluster_->Execute( + const auto res = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, real_medium::sql::kGetArticleWithAuthorProfile.data(), articleId, userId); diff --git a/src/handlers/articles/articles_slug_put.hpp b/src/handlers/articles/articles_slug_put.hpp index accb660..c2676d1 100644 --- a/src/handlers/articles/articles_slug_put.hpp +++ b/src/handlers/articles/articles_slug_put.hpp @@ -1,34 +1,22 @@ #pragma once -#include -#include +#include -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::articles_slug::put { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + +class Handler final : public Common { public: static constexpr std::string_view kName{"handler-update-article"}; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, userver::server::request::RequestContext& request_context) const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace real_medium::handlers::articles_slug::put diff --git a/src/handlers/articles/articles_unfavorite.cpp b/src/handlers/articles/articles_unfavorite.cpp index 57678b3..e7433a1 100644 --- a/src/handlers/articles/articles_unfavorite.cpp +++ b/src/handlers/articles/articles_unfavorite.cpp @@ -5,14 +5,6 @@ namespace real_medium::handlers::articles_favorite::del { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, @@ -21,9 +13,9 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( auto& slug = request.GetPathArg("slug"); auto transaction = - pg_cluster_->Begin("unfavorite_article_transaction", - userver::storages::postgres::ClusterHostType::kMaster, - userver::storages::postgres::Transaction::RW); + GetPg().Begin("unfavorite_article_transaction", + userver::storages::postgres::ClusterHostType::kMaster, + userver::storages::postgres::Transaction::RW); auto res = transaction.Execute(sql::kDeleteFavoritePair.data(), user_id, slug); @@ -35,7 +27,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( transaction.Commit(); } - const auto get_article_res = pg_cluster_->Execute( + const auto get_article_res = GetPg().Execute( userver::storages::postgres::ClusterHostType::kSlave, real_medium::sql::kGetArticleWithAuthorProfileBySlug.data(), slug, user_id); diff --git a/src/handlers/articles/articles_unfavorite.hpp b/src/handlers/articles/articles_unfavorite.hpp index a6e4872..000add7 100644 --- a/src/handlers/articles/articles_unfavorite.hpp +++ b/src/handlers/articles/articles_unfavorite.hpp @@ -1,28 +1,22 @@ #pragma once -#include "userver/components/component.hpp" -#include "userver/components/component_list.hpp" #include "userver/formats/json/serialize_container.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" #include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" + +#include "handlers/common.hpp" namespace real_medium::handlers::articles_favorite::del { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-articles-favorite-delete"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, userver::server::request::RequestContext& context) const override; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace real_medium::handlers::articles_favorite::del diff --git a/src/handlers/articles/feed_articles.cpp b/src/handlers/articles/feed_articles.cpp index 828b8f1..ca60f8e 100644 --- a/src/handlers/articles/feed_articles.cpp +++ b/src/handlers/articles/feed_articles.cpp @@ -1,7 +1,7 @@ #include "feed_articles.hpp" +#include #include #include -#include #include "db/sql.hpp" #include "dto/article.hpp" #include "dto/filter.hpp" @@ -10,16 +10,6 @@ namespace real_medium::handlers::articles::feed::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()), - cache_(component_context.FindComponent< - real_medium::cache::articles_cache::ArticlesCache>()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& /*request_json*/, @@ -35,7 +25,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( } auto user_id = context.GetData>("id"); - auto data = cache_.Get(); + auto data = GetArticlesCache().Get(); auto articles = data->getFeed(filter, user_id.value()); userver::formats::json::ValueBuilder builder; builder["articles"] = userver::formats::common::Type::kArray; diff --git a/src/handlers/articles/feed_articles.hpp b/src/handlers/articles/feed_articles.hpp index afe6ca3..77e9e64 100644 --- a/src/handlers/articles/feed_articles.hpp +++ b/src/handlers/articles/feed_articles.hpp @@ -1,36 +1,19 @@ - #pragma once -#include -#include - -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" +#include -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "../../cache/articles_cache.hpp" -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::articles::feed::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-feed-articles"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; - const real_medium::cache::articles_cache::ArticlesCache& cache_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::articles::feed::get diff --git a/src/handlers/auth/auth_bearer.cpp b/src/handlers/auth/auth_bearer.cpp index 749b784..75746bc 100644 --- a/src/handlers/auth/auth_bearer.cpp +++ b/src/handlers/auth/auth_bearer.cpp @@ -15,14 +15,9 @@ class AuthCheckerBearer final public: using AuthCheckResult = userver::server::handlers::auth::AuthCheckResult; - AuthCheckerBearer( - const userver::components::ComponentContext& component_context, - bool is_required) - : pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()), - is_required_(is_required) {} + AuthCheckerBearer(userver::storages::postgres::ClusterPtr pg_cluster, + bool is_required) + : pg_cluster_(std::move(pg_cluster)), is_required_(is_required) {} [[nodiscard]] AuthCheckResult CheckAuth( const userver::server::http::HttpRequest& request, @@ -32,7 +27,7 @@ class AuthCheckerBearer final private: userver::storages::postgres::ClusterPtr pg_cluster_; - bool is_required_; + const bool is_required_; }; AuthCheckerBearer::AuthCheckResult AuthCheckerBearer::CheckAuth( @@ -89,12 +84,19 @@ AuthCheckerBearer::AuthCheckResult AuthCheckerBearer::CheckAuth( return {}; } -userver::server::handlers::auth::AuthCheckerBasePtr CheckerFactory::operator()( - const userver::components::ComponentContext& context, - const userver::server::handlers::auth::HandlerAuthConfig& auth_config, - const userver::server::handlers::auth::AuthCheckerSettings&) const { +CheckerFactory::CheckerFactory( + const userver::components::ComponentContext& context) + : pg_cluster_(context + .FindComponent( + "realmedium-database") + .GetCluster()) {} + +userver::server::handlers::auth::AuthCheckerBasePtr +CheckerFactory::MakeAuthChecker( + const userver::server::handlers::auth::HandlerAuthConfig& auth_config) + const { auto is_required = auth_config["required"].As(false); - return std::make_shared(context, is_required); + return std::make_shared(pg_cluster_, is_required); } } // namespace real_medium::auth diff --git a/src/handlers/auth/auth_bearer.hpp b/src/handlers/auth/auth_bearer.hpp index d010628..6e63946 100644 --- a/src/handlers/auth/auth_bearer.hpp +++ b/src/handlers/auth/auth_bearer.hpp @@ -1,17 +1,22 @@ #pragma once #include +#include namespace real_medium::auth { class CheckerFactory final : public userver::server::handlers::auth::AuthCheckerFactoryBase { public: - userver::server::handlers::auth::AuthCheckerBasePtr operator()( - const userver::components::ComponentContext& context, - const userver::server::handlers::auth::HandlerAuthConfig& auth_config, - const userver::server::handlers::auth::AuthCheckerSettings&) - const override; + static constexpr std::string_view kAuthType = "bearer"; + + explicit CheckerFactory(const userver::components::ComponentContext& context); + + userver::server::handlers::auth::AuthCheckerBasePtr MakeAuthChecker( + const userver::server::handlers::auth::HandlerAuthConfig&) const override; + + private: + userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace real_medium::auth diff --git a/src/handlers/comments/comment_delete.cpp b/src/handlers/comments/comment_delete.cpp index 559f913..eab266e 100644 --- a/src/handlers/comments/comment_delete.cpp +++ b/src/handlers/comments/comment_delete.cpp @@ -1,29 +1,24 @@ - #include "comment_delete.hpp" + +#include + #include "db/sql.hpp" #include "utils/make_error.hpp" namespace real_medium::handlers::comments::del { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& /*request_json*/, userver::server::request::RequestContext& context) const { auto user_id = context.GetData>("id"); - const auto& comment_id = userver::utils::FromString(request.GetPathArg("id")); + const auto& comment_id = + userver::utils::FromString(request.GetPathArg("id")); const auto& slug = request.GetPathArg("slug"); - const auto result_find_comment = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kFindCommentByIdAndSlug.data(), comment_id, slug); + const auto result_find_comment = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kFindCommentByIdAndSlug.data(), comment_id, slug); if (result_find_comment.IsEmpty()) { auto& response = request.GetHttpResponse(); @@ -31,9 +26,9 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( return utils::error::MakeError("comment_id", "Invalid comment_id."); } - const auto result_delete_comment = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kDeleteCommentById.data(), comment_id, user_id); + const auto result_delete_comment = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kDeleteCommentById.data(), comment_id, user_id); if (result_delete_comment.IsEmpty()) { auto& response = request.GetHttpResponse(); diff --git a/src/handlers/comments/comment_delete.hpp b/src/handlers/comments/comment_delete.hpp index 08c0679..d7e57dc 100644 --- a/src/handlers/comments/comment_delete.hpp +++ b/src/handlers/comments/comment_delete.hpp @@ -1,38 +1,19 @@ - #pragma once -#include -#include -#include -#include - -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" - -#include "userver/formats/json/value.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::comments::del { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-comment-delete"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; + userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::comments::del diff --git a/src/handlers/comments/comment_post.cpp b/src/handlers/comments/comment_post.cpp index fa03b78..3a4e4a3 100644 --- a/src/handlers/comments/comment_post.cpp +++ b/src/handlers/comments/comment_post.cpp @@ -1,9 +1,9 @@ #include +#include #include "comment_post.hpp" #include "db/sql.hpp" #include "models/comment.hpp" -#include #include "utils/errors.hpp" #include "utils/make_error.hpp" @@ -11,14 +11,6 @@ namespace real_medium::handlers::comments::post { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, @@ -39,9 +31,9 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( const auto& comment_body = comment_json.body; const auto& slug = request.GetPathArg("slug"); - const auto res_find_article = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kFindIdArticleBySlug.data(), slug); + const auto res_find_article = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kFindIdArticleBySlug.data(), slug); if (res_find_article.IsEmpty()) { auto& response = request.GetHttpResponse(); @@ -51,7 +43,7 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( const auto article_id = res_find_article.AsSingleRow(); - const auto res_ins_new_comment = pg_cluster_->Execute( + const auto res_ins_new_comment = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, sql::kAddComment.data(), comment_body, user_id, article_id); diff --git a/src/handlers/comments/comment_post.hpp b/src/handlers/comments/comment_post.hpp index 233e798..27d6c0a 100644 --- a/src/handlers/comments/comment_post.hpp +++ b/src/handlers/comments/comment_post.hpp @@ -5,33 +5,20 @@ #include #include -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" - -#include "userver/formats/json/value.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::comments::post { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-comment-post"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; + userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::comments::post diff --git a/src/handlers/comments/comments_get.cpp b/src/handlers/comments/comments_get.cpp index a0d4014..4d416c2 100644 --- a/src/handlers/comments/comments_get.cpp +++ b/src/handlers/comments/comments_get.cpp @@ -1,6 +1,10 @@ - #include "comments_get.hpp" + +#include +#include #include +#include + #include "db/sql.hpp" #include "dto/comment.hpp" #include "utils/make_error.hpp" @@ -9,15 +13,9 @@ namespace real_medium::handlers::comments::get { Handler::Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()), - commentsCache_(component_context.FindComponent< - real_medium::cache::comments_cache::CommentsCache>()), - articlesCache_(component_context.FindComponent< - real_medium::cache::articles_cache::ArticlesCache>()) {} + : Common(config, component_context), + comments_cache_(component_context.FindComponent< + real_medium::cache::comments_cache::CommentsCache>()) {} userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -25,16 +23,16 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( userver::server::request::RequestContext& context) const { auto user_id = context.GetData>("id"); const auto& slug = request.GetPathArg("slug"); - const auto articlesData = articlesCache_.Get(); + const auto articles_data = GetArticlesCache().Get(); userver::formats::json::ValueBuilder result = userver::formats::json::MakeObject(); - if (!articlesData->findArticleBySlug(slug)) { + if (!articles_data->findArticleBySlug(slug)) { auto& response = request.GetHttpResponse(); response.SetStatus(userver::server::http::HttpStatus::kNotFound); return utils::error::MakeError("slug", "Invalid slug"); } - const auto commentsData = commentsCache_.Get(); - const auto res_find_comments = commentsData->findComments(slug); + const auto comments_data = comments_cache_.Get(); + const auto res_find_comments = comments_data->findComments(slug); userver::formats::json::ValueBuilder builder; builder["comments"] = userver::formats::common::Type::kArray; diff --git a/src/handlers/comments/comments_get.hpp b/src/handlers/comments/comments_get.hpp index bf95ced..2ba39a3 100644 --- a/src/handlers/comments/comments_get.hpp +++ b/src/handlers/comments/comments_get.hpp @@ -1,43 +1,24 @@ #pragma once -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include "cache/articles_cache.hpp" #include "cache/comments_cache.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::comments::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-comments-get"; Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& component_context); + userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; + userver::server::request::RequestContext& context) const override; private: - userver::storages::postgres::ClusterPtr pg_cluster_; - const real_medium::cache::comments_cache::CommentsCache& commentsCache_; - const real_medium::cache::articles_cache::ArticlesCache& articlesCache_; + const real_medium::cache::comments_cache::CommentsCache& comments_cache_; }; } // namespace real_medium::handlers::comments::get diff --git a/src/handlers/common.cpp b/src/handlers/common.cpp new file mode 100644 index 0000000..bf94239 --- /dev/null +++ b/src/handlers/common.cpp @@ -0,0 +1,19 @@ +#include "common.hpp" + +#include +#include +#include + +namespace real_medium::handlers { + +Common::Common(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& component_context) + : HttpHandlerJsonBase(config, component_context), + pg_cluster_(component_context + .FindComponent( + "realmedium-database") + .GetCluster()), + articles_cache_(component_context.FindComponent< + real_medium::cache::articles_cache::ArticlesCache>()) {} + +} // namespace real_medium::handlers diff --git a/src/handlers/common.hpp b/src/handlers/common.hpp new file mode 100644 index 0000000..1fa1a78 --- /dev/null +++ b/src/handlers/common.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include "cache/articles_cache.hpp" + +namespace real_medium::handlers { + +class Common : public userver::server::handlers::HttpHandlerJsonBase { + public: + Common(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& component_context); + + const real_medium::cache::articles_cache::ArticlesCache& GetArticlesCache() + const noexcept { + return articles_cache_; + } + + userver::storages::postgres::Cluster& GetPg() const noexcept { + UASSERT(pg_cluster_); + return *pg_cluster_; + } + + private: + userver::storages::postgres::ClusterPtr pg_cluster_; + const real_medium::cache::articles_cache::ArticlesCache& articles_cache_; +}; + +} // namespace real_medium::handlers diff --git a/src/handlers/profiles/profiles.cpp b/src/handlers/profiles/profiles.cpp index 618e23c..758c1a9 100644 --- a/src/handlers/profiles/profiles.cpp +++ b/src/handlers/profiles/profiles.cpp @@ -1,6 +1,6 @@ #include "profiles.hpp" -#include #include +#include #include "db/sql.hpp" #include "models/profile.hpp" #include "utils/make_error.hpp" @@ -17,22 +17,14 @@ using namespace userver::storages::postgres; namespace real_medium::handlers::profiles::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - json::Value Handler::HandleRequestJsonThrow(const HttpRequest& request, const json::Value&, RequestContext& context) const { auto user_id = context.GetData>("id"); const auto& username = request.GetPathArg("username"); auto res = - cluster_->Execute(ClusterHostType::kMaster, - sql::kGetProfileByUsername.data(), username, user_id); + GetPg().Execute(ClusterHostType::kMaster, + sql::kGetProfileByUsername.data(), username, user_id); if (res.IsEmpty()) { auto& response = request.GetHttpResponse(); response.SetStatus(userver::server::http::HttpStatus::kNotFound); @@ -40,8 +32,8 @@ json::Value Handler::HandleRequestJsonThrow(const HttpRequest& request, "There is no user with this nickname."); } - auto profile = res.AsSingleRow( - userver::storages::postgres::kRowTag); + auto profile = + res.AsSingleRow(userver::storages::postgres::kRowTag); userver::formats::json::ValueBuilder builder; builder["profile"] = profile; diff --git a/src/handlers/profiles/profiles.hpp b/src/handlers/profiles/profiles.hpp index d68fa61..49f3de5 100644 --- a/src/handlers/profiles/profiles.hpp +++ b/src/handlers/profiles/profiles.hpp @@ -1,32 +1,19 @@ #pragma once -#include -#include -#include - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" -#include "userver/storages/postgres/postgres_fwd.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::profiles::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-get-profile"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, userver::server::request::RequestContext& context) const override; - - private: - const userver::storages::postgres::ClusterPtr cluster_; }; } // namespace real_medium::handlers::profiles::get diff --git a/src/handlers/profiles/profiles_follow.cpp b/src/handlers/profiles/profiles_follow.cpp index 128a6bb..45c5ba8 100644 --- a/src/handlers/profiles/profiles_follow.cpp +++ b/src/handlers/profiles/profiles_follow.cpp @@ -1,8 +1,8 @@ #include -#include "profiles_follow.hpp" #include "db/sql.hpp" #include "models/profile.hpp" +#include "profiles_follow.hpp" #include "utils/make_error.hpp" #include "userver/formats/yaml/value_builder.hpp" @@ -17,61 +17,53 @@ using namespace userver::storages::postgres; namespace real_medium::handlers::profiles::post { - Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - - userver::formats::json::Value Handler::HandleRequestJsonThrow( - const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, - userver::server::request::RequestContext& context) const { - auto user_id = context.GetData>("id"); - const auto& username = request.GetPathArg("username"); - if (username.empty()) { - auto& response = request.GetHttpResponse(); - response.SetStatus(userver::server::http::HttpStatus::kNotFound); - return utils::error::MakeError("username", "It is null."); - } +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext& context) const { + auto user_id = context.GetData>("id"); + const auto& username = request.GetPathArg("username"); + if (username.empty()) { + auto& response = request.GetHttpResponse(); + response.SetStatus(userver::server::http::HttpStatus::kNotFound); + return utils::error::MakeError("username", "It is null."); + } - const auto res_find_id_username = - pg_cluster_->Execute(userver::storages::postgres::ClusterHostType::kSlave, - sql::kFindUserIDByUsername.data(), username); - if (res_find_id_username.IsEmpty()) { - auto& response = request.GetHttpResponse(); - response.SetStatus(userver::server::http::HttpStatus::kNotFound); - return utils::error::MakeError("username", - "There is no user with this nickname."); - } + const auto res_find_id_username = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kSlave, + sql::kFindUserIDByUsername.data(), username); + if (res_find_id_username.IsEmpty()) { + auto& response = request.GetHttpResponse(); + response.SetStatus(userver::server::http::HttpStatus::kNotFound); + return utils::error::MakeError("username", + "There is no user with this nickname."); + } - std::string username_id = res_find_id_username.AsSingleRow(); + std::string username_id = res_find_id_username.AsSingleRow(); - if (username_id == user_id) { - auto& response = request.GetHttpResponse(); - response.SetStatus(userver::server::http::HttpStatus::kBadRequest); - return utils::error::MakeError("username", - "Username is author of the request."); - } + if (username_id == user_id) { + auto& response = request.GetHttpResponse(); + response.SetStatus(userver::server::http::HttpStatus::kBadRequest); + return utils::error::MakeError("username", + "Username is author of the request."); + } - const auto res_following = - pg_cluster_->Execute(userver::storages::postgres::ClusterHostType::kSlave, - sql::KFollowingUser.data(), username_id, user_id); + const auto res_following = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kSlave, + sql::KFollowingUser.data(), username_id, user_id); - const auto profile = res_following.AsSingleRow( - userver::storages::postgres::kRowTag); + const auto profile = res_following.AsSingleRow( + userver::storages::postgres::kRowTag); - if (!profile.following) { - auto& response = request.GetHttpResponse(); - response.SetStatus(userver::server::http::HttpStatus::kBadRequest); - return utils::error::MakeError("user_id", "has already followed"); - } + if (!profile.following) { + auto& response = request.GetHttpResponse(); + response.SetStatus(userver::server::http::HttpStatus::kBadRequest); + return utils::error::MakeError("user_id", "has already followed"); + } - userver::formats::json::ValueBuilder builder; - builder["profile"] = profile; + userver::formats::json::ValueBuilder builder; + builder["profile"] = profile; - return builder.ExtractValue(); - } -} // namespace real_medium::handlers::profiles::post \ No newline at end of file + return builder.ExtractValue(); +} +} // namespace real_medium::handlers::profiles::post diff --git a/src/handlers/profiles/profiles_follow.hpp b/src/handlers/profiles/profiles_follow.hpp index 0efc001..2dbd614 100644 --- a/src/handlers/profiles/profiles_follow.hpp +++ b/src/handlers/profiles/profiles_follow.hpp @@ -1,28 +1,19 @@ #pragma once -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" -#include "userver/storages/postgres/postgres_fwd.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::profiles::post { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-profile-follow"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, - userver::server::request::RequestContext& context) const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::profiles::post diff --git a/src/handlers/profiles/profiles_follow_delete.cpp b/src/handlers/profiles/profiles_follow_delete.cpp index 40dec85..75d9a2c 100644 --- a/src/handlers/profiles/profiles_follow_delete.cpp +++ b/src/handlers/profiles/profiles_follow_delete.cpp @@ -1,8 +1,8 @@ #include -#include "profiles_follow_delete.hpp" #include "db/sql.hpp" #include "models/profile.hpp" +#include "profiles_follow_delete.hpp" #include "userver/formats/yaml/value_builder.hpp" #include "userver/server/handlers/http_handler_base.hpp" #include "userver/storages/postgres/cluster.hpp" @@ -16,14 +16,6 @@ using namespace userver::storages::postgres; namespace real_medium::handlers::profiles::del { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, @@ -37,8 +29,8 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( } const auto res_find_id_username = - pg_cluster_->Execute(userver::storages::postgres::ClusterHostType::kSlave, - sql::kFindUserIDByUsername.data(), username); + GetPg().Execute(userver::storages::postgres::ClusterHostType::kSlave, + sql::kFindUserIDByUsername.data(), username); if (res_find_id_username.IsEmpty()) { auto& response = request.GetHttpResponse(); response.SetStatus(userver::server::http::HttpStatus::kNotFound); @@ -55,12 +47,11 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( } const auto res_unfollowing = - pg_cluster_->Execute(userver::storages::postgres::ClusterHostType::kSlave, - sql::KUnFollowingUser.data(), username_id, user_id); + GetPg().Execute(userver::storages::postgres::ClusterHostType::kSlave, + sql::KUnFollowingUser.data(), username_id, user_id); - const auto profile = - res_unfollowing.AsSingleRow( - userver::storages::postgres::kRowTag); + const auto profile = res_unfollowing.AsSingleRow( + userver::storages::postgres::kRowTag); if (profile.following) { auto& response = request.GetHttpResponse(); diff --git a/src/handlers/profiles/profiles_follow_delete.hpp b/src/handlers/profiles/profiles_follow_delete.hpp index a185a50..3536b78 100644 --- a/src/handlers/profiles/profiles_follow_delete.hpp +++ b/src/handlers/profiles/profiles_follow_delete.hpp @@ -1,28 +1,19 @@ #pragma once -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" -#include "userver/storages/postgres/postgres_fwd.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::profiles::del { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-profile-unfollow"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value&, - userver::server::request::RequestContext& context) const override final; - - private: - const userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::profiles::del diff --git a/src/handlers/tags/tags.cpp b/src/handlers/tags/tags.cpp index af07cc2..3242680 100644 --- a/src/handlers/tags/tags.cpp +++ b/src/handlers/tags/tags.cpp @@ -1,26 +1,19 @@ #include "tags.hpp" #include "userver/components/component.hpp" +#include "userver/formats/json/serialize_container.hpp" #include "userver/server/handlers/http_handler_json_base.hpp" #include "userver/storages/postgres/cluster.hpp" #include "userver/storages/postgres/component.hpp" namespace real_medium::handlers::tags::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest&, const userver::formats::json::Value&, userver::server::request::RequestContext&) const { constexpr static auto query = "SELECT tag_name FROM real_medium.tag_list"; - auto result = pg_cluster_->Execute( + auto result = GetPg().Execute( userver::storages::postgres::ClusterHostType::kSlave, query); auto tags = result.AsSetOf(); diff --git a/src/handlers/tags/tags.hpp b/src/handlers/tags/tags.hpp index d0cef39..b467983 100644 --- a/src/handlers/tags/tags.hpp +++ b/src/handlers/tags/tags.hpp @@ -1,28 +1,19 @@ #pragma once -#include "userver/components/component.hpp" -#include "userver/components/component_list.hpp" -#include "userver/formats/json/serialize_container.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::tags::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-get-tags"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest&, const userver::formats::json::Value&, userver::server::request::RequestContext&) const override; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace real_medium::handlers::tags::get diff --git a/src/handlers/users/user_get.cpp b/src/handlers/users/user_get.cpp index 7fb8abb..30ec3ba 100644 --- a/src/handlers/users/user_get.cpp +++ b/src/handlers/users/user_get.cpp @@ -5,23 +5,15 @@ namespace real_medium::handlers::users::get { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value& request_json, + const userver::formats::json::Value& /*request_json*/, userver::server::request::RequestContext& context) const { auto user_id = context.GetData>("id"); - const auto result = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kFindUserById.data(), user_id); + const auto result = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kFindUserById.data(), user_id); if (result.IsEmpty()) { auto& response = request.GetHttpResponse(); diff --git a/src/handlers/users/user_get.hpp b/src/handlers/users/user_get.hpp index 85143a1..3259a67 100644 --- a/src/handlers/users/user_get.hpp +++ b/src/handlers/users/user_get.hpp @@ -1,36 +1,21 @@ - #pragma once -#include -#include - -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" +#include -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" - -#include "userver/formats/json/value.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::users::get { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-user-get"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; + userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::users::get diff --git a/src/handlers/users/user_put.cpp b/src/handlers/users/user_put.cpp index 4ed6e4a..d9b5915 100644 --- a/src/handlers/users/user_put.cpp +++ b/src/handlers/users/user_put.cpp @@ -1,20 +1,13 @@ #include "user_put.hpp" -#include #include +#include #include "db/sql.hpp" #include "models/user.hpp" #include "utils/errors.hpp" #include "utils/random.hpp" #include "validators/validators.hpp" -namespace real_medium::handlers::users::put { -Handler::Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} +namespace real_medium::handlers::users::put { userver::formats::json::Value Handler::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -37,11 +30,11 @@ userver::formats::json::Value Handler::HandleRequestJsonThrow( std::optional salt = std::nullopt; if (user_change_data.password) { salt = utils::random::GenerateSalt(); - password_hash = - userver::crypto::hash::Sha256(user_change_data.password.value() + salt.value()); + password_hash = userver::crypto::hash::Sha256( + user_change_data.password.value() + salt.value()); } - const auto result = pg_cluster_->Execute( + const auto result = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, sql::kUpdateUser.data(), user_id, user_change_data.username, user_change_data.email, user_change_data.bio, user_change_data.image, diff --git a/src/handlers/users/user_put.hpp b/src/handlers/users/user_put.hpp index 6866862..cd17782 100644 --- a/src/handlers/users/user_put.hpp +++ b/src/handlers/users/user_put.hpp @@ -1,39 +1,19 @@ - #pragma once -#include -#include -#include - -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" - -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" - -#include -#include +#include "handlers/common.hpp" namespace real_medium::handlers::users::put { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public Common { public: static constexpr std::string_view kName = "handler-user-put"; - Handler(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::users::put diff --git a/src/handlers/users/users.cpp b/src/handlers/users/users.cpp index f13dc60..8e5ed3d 100644 --- a/src/handlers/users/users.cpp +++ b/src/handlers/users/users.cpp @@ -2,8 +2,8 @@ #include "users.hpp" -#include #include +#include #include "db/sql.hpp" #include "models/user.hpp" @@ -14,19 +14,10 @@ namespace real_medium::handlers::users::post { -RegisterUser::RegisterUser( - const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} - userver::formats::json::Value RegisterUser::HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const { + userver::server::request::RequestContext&) const { handlers::UserRegistrationDTO user_register = request_json["user"].As(); ; @@ -44,11 +35,10 @@ userver::formats::json::Value RegisterUser::HandleRequestJsonThrow( userver::crypto::hash::Sha256(user_register.password.value() + salt); models::User result_user; try { - auto query_result = pg_cluster_->Execute( + auto query_result = GetPg().Execute( userver::storages::postgres::ClusterHostType::kMaster, sql::kInsertUser.data(), user_register.username, user_register.email, - user_register.bio, user_register.image, - hash_password, salt); + user_register.bio, user_register.image, hash_password, salt); result_user = query_result.AsSingleRow( userver::storages::postgres::kRowTag); } catch (const userver::storages::postgres::UniqueViolation& ex) { diff --git a/src/handlers/users/users.hpp b/src/handlers/users/users.hpp index 8608f9a..9720669 100644 --- a/src/handlers/users/users.hpp +++ b/src/handlers/users/users.hpp @@ -1,35 +1,19 @@ - #pragma once -#include -#include - -#include "userver/formats/json/value.hpp" -#include "userver/server/handlers/http_handler_base.hpp" -#include "userver/server/handlers/http_handler_json_base.hpp" +#include -#include "userver/storages/postgres/cluster.hpp" -#include "userver/storages/postgres/component.hpp" - -#include "userver/components/component_config.hpp" -#include "userver/components/component_context.hpp" +#include "handlers/common.hpp" namespace real_medium::handlers::users::post { -class RegisterUser final - : public userver::server::handlers::HttpHandlerJsonBase { +class RegisterUser final : public Common { public: static constexpr std::string_view kName = "handler-register-user"; - RegisterUser(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context); + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, const userver::formats::json::Value& request_json, - userver::server::request::RequestContext& context) const override final; - using HttpHandlerJsonBase::HttpHandlerJsonBase; - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; + userver::server::request::RequestContext& context) const override; }; } // namespace real_medium::handlers::users::post diff --git a/src/handlers/users/users_login.cpp b/src/handlers/users/users_login.cpp index 05c5c69..5766ff0 100644 --- a/src/handlers/users/users_login.cpp +++ b/src/handlers/users/users_login.cpp @@ -1,15 +1,13 @@ #include "users_login.hpp" -#include -#include +#include #include -#include #include #include #include -#include #include "db/sql.hpp" +#include "handlers/common.hpp" #include "models/user.hpp" #include "utils/errors.hpp" #include "validators/validators.hpp" @@ -18,17 +16,11 @@ namespace real_medium::handlers::users_login::post { namespace { -class LoginUser final : public userver::server::handlers::HttpHandlerJsonBase { +class LoginUser final : public Common { public: static constexpr std::string_view kName = "handler-login-user"; - LoginUser(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& component_context) - : HttpHandlerJsonBase(config, component_context), - pg_cluster_(component_context - .FindComponent( - "realmedium-database") - .GetCluster()) {} + using Common::Common; userver::formats::json::Value HandleRequestJsonThrow( const userver::server::http::HttpRequest& request, @@ -45,22 +37,21 @@ class LoginUser final : public userver::server::handlers::HttpHandlerJsonBase { return err.GetDetails(); } - auto salt = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kGetSaltByEmail.data(), - user_login.email); + auto salt = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kGetSaltByEmail.data(), user_login.email); if (salt.IsEmpty()) { auto& response = request.GetHttpResponse(); response.SetStatus(userver::server::http::HttpStatus::kNotFound); return {}; } - auto password_hash = - userver::crypto::hash::Sha256(user_login.password.value() + salt.AsSingleRow()); + auto password_hash = userver::crypto::hash::Sha256( + user_login.password.value() + salt.AsSingleRow()); - auto userResult = pg_cluster_->Execute( - userver::storages::postgres::ClusterHostType::kMaster, - sql::kSelectUserByEmailAndPassword.data(), user_login.email, - password_hash); + auto userResult = + GetPg().Execute(userver::storages::postgres::ClusterHostType::kMaster, + sql::kSelectUserByEmailAndPassword.data(), + user_login.email, password_hash); if (userResult.IsEmpty()) { auto& response = request.GetHttpResponse(); @@ -76,9 +67,6 @@ class LoginUser final : public userver::server::handlers::HttpHandlerJsonBase { return response.ExtractValue(); } - - private: - userver::storages::postgres::ClusterPtr pg_cluster_; }; } // namespace diff --git a/src/main.cpp b/src/main.cpp index 2c29180..fb2901c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,8 +38,8 @@ using namespace real_medium::handlers; int main(int argc, char* argv[]) { - userver::server::handlers::auth::RegisterAuthCheckerFactory( - "bearer", std::make_unique()); + userver::server::handlers::auth::RegisterAuthCheckerFactory< + real_medium::auth::CheckerFactory>(); auto component_list = userver::components::MinimalServerComponentList() diff --git a/src/models/article.hpp b/src/models/article.hpp index 0032562..6cf40c5 100644 --- a/src/models/article.hpp +++ b/src/models/article.hpp @@ -7,7 +7,6 @@ #include #include #include -#include "../db/types.hpp" #include "profile.hpp" #include "user.hpp" @@ -47,7 +46,7 @@ struct TaggedArticleWithProfile { std::optional> tags; bool isFavorited; std::int64_t favoritesCount; - Profile authorProfile; + handlers::Profile authorProfile; auto Introspect() { return std::tie(articleId, title, slug, body, description, createdAt, @@ -67,13 +66,12 @@ namespace userver::storages::postgres::io { template <> struct CppToUserPg { static constexpr DBTypeName postgres_name{ - real_medium::sql::types::kTaggedArticleWithProfile.data()}; + "real_medium.tagged_article_with_author_profile"}; }; template <> struct CppToUserPg { - static constexpr DBTypeName postgres_name{ - real_medium::sql::types::kFullArticleInfo.data()}; + static constexpr DBTypeName postgres_name{"real_medium.full_article_info"}; }; } // namespace userver::storages::postgres::io diff --git a/src/models/comment.hpp b/src/models/comment.hpp index 15e3566..9276b77 100644 --- a/src/models/comment.hpp +++ b/src/models/comment.hpp @@ -20,7 +20,7 @@ struct Comment { userver::storages::postgres::TimePointTz updated_at; std::string body; std::string user_id; - real_medium::models::Profile author; + real_medium::handlers::Profile author; auto Introspect() { return std::tie(id, created_at, updated_at, body, user_id, author); @@ -53,8 +53,7 @@ namespace userver::storages::postgres::io { template <> struct CppToUserPg { - static constexpr DBTypeName postgres_name{ - real_medium::sql::types::kComment.data()}; + static constexpr DBTypeName postgres_name{"real_medium.comment"}; }; } // namespace userver::storages::postgres::io diff --git a/src/models/profile.cpp b/src/models/profile.cpp deleted file mode 100644 index 2d40557..0000000 --- a/src/models/profile.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "profile.hpp" -#include - -namespace real_medium::models { - -userver::formats::json::Value Serialize( - const Profile& profile, - userver::formats::serialize::To) { - userver::formats::json::ValueBuilder item; - - item["username"] = profile.username; - item["bio"] = profile.bio; - item["image"] = profile.image; - item["following"] = profile.following; - - return item.ExtractValue(); -} - -} // namespace real_medium::models diff --git a/src/models/profile.hpp b/src/models/profile.hpp index 14caf62..ecbf734 100644 --- a/src/models/profile.hpp +++ b/src/models/profile.hpp @@ -1,35 +1,15 @@ #pragma once -#include -#include -#include -#include #include #include -#include "db/types.hpp" -namespace real_medium::models { - -struct Profile final { - std::string username; - std::string bio; - std::string image; - bool following{false}; - auto Introspect() { return std::tie(username, bio, image, following); } -}; - -userver::formats::json::Value Serialize( - const Profile& profile, - userver::formats::serialize::To); - -} // namespace real_medium::models +#include namespace userver::storages::postgres::io { template <> -struct CppToUserPg { - static constexpr DBTypeName postgres_name{ - real_medium::sql::types::kProfile.data()}; +struct CppToUserPg { + static constexpr DBTypeName postgres_name{"real_medium.profile"}; }; } // namespace userver::storages::postgres::io diff --git a/src/models/user.hpp b/src/models/user.hpp index 7f87338..9afae81 100644 --- a/src/models/user.hpp +++ b/src/models/user.hpp @@ -7,7 +7,6 @@ #include #include #include -#include "db/types.hpp" namespace real_medium::models { @@ -36,8 +35,7 @@ namespace userver::storages::postgres::io { template <> struct CppToUserPg { - static constexpr DBTypeName postgres_name{ - real_medium::sql::types::kUser.data()}; + static constexpr DBTypeName postgres_name{"real_medium.user"}; }; } // namespace userver::storages::postgres::io diff --git a/src/validators/validators.cpp b/src/validators/validators.cpp index c3d32f2..1369edd 100644 --- a/src/validators/validators.cpp +++ b/src/validators/validators.cpp @@ -3,7 +3,6 @@ #include "user_validators.hpp" #include "utils/errors.hpp" - namespace real_medium::validator { void validate(const handlers::UserLoginDTO& dto) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index 0cbb204..0000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -set(CONFIG_VARS_PATH "${CMAKE_SOURCE_DIR}/configs/config_vars_testing.yaml") -if (EXISTS "${CONFIG_VARS_PATH}") - set(PYTEST_ARGS_CONFIG_VARS "--service-config-vars=${CONFIG_VARS_PATH}") -else() - set(PYTEST_ARGS_CONFIG_VARS "") -endif() - -userver_testsuite_add( - SERVICE_TARGET realmedium_sample - REQUIREMENTS ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - PYTEST_ARGS - --service-config=${CMAKE_SOURCE_DIR}/configs/static_config.yaml - --service-binary=${CMAKE_BINARY_DIR}/realmedium_sample - ${PYTEST_ARGS_CONFIG_VARS} -) diff --git a/tests/articles/test_delete_article.py b/tests/articles/test_delete_article.py index 737d448..371af00 100644 --- a/tests/articles/test_delete_article.py +++ b/tests/articles/test_delete_article.py @@ -66,14 +66,14 @@ async def test_delete_article(service_client): response = await delete_article(service_client, article, user_token) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, user_token) assert response.status == HTTPStatus.NOT_FOUND response = await create_article(service_client, article, user_token) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_comments(CommentList(0), response) diff --git a/tests/articles/test_favourite_article.py b/tests/articles/test_favourite_article.py index bdf19ab..c83b1ba 100644 --- a/tests/articles/test_favourite_article.py +++ b/tests/articles/test_favourite_article.py @@ -64,7 +64,7 @@ async def test_favourite_article(service_client): article.favorited = True assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, another_user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) @@ -101,7 +101,7 @@ async def test_self_favorite_article(service_client): assert response.status == HTTPStatus.OK assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) @@ -132,7 +132,7 @@ async def test_multiple_favorite_article(service_client): article.favoritesCount += 1 assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() for token in tokens: response = await get_article(service_client, article, token) assert response.status == HTTPStatus.OK diff --git a/tests/articles/test_feed_articles.py b/tests/articles/test_feed_articles.py index 5d639ae..bb0bbc1 100644 --- a/tests/articles/test_feed_articles.py +++ b/tests/articles/test_feed_articles.py @@ -35,7 +35,7 @@ async def test_feed_articles(service_client): response = await create_article(service_client, article, user_token) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await feed_articles(service_client, another_user_token, 2, 0) assert response.status == HTTPStatus.OK assert validate_articles(ArticleList(0), response) @@ -47,7 +47,7 @@ async def test_feed_articles(service_client): feed_articles_result = ArticleList( init_articles=article_lst.articles[:-3:-1], ) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await feed_articles(service_client, another_user_token, 2, 0) assert response.status == HTTPStatus.OK assert validate_articles(feed_articles_result, response) diff --git a/tests/articles/test_get_article.py b/tests/articles/test_get_article.py index a183995..2dbcf63 100644 --- a/tests/articles/test_get_article.py +++ b/tests/articles/test_get_article.py @@ -22,7 +22,7 @@ async def test_get_article(service_client): response = await create_article(service_client, article, user_token) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) @@ -37,7 +37,7 @@ async def test_get_unknown_article(service_client): user_token = get_user_token(response) article = Article(Profile(user)) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, user_token) assert response.status == HTTPStatus.NOT_FOUND @@ -54,7 +54,7 @@ async def test_get_article_unauthorized(service_client): response = await create_article(service_client, article, user_token) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, None) assert response.status == HTTPStatus.OK assert validate_article(article, response) diff --git a/tests/articles/test_list_articles.py b/tests/articles/test_list_articles.py index 560f268..4d1f400 100644 --- a/tests/articles/test_list_articles.py +++ b/tests/articles/test_list_articles.py @@ -52,7 +52,7 @@ async def test_list_articles_unauthorized(service_client): article.favoritesCount = 1 assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await list_articles( service_client, None, @@ -109,7 +109,7 @@ async def test_list_articles(service_client): assert response.status == HTTPStatus.OK author_profile.following = True - await service_client.invalidate_caches() + await service_client.update_server_state() response = await list_articles( service_client, user_token, diff --git a/tests/articles/test_unfavourite_article.py b/tests/articles/test_unfavourite_article.py index 8b7176b..2287ebd 100644 --- a/tests/articles/test_unfavourite_article.py +++ b/tests/articles/test_unfavourite_article.py @@ -68,7 +68,7 @@ async def test_unfavourite_article(service_client): assert response.status == HTTPStatus.OK assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, another_user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) @@ -79,7 +79,7 @@ async def test_unfavourite_article(service_client): assert response.status == HTTPStatus.OK assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, another_user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) @@ -88,7 +88,7 @@ async def test_unfavourite_article(service_client): assert response.status == HTTPStatus.OK assert validate_article(article, response) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_article(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_article(article, response) diff --git a/tests/comments/test_delete_comment.py b/tests/comments/test_delete_comment.py index 677cb6e..f7430bc 100644 --- a/tests/comments/test_delete_comment.py +++ b/tests/comments/test_delete_comment.py @@ -33,7 +33,7 @@ async def test_delete_self_comment(service_client): assert response.status == HTTPStatus.OK commentList = CommentList(0) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_comments(commentList, response) @@ -66,9 +66,9 @@ async def test_delete_not_self_comment(service_client): response = await delete_comment(service_client, 1, article, user_token) assert response.status == HTTPStatus.FORBIDDEN - await service_client.invalidate_caches() + await service_client.update_server_state() commentList = CommentList(init_comments=[comment]) - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_comments(commentList, response) diff --git a/tests/comments/test_get_comments.py b/tests/comments/test_get_comments.py index 63161c4..3d62689 100644 --- a/tests/comments/test_get_comments.py +++ b/tests/comments/test_get_comments.py @@ -42,7 +42,7 @@ async def test_get_comments_authorized(service_client): ) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, user_token) assert response.status == HTTPStatus.OK assert validate_comments(commentList, response) @@ -74,7 +74,7 @@ async def test_get_comments_unknown_article(service_client): assert response.status == HTTPStatus.OK article.slug = 'some_slug' - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, user_token) assert response.status == HTTPStatus.NOT_FOUND @@ -105,7 +105,7 @@ async def test_get_comments_unauthorized(service_client): ) assert response.status == HTTPStatus.OK - await service_client.invalidate_caches() + await service_client.update_server_state() response = await get_comments(service_client, article, None) assert response.status == HTTPStatus.OK assert validate_comments(commentList, response) diff --git a/tests/conftest.py b/tests/conftest.py index 2146303..952dafc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,4 @@ import os -import pathlib import sys import pytest @@ -9,24 +8,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers')) -pytest_plugins = [ - 'pytest_userver.plugins.core', - 'pytest_userver.plugins.postgresql', -] - - -@pytest.fixture(scope='session') -def service_source_dir(): - """Path to root directory service.""" - return pathlib.Path(__file__).parent.parent - - -@pytest.fixture(scope='session') -def initial_data_path(service_source_dir): - """Path for find files with data""" - return [ - service_source_dir / 'postgresql/data', - ] +pytest_plugins = ['pytest_userver.plugins.postgresql'] @pytest.fixture(scope='session') diff --git a/tests/helpers/endpoints.py b/tests/helpers/endpoints.py index 722693d..72e95cb 100644 --- a/tests/helpers/endpoints.py +++ b/tests/helpers/endpoints.py @@ -39,21 +39,25 @@ async def get_profile(service_client, user, token): async def follow_user(service_client, user, token): - return await service_client.post( + result = await service_client.post( Routes.FOLLOW_PROFILE.format(username=user.username), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['articles-cache']) + return result async def unfollow_user(service_client, user, token): - return await service_client.delete( + result = await service_client.delete( Routes.UNFOLLOW_PROFILE.format(username=user.username), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['articles-cache']) + return result async def create_article(service_client, article, token): - return await service_client.post( + result = await service_client.post( Routes.CREATE_ARTICLE, json=model_dump( article, @@ -62,6 +66,11 @@ async def create_article(service_client, article, token): ), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=[ + 'articles-cache', + 'comments-cache', + ]) + return result async def get_article(service_client, article, token): @@ -84,32 +93,40 @@ async def update_article(service_client, article, slug, token): async def delete_article(service_client, article, token): - return await service_client.delete( + result = await service_client.delete( Routes.UPDATE_ARTICLE.format(slug=article.slug), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['articles-cache']) + return result async def favourite_article(service_client, article, token): - return await service_client.post( + result = await service_client.post( Routes.FAVOURITE_ARTICLE.format(slug=article.slug), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['articles-cache']) + return result async def unfavourite_article(service_client, article, token): - return await service_client.delete( + result = await service_client.delete( Routes.UNFAVOURITE_ARTICLE.format(slug=article.slug), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['articles-cache']) + return result async def add_comment(service_client, comment, article, token): - return await service_client.post( + result = await service_client.post( Routes.ADD_COMMENT.format(slug=article.slug), json=model_dump(comment, include=RequiredFields.ADD_COMMENT.value), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['comments-cache']) + return result async def get_comments(service_client, article, token): @@ -120,10 +137,12 @@ async def get_comments(service_client, article, token): async def delete_comment(service_client, comment_id, article, token): - return await service_client.delete( + result = await service_client.delete( Routes.DELETE_COMMENT.format(slug=article.slug, id=comment_id), headers={'Authorization': token}, ) + await service_client.invalidate_caches(cache_names=['comments-cache']) + return result async def feed_articles(service_client, token, limit, offset): diff --git a/third_party/userver b/third_party/userver deleted file mode 160000 index b13acb8..0000000 --- a/third_party/userver +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b13acb8f2468fcfef8b3fce00959b111d5e440ab