From d7c5e7292813940d5f0a7559f5a0d44418355ed3 Mon Sep 17 00:00:00 2001 From: Torsten Schulz Date: Wed, 29 May 2024 14:19:07 +0200 Subject: [PATCH] easy access to admin information --- CMakeLists.txt.user | 2 +- docroot/style.css | 3 ++ src/app.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++ src/app.h | 9 ++++ src/broadcast.cpp | 23 ++++++--- 5 files changed, 147 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index a7ced9e..5673e9a 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/docroot/style.css b/docroot/style.css index cbf1dba..2cdfd5d 100644 --- a/docroot/style.css +++ b/docroot/style.css @@ -217,3 +217,6 @@ main { .output-box-format-other { background-color: #fff; } +.padding-right { + padding-right: 1em; +} diff --git a/src/app.cpp b/src/app.cpp index 43f1f34..540ff5b 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -524,11 +525,129 @@ void App::onInternalPathChanged(const std::string &path) { showStandardPage(); } else if (path == "/partners") { showPartnerSites(); + } else if (path == "/adm/info/logins" || path == "/adm/info/starts") { + showAdminPage(path); } else { setInternalPath("/", true); } } +void App::showAdminPage(std::string page) { + if (isLoggedInAsAdmin) { + if (page == "/adm/info/logins") { + showAdminLogins(); + } else if (page == "/adm/info/starts") { + showAdminStarts(); + } else { + showPageNotExists(); + } + return; + } + showAdminLogin(page); +} + +void App::showAdminLogin(std::string page) { + contentContainer_->clear(); + auto loginContainer = contentContainer_->addNew(); + loginContainer->addNew("Name:"); + auto nameEdit = loginContainer->addNew(); + loginContainer->addNew(); + loginContainer->addNew("Password:"); + auto passwordEdit = loginContainer->addNew(); + passwordEdit->setEchoMode(Wt::EchoMode::Password); + loginContainer->addNew(); + auto loginButton = loginContainer->addNew("Login"); + auto messageLabel = loginContainer->addNew(); + auto loginAction = [=, this] { + if (nameEdit->text().toUTF8() == adminName && passwordEdit->text().toUTF8() == adminPassword) { + isLoggedInAsAdmin = true; + messageLabel->setText(""); + showAdminPage(page); + } else { + isLoggedInAsAdmin = false; + messageLabel->setText("Incorrect username or password."); + messageLabel->decorationStyle().setForegroundColor(Wt::WColor("red")); + } + }; + loginButton->clicked().connect(loginAction); + passwordEdit->enterPressed().connect(loginAction); +} + +void App::showPageNotExists() { + contentContainer_->clear(); + auto errorMessageLabel = contentContainer_->addNew("Error 400 - Page not found"); + errorMessageLabel->decorationStyle().setForegroundColor(Wt::WColor("red")); +} + +void App::showAdminLogins() { + contentContainer_->clear(); + contentContainer_->addNew("

Logins

", Wt::TextFormat::UnsafeXHTML); + std::ifstream file("../logs/logins.log"); + if (!file.is_open()) { + contentContainer_->addNew("Error opening file."); + return; + } + std::stringstream buffer; + buffer << file.rdbuf(); + std::string fileContent = buffer.str(); + Wt::Json::Array jsonArray; + Wt::Json::parse(fileContent, jsonArray); + auto table = contentContainer_->addNew(); + table->setHeaderCount(1); + table->elementAt(0, 0)->addNew("Name"); + table->elementAt(0, 1)->addNew("Country"); + table->elementAt(0, 2)->addNew("Gender"); + table->elementAt(0, 3)->addNew("Age"); + int row = 1; + for (const auto& item : jsonArray) { + Wt::Json::Object jsonData = item; + std::string name = jsonData.get("name").orIfNull(""); + std::string country = jsonData.get("country").orIfNull(""); + std::string gender = jsonData.get("gender").orIfNull(""); + int age = jsonData.get("age").orIfNull(0); + auto nameCell = table->elementAt(row, 0)->addNew(name); + nameCell->setStyleClass("padding-right"); + auto countryCell = table->elementAt(row, 1)->addNew(country); + countryCell->setStyleClass("padding-right"); + auto genderCell = table->elementAt(row, 2)->addNew(gender); + genderCell->setStyleClass("padding-right"); + table->elementAt(row, 3)->addNew(std::to_string(age)); + row++; + } +} + + +void App::showAdminStarts() { + contentContainer_->clear(); + contentContainer_->addNew("

Chat starts

", Wt::TextFormat::UnsafeXHTML); + std::ifstream file("../logs/starts.log"); + if (!file.is_open()) { + contentContainer_->addNew("Error opening file."); + return; + } + auto table = contentContainer_->addNew(); + table->setHeaderCount(1); + table->elementAt(0, 0)->addNew("Datum"); + table->elementAt(0, 1)->addNew("Uhrzeit"); + std::string line; + int row = 1; + while (std::getline(file, line)) { + std::istringstream ss(line); + std::tm tm{}; + ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); + std::ostringstream dateStream; + std::ostringstream timeStream; + dateStream.imbue(std::locale("de_DE.utf8")); + timeStream.imbue(std::locale("de_DE.utf8")); + dateStream << std::put_time(&tm, "%d.%m.%Y"); + timeStream << std::put_time(&tm, "%H:%M:%S"); + auto dateCell = table->elementAt(row, 0)->addNew(dateStream.str()); + dateCell->setStyleClass("padding-right"); + table->elementAt(row, 1)->addNew(timeStream.str()); + row++; + } +} + Wt::WContainerWidget* App::createSmileyButton(Wt::WHBoxLayout* inputLayout, Wt::WLineEdit* inputLine, std::shared_ptr cursorPosition) { auto smileyButton = inputLayout->addNew(); smileyButton->addNew(Wt::WLink("/smileys.png")); diff --git a/src/app.h b/src/app.h index b9b0e70..7866e38 100644 --- a/src/app.h +++ b/src/app.h @@ -20,6 +20,9 @@ public: ~App(); private: + const std::string adminName {"comiciusadmin"}; + const std::string adminPassword {"p3Lv9!7?+Qq"}; + std::map genders_ { {"F", "Female"}, {"M", "Male"}, @@ -94,6 +97,7 @@ private: Search searchFields; Wt::WTimer *loginTimer_; Wt::WTimer *timeoutRemainingTimer_; + bool isLoggedInAsAdmin {false}; void setMetaTags(); void initApp(); void reSetUser(); @@ -212,6 +216,11 @@ private: bool isAnimatedGIF(const Magick::Blob &blob); void showStandardPage(); void onInternalPathChanged(const std::string &path); + void showAdminPage(std::string page); + void showAdminLogin(std::string page); + void showPageNotExists(); + void showAdminLogins(); + void showAdminStarts(); }; #endif // APP_H diff --git a/src/broadcast.cpp b/src/broadcast.cpp index d5f09b3..f8ef7fb 100644 --- a/src/broadcast.cpp +++ b/src/broadcast.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -61,17 +63,22 @@ void Broadcast::connect(Client *client, const std::function &fct) { } void Broadcast::logClientLogin(const Wt::Json::Object &clientJson) { - const std::string logFilePath = "/opt/ypchat/logs/logins.log"; + const std::string logFilePath = "../logs/logins.log"; + Wt::Json::Array logArray; std::ifstream infile(logFilePath); - if (!infile.good()) { - std::ofstream outfile(logFilePath); - outfile.close(); + if (infile.is_open()) { + std::stringstream buffer; + buffer << infile.rdbuf(); + std::string fileContent = buffer.str(); + infile.close(); + if (!fileContent.empty()) { + Wt::Json::parse(fileContent, logArray); + } } - infile.close(); - std::string clientData = Wt::Json::serialize(clientJson); - std::ofstream outfile(logFilePath, std::ios_base::app); + logArray.push_back(clientJson); + std::ofstream outfile(logFilePath); if (outfile.is_open()) { - outfile << clientData << std::endl; + outfile << Wt::Json::serialize(logArray) << std::endl; outfile.close(); } else { std::cerr << "Fehler beim Öffnen der Datei: " << logFilePath << std::endl;