From 458524fa9a439885ff6ac63b7fc5893c4a0620a0 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 16:16:06 +0300 Subject: [PATCH 01/13] check no pipline --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 2159626..515ff57 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,6 @@ class Command : public TgBot::BotCommand { }; int main() { - std::cerr << std::getenv("TOKEN") << std::endl; TgBot::Bot bot(std::getenv("TOKEN")); bool is_alive = true; From da34ce9e2bc63ec732911833f3ea1b392f12b378 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 17:49:42 +0300 Subject: [PATCH 02/13] anti ddos --- .github/workflows/docker-image.yml | 2 -- Dockerfile | 27 +++++++++--------- src/main.cpp | 44 ++++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 4f843ab..406887d 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,8 +3,6 @@ name: Docker Image CI on: push: branches: [ "master" ] - pull_request: - branches: [ "master" ] jobs: diff --git a/Dockerfile b/Dockerfile index 4335a5a..eea6a88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +#building bot FROM gcc:latest as build RUN apt-get update && \ @@ -5,8 +6,10 @@ RUN apt-get update && \ libboost-dev libboost-system-dev \ cmake + RUN apt-get install g++ make binutils libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev +#installing tgbot lib RUN git clone https://github.com/reo7sp/tgbot-cpp RUN cmake ./tgbot-cpp RUN cd tgbot-cpp @@ -14,14 +17,9 @@ RUN make -j4 RUN make install RUN cd .. -RUN apt-get install -y libpq-dev libpqxx-dev -# RUN git clone https://github.com/jtv/libpqxx.git -# RUN cd libpqxx && \ -# ./configure --disable-shared && \ -# make && \ -# make install && \ -# cd .. +#installing libpqxx +RUN apt-get install -y libpq-dev libpqxx-dev RUN git clone https://github.com/jtv/libpqxx.git \ --branch 6.4 --depth 1 \ @@ -35,19 +33,17 @@ RUN git clone https://github.com/jtv/libpqxx.git \ -DCMAKE_MODULE_PATH=/usr/src/libpqxx-r6.4/cmake .. \ && make && make install && ldconfig /usr/local/lib - -RUN ls /usr/local/lib/ - +#building sources ADD ./src /app/src WORKDIR /app/build RUN cmake ../src && \ cmake --build . - +#run configuration FROM ubuntu:latest - +#installing base dependencies RUN apt-get -y update && \ apt-get install -y software-properties-common && \ apt-get -y update @@ -66,6 +62,7 @@ RUN apt-get update && \ apt-get upgrade -y && \ apt-get install -y git make cmake g++ +#installing libpqxx RUN apt-get install -y libpq-dev libpqxx-dev @@ -83,11 +80,15 @@ RUN git clone https://github.com/jtv/libpqxx.git \ RUN find / -name libpq.so.5 +#changing rights RUN groupadd -r sample && useradd -r -g sample sample USER sample -WORKDIR /app +#installing postgresql +# RUN apt-get -y install postgresql +#runnhing +WORKDIR /app COPY --from=build /app/build/database . ENTRYPOINT ["./database"] diff --git a/src/main.cpp b/src/main.cpp index 515ff57..4247449 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,13 @@ #include #include #include +#include #include "ddl.h" #include "util.h" +const size_t kMaxQueries = 50; + class Command : public TgBot::BotCommand { public: Command(std::initializer_list args) { @@ -16,6 +19,15 @@ class Command : public TgBot::BotCommand { } }; +bool HandleUser(size_t id, std::unordered_map& users) { + if (users.contains(id)) { + ++users[id]; + } else { + users[id] = 0; + } + return users[id] > kMaxQueries; +} + int main() { TgBot::Bot bot(std::getenv("TOKEN")); bool is_alive = true; @@ -26,7 +38,12 @@ int main() { {"kill", "Kills bot if you have permission"}, {"help", "Commands info"}}; - bot.getEvents().onAnyMessage([&bot, &bot_commands](TgBot::Message::Ptr message) { + std::unordered_map users; + + bot.getEvents().onAnyMessage([&bot, &bot_commands, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } std::cerr << GetCurrentTime() << std::format(" | {} wrote {}\n", message->from->username, message->text); for (const auto& command : bot_commands) { @@ -37,7 +54,10 @@ int main() { bot.getApi().sendMessage(message->chat->id, "Unknown command: " + message->text); }); - bot.getEvents().onCommand("start", [&bot](TgBot::Message::Ptr message) { + bot.getEvents().onCommand("start", [&bot, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } if (IsAdmin(message->from->username)) { bot.getApi().sendMessage(message->chat->id, std::format("Hello master {}!", message->from->username)); @@ -46,7 +66,10 @@ int main() { bot.getApi().sendMessage(message->chat->id, "Hello!"); } }); - bot.getEvents().onCommand("kill", [&bot, &is_alive](TgBot::Message::Ptr message) { + bot.getEvents().onCommand("kill", [&bot, &is_alive, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } if (IsAdmin(message->from->username)) { bot.getApi().sendMessage(message->chat->id, "Change the world my final message. Goodbye......."); @@ -56,7 +79,11 @@ int main() { bot.getApi().sendMessage(message->chat->id, "Permission denied"); } }); - bot.getEvents().onCommand("help", [&bot, &bot_commands](TgBot::Message::Ptr message) { + bot.getEvents().onCommand("help", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } + std::string result; for (const auto& command : bot_commands) { result.append("- ") @@ -71,16 +98,23 @@ int main() { try { std::cerr << GetCurrentTime() << std::format(" | Bot username: {}\n", bot.getApi().getMe()->username); + TgBot::TgLongPoll longPoll(bot); while (true) { - std::cerr << GetCurrentTime() << " | Long poll started\n"; + std::cerr << GetCurrentTime() << " | Long poll started on thread " << 0 << "\n"; longPoll.start(); if (!is_alive) { + for (auto& [id, count] : users) { + bot.getApi().sendMessage(id, "Guys, I've been killed("); + } std::exit(0); } } + } catch (TgBot::TgException& e) { std::cerr << GetCurrentTime() << std::format(" | error: {}\n", e.what()); + } catch (...) { + std::cerr << GetCurrentTime() << "Unknown exception"; } return 0; } \ No newline at end of file From 9dd017c3b2f68ed5b88c6eb346eff0e3d4f398c2 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 19:57:23 +0300 Subject: [PATCH 03/13] pg done? 1000-7 --- Dockerfile | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index eea6a88..6c7771c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,8 +48,8 @@ RUN apt-get -y update && \ apt-get install -y software-properties-common && \ apt-get -y update -RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test && \ - apt-get -y update && \ +RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test +RUN apt-get -y update && \ apt-get install -y gcc-4.9 && \ apt-get upgrade -y libstdc++6 @@ -78,17 +78,41 @@ RUN git clone https://github.com/jtv/libpqxx.git \ -DCMAKE_MODULE_PATH=/usr/src/libpqxx-r6.4/cmake .. \ && make && make install && ldconfig /usr/local/lib -RUN find / -name libpq.so.5 - +#installing postgresql +RUN apt-get install -y locales locales-all +ENV LC_ALL en_US.UTF-8 +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US.UTF-8 +RUN localedef -i en_GB -c -f UTF-8 -A /usr/share/locale/locale.alias en_GB.UTF-8 +RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata +RUN apt-get -y install wget ca-certificates && \ + wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \ + sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" >> /etc/apt/sources.list.d/pgdg.list' &&\ + apt-get -y update +RUN apt-get -y install postgresql postgresql-contrib + +RUN ls -la /etc/init.d/ +RUN /etc/init.d/postgresql start +RUN echo "host all all 0.0.0.0/0 md5" >>/etc/postgresql/16/main/pg_hba.conf && \ + echo "listen_addresses='*'" >> /etc/postgresql/16/main/postgresql.conf +RUN /etc/init.d/postgresql restart #changing rights RUN groupadd -r sample && useradd -r -g sample sample USER sample +USER postgres +RUN pg_lsclusters +ENV PGPASSWORD=postgres +# CMD ["/start_postgres.sh"] -#installing postgresql -# RUN apt-get -y install postgresql +RUN pg_ctlcluster 16 main start && \ + # psql "ALTER USER postgres WITH PASSWORD 'mint';" && \ + createdb mintdb +RUN pg_lsclusters #runnhing WORKDIR /app COPY --from=build /app/build/database . +EXPOSE 5432 + ENTRYPOINT ["./database"] From 9d7ab701a9a11316bce439f4aee30f8a7b6a55d0 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 20:32:35 +0300 Subject: [PATCH 04/13] pd init --- Dockerfile | 16 ++++++++++------ src/CMakeLists.txt | 4 +--- src/ddl.cpp | 4 ---- src/ddl.h | 4 ---- src/main.cpp | 12 ++++++++++-- src/run.sh | 4 ++++ 6 files changed, 25 insertions(+), 19 deletions(-) delete mode 100644 src/ddl.cpp delete mode 100644 src/ddl.h create mode 100644 src/run.sh diff --git a/Dockerfile b/Dockerfile index 6c7771c..4be8ec9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -96,23 +96,27 @@ RUN /etc/init.d/postgresql start RUN echo "host all all 0.0.0.0/0 md5" >>/etc/postgresql/16/main/pg_hba.conf && \ echo "listen_addresses='*'" >> /etc/postgresql/16/main/postgresql.conf RUN /etc/init.d/postgresql restart + +WORKDIR /app +COPY --from=build /app/build/database . +COPY --from=build /app/src . +RUN ls -la +RUN chmod +x ./run.sh + #changing rights RUN groupadd -r sample && useradd -r -g sample sample USER sample USER postgres RUN pg_lsclusters ENV PGPASSWORD=postgres -# CMD ["/start_postgres.sh"] RUN pg_ctlcluster 16 main start && \ - # psql "ALTER USER postgres WITH PASSWORD 'mint';" && \ createdb mintdb RUN pg_lsclusters -#runnhing -WORKDIR /app -COPY --from=build /app/build/database . +#running EXPOSE 5432 -ENTRYPOINT ["./database"] +ENTRYPOINT ["./run.sh"] +# RUN pg_ctlcluster 16 main start diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2ed0e8..bc89e7a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,9 +25,7 @@ if (CURL_FOUND) endif() set(SOURCES main.cpp - util.h - ddl.h - ddl.cpp) + util.h) add_executable(database ${SOURCES}) target_include_directories(database PRIVATE ".") target_link_libraries(database /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} libpqxx::pqxx_shared PostgreSQL::PostgreSQL) diff --git a/src/ddl.cpp b/src/ddl.cpp deleted file mode 100644 index d5b0968..0000000 --- a/src/ddl.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include - -void InitDatabase() { -} \ No newline at end of file diff --git a/src/ddl.h b/src/ddl.h deleted file mode 100644 index 80a970f..0000000 --- a/src/ddl.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include - -void InitDatabase(); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 4247449..689a5c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,9 +4,9 @@ #include #include #include +#include #include -#include "ddl.h" #include "util.h" const size_t kMaxQueries = 50; @@ -32,7 +32,15 @@ int main() { TgBot::Bot bot(std::getenv("TOKEN")); bool is_alive = true; - InitDatabase(); + while (true) { + try { + pqxx::connection c; + std::cout << "Connected to " << c.dbname() << '\n'; + break; + + } catch (const std::exception& e) { + } + } std::vector bot_commands = {{"start", "User greetings"}, {"kill", "Kills bot if you have permission"}, diff --git a/src/run.sh b/src/run.sh new file mode 100644 index 0000000..b91d60b --- /dev/null +++ b/src/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +pg_ctlcluster 16 main start +./database \ No newline at end of file From 7e7a96a407de80316ae5b1c12feaf9a44b5d3851 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 21:47:00 +0300 Subject: [PATCH 05/13] minor ddl --- src/cw.sql | 95 ---------------------------------------------------- src/ddl.sql | 83 +++++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 70 ++++++++++++++++++++++++++++---------- 3 files changed, 136 insertions(+), 112 deletions(-) create mode 100644 src/ddl.sql diff --git a/src/cw.sql b/src/cw.sql index 99bc523..c4acc0b 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -1,98 +1,3 @@ -create table crops ( - crop_id serial primary key, - name text not null, - humidity real check (humidity >= 0 and humidity <= 100), - brightness real check (brightness > 0), - is_legal boolean not null, - brain_damage real check (brain_damage > -200 and brain_damage < 200) -); - - -create table estate ( - estate_id serial primary key, - name text not null, - area real not null check (area > 100), - county text not null, - rent real not null check (rent > 0) -); - - -create table plantation ( - plantation_id serial primary key, - capacity integer not null, - revenue real not null, - estate_id integer references estate(estate_id) -); - - -create table crops_plantations ( - crop_id integer references crops(crop_id), - plantation_id integer references plantation(plantation_id), - counter integer check (counter >= 0), - primary key(crop_id, plantation_id) -); - - -create table worker ( - worker_id serial primary key, - plantation_id integer references plantation(plantation_id), - name text not null, - salary real check (salary >= 0), - profession text not null -); - - -create table worker_family_member ( - worker_fm_id serial primary key, - worker_id integer references worker(worker_id), - name text not null, - relationship text not null, - adress text not null -); - - -create table landlord ( - landlord_id serial primary key, - estate_id integer references estate(estate_id), - name text not null, - capital real check (capital > 0) -); - - -create table evidence_info ( - evidence_info_id serial primary key, - landlord_id integer references landlord(landlord_id), - description text, - worth real check (worth >= 20 AND worth <= 100) -); - - -create table manager ( - manager_id serial primary key, - plantation_id integer references plantation(plantation_id), - name text not null, - salary real check (salary >=100) -); - - -create table client ( - client_id serial primary key, - manager_id integer references manager(manager_id), - name text not null, - debt real check (debt < 10000), - is_highly_addicted boolean, - brain_resource real -); - - -create table client_family_member( - client_fm serial primary key, - client_id integer references client(client_id), - adress text not null, - email text unique check (email ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$') -); - - create or replace function cell(id_client integer, id_crop integer, amount integer) returns void as $$ begin diff --git a/src/ddl.sql b/src/ddl.sql new file mode 100644 index 0000000..90ae88f --- /dev/null +++ b/src/ddl.sql @@ -0,0 +1,83 @@ +create table crops ( + crop_id serial primary key, + name text not null, + humidity real check (humidity >= 0 and humidity <= 100), + brightness real check (brightness > 0), + is_legal boolean not null, + brain_damage real check (brain_damage > -200 and brain_damage < 200) +); + +create table estate ( + estate_id serial primary key, + name text not null, + area real not null check (area > 100), + county text not null, + rent real not null check (rent > 0) +); + +create table plantation ( + plantation_id serial primary key, + capacity integer not null, + revenue real not null, + estate_id integer references estate(estate_id) +); + +create table crops_plantations ( + crop_id integer references crops(crop_id), + plantation_id integer references plantation(plantation_id), + counter integer check (counter >= 0), + primary key(crop_id, plantation_id) +); + +create table worker ( + worker_id serial primary key, + plantation_id integer references plantation(plantation_id), + name text not null, + salary real check (salary >= 0), + profession text not null +); + +create table worker_family_member ( + worker_fm_id serial primary key, + worker_id integer references worker(worker_id), + name text not null, + relationship text not null, + adress text not null +); + +create table landlord ( + landlord_id serial primary key, + estate_id integer references estate(estate_id), + name text not null, + capital real check (capital > 0) +); + +create table evidence_info ( + evidence_info_id serial primary key, + landlord_id integer references landlord(landlord_id), + description text, + worth real check (worth >= 20 AND worth <= 100) +); + +create table manager ( + manager_id serial primary key, + plantation_id integer references plantation(plantation_id), + name text not null, + salary real check (salary >=100) +); + +create table client ( + client_id serial primary key, + manager_id integer references manager(manager_id), + name text not null, + debt real check (debt < 10000), + is_highly_addicted boolean, + brain_resource real +); + +create table client_family_member( + client_fm serial primary key, + client_id integer references client(client_id), + adress text not null, + email text unique check (email ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$') +); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 689a5c4..eed8352 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -20,33 +21,67 @@ class Command : public TgBot::BotCommand { }; bool HandleUser(size_t id, std::unordered_map& users) { - if (users.contains(id)) { - ++users[id]; - } else { - users[id] = 0; - } + ++users[id]; return users[id] > kMaxQueries; } -int main() { - TgBot::Bot bot(std::getenv("TOKEN")); - bool is_alive = true; +std::vector ReadDDLQueries(std::string filename) { + std::ifstream file(filename); + std::vector result; + std::string line; + std::string query; + while (std::getline(file, line)) { + query.append(line); + std::cerr << line[line.size() - 1] << std::endl; + if (line[line.size() - 1] == ';') { + std::cerr << query << std::endl; + result.emplace_back(query); + query.clear(); + } + } + return result; +} - while (true) { +void InitDatabase() { + pqxx::connection c; + std::cout << GetCurrentTime() << " | Connected to " << c.dbname() << " " << c.hostname() << " " + << c.port() << '\n'; + + // std::vector ddl_queries = {R"EOF( + // create table crops ( + // crop_id serial primary key, + // name text not null, + // humidity real check (humidity >= 0 and humidity <= 100), + // brightness real check (brightness > 0), + // is_legal boolean not null, + // brain_damage real check (brain_damage > -200 and brain_damage < 200) + // );)EOF"}; + + auto ddl_queries = ReadDDLQueries("./ddl.sql"); + + for (const auto& ddl_query : ddl_queries) { + pqxx::work query(c); try { - pqxx::connection c; - std::cout << "Connected to " << c.dbname() << '\n'; - break; - - } catch (const std::exception& e) { + std::cerr << ddl_query << std::endl; + pqxx::result res = query.exec(ddl_query); + query.commit(); + } catch (...) { + std::cout << "Database: failed to execute query: " << ddl_query << std::endl; } } +} + +int main() { + TgBot::Bot bot(std::getenv("TOKEN")); + bool is_alive = true; + + InitDatabase(); std::vector bot_commands = {{"start", "User greetings"}, {"kill", "Kills bot if you have permission"}, {"help", "Commands info"}}; - std::unordered_map users; + std::unordered_map users{}; bot.getEvents().onAnyMessage([&bot, &bot_commands, &users](TgBot::Message::Ptr message) { if (HandleUser(message->chat->id, users)) { @@ -68,10 +103,11 @@ int main() { } if (IsAdmin(message->from->username)) { bot.getApi().sendMessage(message->chat->id, - std::format("Hello master {}!", message->from->username)); + std::format("Hello master {}!", message->from->firstName)); } else { - bot.getApi().sendMessage(message->chat->id, "Hello!"); + bot.getApi().sendMessage(message->chat->id, + std::format("Hello padavan {}!", message->from->firstName)); } }); bot.getEvents().onCommand("kill", [&bot, &is_alive, &users](TgBot::Message::Ptr message) { From e458d315fdf0e5c615844235f5d9913ad38b7999 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 22:19:47 +0300 Subject: [PATCH 06/13] init database --- src/cw.sql | 98 ++++++++++++++++++++++++++++++++++++++++++++++------ src/ddl.sql | 83 -------------------------------------------- src/main.cpp | 22 ++++-------- 3 files changed, 94 insertions(+), 109 deletions(-) delete mode 100644 src/ddl.sql diff --git a/src/cw.sql b/src/cw.sql index c4acc0b..b5c09ba 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -1,4 +1,88 @@ -create or replace function cell(id_client integer, id_crop integer, amount integer) +create table crops ( + crop_id serial primary key, + name text not null, + humidity real check (humidity >= 0 and humidity <= 100), + brightness real check (brightness > 0), + is_legal boolean not null, + brain_damage real check (brain_damage > -200 and brain_damage < 200) +); + +create table estate ( + estate_id serial primary key, + name text not null, + area real not null check (area > 100), + county text not null, + rent real not null check (rent > 0) +); + +create table plantation ( + plantation_id serial primary key, + capacity integer not null, + revenue real not null, + estate_id integer references estate(estate_id) +); + +create table crops_plantations ( + crop_id integer references crops(crop_id), + plantation_id integer references plantation(plantation_id), + counter integer check (counter >= 0), + primary key(crop_id, plantation_id) +); + +create table worker ( + worker_id serial primary key, + plantation_id integer references plantation(plantation_id), + name text not null, + salary real check (salary >= 0), + profession text not null +); + +create table worker_family_member ( + worker_fm_id serial primary key, + worker_id integer references worker(worker_id), + name text not null, + relationship text not null, + adress text not null +); + +create table landlord ( + landlord_id serial primary key, + estate_id integer references estate(estate_id), + name text not null, + capital real check (capital > 0) +); + +create table evidence_info ( + evidence_info_id serial primary key, + landlord_id integer references landlord(landlord_id), + description text, + worth real check (worth >= 20 AND worth <= 100) +); + +create table manager ( + manager_id serial primary key, + plantation_id integer references plantation(plantation_id), + name text not null, + salary real check (salary >=100) +); + +create table client ( + client_id serial primary key, + manager_id integer references manager(manager_id), + name text not null, + debt real check (debt < 10000), + is_highly_addicted boolean, + brain_resource real +); + +create table client_family_member( + client_fm serial primary key, + client_id integer references client(client_id), + adress text not null, + email text unique check (email ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$') +); + +create or replace function sell(id_client integer, id_crop integer, amount integer) returns void as $$ begin update crops_plantations set counter = counter - amount where crop_id = id_crop and counter >= amount; @@ -6,9 +90,6 @@ returns void as $$ end; $$ language plpgsql; - - - create or replace function killer_f() returns trigger as $$ begin @@ -22,13 +103,10 @@ returns trigger as $$ end; $$ language plpgsql; - create trigger killer_t before insert or update on client for each row execute function killer_f(); - - create or replace function plant_capacity_checker_f() returns trigger as $$ begin @@ -46,12 +124,10 @@ returns trigger as $$ end; $$ language plpgsql; - create trigger plant_capacity_checker_t before insert or update on crops_plantations for each row execute function plant_capacity_checker_f(); - create or replace function enum_crops_on_plantation(name text) returns setof text as $$ begin @@ -62,7 +138,6 @@ returns setof text as $$ end; $$ language plpgsql; - create or replace function get_friends_email(name text) returns setof text as $$ begin @@ -72,6 +147,7 @@ returns setof text as $$ $$ language plpgsql; create index crop_id_i on crops using hash(crop_id); + create index client_id_i on client using hash(client_id); -create index brain_damage_i on crops using btree(brain_damage); +create index brain_damage_i on crops using btree(brain_damage); diff --git a/src/ddl.sql b/src/ddl.sql deleted file mode 100644 index 90ae88f..0000000 --- a/src/ddl.sql +++ /dev/null @@ -1,83 +0,0 @@ -create table crops ( - crop_id serial primary key, - name text not null, - humidity real check (humidity >= 0 and humidity <= 100), - brightness real check (brightness > 0), - is_legal boolean not null, - brain_damage real check (brain_damage > -200 and brain_damage < 200) -); - -create table estate ( - estate_id serial primary key, - name text not null, - area real not null check (area > 100), - county text not null, - rent real not null check (rent > 0) -); - -create table plantation ( - plantation_id serial primary key, - capacity integer not null, - revenue real not null, - estate_id integer references estate(estate_id) -); - -create table crops_plantations ( - crop_id integer references crops(crop_id), - plantation_id integer references plantation(plantation_id), - counter integer check (counter >= 0), - primary key(crop_id, plantation_id) -); - -create table worker ( - worker_id serial primary key, - plantation_id integer references plantation(plantation_id), - name text not null, - salary real check (salary >= 0), - profession text not null -); - -create table worker_family_member ( - worker_fm_id serial primary key, - worker_id integer references worker(worker_id), - name text not null, - relationship text not null, - adress text not null -); - -create table landlord ( - landlord_id serial primary key, - estate_id integer references estate(estate_id), - name text not null, - capital real check (capital > 0) -); - -create table evidence_info ( - evidence_info_id serial primary key, - landlord_id integer references landlord(landlord_id), - description text, - worth real check (worth >= 20 AND worth <= 100) -); - -create table manager ( - manager_id serial primary key, - plantation_id integer references plantation(plantation_id), - name text not null, - salary real check (salary >=100) -); - -create table client ( - client_id serial primary key, - manager_id integer references manager(manager_id), - name text not null, - debt real check (debt < 10000), - is_highly_addicted boolean, - brain_resource real -); - -create table client_family_member( - client_fm serial primary key, - client_id integer references client(client_id), - adress text not null, - email text unique check (email ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$') -); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index eed8352..b66b5a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,14 +31,16 @@ std::vector ReadDDLQueries(std::string filename) { std::string line; std::string query; while (std::getline(file, line)) { - query.append(line); - std::cerr << line[line.size() - 1] << std::endl; - if (line[line.size() - 1] == ';') { - std::cerr << query << std::endl; + if (line == "") { result.emplace_back(query); query.clear(); + } else { + query.append(line); + query.append("\n"); } } + result.emplace_back(query); + query.clear(); return result; } @@ -47,17 +49,7 @@ void InitDatabase() { std::cout << GetCurrentTime() << " | Connected to " << c.dbname() << " " << c.hostname() << " " << c.port() << '\n'; - // std::vector ddl_queries = {R"EOF( - // create table crops ( - // crop_id serial primary key, - // name text not null, - // humidity real check (humidity >= 0 and humidity <= 100), - // brightness real check (brightness > 0), - // is_legal boolean not null, - // brain_damage real check (brain_damage > -200 and brain_damage < 200) - // );)EOF"}; - - auto ddl_queries = ReadDDLQueries("./ddl.sql"); + auto ddl_queries = ReadDDLQueries("./cw.sql"); for (const auto& ddl_query : ddl_queries) { pqxx::work query(c); From 2ceb59c7867cf09a89c80b6e20e38d227e4e06da Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Sun, 18 Feb 2024 23:01:48 +0300 Subject: [PATCH 07/13] addition --- src/main.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b66b5a7..9eb96af 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,8 @@ #include +#include +#include #include #include #include @@ -25,6 +27,12 @@ bool HandleUser(size_t id, std::unordered_map& users) { return users[id] > kMaxQueries; } +std::vector GetArguments(std::string message) { + std::vector tokens; + boost::split(tokens, message, boost::is_any_of(" ")); + return tokens; +} + std::vector ReadDDLQueries(std::string filename) { std::ifstream file(filename); std::vector result; @@ -54,7 +62,7 @@ void InitDatabase() { for (const auto& ddl_query : ddl_queries) { pqxx::work query(c); try { - std::cerr << ddl_query << std::endl; + // std::cerr << ddl_query << std::endl; pqxx::result res = query.exec(ddl_query); query.commit(); } catch (...) { @@ -69,9 +77,22 @@ int main() { InitDatabase(); - std::vector bot_commands = {{"start", "User greetings"}, - {"kill", "Kills bot if you have permission"}, - {"help", "Commands info"}}; + std::vector bot_commands = { + {"start", "User greetings"}, + {"kill", "Kills bot if you have permission"}, + {"help", "Commands info"}, + {"get_friend_email", "Get email of friends by name"}, + {"add_crop", "Add new crop into database (string, percent, uint, bool, percent)"}, + {"add_client", "Add new client into database"}, + {"add_client_family_member", "Add new client family member into database"}, + {"add_crops_plantation", "Add new crops plantation into database"}, + {"add_estate", "Add new estate into database"}, + {"add_evidence_info", "Add new evidence_info into database"}, + {"add_landlord", "Add new landlord into database"}, + {"add_manager", "Add new manager into database"}, + {"add_plantation", "Add new plantation into database"}, + {"add_worker", "Add new worker into database"}, + {"add_worker_family_member", "Add new worker family member into database"}}; std::unordered_map users{}; @@ -130,6 +151,48 @@ int main() { } bot.getApi().sendMessage(message->chat->id, std::move(result)); }); + bot.getEvents().onCommand( + "get_friend_email", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } + std::string result; + auto args = GetArguments(message->text); + + pqxx::connection conn; + pqxx::work query(conn); + try { + pqxx::result res = query.exec(std::format("")); + query.commit(); + } catch (...) { + std::cout << "Database: failed to execute query: " << message->text << std::endl; + } + bot.getApi().sendMessage(message->chat->id, std::move(result)); + }); + + bot.getEvents().onCommand( + "add_crop", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } + std::string result; + auto args = GetArguments(message->text); + + pqxx::connection conn; + pqxx::work query(conn); + try { + + auto resp = std::format( + "insert into crops (name, humidity, brightness, is_legal, " + "brain_damage) values('{}', {}, {}, {}, {});", + args[1], args[2], args[3], args[4], args[5]); + pqxx::result res = query.exec(resp); + query.commit(); + bot.getApi().sendMessage(message->chat->id, resp); + } catch (...) { + std::cout << "Database: failed to execute query: " << message->text << std::endl; + } + }); try { std::cerr << GetCurrentTime() From 0595f5b95a84cb346635c522090ca567cca4a8b3 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Mon, 19 Feb 2024 13:48:09 +0300 Subject: [PATCH 08/13] 1000-7 prepared statement --- src/CMakeLists.txt | 3 +- src/main.cpp | 266 ++++++++++++++++++++------------------- src/main.hpp | 14 +++ src/{util.h => util.hpp} | 10 +- 4 files changed, 165 insertions(+), 128 deletions(-) create mode 100644 src/main.hpp rename src/{util.h => util.hpp} (69%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bc89e7a..4bd1b30 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,7 +25,8 @@ if (CURL_FOUND) endif() set(SOURCES main.cpp - util.h) + main.hpp + util.hpp) add_executable(database ${SOURCES}) target_include_directories(database PRIVATE ".") target_link_libraries(database /usr/local/lib/libTgBot.a ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} ${CURL_LIBRARIES} libpqxx::pqxx_shared PostgreSQL::PostgreSQL) diff --git a/src/main.cpp b/src/main.cpp index 9eb96af..b7900b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,7 @@ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" +#include "main.hpp" const size_t kMaxQueries = 50; +using UserVault = std::unordered_map; class Command : public TgBot::BotCommand { public: @@ -22,17 +11,11 @@ class Command : public TgBot::BotCommand { } }; -bool HandleUser(size_t id, std::unordered_map& users) { +bool HandleUser(size_t id, UserVault& users) { ++users[id]; return users[id] > kMaxQueries; } -std::vector GetArguments(std::string message) { - std::vector tokens; - boost::split(tokens, message, boost::is_any_of(" ")); - return tokens; -} - std::vector ReadDDLQueries(std::string filename) { std::ifstream file(filename); std::vector result; @@ -52,36 +35,161 @@ std::vector ReadDDLQueries(std::string filename) { return result; } -void InitDatabase() { - pqxx::connection c; - std::cout << GetCurrentTime() << " | Connected to " << c.dbname() << " " << c.hostname() << " " - << c.port() << '\n'; +void InitDatabase(pqxx::connection& connection) { auto ddl_queries = ReadDDLQueries("./cw.sql"); for (const auto& ddl_query : ddl_queries) { - pqxx::work query(c); + pqxx::work query(connection); try { - // std::cerr << ddl_query << std::endl; pqxx::result res = query.exec(ddl_query); query.commit(); } catch (...) { std::cout << "Database: failed to execute query: " << ddl_query << std::endl; } } + std::cout << GetCurrentTime() << " | Successfully created database" << std::endl; +} + +std::vector GetArguments(std::string message) { + std::vector tokens{}; + boost::split(tokens, message, boost::is_any_of(" ")); + return tokens; +} + +std::string GetPrettyTable(const pqxx::result& query_result) { + std::string answer; + answer.append(" "); + for (pqxx::row_size_type column = 0; column < query_result.columns(); ++column) { + answer.append(query_result.column_name(column)).append(" "); + } + answer.append("\n"); + + for (auto row : query_result) { + answer.append(" "); + for (auto field : row) { + answer.append(field.c_str()).append(" "); + } + answer.append("\n"); + } + return answer; +} + +void PrepareCommands(pqxx::connection& connection) { + connection.prepare("add_crop", + "insert into crops (name, humidity, brightness, is_legal, " + "brain_damage) values($1, $2, $3, $4, $5);"); + connection.prepare("view_crops", "select * from crops;"); +} + +pqxx::result ExecutePrepared(pqxx::work& query, std::string command, + std::vector&& args) { + if (command == "add_crop") { + return query.exec_prepared(command, args[1], args[2], args[3], args[4], args[5]); + } else if (command == "view_crops") { + return query.exec_prepared(command); + } + + return pqxx::result{}; +} + +void HandleCommands(TgBot::Bot& bot, pqxx::connection& connection, + const std::vector& bot_commands, UserVault& users, bool* is_alive) { + + bot.getEvents().onAnyMessage([&bot, &bot_commands, &users](TgBot::Message::Ptr message) { + if (HandleUser(message->chat->id, users)) { + return; + } + std::cout << GetCurrentTime() + << std::format(" | {} wrote {}\n", message->from->username, message->text); + for (const auto& command : bot_commands) { + if (StringTools::startsWith(message->text, "/" + command.command)) { + return; + } + } + bot.getApi().sendMessage(message->chat->id, "Unknown command: " + message->text); + }); + + for (auto& command : bot_commands) { + if (command.command == "start") { + bot.getEvents().onCommand(command.command, [&bot](TgBot::Message::Ptr message) { + if (IsAdmin(message->from->username)) { + bot.getApi().sendMessage( + message->chat->id, + std::format("Hello master {}!", message->from->firstName)); + + } else { + bot.getApi().sendMessage( + message->chat->id, + std::format("Hello padavan {}!", message->from->firstName)); + } + }); + } else if (command.command == "kill") { + bot.getEvents().onCommand( + command.command, [&bot, is_alive](TgBot::Message::Ptr message) { + if (IsAdmin(message->from->username)) { + bot.getApi().sendMessage( + message->chat->id, "Change the world my final message. Goodbye......."); + std::cout << GetCurrentTime() << " | Killed\n"; + *is_alive = false; + } else { + bot.getApi().sendMessage(message->chat->id, "Permission denied"); + } + }); + } else if (command.command == "help") { + bot.getEvents().onCommand( + command.command, [&bot, &bot_commands](TgBot::Message::Ptr message) { + std::string result; + for (const auto& command : bot_commands) { + result.append("- ") + .append(command.command) + .append(": ") + .append(command.description) + .append("\n"); + } + bot.getApi().sendMessage(message->chat->id, std::move(result)); + }); + } else { + bot.getEvents().onCommand(command.command, [command, &bot, &connection, &bot_commands]( + TgBot::Message::Ptr message) { + std::string result; + pqxx::work query(connection); + try { + pqxx::result query_result = + ExecutePrepared(query, command.command, GetArguments(message->text)); + query.commit(); + if (StringTools::startsWith(command.command, "add")) { + bot.getApi().sendMessage(message->chat->id, "Successfully added"); + } else if (StringTools::startsWith(command.command, "view")) { + bot.getApi().sendMessage(message->chat->id, GetPrettyTable(query_result)); + } + } catch (std::exception& e) { + std::cout << "Database: failed to execute query: " << message->text + << " due to " << e.what() << std::endl; + + bot.getApi().sendMessage(message->chat->id, + "Error occured " + std::string{e.what()} + "\n"); + } + }); + } + } } int main() { TgBot::Bot bot(std::getenv("TOKEN")); bool is_alive = true; - InitDatabase(); + pqxx::connection connection; + std::cout << GetCurrentTime() << " | Connected to " << connection.dbname() << " " + << connection.hostname() << " " << connection.port() << '\n'; + + InitDatabase(connection); std::vector bot_commands = { {"start", "User greetings"}, {"kill", "Kills bot if you have permission"}, {"help", "Commands info"}, - {"get_friend_email", "Get email of friends by name"}, + {"view_crops", "Check all current crops"}, {"add_crop", "Add new crop into database (string, percent, uint, bool, percent)"}, {"add_client", "Add new client into database"}, {"add_client_family_member", "Add new client family member into database"}, @@ -94,105 +202,11 @@ int main() { {"add_worker", "Add new worker into database"}, {"add_worker_family_member", "Add new worker family member into database"}}; - std::unordered_map users{}; - - bot.getEvents().onAnyMessage([&bot, &bot_commands, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - std::cerr << GetCurrentTime() - << std::format(" | {} wrote {}\n", message->from->username, message->text); - for (const auto& command : bot_commands) { - if (StringTools::startsWith(message->text, "/" + command.command)) { - return; - } - } - bot.getApi().sendMessage(message->chat->id, "Unknown command: " + message->text); - }); + UserVault users{}; - bot.getEvents().onCommand("start", [&bot, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - if (IsAdmin(message->from->username)) { - bot.getApi().sendMessage(message->chat->id, - std::format("Hello master {}!", message->from->firstName)); + PrepareCommands(connection); - } else { - bot.getApi().sendMessage(message->chat->id, - std::format("Hello padavan {}!", message->from->firstName)); - } - }); - bot.getEvents().onCommand("kill", [&bot, &is_alive, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - if (IsAdmin(message->from->username)) { - bot.getApi().sendMessage(message->chat->id, - "Change the world my final message. Goodbye......."); - std::cerr << GetCurrentTime() << " | Killed\n"; - is_alive = false; - } else { - bot.getApi().sendMessage(message->chat->id, "Permission denied"); - } - }); - bot.getEvents().onCommand("help", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - - std::string result; - for (const auto& command : bot_commands) { - result.append("- ") - .append(command.command) - .append(": ") - .append(command.description) - .append("\n"); - } - bot.getApi().sendMessage(message->chat->id, std::move(result)); - }); - bot.getEvents().onCommand( - "get_friend_email", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - std::string result; - auto args = GetArguments(message->text); - - pqxx::connection conn; - pqxx::work query(conn); - try { - pqxx::result res = query.exec(std::format("")); - query.commit(); - } catch (...) { - std::cout << "Database: failed to execute query: " << message->text << std::endl; - } - bot.getApi().sendMessage(message->chat->id, std::move(result)); - }); - - bot.getEvents().onCommand( - "add_crop", [&bot, &bot_commands, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { - return; - } - std::string result; - auto args = GetArguments(message->text); - - pqxx::connection conn; - pqxx::work query(conn); - try { - - auto resp = std::format( - "insert into crops (name, humidity, brightness, is_legal, " - "brain_damage) values('{}', {}, {}, {}, {});", - args[1], args[2], args[3], args[4], args[5]); - pqxx::result res = query.exec(resp); - query.commit(); - bot.getApi().sendMessage(message->chat->id, resp); - } catch (...) { - std::cout << "Database: failed to execute query: " << message->text << std::endl; - } - }); + HandleCommands(bot, connection, bot_commands, users, &is_alive); try { std::cerr << GetCurrentTime() @@ -206,7 +220,7 @@ int main() { for (auto& [id, count] : users) { bot.getApi().sendMessage(id, "Guys, I've been killed("); } - std::exit(0); + return 0; } } diff --git a/src/main.hpp b/src/main.hpp new file mode 100644 index 0000000..3de958d --- /dev/null +++ b/src/main.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.hpp" diff --git a/src/util.h b/src/util.hpp similarity index 69% rename from src/util.h rename to src/util.hpp index 88439dd..c94b18f 100644 --- a/src/util.h +++ b/src/util.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include inline const std::string GetCurrentTime() { @@ -21,4 +23,10 @@ inline bool IsAdmin(const std::string& username) { } } return false; -} \ No newline at end of file +} + +// inline std::vector GetArguments(std::string message) { +// std::vector tokens; +// boost::split(tokens, message, boost::is_any_of(" ")); +// return tokens; +// } From 2c80b7763af47c0036860f41a27345a51894e28c Mon Sep 17 00:00:00 2001 From: Mopstream <93407507+Mopstream@users.noreply.github.com> Date: Mon, 19 Feb 2024 16:39:53 +0300 Subject: [PATCH 09/13] add default to client --- src/cw.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cw.sql b/src/cw.sql index b5c09ba..a1af443 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -70,8 +70,8 @@ create table client ( client_id serial primary key, manager_id integer references manager(manager_id), name text not null, - debt real check (debt < 10000), - is_highly_addicted boolean, + debt real check (debt < 10000) default 0, + is_highly_addicted boolean defaut false, brain_resource real ); From d6742894064df8ff276858eec102c2ec54a7f3e8 Mon Sep 17 00:00:00 2001 From: Mopstream <93407507+Mopstream@users.noreply.github.com> Date: Mon, 19 Feb 2024 16:46:47 +0300 Subject: [PATCH 10/13] fix tables creating --- src/cw.sql | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/cw.sql b/src/cw.sql index a1af443..907fb79 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -1,4 +1,4 @@ -create table crops ( +create if not exists table crops ( crop_id serial primary key, name text not null, humidity real check (humidity >= 0 and humidity <= 100), @@ -7,7 +7,7 @@ create table crops ( brain_damage real check (brain_damage > -200 and brain_damage < 200) ); -create table estate ( +create if not exists table estate ( estate_id serial primary key, name text not null, area real not null check (area > 100), @@ -15,21 +15,21 @@ create table estate ( rent real not null check (rent > 0) ); -create table plantation ( +create if not exists table plantation ( plantation_id serial primary key, capacity integer not null, revenue real not null, estate_id integer references estate(estate_id) ); -create table crops_plantations ( +create if not exists table crops_plantations ( crop_id integer references crops(crop_id), plantation_id integer references plantation(plantation_id), counter integer check (counter >= 0), primary key(crop_id, plantation_id) ); -create table worker ( +create if not exists table worker ( worker_id serial primary key, plantation_id integer references plantation(plantation_id), name text not null, @@ -37,7 +37,7 @@ create table worker ( profession text not null ); -create table worker_family_member ( +create if not exists table worker_family_member ( worker_fm_id serial primary key, worker_id integer references worker(worker_id), name text not null, @@ -45,28 +45,28 @@ create table worker_family_member ( adress text not null ); -create table landlord ( +create if not exists table landlord ( landlord_id serial primary key, estate_id integer references estate(estate_id), name text not null, capital real check (capital > 0) ); -create table evidence_info ( +create if not exists table evidence_info ( evidence_info_id serial primary key, landlord_id integer references landlord(landlord_id), description text, worth real check (worth >= 20 AND worth <= 100) ); -create table manager ( +create if not exists table manager ( manager_id serial primary key, plantation_id integer references plantation(plantation_id), name text not null, salary real check (salary >=100) ); -create table client ( +create if not exists table client ( client_id serial primary key, manager_id integer references manager(manager_id), name text not null, @@ -75,7 +75,7 @@ create table client ( brain_resource real ); -create table client_family_member( +create if not exists table client_family_member( client_fm serial primary key, client_id integer references client(client_id), adress text not null, From 90e2ee12fa9d6d6e43b3e0fd45e76e5c8f33eaa3 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Mon, 19 Feb 2024 17:51:00 +0300 Subject: [PATCH 11/13] some --- src/cw.sql | 23 +++---- src/main.cpp | 171 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 165 insertions(+), 29 deletions(-) diff --git a/src/cw.sql b/src/cw.sql index b5c09ba..0a51a5a 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -1,4 +1,4 @@ -create table crops ( +create table if not exists crops ( crop_id serial primary key, name text not null, humidity real check (humidity >= 0 and humidity <= 100), @@ -7,7 +7,7 @@ create table crops ( brain_damage real check (brain_damage > -200 and brain_damage < 200) ); -create table estate ( +create table if not exists estate ( estate_id serial primary key, name text not null, area real not null check (area > 100), @@ -15,21 +15,21 @@ create table estate ( rent real not null check (rent > 0) ); -create table plantation ( +create table if not exists plantation ( plantation_id serial primary key, capacity integer not null, revenue real not null, estate_id integer references estate(estate_id) ); -create table crops_plantations ( +create table if not exists crops_plantations ( crop_id integer references crops(crop_id), plantation_id integer references plantation(plantation_id), counter integer check (counter >= 0), primary key(crop_id, plantation_id) ); -create table worker ( +create table if not exists worker ( worker_id serial primary key, plantation_id integer references plantation(plantation_id), name text not null, @@ -37,7 +37,7 @@ create table worker ( profession text not null ); -create table worker_family_member ( +create table if not exists worker_family_member ( worker_fm_id serial primary key, worker_id integer references worker(worker_id), name text not null, @@ -45,28 +45,28 @@ create table worker_family_member ( adress text not null ); -create table landlord ( +create table if not exists landlord ( landlord_id serial primary key, estate_id integer references estate(estate_id), name text not null, capital real check (capital > 0) ); -create table evidence_info ( +create table if not exists evidence_info ( evidence_info_id serial primary key, landlord_id integer references landlord(landlord_id), description text, worth real check (worth >= 20 AND worth <= 100) ); -create table manager ( +create table if not exists manager ( manager_id serial primary key, plantation_id integer references plantation(plantation_id), name text not null, salary real check (salary >=100) ); -create table client ( +create table if not exists client ( client_id serial primary key, manager_id integer references manager(manager_id), name text not null, @@ -75,7 +75,7 @@ create table client ( brain_resource real ); -create table client_family_member( +create table if not exists client_family_member( client_fm serial primary key, client_id integer references client(client_id), adress text not null, @@ -100,6 +100,7 @@ returns trigger as $$ return null; end; else return NEW; + end if; end; $$ language plpgsql; diff --git a/src/main.cpp b/src/main.cpp index b7900b8..4f596c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,8 +44,9 @@ void InitDatabase(pqxx::connection& connection) { try { pqxx::result res = query.exec(ddl_query); query.commit(); - } catch (...) { - std::cout << "Database: failed to execute query: " << ddl_query << std::endl; + } catch (std::exception& e) { + std::cout << "Database: failed to execute query: " << ddl_query << std::endl + << " Error: " << e.what() << std::endl; } } std::cout << GetCurrentTime() << " | Successfully created database" << std::endl; @@ -76,17 +77,120 @@ std::string GetPrettyTable(const pqxx::result& query_result) { } void PrepareCommands(pqxx::connection& connection) { + + connection.prepare("add_crop", + "insert into crops (name, humidity, brightness, is_legal, " + "brain_damage) values($1, $2, $3, $4, $5);"); + connection.prepare("add_crop", "insert into crops (name, humidity, brightness, is_legal, " "brain_damage) values($1, $2, $3, $4, $5);"); connection.prepare("view_crops", "select * from crops;"); + + connection.prepare("add_client", + "insert into client (manager_id, name, debt, is_highly_addicted, " + "brain_resource) values($1, $2, 0, false, 100);"); + connection.prepare("view_clients", "select * from client;"); + + connection.prepare("add_client_family_member", + "insert into client (client_id, adress, email) values($1, $2, $3);"); + connection.prepare("view_client_family_members", "select * from client_family_member;"); + + connection.prepare("add_estate", + "insert into estate (name, area, county, rent) values($1, $2, $3, $4);"); + connection.prepare("view_estates", "select * from estate;"); + + connection.prepare("add_plantation", + "insert into plantation (capacity, revenue, estate_id) values($1, $2, $3);"); + connection.prepare("view_plantations", "select * from plantation;"); + + connection.prepare( + "add_worker", + "insert into worker (plantation_id, name, salary, profession) values($1, $2, $3, $4);"); + connection.prepare("view_workers", "select * from worker;"); + + connection.prepare("add_landlord", + "insert into landlord (estate_id, name, capital) values($1, $2, $3);"); + connection.prepare("view_landlords", "select * from landlord;"); + + connection.prepare("add_manager", + "insert into manager (plantation_id, name, salary) values($1, $2, $3);"); + connection.prepare("view_managers", "select * from manager;"); + + connection.prepare( + "add_evidence_info", + "insert into evidence_info (landlord_id, description, worth) values($1, $2, $3);"); + connection.prepare("view_evidence_info", "select * from evidence_info;"); + + connection.prepare( + "add_crops_plantations", + "insert into crops_plantations (crop_id, plantation_id, counter) values($1, $2, $3);"); + connection.prepare("view_crops_plantations", "select * from crops_plantations;"); + + connection.prepare("add_worker_family_member", + "insert into worker_family_member (worker_id, name, relationship, adress) " + "values($1, $2, $3, $4);"); + connection.prepare("view_worker_family_members", "select * from worker_family_member;"); } pqxx::result ExecutePrepared(pqxx::work& query, std::string command, std::vector&& args) { if (command == "add_crop") { + if (args.size() < 6) { + throw std::runtime_error("Invalid number of arguments"); + } return query.exec_prepared(command, args[1], args[2], args[3], args[4], args[5]); - } else if (command == "view_crops") { + } else if (command == "add_client") { + if (args.size() < 3) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2]); + } else if (command == "add_client_family_member") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_estate") { + if (args.size() < 5) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3], args[4]); + } else if (command == "add_plantation") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_worker") { + if (args.size() < 5) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3], args[4]); + } else if (command == "add_landlord") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_manager") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_evidence_info") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_crops_plantations") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "add_worker_family_member") { + if (args.size() < 5) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3], args[4]); + } else if (StringTools::startsWith(command, "view")) { return query.exec_prepared(command); } @@ -141,9 +245,8 @@ void HandleCommands(TgBot::Bot& bot, pqxx::connection& connection, command.command, [&bot, &bot_commands](TgBot::Message::Ptr message) { std::string result; for (const auto& command : bot_commands) { - result.append("- ") - .append(command.command) - .append(": ") + result.append(command.command) + .append(" - ") .append(command.description) .append("\n"); } @@ -190,17 +293,49 @@ int main() { {"kill", "Kills bot if you have permission"}, {"help", "Commands info"}, {"view_crops", "Check all current crops"}, - {"add_crop", "Add new crop into database (string, percent, uint, bool, percent)"}, - {"add_client", "Add new client into database"}, - {"add_client_family_member", "Add new client family member into database"}, - {"add_crops_plantation", "Add new crops plantation into database"}, - {"add_estate", "Add new estate into database"}, - {"add_evidence_info", "Add new evidence_info into database"}, - {"add_landlord", "Add new landlord into database"}, - {"add_manager", "Add new manager into database"}, - {"add_plantation", "Add new plantation into database"}, - {"add_worker", "Add new worker into database"}, - {"add_worker_family_member", "Add new worker family member into database"}}; + {"add_crop", + "Add new crop into database. Arguments: (name: string, humidity: percent, brightness: " + "uint, is_legal: bool, brain_damage: percent)"}, + {"view_clients", "Check all current clients"}, + {"add_client", "Add new client into database. Arguments: (manager_id: int, name: string)"}, + {"view_client_family_members", "Check all current client's family members"}, + {"add_client_family_member", + "Add new client family member into database. Arguments: (client_id: int, adress: " + "string, email: string)"}, + {"view_estates", "Check all current estates"}, + {"add_estate", + "Add new estate into database. Arguments: (name: string, area: uint, country: string, " + "rent: real)"}, + {"view_crops_plantations", "Check all crops related to plantations"}, + {"add_crops_plantations", + "Add new crops related to plantations into database. Arguments: (crops_id: int, " + "plantation_id: int, " + "counter: " + "uint)"}, + {"view_evidence_info", "Check all current evidence_info"}, + {"add_evidence_info", + "Add new evidence_info into database. Arguments: (landlord_id: int, description: " + "string, worth: percent)"}, + {"view_landlords", "Check all current landlords"}, + {"add_landlord", + "Add new landlord into database. Arguments: (estate_id: int, name: string, capital: " + "real)"}, + {"view_managers", "Check all current managers"}, + {"add_manager", + "Add new manager into database. Arguments: (plantation_id: int, name:string, salary: " + "real)"}, + {"view_plantations", "Check all current plantations"}, + {"add_plantation", + "Add new plantation into database. Arguments: (capacity: uint, revenue: real, " + "estate_id: int)"}, + {"view_workers", "Check all current workers"}, + {"add_worker", + "Add new worker into database. Arguments: (plantation_id: int, name: string, salary: " + "real, profession: string)"}, + {"view_worker_family_members", "Check all current worker's family members"}, + {"add_worker_family_member", + "Add new worker family member into database. Argument: (worker_id: int, name: string, " + "relationship: string, adress: string)"}}; UserVault users{}; @@ -214,7 +349,7 @@ int main() { TgBot::TgLongPoll longPoll(bot); while (true) { - std::cerr << GetCurrentTime() << " | Long poll started on thread " << 0 << "\n"; + std::cerr << GetCurrentTime() << " | Long poll started" << std::endl; longPoll.start(); if (!is_alive) { for (auto& [id, count] : users) { From 2993550605bcce8c673a97dc69616fec91694a2e Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Mon, 19 Feb 2024 20:01:27 +0300 Subject: [PATCH 12/13] final --- src/cw.sql | 18 +++++++++--------- src/main.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/cw.sql b/src/cw.sql index 4120572..c58d24f 100644 --- a/src/cw.sql +++ b/src/cw.sql @@ -70,8 +70,8 @@ create table client ( client_id serial primary key, manager_id integer references manager(manager_id), name text not null, - debt real check (debt < 10000) default 0, - is_highly_addicted boolean defaut false, + debt real check (debt < 10000), + is_highly_addicted boolean, brain_resource real ); @@ -129,24 +129,24 @@ create trigger plant_capacity_checker_t before insert or update on crops_plantations for each row execute function plant_capacity_checker_f(); -create or replace function enum_crops_on_plantation(name text) +create or replace function enum_crops_on_plantation(crop_name text) returns setof text as $$ begin select name from crops c join crops_plantations cp on c.crops_id = cp.crops_id join plantation p on cp.plantation_td = p.plantation_id - where p.name = name; + where p.name = crop_name; end; $$ language plpgsql; -create or replace function get_friends_email(name text) +create or replace function get_friends_email(client_name text) returns setof text as $$ - begin - select email from client_family_member - where client_id = (select client_id from client where client.name = name); - end; + begin + return query select email from client_family_member where client_id = (select client_id from client where client.name = client_name); + end; $$ language plpgsql; + create index crop_id_i on crops using hash(crop_id); create index client_id_i on client using hash(client_id); diff --git a/src/main.cpp b/src/main.cpp index 4f596c5..93cecae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,6 +77,9 @@ std::string GetPrettyTable(const pqxx::result& query_result) { } void PrepareCommands(pqxx::connection& connection) { + connection.prepare("get_friends_email", "select get_friends_email($1)"); + connection.prepare("enum_crops_on_plantation", "select enum_crops_on_plantation($1)"); + connection.prepare("sell", "select sell($1, $2, $3)"); connection.prepare("add_crop", "insert into crops (name, humidity, brightness, is_legal, " @@ -92,8 +95,9 @@ void PrepareCommands(pqxx::connection& connection) { "brain_resource) values($1, $2, 0, false, 100);"); connection.prepare("view_clients", "select * from client;"); - connection.prepare("add_client_family_member", - "insert into client (client_id, adress, email) values($1, $2, $3);"); + connection.prepare( + "add_client_family_member", + "insert into client_family_member (client_id, adress, email) values($1, $2, $3);"); connection.prepare("view_client_family_members", "select * from client_family_member;"); connection.prepare("add_estate", @@ -135,7 +139,23 @@ void PrepareCommands(pqxx::connection& connection) { pqxx::result ExecutePrepared(pqxx::work& query, std::string command, std::vector&& args) { - if (command == "add_crop") { + + if (command == "sell") { + if (args.size() < 4) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1], args[2], args[3]); + } else if (command == "enum_crops_on_plantation") { + if (args.size() < 2) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1]); + } else if (command == "get_friends_email") { + if (args.size() < 2) { + throw std::runtime_error("Invalid number of arguments"); + } + return query.exec_prepared(command, args[1]); + } else if (command == "add_crop") { if (args.size() < 6) { throw std::runtime_error("Invalid number of arguments"); } @@ -248,7 +268,7 @@ void HandleCommands(TgBot::Bot& bot, pqxx::connection& connection, result.append(command.command) .append(" - ") .append(command.description) - .append("\n"); + .append("\n\n"); } bot.getApi().sendMessage(message->chat->id, std::move(result)); }); @@ -265,6 +285,21 @@ void HandleCommands(TgBot::Bot& bot, pqxx::connection& connection, bot.getApi().sendMessage(message->chat->id, "Successfully added"); } else if (StringTools::startsWith(command.command, "view")) { bot.getApi().sendMessage(message->chat->id, GetPrettyTable(query_result)); + } else if (command.command == "sell") { + bot.getApi().sendMessage(message->chat->id, "Sold some sweat crops!"); + } else if (command.command == "enum_crops_on_plantation") { + // for (auto& res : query_result) { + // std::cout << GetCurrentTime() << " | " << res.c_str(); + // bot.getApi().sendMessage(message->chat->id, res.c_str()); + // } + bot.getApi().sendMessage(message->chat->id, GetPrettyTable(query_result)); + + } else if (command.command == "get_friends_email") { + // for (auto& res : query_result) { + // std::cout << GetCurrentTime() << " | " << res.c_str(); + // bot.getApi().sendMessage(message->chat->id, res.c_str()); + // } + bot.getApi().sendMessage(message->chat->id, GetPrettyTable(query_result)); } } catch (std::exception& e) { std::cout << "Database: failed to execute query: " << message->text @@ -293,6 +328,13 @@ int main() { {"kill", "Kills bot if you have permission"}, {"help", "Commands info"}, {"view_crops", "Check all current crops"}, + {"sell", + "Sells certain amount of crop to client. Arguments: (id_client: int,id_crop: int, amount: " + "int)"}, + {"enum_crops_on_plantation", + "Enums certain crop on plantation by name. Arguments: (crop_name: string)"}, + {"get_friends_email", + "Returns emails of friends of client. Arguments: (client_name: string)"}, {"add_crop", "Add new crop into database. Arguments: (name: string, humidity: percent, brightness: " "uint, is_legal: bool, brain_damage: percent)"}, From ec12dcefaeab662a1fd0d2ed0edb3de63cef4cb2 Mon Sep 17 00:00:00 2001 From: hyperb0rean Date: Mon, 19 Feb 2024 20:08:04 +0300 Subject: [PATCH 13/13] review fixes --- Dockerfile | 12 +++++++++++- src/main.cpp | 13 ++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4be8ec9..541512e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ #building bot + FROM gcc:latest as build RUN apt-get update && \ @@ -10,6 +11,7 @@ RUN apt-get update && \ RUN apt-get install g++ make binutils libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev #installing tgbot lib + RUN git clone https://github.com/reo7sp/tgbot-cpp RUN cmake ./tgbot-cpp RUN cd tgbot-cpp @@ -19,6 +21,7 @@ RUN cd .. #installing libpqxx + RUN apt-get install -y libpq-dev libpqxx-dev RUN git clone https://github.com/jtv/libpqxx.git \ @@ -34,6 +37,7 @@ RUN git clone https://github.com/jtv/libpqxx.git \ && make && make install && ldconfig /usr/local/lib #building sources + ADD ./src /app/src WORKDIR /app/build @@ -41,9 +45,11 @@ RUN cmake ../src && \ cmake --build . #run configuration + FROM ubuntu:latest #installing base dependencies + RUN apt-get -y update && \ apt-get install -y software-properties-common && \ apt-get -y update @@ -63,6 +69,7 @@ RUN apt-get update && \ apt-get install -y git make cmake g++ #installing libpqxx + RUN apt-get install -y libpq-dev libpqxx-dev @@ -79,6 +86,7 @@ RUN git clone https://github.com/jtv/libpqxx.git \ && make && make install && ldconfig /usr/local/lib #installing postgresql + RUN apt-get install -y locales locales-all ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 @@ -91,7 +99,6 @@ RUN apt-get -y install wget ca-certificates && \ apt-get -y update RUN apt-get -y install postgresql postgresql-contrib -RUN ls -la /etc/init.d/ RUN /etc/init.d/postgresql start RUN echo "host all all 0.0.0.0/0 md5" >>/etc/postgresql/16/main/pg_hba.conf && \ echo "listen_addresses='*'" >> /etc/postgresql/16/main/postgresql.conf @@ -104,12 +111,15 @@ RUN ls -la RUN chmod +x ./run.sh #changing rights + RUN groupadd -r sample && useradd -r -g sample sample USER sample USER postgres RUN pg_lsclusters ENV PGPASSWORD=postgres +# creating database + RUN pg_ctlcluster 16 main start && \ createdb mintdb RUN pg_lsclusters diff --git a/src/main.cpp b/src/main.cpp index 93cecae..508f92b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,13 +11,12 @@ class Command : public TgBot::BotCommand { } }; -bool HandleUser(size_t id, UserVault& users) { - ++users[id]; - return users[id] > kMaxQueries; +bool CheckDDOSUser(size_t user_id, UserVault& users) { + ++users[user_id]; + return users[user_id] > kMaxQueries; } -std::vector ReadDDLQueries(std::string filename) { - std::ifstream file(filename); +std::vector ReadDDLQueries(std::ifstream&& file) { std::vector result; std::string line; std::string query; @@ -37,7 +36,7 @@ std::vector ReadDDLQueries(std::string filename) { void InitDatabase(pqxx::connection& connection) { - auto ddl_queries = ReadDDLQueries("./cw.sql"); + auto ddl_queries = ReadDDLQueries(std::ifstream("./cw.sql")); for (const auto& ddl_query : ddl_queries) { pqxx::work query(connection); @@ -221,7 +220,7 @@ void HandleCommands(TgBot::Bot& bot, pqxx::connection& connection, const std::vector& bot_commands, UserVault& users, bool* is_alive) { bot.getEvents().onAnyMessage([&bot, &bot_commands, &users](TgBot::Message::Ptr message) { - if (HandleUser(message->chat->id, users)) { + if (CheckDDOSUser(message->chat->id, users)) { return; } std::cout << GetCurrentTime()