Use mariadbpp rather than the mysql C connector.
Reasoning being: * The result_set and other APIs are nicer to use. * We use mariadb on our server rather than mysql, so this would minimize the chance of any incompatibilities. * The mysql C++ connector 1.1 isn't compatible with with c++17 (https://stackoverflow.com/q/47284705).
This commit is contained in:
parent
f996803cf6
commit
113a4e0913
21 changed files with 786 additions and 572 deletions
|
@ -1,6 +1,6 @@
|
|||
|
||||
# set minimum version
|
||||
cmake_minimum_required(VERSION 2.8.5)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(wesnoth)
|
||||
|
||||
|
@ -62,6 +62,11 @@ option(ENABLE_HISTORY "Enable using GNU history for history in lua console" ON)
|
|||
if(NOT CXX_STD)
|
||||
set(CXX_STD "14")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD ${CXX_STD})
|
||||
# make sure to force using it
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# forbid defaulting to gnu++NN instead of c++NN
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if(ENABLE_GAME OR ENABLE_TESTS)
|
||||
# find_package(OpenGL REQUIRED)
|
||||
|
@ -209,7 +214,7 @@ if(NOT DEFINED CXX_FLAGS_USER)
|
|||
|
||||
endif(NOT DEFINED CXX_FLAGS_USER)
|
||||
|
||||
set(COMPILER_FLAGS "-std=c++${CXX_STD} -Wall -Wextra -Werror=non-virtual-dtor -Wno-unused-local-typedefs -Wno-maybe-uninitialized -Wold-style-cast -Wtrampolines")
|
||||
set(COMPILER_FLAGS "-Wall -Wextra -Werror=non-virtual-dtor -Wno-unused-local-typedefs -Wno-maybe-uninitialized -Wold-style-cast -Wtrampolines")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -Qunused-arguments -Wno-unknown-warning-option -Wmismatched-tags -Wno-conditional-uninitialized -Wno-unused-lambda-capture")
|
||||
|
|
|
@ -1709,6 +1709,13 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\gui\dialogs\server_info_dialog.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\gui\dialogs\help_browser.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|x64'">$(IntDir)Gui\Dialogs\</ObjectFileName>
|
||||
|
|
|
@ -596,6 +596,9 @@
|
|||
<ClCompile Include="..\..\src\gui\dialogs\game_version_dialog.cpp">
|
||||
<Filter>Gui\Dialogs</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\gui\dialogs\server_info_dialog.cpp">
|
||||
<Filter>Gui\Dialogs</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\gui\dialogs\gamestate_inspector.cpp">
|
||||
<Filter>Gui\Dialogs</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -342,6 +342,30 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\dbconn.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\resultsets\tournaments.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\resultsets\ban_check.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\player.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)Server\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Server\</ObjectFileName>
|
||||
|
|
|
@ -39,6 +39,15 @@
|
|||
<ClCompile Include="..\..\src\server\metrics.cpp">
|
||||
<Filter>Server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\dbconn.cpp">
|
||||
<Filter>Server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\resultsets\tournaments.cpp">
|
||||
<Filter>Server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\resultsets\ban_check.cpp">
|
||||
<Filter>Server</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\server\player.cpp">
|
||||
<Filter>Server</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -2,6 +2,7 @@ server/ban.cpp
|
|||
server/forum_user_handler.cpp
|
||||
server/game.cpp
|
||||
server/metrics.cpp
|
||||
server/dbconn.cpp
|
||||
server/player.cpp
|
||||
server/player_connection.cpp
|
||||
server/player_network.cpp
|
||||
|
@ -9,3 +10,5 @@ server/server.cpp
|
|||
server/server_base.cpp
|
||||
server/simple_wml.cpp
|
||||
server/user_handler.cpp
|
||||
server/resultsets/tournaments.cpp
|
||||
server/resultsets/ban_check.cpp
|
||||
|
|
|
@ -12,6 +12,7 @@ if(ENABLE_MYSQL)
|
|||
string(REGEX REPLACE "-I" "" MYSQL_CFLAGS "${MYSQL_CFLAGS}")
|
||||
string(REGEX REPLACE "-DNDEBUG" "" MYSQL_CFLAGS "${MYSQL_CFLAGS}")
|
||||
execute_process(COMMAND mysql_config --libs OUTPUT_VARIABLE MYSQL_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
find_package(mariadbclientpp)
|
||||
endif(ENABLE_MYSQL)
|
||||
|
||||
## some includes ##
|
||||
|
@ -343,6 +344,7 @@ if(ENABLE_SERVER)
|
|||
if(ENABLE_MYSQL)
|
||||
target_include_directories(wesnothd SYSTEM PRIVATE ${MYSQL_CFLAGS})
|
||||
target_compile_definitions(wesnothd PRIVATE HAVE_MYSQLPP)
|
||||
target_link_libraries(wesnothd mariadbclientpp::mariadbclientpp)
|
||||
endif(ENABLE_MYSQL)
|
||||
|
||||
target_link_libraries(wesnothd
|
||||
|
@ -366,6 +368,7 @@ if(ENABLE_CAMPAIGN_SERVER)
|
|||
if(ENABLE_MYSQL)
|
||||
target_include_directories(campaignd SYSTEM PRIVATE ${MYSQL_CFLAGS})
|
||||
target_compile_definitions(campaignd PRIVATE HAVE_MYSQLPP)
|
||||
target_link_libraries(wesnothd mariadbclientpp::mariadbclientpp)
|
||||
endif(ENABLE_MYSQL)
|
||||
|
||||
target_link_libraries(campaignd
|
||||
|
|
|
@ -175,6 +175,8 @@ if have_client_prereqs:
|
|||
wesnothd_sources = GetSources("wesnothd")
|
||||
if env["PLATFORM"] == 'win32':
|
||||
env.WesnothProgram("wesnothd", wesnothd_sources + libwesnoth_core + env["wesnothd_res"], have_server_prereqs)
|
||||
elif env["forum_user_handler"]:
|
||||
env.WesnothProgram("wesnothd", wesnothd_sources + libwesnoth_core + ["/usr/local/lib/libmariadbclientpp.a"], have_server_prereqs)
|
||||
else:
|
||||
env.WesnothProgram("wesnothd", wesnothd_sources + libwesnoth_core, have_server_prereqs)
|
||||
|
||||
|
|
397
src/server/dbconn.cpp
Normal file
397
src/server/dbconn.cpp
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MYSQLPP
|
||||
|
||||
#include "dbconn.hpp"
|
||||
#include "resultsets/tournaments.hpp"
|
||||
#include "resultsets/ban_check.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
static lg::log_domain log_sql_handler("sql_executor");
|
||||
#define ERR_SQL LOG_STREAM(err, log_sql_handler)
|
||||
#define WRN_SQL LOG_STREAM(warn, log_sql_handler)
|
||||
#define LOG_SQL LOG_STREAM(info, log_sql_handler)
|
||||
#define DBG_SQL LOG_STREAM(debug, log_sql_handler)
|
||||
|
||||
dbconn::dbconn(const config& c)
|
||||
: db_users_table_(c["db_users_table"].str())
|
||||
, db_banlist_table_(c["db_banlist_table"].str())
|
||||
, db_extra_table_(c["db_extra_table"].str())
|
||||
, db_game_info_table_(c["db_game_info_table"].str())
|
||||
, db_game_player_info_table_(c["db_game_player_info_table"].str())
|
||||
, db_game_modification_info_table_(c["db_game_modification_info_table"].str())
|
||||
, db_user_group_table_(c["db_user_group_table"].str())
|
||||
, db_tournament_query_(c["db_tournament_query"].str())
|
||||
{
|
||||
try
|
||||
{
|
||||
// NOTE: settings put on the connection, rather than the account, are NOT kept if a reconnect occurs!
|
||||
account_ = mariadb::account::create(c["db_host"].str(), c["db_user"].str(), c["db_password"].str());
|
||||
account_->set_connect_option(mysql_option::MYSQL_SET_CHARSET_NAME, std::string("utf8mb4"));
|
||||
account_->set_schema(c["db_name"].str());
|
||||
connection_ = mariadb::connection::create(account_);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to connect to the database!", e);
|
||||
}
|
||||
}
|
||||
|
||||
void dbconn::log_sql_exception(const std::string& text, const mariadb::exception::base& e)
|
||||
{
|
||||
ERR_SQL << text << '\n'
|
||||
<< "what: " << e.what() << '\n'
|
||||
<< "error id: " << e.error_id() << std::endl;
|
||||
}
|
||||
|
||||
//
|
||||
// queries
|
||||
//
|
||||
std::string dbconn::get_uuid()
|
||||
{
|
||||
try
|
||||
{
|
||||
return get_single_string("SELECT UUID()");
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Could not retrieve a UUID!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string dbconn::get_tournaments()
|
||||
{
|
||||
if(db_tournament_query_ == "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
tournaments t;
|
||||
get_complex_results(t, db_tournament_query_);
|
||||
return t.str();
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Could not retrieve the tournaments!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool dbconn::user_exists(const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return exists("SELECT 1 FROM `"+db_users_table_+"` WHERE UPPER(username)=UPPER(?)", name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to check if user row for '"+name+"' exists!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool dbconn::extra_row_exists(const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return exists("SELECT 1 FROM `"+db_extra_table_+"` WHERE UPPER(username)=UPPER(?)", name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to check if extra row for '"+name+"' exists!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool dbconn::is_user_in_group(const std::string& name, int group_id)
|
||||
{
|
||||
try
|
||||
{
|
||||
return exists("SELECT 1 FROM `"+db_users_table_+"` u, `"+db_user_group_table_+"` ug WHERE UPPER(u.username)=UPPER(?) AND u.USER_ID = ug.USER_ID AND ug.GROUP_ID = ?", name, group_id);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to check if the user '"+name+"' is in group '"+std::to_string(group_id)+"'!", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ban_check dbconn::get_ban_info(const std::string& name, const std::string& ip)
|
||||
{
|
||||
try
|
||||
{
|
||||
// selected ban_type value must be part of user_handler::BAN_TYPE
|
||||
ban_check b;
|
||||
get_complex_results(b, "select ban_userid, ban_email, case when ban_ip != '' then 1 when ban_userid != 0 then 2 when ban_email != '' then 3 end as ban_type, ban_end from `"+db_banlist_table_+"` where (ban_ip = ? or ban_userid = (select user_id from `"+db_users_table_+"` where UPPER(username) = UPPER(?)) or UPPER(ban_email) = (select UPPER(user_email) from `"+db_users_table_+"` where UPPER(username) = UPPER(?))) AND ban_exclude = 0 AND (ban_end = 0 OR ban_end >= ?)", ip, name, name, std::time(nullptr));
|
||||
return b;
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to check ban info for user '"+name+"' connecting from ip '"+ip+"'!", e);
|
||||
return ban_check();
|
||||
}
|
||||
}
|
||||
|
||||
std::string dbconn::get_user_string(const std::string& table, const std::string& column, const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return get_single_string("SELECT `"+column+"` from `"+table+"` WHERE UPPER(username)=UPPER(?)", name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to query column `"+column+"` from table `"+table+"` for user `"+name+"`", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
int dbconn::get_user_int(const std::string& table, const std::string& column, const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return get_single_int("SELECT `"+column+"` from `"+table+"` WHERE UPPER(username)=UPPER(?)", name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to query column `"+column+"` from table `"+table+"` for user `"+name+"`", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
void dbconn::write_user_int(const std::string& column, const std::string& name, int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!extra_row_exists(name))
|
||||
{
|
||||
modify("INSERT INTO `"+db_extra_table_+"` VALUES(?,?,'0')", name, value);
|
||||
}
|
||||
modify("UPDATE `"+db_extra_table_+"` SET "+column+"=? WHERE UPPER(username)=UPPER(?)", value, name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Unable to write `"+std::to_string(value)+"` to column `"+column+"` on table `"+db_extra_table_+"` for user `"+name+"`", e);
|
||||
}
|
||||
}
|
||||
|
||||
void dbconn::insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, const std::string& map_name, const std::string& era_name, int reload, int observers, int is_public, int has_password)
|
||||
{
|
||||
try
|
||||
{
|
||||
modify("INSERT INTO `"+db_game_info_table_+"`(INSTANCE_UUID, GAME_ID, INSTANCE_VERSION, GAME_NAME, MAP_NAME, ERA_NAME, RELOAD, OBSERVERS, PUBLIC, PASSWORD) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
uuid, game_id, version, name, map_name, era_name, reload, observers, is_public, has_password);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to insert game info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
|
||||
}
|
||||
}
|
||||
void dbconn::update_game_end(const std::string& uuid, int game_id, const std::string& replay_location)
|
||||
{
|
||||
try
|
||||
{
|
||||
modify("UPDATE `"+db_game_info_table_+"` SET END_TIME = CURRENT_TIMESTAMP, REPLAY_NAME = ? WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
|
||||
replay_location, uuid, game_id);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to update the game end for game info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
|
||||
}
|
||||
}
|
||||
void dbconn::insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user)
|
||||
{
|
||||
try
|
||||
{
|
||||
modify("INSERT INTO `"+db_game_player_info_table_+"`(INSTANCE_UUID, GAME_ID, USER_ID, SIDE_NUMBER, IS_HOST, FACTION, CLIENT_VERSION, CLIENT_SOURCE, USER_NAME) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?)",
|
||||
uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to insert game player info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
|
||||
}
|
||||
}
|
||||
void dbconn::insert_modification_info(const std::string& uuid, int game_id, const std::string& modification_name)
|
||||
{
|
||||
try
|
||||
{
|
||||
modify("INSERT INTO `"+db_game_modification_info_table_+"`(INSTANCE_UUID, GAME_ID, MODIFICATION_NAME) VALUES(?, ?, ?)",
|
||||
uuid, game_id, modification_name);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to insert game modification info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
|
||||
}
|
||||
}
|
||||
void dbconn::set_oos_flag(const std::string& uuid, int game_id)
|
||||
{
|
||||
try
|
||||
{
|
||||
modify("UPDATE `"+db_game_info_table_+"` SET OOS = 1 WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
|
||||
uuid, game_id);
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
log_sql_exception("Failed to set the OOS flag for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// queries can return data with various types that can't be easily fit into a pre-determined structure
|
||||
// therefore for queries that can return multiple rows of multiple columns, implement a class to define how the results should be read
|
||||
//
|
||||
template<typename... Args>
|
||||
void dbconn::get_complex_results(rs_base& base, const std::string& sql, Args&&... args)
|
||||
{
|
||||
mariadb::result_set_ref rslt = select(sql, args...);
|
||||
base.read(rslt);
|
||||
}
|
||||
//
|
||||
// get single values
|
||||
//
|
||||
template<typename... Args>
|
||||
std::string dbconn::get_single_string(const std::string& sql, Args&&... args)
|
||||
{
|
||||
mariadb::result_set_ref rslt = select(sql, args...);
|
||||
if(rslt->next())
|
||||
{
|
||||
return rslt->get_string(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw mariadb::exception::base("No string value found in the database!");
|
||||
}
|
||||
}
|
||||
template<typename... Args>
|
||||
int dbconn::get_single_int(const std::string& sql, Args&&... args)
|
||||
{
|
||||
mariadb::result_set_ref rslt = select(sql, args...);
|
||||
if(rslt->next())
|
||||
{
|
||||
// mariadbpp checks for strict integral equivalence, but we don't care
|
||||
// so check the type beforehand, call the associated getter, and let it silently get upcast to an int if needed
|
||||
switch(rslt->column_type(0))
|
||||
{
|
||||
case mariadb::value::type::unsigned8:
|
||||
case mariadb::value::type::signed8:
|
||||
return rslt->get_signed8(0);
|
||||
case mariadb::value::type::unsigned16:
|
||||
case mariadb::value::type::signed16:
|
||||
return rslt->get_signed16(0);
|
||||
case mariadb::value::type::unsigned32:
|
||||
case mariadb::value::type::signed32:
|
||||
return rslt->get_signed32(0);
|
||||
default:
|
||||
throw mariadb::exception::base("Value retrieved was not an int!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw mariadb::exception::base("No int value found in the database!");
|
||||
}
|
||||
}
|
||||
template<typename... Args>
|
||||
bool dbconn::exists(const std::string& sql, Args&&... args)
|
||||
{
|
||||
mariadb::result_set_ref rslt = select(sql, args...);
|
||||
return rslt->next();
|
||||
}
|
||||
|
||||
//
|
||||
// select or modify values
|
||||
//
|
||||
template<typename... Args>
|
||||
mariadb::result_set_ref dbconn::select(const std::string& sql, Args&&... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
mariadb::statement_ref stmt = query(sql, args...);
|
||||
return mariadb::result_set_ref(stmt->query());
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
if(!connection_->connected())
|
||||
{
|
||||
ERR_SQL << "Connection is invalid!" << std::endl;
|
||||
}
|
||||
ERR_SQL << "SQL query failed for query: `"+sql+"`!" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
template<typename... Args>
|
||||
int dbconn::modify(const std::string& sql, Args&&... args)
|
||||
{
|
||||
try
|
||||
{
|
||||
mariadb::statement_ref stmt = query(sql, args...);
|
||||
return stmt->insert();
|
||||
}
|
||||
catch(const mariadb::exception::base& e)
|
||||
{
|
||||
if(!connection_->connected())
|
||||
{
|
||||
ERR_SQL << "Connection is invalid!" << std::endl;
|
||||
}
|
||||
ERR_SQL << "SQL query failed for query: `"+sql+"`!" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// start of recursive unpacking of variadic template in order to be able to call correct parameterized setters on query
|
||||
//
|
||||
template<typename... Args>
|
||||
mariadb::statement_ref dbconn::query(const std::string& sql, Args&&... args)
|
||||
{
|
||||
mariadb::statement_ref stmt = connection_->create_statement(sql);
|
||||
prepare(stmt, 0, args...);
|
||||
return stmt;
|
||||
}
|
||||
// split off the next parameter
|
||||
template<typename Arg, typename... Args>
|
||||
void dbconn::prepare(mariadb::statement_ref stmt, int i, Arg arg, Args&&... args)
|
||||
{
|
||||
i = prepare(stmt, i, arg);
|
||||
prepare(stmt, i, args...);
|
||||
}
|
||||
// template specialization for supported parameter types
|
||||
// there are other parameter setters, but so far there hasn't been a reason to add them
|
||||
template<>
|
||||
int dbconn::prepare(mariadb::statement_ref stmt, int i, int arg)
|
||||
{
|
||||
stmt->set_signed32(i++, arg);
|
||||
return i;
|
||||
}
|
||||
template<>
|
||||
int dbconn::prepare(mariadb::statement_ref stmt, int i, long arg)
|
||||
{
|
||||
stmt->set_signed64(i++, arg);
|
||||
return i;
|
||||
}
|
||||
template<>
|
||||
int dbconn::prepare(mariadb::statement_ref stmt, int i, const char* arg)
|
||||
{
|
||||
stmt->set_string(i++, arg);
|
||||
return i;
|
||||
}
|
||||
template<>
|
||||
int dbconn::prepare(mariadb::statement_ref stmt, int i, std::string arg)
|
||||
{
|
||||
stmt->set_string(i++, arg);
|
||||
return i;
|
||||
}
|
||||
// no more parameters, nothing left to do
|
||||
void dbconn::prepare(mariadb::statement_ref, int){}
|
||||
|
||||
#endif //HAVE_MYSQLPP
|
92
src/server/dbconn.hpp
Normal file
92
src/server/dbconn.hpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.hpp"
|
||||
#include "resultsets/rs_base.hpp"
|
||||
#include "resultsets/ban_check.hpp"
|
||||
|
||||
#include <mysql/mysql.h>
|
||||
#include <mariadb++/account.hpp>
|
||||
#include <mariadb++/connection.hpp>
|
||||
#include <mariadb++/statement.hpp>
|
||||
#include <mariadb++/result_set.hpp>
|
||||
#include <mariadb++/exceptions.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class dbconn
|
||||
{
|
||||
public:
|
||||
dbconn(const config& c);
|
||||
std::string get_uuid();
|
||||
std::string get_tournaments();
|
||||
bool user_exists(const std::string& name);
|
||||
bool extra_row_exists(const std::string& name);
|
||||
bool is_user_in_group(const std::string& name, int group_id);
|
||||
std::string get_user_string(const std::string& table, const std::string& column, const std::string& name);
|
||||
int get_user_int(const std::string& table, const std::string& column, const std::string& name);
|
||||
void write_user_int(const std::string& column, const std::string& name, int value);
|
||||
ban_check get_ban_info(const std::string& name, const std::string& ip);
|
||||
void insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, const std::string& map_name, const std::string& era_name, int reload, int observers, int is_public, int has_password);
|
||||
void update_game_end(const std::string& uuid, int game_id, const std::string& replay_location);
|
||||
void insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user);
|
||||
void insert_modification_info(const std::string& uuid, int game_id, const std::string& modification_name);
|
||||
void set_oos_flag(const std::string& uuid, int game_id);
|
||||
|
||||
private:
|
||||
mariadb::account_ref account_;
|
||||
mariadb::connection_ref connection_;
|
||||
|
||||
std::string db_users_table_;
|
||||
std::string db_banlist_table_;
|
||||
std::string db_extra_table_;
|
||||
std::string db_game_info_table_;
|
||||
std::string db_game_player_info_table_;
|
||||
std::string db_game_modification_info_table_;
|
||||
std::string db_user_group_table_;
|
||||
std::string db_tournament_query_;
|
||||
|
||||
void log_sql_exception(const std::string& text, const mariadb::exception::base& e);
|
||||
|
||||
template<typename... Args>
|
||||
void get_complex_results(rs_base& base, const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
std::string get_single_string(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
int get_single_int(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
bool exists(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
mariadb::result_set_ref select(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
int modify(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename... Args>
|
||||
mariadb::statement_ref query(const std::string& sql, Args&&... args);
|
||||
|
||||
template<typename Arg, typename... Args>
|
||||
void prepare(mariadb::statement_ref stmt, int i, Arg arg, Args&&... args);
|
||||
|
||||
template<typename Arg>
|
||||
int prepare(mariadb::statement_ref stmt, int i, Arg arg);
|
||||
|
||||
void prepare(mariadb::statement_ref stmt, int i);
|
||||
};
|
|
@ -15,7 +15,6 @@
|
|||
#ifdef HAVE_MYSQLPP
|
||||
|
||||
#include "server/forum_user_handler.hpp"
|
||||
#include "server/mysql_prepared_statement.ipp"
|
||||
#include "hash.hpp"
|
||||
#include "log.hpp"
|
||||
#include "config.hpp"
|
||||
|
@ -35,41 +34,20 @@ namespace {
|
|||
}
|
||||
|
||||
fuh::fuh(const config& c)
|
||||
: db_name_(c["db_name"].str())
|
||||
, db_host_(c["db_host"].str())
|
||||
, db_user_(c["db_user"].str())
|
||||
, db_password_(c["db_password"].str())
|
||||
: conn(c)
|
||||
, db_users_table_(c["db_users_table"].str())
|
||||
, db_banlist_table_(c["db_banlist_table"].str())
|
||||
, db_extra_table_(c["db_extra_table"].str())
|
||||
, db_game_info_table_(c["db_game_info_table"].str())
|
||||
, db_game_player_info_table_(c["db_game_player_info_table"].str())
|
||||
, db_game_modification_info_table_(c["db_game_modification_info_table"].str())
|
||||
, db_user_group_table_(c["db_user_group_table"].str())
|
||||
, db_tournament_query_(c["db_tournament_query"].str())
|
||||
, mp_mod_group_(0)
|
||||
, conn(mysql_init(nullptr))
|
||||
{
|
||||
try {
|
||||
mp_mod_group_ = std::stoi(c["mp_mod_group"].str());
|
||||
} catch(...) {
|
||||
ERR_UH << "Failed to convert the mp_mod_group value of '" << c["mp_mod_group"].str() << "' into an int! Defaulting to " << mp_mod_group_ << "." << std::endl;
|
||||
}
|
||||
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");
|
||||
if(!conn || !mysql_real_connect(conn, db_host_.c_str(), db_user_.c_str(), db_password_.c_str(), db_name_.c_str(), 0, nullptr, 0)) {
|
||||
ERR_UH << "Could not connect to database: " << mysql_errno(conn) << ": " << mysql_error(conn) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
fuh::~fuh() {
|
||||
mysql_close(conn);
|
||||
}
|
||||
|
||||
// The hashing code is basically taken from forum_auth.cpp
|
||||
bool fuh::login(const std::string& name, const std::string& password, const std::string& seed) {
|
||||
|
||||
// Retrieve users' password as hash
|
||||
|
||||
std::string hash;
|
||||
|
||||
try {
|
||||
|
@ -131,49 +109,26 @@ void fuh::user_logged_in(const std::string& name) {
|
|||
}
|
||||
|
||||
bool fuh::user_exists(const std::string& name) {
|
||||
|
||||
// Make a test query for this username
|
||||
try {
|
||||
return prepared_statement<bool>("SELECT 1 FROM `" + db_users_table_ + "` WHERE UPPER(username)=UPPER(?)", name);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl;
|
||||
// If the database is down just let all usernames log in
|
||||
return false;
|
||||
}
|
||||
return conn.user_exists(name);
|
||||
}
|
||||
|
||||
bool fuh::user_is_active(const std::string& name) {
|
||||
try {
|
||||
int user_type = get_detail_for_user<int>(name, "user_type");
|
||||
return user_type != USER_INACTIVE && user_type != USER_IGNORE;
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not retrieve user type for user '" << name << "' :" << e.message << std::endl;
|
||||
return false;
|
||||
}
|
||||
int user_type = conn.get_user_int(db_users_table_, "user_type", name);
|
||||
return user_type != USER_INACTIVE && user_type != USER_IGNORE;
|
||||
}
|
||||
|
||||
bool fuh::user_is_moderator(const std::string& name) {
|
||||
|
||||
if(!user_exists(name)) return false;
|
||||
|
||||
try {
|
||||
return get_writable_detail_for_user<int>(name, "user_is_moderator") == 1 || (mp_mod_group_ != 0 && is_user_in_group(name, mp_mod_group_));
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not query user_is_moderator/MP Moderators group for user '" << name << "' :" << e.message << std::endl;
|
||||
// If the database is down mark nobody as a mod
|
||||
if(!user_exists(name)){
|
||||
return false;
|
||||
}
|
||||
return conn.get_user_int(db_extra_table_, "user_is_moderator", name) == 1 || (mp_mod_group_ != 0 && conn.is_user_in_group(name, mp_mod_group_));
|
||||
}
|
||||
|
||||
void fuh::set_is_moderator(const std::string& name, const bool& is_moderator) {
|
||||
|
||||
if(!user_exists(name)) return;
|
||||
|
||||
try {
|
||||
write_detail(name, "user_is_moderator", static_cast<int>(is_moderator));
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not set is_moderator for user '" << name << "' :" << e.message << std::endl;
|
||||
if(!user_exists(name)){
|
||||
return;
|
||||
}
|
||||
conn.write_user_int("user_is_moderator", name, is_moderator);
|
||||
}
|
||||
|
||||
fuh::ban_info fuh::user_is_banned(const std::string& name, const std::string& addr)
|
||||
|
@ -184,95 +139,24 @@ fuh::ban_info fuh::user_is_banned(const std::string& name, const std::string& ad
|
|||
// prepared SQL statement API right now. However, they are basically
|
||||
// never used on forums.wesnoth.org, so this shouldn't be a problem
|
||||
// for the time being.
|
||||
//
|
||||
|
||||
// NOTE: A ban end time of 0 is a permanent ban.
|
||||
const std::string& is_extant_ban_sql =
|
||||
"ban_exclude = 0 AND (ban_end = 0 OR ban_end >=" + std::to_string(std::time(nullptr)) + ")";
|
||||
|
||||
// TODO: retrieve full ban info in a single statement instead of issuing
|
||||
// separate queries to check for a ban's existence and its duration.
|
||||
|
||||
try {
|
||||
if(!addr.empty() && prepared_statement<bool>("SELECT 1 FROM `" + db_banlist_table_ + "` WHERE UPPER(ban_ip) = UPPER(?) AND " + is_extant_ban_sql, addr)) {
|
||||
ban_check b = conn.get_ban_info(name, addr);
|
||||
switch(b.get_ban_type())
|
||||
{
|
||||
case BAN_NONE:
|
||||
return {};
|
||||
case BAN_IP:
|
||||
LOG_UH << "User '" << name << "' ip " << addr << " banned by IP address\n";
|
||||
return retrieve_ban_info(BAN_IP, addr);
|
||||
}
|
||||
} catch(const sql_error& e) {
|
||||
ERR_UH << "Could not check forum bans on address '" << addr << "' :" << e.message << '\n';
|
||||
return {};
|
||||
return { BAN_IP, b.get_ban_duration() };
|
||||
case BAN_USER:
|
||||
LOG_UH << "User '" << name << "' uid " << b.get_user_id() << " banned by uid\n";
|
||||
return { BAN_USER, b.get_ban_duration() };
|
||||
case BAN_EMAIL:
|
||||
LOG_UH << "User '" << name << "' email " << b.get_email() << " banned by email address\n";
|
||||
return { BAN_EMAIL, b.get_ban_duration() };
|
||||
default:
|
||||
ERR_UH << "Invalid ban type '" << b.get_ban_type() << "' returned for user '" << name << "'\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
if(!user_exists(name)) return {};
|
||||
|
||||
try {
|
||||
auto uid = get_detail_for_user<unsigned int>(name, "user_id");
|
||||
|
||||
if(uid == 0) {
|
||||
ERR_UH << "Invalid user id for user '" << name << "'\n";
|
||||
} else if(prepared_statement<bool>("SELECT 1 FROM `" + db_banlist_table_ + "` WHERE ban_userid = ? AND " + is_extant_ban_sql, uid)) {
|
||||
LOG_UH << "User '" << name << "' uid " << uid << " banned by uid\n";
|
||||
return retrieve_ban_info(BAN_USER, uid);
|
||||
}
|
||||
|
||||
auto email = get_detail_for_user<std::string>(name, "user_email");
|
||||
|
||||
if(!email.empty() && prepared_statement<bool>("SELECT 1 FROM `" + db_banlist_table_ + "` WHERE UPPER(ban_email) = UPPER(?) AND " + is_extant_ban_sql, email)) {
|
||||
LOG_UH << "User '" << name << "' email " << email << " banned by email address\n";
|
||||
return retrieve_ban_info(BAN_EMAIL, email);
|
||||
}
|
||||
|
||||
} catch(const sql_error& e) {
|
||||
ERR_UH << "Could not check forum bans on user '" << name << "' :" << e.message << '\n';
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
fuh::ban_info fuh::retrieve_ban_info(fuh::BAN_TYPE type, T detail)
|
||||
{
|
||||
std::string col;
|
||||
|
||||
switch(type) {
|
||||
case BAN_USER:
|
||||
col = "ban_userid";
|
||||
break;
|
||||
case BAN_EMAIL:
|
||||
col = "ban_email";
|
||||
break;
|
||||
case BAN_IP:
|
||||
col = "ban_ip";
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
return { type, retrieve_ban_duration_internal(col, detail) };
|
||||
} catch(const sql_error& e) {
|
||||
//
|
||||
// NOTE:
|
||||
// If retrieve_ban_internal() fails to fetch the ban row, odds are the ban was
|
||||
// lifted in the meantime (it's meant to be called by user_is_banned(), so we
|
||||
// assume the ban expires in one second instead of returning 0 (permanent ban)
|
||||
// just to err on the safe side (returning BAN_NONE would be a terrible idea,
|
||||
// for that matter).
|
||||
//
|
||||
return { type, 1 };
|
||||
}
|
||||
}
|
||||
|
||||
std::time_t fuh::retrieve_ban_duration_internal(const std::string& col, const std::string& detail)
|
||||
{
|
||||
const std::time_t end_time = prepared_statement<int>("SELECT `ban_end` FROM `" + db_banlist_table_ + "` WHERE UPPER(" + col + ") = UPPER(?)", detail);
|
||||
return end_time ? end_time - std::time(nullptr) : 0;
|
||||
}
|
||||
|
||||
std::time_t fuh::retrieve_ban_duration_internal(const std::string& col, unsigned int detail)
|
||||
{
|
||||
const std::time_t end_time = prepared_statement<int>("SELECT `ban_end` FROM `" + db_banlist_table_ + "` WHERE " + col + " = ?", detail);
|
||||
return end_time ? end_time - std::time(nullptr) : 0;
|
||||
}
|
||||
|
||||
std::string fuh::user_info(const std::string& name) {
|
||||
|
@ -304,175 +188,47 @@ std::string fuh::user_info(const std::string& name) {
|
|||
}
|
||||
|
||||
std::string fuh::get_hash(const std::string& user) {
|
||||
try {
|
||||
return get_detail_for_user<std::string>(user, "user_password");
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not retrieve password for user '" << user << "' :" << e.message << std::endl;
|
||||
return "";
|
||||
}
|
||||
return conn.get_user_string(db_users_table_, "user_password", user);
|
||||
}
|
||||
|
||||
std::time_t fuh::get_lastlogin(const std::string& user) {
|
||||
try {
|
||||
int time_int = get_writable_detail_for_user<int>(user, "user_lastvisit");
|
||||
return std::time_t(time_int);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not retrieve last visit for user '" << user << "' :" << e.message << std::endl;
|
||||
return std::time_t(0);
|
||||
}
|
||||
return std::time_t(conn.get_user_int(db_extra_table_, "user_lastvisit", user));
|
||||
}
|
||||
|
||||
std::time_t fuh::get_registrationdate(const std::string& user) {
|
||||
try {
|
||||
int time_int = get_detail_for_user<int>(user, "user_regdate");
|
||||
return std::time_t(time_int);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not retrieve registration date for user '" << user << "' :" << e.message << std::endl;
|
||||
return std::time_t(0);
|
||||
}
|
||||
return std::time_t(conn.get_user_int(db_users_table_, "user_regdate", user));
|
||||
}
|
||||
|
||||
void fuh::set_lastlogin(const std::string& user, const std::time_t& lastlogin) {
|
||||
|
||||
try {
|
||||
write_detail(user, "user_lastvisit", static_cast<int>(lastlogin));
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not set last visit for user '" << user << "' :" << e.message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline T fuh::prepared_statement(const std::string& sql, Args&&... args)
|
||||
{
|
||||
try {
|
||||
return ::prepared_statement<T>(conn, sql, std::forward<Args>(args)...);
|
||||
} catch (const sql_error& e) {
|
||||
WRN_UH << "caught sql error: " << e.message << std::endl;
|
||||
WRN_UH << "trying to reconnect and retry..." << std::endl;
|
||||
//Try to reconnect and execute query again
|
||||
mysql_close(conn);
|
||||
conn = mysql_init(nullptr);
|
||||
mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8mb4");
|
||||
if(!conn || !mysql_real_connect(conn, db_host_.c_str(), db_user_.c_str(), db_password_.c_str(), db_name_.c_str(), 0, nullptr, 0)) {
|
||||
ERR_UH << "Could not connect to database: " << mysql_errno(conn) << ": " << mysql_error(conn) << std::endl;
|
||||
throw sql_error("Error querying database.");
|
||||
}
|
||||
}
|
||||
return ::prepared_statement<T>(conn, sql, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T fuh::get_detail_for_user(const std::string& name, const std::string& detail) {
|
||||
return prepared_statement<T>(
|
||||
"SELECT `" + detail + "` FROM `" + db_users_table_ + "` WHERE UPPER(username)=UPPER(?)",
|
||||
name);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T fuh::get_writable_detail_for_user(const std::string& name, const std::string& detail) {
|
||||
if(!extra_row_exists(name)) throw sql_error("row doesn't exist");
|
||||
return prepared_statement<T>(
|
||||
"SELECT `" + detail + "` FROM `" + db_extra_table_ + "` WHERE UPPER(username)=UPPER(?)",
|
||||
name);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void fuh::write_detail(const std::string& name, const std::string& detail, T&& value) {
|
||||
try {
|
||||
// Check if we do already have a row for this user in the extra table
|
||||
if(!extra_row_exists(name)) {
|
||||
// If not create the row
|
||||
prepared_statement<void>("INSERT INTO `" + db_extra_table_ + "` VALUES(?,?,'0')", name, std::forward<T>(value));
|
||||
}
|
||||
prepared_statement<void>("UPDATE `" + db_extra_table_ + "` SET " + detail + "=? WHERE UPPER(username)=UPPER(?)", std::forward<T>(value), name);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not set detail for user '" << name << "': " << e.message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool fuh::is_user_in_group(const std::string& name, unsigned int group_id) {
|
||||
try {
|
||||
return prepared_statement<bool>("SELECT 1 FROM `" + db_users_table_ + "` u, `" + db_user_group_table_ + "` ug WHERE UPPER(u.username)=UPPER(?) AND u.USER_ID = ug.USER_ID AND ug.GROUP_ID = ?", name, group_id);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not execute test query for user group '" << group_id << "' and username '" << name << "'" << e.message << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool fuh::extra_row_exists(const std::string& name) {
|
||||
|
||||
// Make a test query for this username
|
||||
try {
|
||||
return prepared_statement<bool>("SELECT 1 FROM `" + db_extra_table_ + "` WHERE UPPER(username)=UPPER(?)", name);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not execute test query for user '" << name << "' :" << e.message << std::endl;
|
||||
return false;
|
||||
}
|
||||
conn.write_user_int("user_lastvisit", user, static_cast<int>(lastlogin));
|
||||
}
|
||||
|
||||
std::string fuh::get_uuid(){
|
||||
try {
|
||||
return prepared_statement<std::string>("SELECT UUID()");
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not retrieve a UUID:" << e.message << std::endl;
|
||||
return "";
|
||||
}
|
||||
return conn.get_uuid();
|
||||
}
|
||||
|
||||
// TODO - WIP
|
||||
// select substring(substring_index(topic_title, ']', 1), 2) as STATUS, concat('https://r.wesnoth.org/t', topic_id) as URL, substring_index(topic_title, ']', -1) as TITLE from tournaments where forum_id = 70 and (topic_title like '[Open]%' or topic_title like '[In Progress]%')
|
||||
std::string fuh::get_tournaments(){
|
||||
try {
|
||||
return "";
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "TBD:" << e.message << std::endl;
|
||||
return "";
|
||||
}
|
||||
return conn.get_tournaments();
|
||||
}
|
||||
|
||||
void fuh::db_insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, const std::string& map_name, const std::string& era_name, int reload, int observers, int is_public, int has_password){
|
||||
try {
|
||||
prepared_statement<void>("INSERT INTO `" + db_game_info_table_ + "`(INSTANCE_UUID, GAME_ID, INSTANCE_VERSION, GAME_NAME, MAP_NAME, ERA_NAME, RELOAD, OBSERVERS, PUBLIC, PASSWORD) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
uuid, game_id, version, name, map_name, era_name, reload, observers, is_public, has_password);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not insert into table `" + db_game_info_table_ + "`:" << e.message << std::endl;
|
||||
}
|
||||
conn.insert_game_info(uuid, game_id, version, name, map_name, era_name, reload, observers, is_public, has_password);
|
||||
}
|
||||
|
||||
void fuh::db_update_game_end(const std::string& uuid, int game_id, const std::string& replay_location){
|
||||
try {
|
||||
prepared_statement<void>("UPDATE `" + db_game_info_table_ + "` SET END_TIME = CURRENT_TIMESTAMP, REPLAY_NAME = ? WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
|
||||
replay_location, uuid, game_id);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not update the game's ending information on table `" + db_game_info_table_ + "`:" << e.message << std::endl;
|
||||
}
|
||||
conn.update_game_end(uuid, game_id, replay_location);
|
||||
}
|
||||
|
||||
void fuh::db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user){
|
||||
try {
|
||||
prepared_statement<void>("INSERT INTO `" + db_game_player_info_table_ + "`(INSTANCE_UUID, GAME_ID, USER_ID, SIDE_NUMBER, IS_HOST, FACTION, CLIENT_VERSION, CLIENT_SOURCE, USER_NAME) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?)",
|
||||
uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not insert the game's player information on table `" + db_game_player_info_table_ + "`:" << e.message << std::endl;
|
||||
}
|
||||
conn.insert_game_player_info(uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
|
||||
}
|
||||
|
||||
void fuh::db_insert_modification_info(const std::string& uuid, int game_id, const std::string& modification_name){
|
||||
try {
|
||||
prepared_statement<void>("INSERT INTO `" + db_game_modification_info_table_ + "`(INSTANCE_UUID, GAME_ID, MODIFICATION_NAME) VALUES(?, ?, ?)",
|
||||
uuid, game_id, modification_name);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not insert the game's modification information on table `" + db_game_modification_info_table_ + "`:" << e.message << std::endl;
|
||||
}
|
||||
conn.insert_modification_info(uuid, game_id, modification_name);
|
||||
}
|
||||
|
||||
void fuh::db_set_oos_flag(const std::string& uuid, int game_id){
|
||||
try {
|
||||
prepared_statement<void>("UPDATE `" + db_game_info_table_ + "` SET OOS = 1 WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
|
||||
uuid, game_id);
|
||||
} catch (const sql_error& e) {
|
||||
ERR_UH << "Could not update the game's OOS flag on table `" + db_game_info_table_ + "`:" << e.message << std::endl;
|
||||
}
|
||||
conn.set_oos_flag(uuid, game_id);
|
||||
}
|
||||
|
||||
#endif //HAVE_MYSQLPP
|
||||
|
|
|
@ -15,13 +15,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "server/user_handler.hpp"
|
||||
#include "dbconn.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ctime>
|
||||
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
// The [user_handler] section in the server configuration
|
||||
// file could look like this:
|
||||
//
|
||||
|
@ -41,7 +40,6 @@
|
|||
class fuh : public user_handler {
|
||||
public:
|
||||
fuh(const config& c);
|
||||
~fuh();
|
||||
|
||||
bool login(const std::string& name, const std::string& password, const std::string& seed);
|
||||
|
||||
|
@ -64,7 +62,6 @@ class fuh : public user_handler {
|
|||
|
||||
ban_info user_is_banned(const std::string& name, const std::string& addr);
|
||||
|
||||
// Throws user_handler::error
|
||||
std::string user_info(const std::string& name);
|
||||
|
||||
bool use_phpbb_encryption() const { return true; }
|
||||
|
@ -78,40 +75,16 @@ class fuh : public user_handler {
|
|||
void db_set_oos_flag(const std::string& uuid, int game_id);
|
||||
|
||||
private:
|
||||
dbconn conn;
|
||||
std::string db_users_table_;
|
||||
std::string db_extra_table_;
|
||||
int mp_mod_group_;
|
||||
|
||||
std::string get_hash(const std::string& user);
|
||||
std::time_t get_lastlogin(const std::string& user);
|
||||
std::time_t get_registrationdate(const std::string& user);
|
||||
bool is_inactive(const std::string& user);
|
||||
|
||||
void set_lastlogin(const std::string& user, const std::time_t& lastlogin);
|
||||
|
||||
template<typename T>
|
||||
ban_info retrieve_ban_info(BAN_TYPE, T detail);
|
||||
|
||||
std::time_t retrieve_ban_duration_internal(const std::string& col, const std::string& detail);
|
||||
std::time_t retrieve_ban_duration_internal(const std::string& col, unsigned int detail);
|
||||
|
||||
std::string db_name_, db_host_, db_user_, db_password_, db_users_table_, db_banlist_table_, db_extra_table_, db_game_info_table_, db_game_player_info_table_, db_game_modification_info_table_, db_user_group_table_;
|
||||
std::string db_tournament_query_;
|
||||
unsigned int mp_mod_group_;
|
||||
|
||||
MYSQL *conn;
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline T prepared_statement(const std::string& sql, Args&&...);
|
||||
// Query a detail for a particular user from the database
|
||||
template<typename T>
|
||||
T get_detail_for_user(const std::string& name, const std::string& detail);
|
||||
template<typename T>
|
||||
T get_writable_detail_for_user(const std::string& name, const std::string& detail);
|
||||
|
||||
// Write something to the write table
|
||||
template<typename T>
|
||||
void write_detail(const std::string& name, const std::string& detail, T&& value);
|
||||
|
||||
// Same as user_exists() but checks if we have a row for this user in the extra table
|
||||
bool extra_row_exists(const std::string& name);
|
||||
|
||||
bool is_user_in_group(const std::string& name, unsigned int group_id);
|
||||
bool is_user_in_group(const std::string& name, int group_id);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,245 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2016 by Sergey Popov <loonycyborg@gmail.com>
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License 2
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef MYSQL_PREPARED_STATEMENT_IPP
|
||||
#define MYSQL_PREPARED_STATEMENT_IPP
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#define BOOST_SCOPE_EXIT_CONFIG_USE_LAMBDAS
|
||||
#include <boost/scope_exit.hpp>
|
||||
|
||||
#include <mysql/mysql.h>
|
||||
#if !defined(MARIADB_VERSION_ID) && defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 80000
|
||||
using my_bool = bool;
|
||||
#endif
|
||||
|
||||
#include "exceptions.hpp"
|
||||
|
||||
struct sql_error : public game::error
|
||||
{
|
||||
bool no_data = false;
|
||||
sql_error(const std::string& message, const std::string& sql, bool no_data = false)
|
||||
: game::error("Error evaluating SQL statement: '" + sql + "': " + message), no_data(no_data) {}
|
||||
sql_error(const std::string& message) : game::error(message) {}
|
||||
};
|
||||
|
||||
// make_bind functions embed pointers to their arguments in the
|
||||
// MYSQL_BIND structure returned. It's caller's responsibility
|
||||
// to ensure that argument's lifetime doesn't end before mysql
|
||||
// is done with those MYSQL_BINDs
|
||||
static MYSQL_BIND make_bind(const std::string& str, my_bool* is_null = 0)
|
||||
{
|
||||
MYSQL_BIND result;
|
||||
memset(&result, 0, sizeof (MYSQL_BIND));
|
||||
result.buffer_type = MYSQL_TYPE_STRING;
|
||||
result.buffer = const_cast<void*>(static_cast<const void*>(str.c_str()));
|
||||
result.buffer_length = str.size();
|
||||
result.is_unsigned = 0;
|
||||
result.is_null = is_null;
|
||||
result.length = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static MYSQL_BIND make_bind(char* str, std::size_t* len, my_bool* is_null = 0)
|
||||
{
|
||||
MYSQL_BIND result;
|
||||
memset(&result, 0, sizeof (MYSQL_BIND));
|
||||
result.buffer_type = MYSQL_TYPE_STRING;
|
||||
result.buffer = static_cast<void*>(str);
|
||||
result.buffer_length = *len;
|
||||
result.is_unsigned = 0;
|
||||
result.is_null = is_null;
|
||||
result.length = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
static MYSQL_BIND make_bind(int& i, my_bool* is_null = 0)
|
||||
{
|
||||
MYSQL_BIND result;
|
||||
memset(&result, 0, sizeof (MYSQL_BIND));
|
||||
result.buffer_type = MYSQL_TYPE_LONG;
|
||||
result.buffer = static_cast<void*>(&i);
|
||||
result.is_unsigned = 0;
|
||||
result.is_null = is_null;
|
||||
return result;
|
||||
}
|
||||
|
||||
static MYSQL_BIND make_bind(unsigned int& i, my_bool* is_null = 0)
|
||||
{
|
||||
MYSQL_BIND result;
|
||||
memset(&result, 0, sizeof (MYSQL_BIND));
|
||||
result.buffer_type = MYSQL_TYPE_LONG;
|
||||
result.buffer = static_cast<void*>(&i);
|
||||
result.is_unsigned = 1;
|
||||
result.is_null = is_null;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename... Args> constexpr auto make_binds(Args&&... args)
|
||||
-> std::array<MYSQL_BIND, sizeof...(Args)>
|
||||
{
|
||||
return { { (make_bind(std::forward<Args>(args))) ... } };
|
||||
}
|
||||
|
||||
template<typename T> T fetch_result(MYSQL_STMT* stmt, const std::string& sql);
|
||||
template<> std::string fetch_result<std::string>(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
char* buf = nullptr;
|
||||
std::string result;
|
||||
std::size_t len = 0;
|
||||
my_bool is_null;
|
||||
MYSQL_BIND result_bind[1] = { make_bind(buf, &len, &is_null) };
|
||||
|
||||
if(mysql_stmt_bind_result(stmt, result_bind) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
|
||||
BOOST_SCOPE_EXIT(&stmt) {
|
||||
mysql_stmt_free_result(stmt);
|
||||
} ;
|
||||
|
||||
mysql_stmt_store_result(stmt);
|
||||
|
||||
int res = mysql_stmt_fetch(stmt);
|
||||
if(res == MYSQL_NO_DATA)
|
||||
throw sql_error("no data returned", sql, true);
|
||||
if(is_null)
|
||||
throw sql_error("null value returned", sql);
|
||||
if(res != MYSQL_DATA_TRUNCATED)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
if(len > 0) {
|
||||
buf = new char[len];
|
||||
result_bind[0].buffer = buf;
|
||||
result_bind[0].buffer_length = len;
|
||||
res = mysql_stmt_fetch_column(stmt, result_bind, 0, 0);
|
||||
result = std::string(buf, len);
|
||||
delete[] buf;
|
||||
}
|
||||
if(res == MYSQL_NO_DATA)
|
||||
throw sql_error("no data returned", sql, true);
|
||||
if(res != 0)
|
||||
throw sql_error("mysql_stmt_fetch_column failed", sql);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T> T fetch_result_long_internal_(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
T result;
|
||||
my_bool is_null;
|
||||
MYSQL_BIND result_bind[1] = { make_bind(result, &is_null) };
|
||||
|
||||
if(mysql_stmt_bind_result(stmt, result_bind) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
|
||||
BOOST_SCOPE_EXIT(&stmt) {
|
||||
mysql_stmt_free_result(stmt);
|
||||
} ;
|
||||
|
||||
int res = mysql_stmt_fetch(stmt);
|
||||
if(res == MYSQL_NO_DATA)
|
||||
throw sql_error("no data returned", sql, true);
|
||||
if(is_null)
|
||||
throw sql_error("null value returned", sql);
|
||||
if(res != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> int fetch_result<int>(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
return fetch_result_long_internal_<int>(stmt, sql);
|
||||
}
|
||||
|
||||
template<> unsigned int fetch_result<unsigned int>(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
return fetch_result_long_internal_<unsigned int>(stmt, sql);
|
||||
}
|
||||
|
||||
template<> bool fetch_result<bool>(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
int result;
|
||||
my_bool is_null;
|
||||
MYSQL_BIND result_bind[1] = { make_bind(result, &is_null) };
|
||||
|
||||
if(mysql_stmt_bind_result(stmt, result_bind) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
|
||||
BOOST_SCOPE_EXIT(&stmt) {
|
||||
mysql_stmt_free_result(stmt);
|
||||
} ;
|
||||
|
||||
int res = mysql_stmt_fetch(stmt);
|
||||
if(res == MYSQL_NO_DATA)
|
||||
return false;
|
||||
if(is_null)
|
||||
throw sql_error("null value returned", sql);
|
||||
if(res != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt), sql);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename C> C fetch_result(MYSQL_STMT* stmt, const std::string& sql)
|
||||
{
|
||||
C result;
|
||||
|
||||
try {
|
||||
while(true)
|
||||
result.push_back(fetch_result<typename C::value_type>(stmt, sql));
|
||||
} catch(const sql_error& e) {
|
||||
if(!e.no_data)
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<> void fetch_result<void>(MYSQL_STMT*, const std::string&)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an sql query using mysql prepared statements API
|
||||
* This function can convert its arguments and results to appropriate
|
||||
* MYSQL_BIND structures automatically based on their C++ type
|
||||
* though each type requires explicit support. For now only ints and
|
||||
* std::strings are supported.
|
||||
* Setting return type to bool causes this function to do a test query
|
||||
* and return true if there is any data in result set, false otherwise
|
||||
*/
|
||||
template<typename R, typename... Args>
|
||||
R prepared_statement(MYSQL* conn, const std::string& sql, Args&&... args)
|
||||
{
|
||||
auto arg_binds = make_binds(args...);
|
||||
|
||||
std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)> stmt{mysql_stmt_init(conn), mysql_stmt_close};
|
||||
if(stmt == nullptr)
|
||||
throw sql_error("mysql_stmt_init failed", sql);
|
||||
|
||||
if(mysql_stmt_prepare(stmt.get(), sql.c_str(), sql.size()) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt.get()), sql);
|
||||
|
||||
if(mysql_stmt_bind_param(stmt.get(), arg_binds.data()) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt.get()), sql);
|
||||
|
||||
if(mysql_stmt_execute(stmt.get()) != 0)
|
||||
throw sql_error(mysql_stmt_error(stmt.get()), sql);
|
||||
|
||||
return fetch_result<R>(stmt.get(), sql);
|
||||
}
|
||||
|
||||
#endif // MYSQL_PREPARED_STATEMENT_IPP
|
60
src/server/resultsets/ban_check.cpp
Normal file
60
src/server/resultsets/ban_check.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MYSQLPP
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "ban_check.hpp"
|
||||
#include "server/user_handler.hpp"
|
||||
|
||||
ban_check::ban_check()
|
||||
{
|
||||
ban_type = user_handler::BAN_TYPE::BAN_NONE;
|
||||
ban_duration = 0;
|
||||
user_id = 0;
|
||||
email = "";
|
||||
}
|
||||
|
||||
void ban_check::read(mariadb::result_set_ref rslt)
|
||||
{
|
||||
if(rslt->next())
|
||||
{
|
||||
ban_type = rslt->get_signed64("ban_type");
|
||||
ban_duration = rslt->get_signed32("ban_end") != 0 ? rslt->get_signed32("ban_end") - std::time(nullptr) : 0;
|
||||
user_id = rslt->get_signed32("ban_userid");
|
||||
email = rslt->get_string("ban_email");
|
||||
}
|
||||
}
|
||||
|
||||
long ban_check::get_ban_type()
|
||||
{
|
||||
return ban_type;
|
||||
}
|
||||
|
||||
int ban_check::get_ban_duration()
|
||||
{
|
||||
return ban_duration;
|
||||
}
|
||||
|
||||
int ban_check::get_user_id()
|
||||
{
|
||||
return user_id;
|
||||
}
|
||||
|
||||
std::string ban_check::get_email()
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
#endif //HAVE_MYSQLPP
|
35
src/server/resultsets/ban_check.hpp
Normal file
35
src/server/resultsets/ban_check.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mariadb++/result_set.hpp>
|
||||
|
||||
#include "rs_base.hpp"
|
||||
|
||||
class ban_check : public rs_base
|
||||
{
|
||||
public:
|
||||
ban_check();
|
||||
void read(mariadb::result_set_ref rslt);
|
||||
long get_ban_type();
|
||||
int get_ban_duration();
|
||||
int get_user_id();
|
||||
std::string get_email();
|
||||
|
||||
private:
|
||||
long ban_type;
|
||||
int ban_duration;
|
||||
int user_id;
|
||||
std::string email;
|
||||
};
|
24
src/server/resultsets/rs_base.hpp
Normal file
24
src/server/resultsets/rs_base.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mariadb++/result_set.hpp>
|
||||
|
||||
class rs_base
|
||||
{
|
||||
public:
|
||||
rs_base(){}
|
||||
virtual ~rs_base(){}
|
||||
virtual void read(mariadb::result_set_ref rslt) =0;
|
||||
};
|
36
src/server/resultsets/tournaments.cpp
Normal file
36
src/server/resultsets/tournaments.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MYSQLPP
|
||||
|
||||
#include "tournaments.hpp"
|
||||
|
||||
void tournaments::read(mariadb::result_set_ref rslt)
|
||||
{
|
||||
while(rslt->next())
|
||||
{
|
||||
rows.push_back(data{ rslt->get_string("TITLE"), rslt->get_string("STATUS"), rslt->get_string("URL") });
|
||||
}
|
||||
}
|
||||
|
||||
std::string tournaments::str()
|
||||
{
|
||||
std::string text;
|
||||
for(const auto& row : rows)
|
||||
{
|
||||
text += "\nThe tournament "+row.title+" is "+row.status+". More information can be found at "+row.url;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
#endif //HAVE_MYSQLPP
|
36
src/server/resultsets/tournaments.hpp
Normal file
36
src/server/resultsets/tournaments.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mariadb++/result_set.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "rs_base.hpp"
|
||||
|
||||
class tournaments : public rs_base
|
||||
{
|
||||
struct data
|
||||
{
|
||||
std::string title;
|
||||
std::string status;
|
||||
std::string url;
|
||||
};
|
||||
|
||||
public:
|
||||
void read(mariadb::result_set_ref rslt);
|
||||
std::string str();
|
||||
|
||||
private:
|
||||
std::vector<data> rows;
|
||||
};
|
|
@ -78,10 +78,10 @@ class user_handler {
|
|||
/** Ban type values */
|
||||
enum BAN_TYPE
|
||||
{
|
||||
BAN_NONE, /**< Not a ban */
|
||||
BAN_USER, /**< User account/name ban */
|
||||
BAN_IP, /**< IP address ban */
|
||||
BAN_EMAIL, /**< Account email address ban */
|
||||
BAN_NONE = 0, /**< Not a ban */
|
||||
BAN_IP = 1, /**< IP address ban */
|
||||
BAN_USER = 2, /**< User account/name ban */
|
||||
BAN_EMAIL = 3, /**< Account email address ban */
|
||||
};
|
||||
|
||||
/** Ban status description */
|
||||
|
|
|
@ -25,10 +25,4 @@ RUN yes | pip3 install paramiko
|
|||
# programs
|
||||
RUN apt install -y -qq openssl gdb xvfb bzip2 git scons cmake make ccache gcc g++ clang lld
|
||||
|
||||
# mariadbpp
|
||||
RUN git clone --depth 1 https://github.com/viaduck/mariadbpp.git mariadbpp && \
|
||||
cd mariadbpp && git submodule update --init && mkdir build && cd build && \
|
||||
cmake .. && \
|
||||
make install
|
||||
|
||||
WORKDIR /home/wesnoth-travis
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
-- table which the forum inserts bans into, which wesnothd checks during login
|
||||
-- create table ban
|
||||
-- (
|
||||
-- BAN_USERID VARCHAR(100) NOT NULL,
|
||||
-- BAN_USERID INT(10) UNSIGNED NOT NULL,
|
||||
-- BAN_END INT(10) UNSIGNED NOT NULL DEFAULT 0,
|
||||
-- BAN_IP VARCHAR(100) DEFAULT NULL,
|
||||
-- BAN_EMAIL VARCHAR(100) DEFAULT NULL,
|
||||
|
|
Loading…
Add table
Reference in a new issue