diff --git a/Server/Database/Database.cpp b/Server/Database/Database.cpp index be856ee..217dc7c 100644 --- a/Server/Database/Database.cpp +++ b/Server/Database/Database.cpp @@ -150,6 +150,72 @@ void Database::updateTodayVisitCount(const std::string &url, const std::string & sqlite3_finalize(stmt); } +void Database::clearTodayVisitRecord() { + char *message = nullptr; + constexpr auto sql = "DELETE FROM today_visit_count"; + int rc = sqlite3_exec(m_sqlite3, sql, nullptr, nullptr, &message); + if (rc != SQLITE_OK) { + LOG(error) << "SQL error: " << message; + sqlite3_free(message); + } +} + +static bool urlExists(sqlite3 *db, const std::string &url) { + std::string sql = "SELECT 1 FROM visit_count WHERE url = '" + url + "'"; + sqlite3_stmt *stmt; + int rc = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(db); + return false; + } + rc = sqlite3_step(stmt); + bool exists = (rc == SQLITE_ROW); + sqlite3_finalize(stmt); + return exists; +} + +void Database::updateVisitCount() { + constexpr auto sql = "SELECT url, COUNT(DISTINCT visitor_uuid) AS unique_visitors, SUM(page_view_count) AS " + "total_page_views FROM today_visit_count GROUP BY url"; + sqlite3_stmt *stmt; + + int rc = sqlite3_prepare_v2(m_sqlite3, sql, -1, &stmt, nullptr); + if (rc != SQLITE_OK) { + LOG(error) << "Failed to prepare statement: " << sqlite3_errmsg(m_sqlite3); + return; + } + + std::unordered_map> urlData; + while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + std::string url = reinterpret_cast(sqlite3_column_text(stmt, 0)); + int uniqueVisitors = sqlite3_column_int(stmt, 1); + int totalPageViews = sqlite3_column_int(stmt, 2); + urlData[url] = {uniqueVisitors, totalPageViews}; + } + + sqlite3_finalize(stmt); + for (const auto &[url, data] : urlData) { + int uniqueVisitors = data.first; + int totalPageViews = data.second; + std::string updateSql; + if (urlExists(m_sqlite3, url)) { + updateSql = "UPDATE visit_count SET unique_visitor_count = unique_visitor_count + " + + std::to_string(uniqueVisitors) + ", page_view_count = page_view_count + " + + std::to_string(totalPageViews) + " WHERE url = '" + url + "'"; + } else { + updateSql = "INSERT INTO visit_count (url, unique_visitor_count, page_view_count) VALUES ('" + url + "', " + + std::to_string(uniqueVisitors) + ", " + std::to_string(totalPageViews) + ")"; + } + char *message = nullptr; + LOG(info) << updateSql; + rc = sqlite3_exec(m_sqlite3, updateSql.c_str(), nullptr, nullptr, &message); + if (rc != SQLITE_OK) { + LOG(error) << "SQL error: " << message; + sqlite3_free(message); + } + } +} + bool Database::addHomeBoxItem(const std::string &name, const std::string &location, int cost) { bool ret = true; std::ostringstream oss; diff --git a/Server/Database/Database.h b/Server/Database/Database.h index 3c91683..c39ec60 100644 --- a/Server/Database/Database.h +++ b/Server/Database/Database.h @@ -21,6 +21,9 @@ public: void setTaskFinished(int id, bool finished, uint64_t finishedTime); void updateTodayVisitCount(const std::string &url, const std::string &visitorUuid); + void clearTodayVisitRecord(); + void updateVisitCount(); + HomeBox::Items homeBoxItems(); bool addHomeBoxItem(const std::string &name, const std::string &location, int cost); diff --git a/UnitTest/DatabaseTest.cpp b/UnitTest/DatabaseTest.cpp index 73e791f..f378947 100644 --- a/UnitTest/DatabaseTest.cpp +++ b/UnitTest/DatabaseTest.cpp @@ -27,4 +27,7 @@ BOOST_AUTO_TEST_CASE(DatabaseTest) { database.updateTodayVisitCount("/note", "uuid_123"); database.updateTodayVisitCount("/note/1", "uuid_1232"); database.updateTodayVisitCount("/note", "uuid_123"); + database.updateTodayVisitCount("/note", "uuid_1234"); + + database.updateVisitCount(); } \ No newline at end of file