From 39d5a02a3176875257ae8b59383fa7ff846e09a1 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Wed, 21 Dec 2022 01:17:42 +0100 Subject: [PATCH] Initial release of adventure agency (#7224) Thanks to @Dia, @OptimusM, @Balferian and @ecdarreola --- conf/inter_athena.conf | 3 +- sql-files/main.sql | 21 + sql-files/upgrades/upgrade_20221220.sql | 20 + src/map/clif.cpp | 120 +++++ src/map/clif_packetdb.hpp | 5 + src/map/map.cpp | 3 + src/map/map.hpp | 1 + src/map/packets.hpp | 34 ++ src/map/party.cpp | 100 +++++ src/map/party.hpp | 8 + src/map/pc.hpp | 2 + src/web/partybooking_controller.cpp | 569 ++++++++++++++++++++++++ src/web/partybooking_controller.hpp | 16 + src/web/sqllock.cpp | 10 + src/web/sqllock.hpp | 1 + src/web/web-server.vcxproj | 2 + src/web/web-server.vcxproj.filters | 18 +- src/web/web.cpp | 76 +++- src/web/web.hpp | 2 + 19 files changed, 991 insertions(+), 20 deletions(-) create mode 100644 sql-files/upgrades/upgrade_20221220.sql create mode 100644 src/web/partybooking_controller.cpp create mode 100644 src/web/partybooking_controller.hpp diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index cbc07d7cae..aca5da4274 100644 --- a/conf/inter_athena.conf +++ b/conf/inter_athena.conf @@ -158,6 +158,7 @@ renewal-mob_skill_table: mob_skill_db_re mob_skill2_table: mob_skill_db2 renewal-mob_skill2_table: mob_skill_db2_re mapreg_table: mapreg +partybookings_table: party_bookings sales_table: sales vending_table: vendings vending_items_table: vending_items @@ -166,7 +167,7 @@ roulette_table: db_roulette guild_storage_log: guild_storage_log // Web Database Tables -// NOTE: The web server reads the login (login) and char (guild) tables, so it needs +// NOTE: The web server reads the login (login) and char (party,guild) tables and map (party_bookings), so it needs // the ability to connect to those databases. guild_emblems: guild_emblems user_configs: user_configs diff --git a/sql-files/main.sql b/sql-files/main.sql index 6de5038a82..f9b7b49529 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -973,6 +973,27 @@ CREATE TABLE IF NOT EXISTS `party` ( PRIMARY KEY (`party_id`) ) ENGINE=MyISAM; +-- +-- Table structure for table `party_bookings` +-- + +CREATE TABLE IF NOT EXISTS `party_bookings` ( + `world_name` varchar(32) NOT NULL, + `account_id` int(11) unsigned NOT NULL, + `char_id` int(11) unsigned NOT NULL, + `char_name` varchar(23) NOT NULL, + `purpose` smallint(5) unsigned NOT NULL DEFAULT '0', + `assist` tinyint(3) unsigned NOT NULL DEFAULT '0', + `damagedealer` tinyint(3) unsigned NOT NULL DEFAULT '0', + `healer` tinyint(3) unsigned NOT NULL DEFAULT '0', + `tanker` tinyint(3) unsigned NOT NULL DEFAULT '0', + `minimum_level` smallint(5) unsigned NOT NULL, + `maximum_level` smallint(5) unsigned NOT NULL, + `comment` varchar(255) NOT NULL DEFAULT '', + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`world_name`, `account_id`, `char_id`) +) ENGINE=MyISAM; + -- -- Table structure for table `pet` -- diff --git a/sql-files/upgrades/upgrade_20221220.sql b/sql-files/upgrades/upgrade_20221220.sql new file mode 100644 index 0000000000..25c1dead93 --- /dev/null +++ b/sql-files/upgrades/upgrade_20221220.sql @@ -0,0 +1,20 @@ +-- +-- Table structure for table `party_bookings` +-- + +CREATE TABLE IF NOT EXISTS `party_bookings` ( + `world_name` varchar(32) NOT NULL, + `account_id` int(11) unsigned NOT NULL, + `char_id` int(11) unsigned NOT NULL, + `char_name` varchar(23) NOT NULL, + `purpose` smallint(5) unsigned NOT NULL DEFAULT '0', + `assist` tinyint(3) unsigned NOT NULL DEFAULT '0', + `damagedealer` tinyint(3) unsigned NOT NULL DEFAULT '0', + `healer` tinyint(3) unsigned NOT NULL DEFAULT '0', + `tanker` tinyint(3) unsigned NOT NULL DEFAULT '0', + `minimum_level` smallint(5) unsigned NOT NULL, + `maximum_level` smallint(5) unsigned NOT NULL, + `comment` varchar(255) NOT NULL DEFAULT '', + `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`world_name`, `account_id`, `char_id`) +) ENGINE=MyISAM; diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 2d6ed60654..a8c521e0b4 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -24853,6 +24853,126 @@ void clif_dynamicnpc_result( map_session_data& sd, e_dynamicnpc_result result ){ #endif } +void clif_partybooking_ask( map_session_data* sd, map_session_data* joining_sd ){ +#if PACKETVER >= 20191204 + struct PACKET_ZC_PARTY_REQ_MASTER_TO_JOIN p = { 0 }; + + p.packetType = HEADER_ZC_PARTY_REQ_MASTER_TO_JOIN; + p.CID = joining_sd->status.char_id; + p.AID = joining_sd->status.account_id; + safestrncpy( p.name, joining_sd->status.name, NAME_LENGTH ); + p.x = joining_sd->status.base_level; + p.y = joining_sd->status.class_; + + clif_send( &p, sizeof( p ), &sd->bl, SELF ); +#endif +} + +void clif_parse_partybooking_join( int fd, map_session_data* sd ){ +#if PACKETVER >= 20191204 + struct PACKET_CZ_PARTY_REQ_MASTER_TO_JOIN* p = (struct PACKET_CZ_PARTY_REQ_MASTER_TO_JOIN*)RFIFOP( fd, 0 ); + + // Character is already in a party + if( sd->status.party_id != 0 ){ + return; + } + + map_session_data* tsd = map_charid2sd( p->CID ); + + // Target player is offline + if( tsd == nullptr ){ + return; + } + + if( tsd->status.account_id != p->AID ){ + return; + } + + struct s_party_booking_requirement requirement; + + if( !party_booking_load( tsd->status.account_id, tsd->status.char_id, &requirement ) ){ + return; + } + + if( sd->status.base_level < requirement.minimum_level ){ + return; + } + + if( sd->status.base_level > requirement.maximum_level ){ + return; + } + + // Already requested to join this party + if( util::vector_exists( tsd->party_booking_requests, sd->status.char_id ) ){ + return; + } + + // Store information that the player tried to join the party + tsd->party_booking_requests.push_back( sd->status.char_id ); + + clif_partybooking_ask( tsd, sd ); +#endif +} + +void clif_partybooking_reply( map_session_data* sd, map_session_data* party_leader_sd, bool accepted ){ +#if PACKETVER >= 20191204 + struct PACKET_ZC_PARTY_JOIN_REQ_ACK_FROM_MASTER p = { 0 }; + + if( party_leader_sd->status.party_id == 0 ){ + return; + } + + struct party_data* party = party_search( party_leader_sd->status.party_id ); + + if( party == nullptr ){ + return; + } + + p.packetType = HEADER_ZC_PARTY_JOIN_REQ_ACK_FROM_MASTER; + safestrncpy( p.player_name, party_leader_sd->status.name, NAME_LENGTH ); + safestrncpy( p.party_name, party->party.name, NAME_LENGTH ); + p.AID = party_leader_sd->status.account_id; + p.refused = !accepted; + + clif_send( &p, sizeof( p ), &sd->bl, SELF ); +#endif +} + +void clif_parse_partybooking_reply( int fd, map_session_data* sd ){ +#if PACKETVER >= 20191204 + struct PACKET_CZ_PARTY_REQ_ACK_MASTER_TO_JOIN* p = (struct PACKET_CZ_PARTY_REQ_ACK_MASTER_TO_JOIN*)RFIFOP( fd, 0 ); + + map_session_data* tsd = map_charid2sd( p->CID ); + + // Target player is offline + if( tsd == nullptr ){ + return; + } + + if( tsd->status.account_id != p->AID ){ + return; + } + + // Check if the player even requested to join the party + if( !util::vector_exists( sd->party_booking_requests, p->CID ) ){ + return; + } + + util::vector_erase_if_exists( sd->party_booking_requests, p->CID ); + + // Only party leaders can reply + if( !party_isleader( sd ) ){ + return; + } + + if( p->accept ){ + party_join( tsd, sd->status.party_id ); + } + + clif_partybooking_reply( tsd, sd, p->accept ); +#endif +} + /*========================================== * Main client packet processing function *------------------------------------------*/ diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index e2ae5ab061..33dfc21a33 100644 --- a/src/map/clif_packetdb.hpp +++ b/src/map/clif_packetdb.hpp @@ -2409,6 +2409,11 @@ parseable_packet( HEADER_CZ_REQ_ITEMREPAIR2, sizeof( struct PACKET_CZ_REQ_ITEMREPAIR2 ), clif_parse_RepairItem, 0 ); #endif +#if PACKETVER >= 20191204 + parseable_packet( HEADER_CZ_PARTY_REQ_MASTER_TO_JOIN, sizeof( struct PACKET_CZ_PARTY_REQ_MASTER_TO_JOIN ), clif_parse_partybooking_join, 0 ); + parseable_packet( HEADER_CZ_PARTY_REQ_ACK_MASTER_TO_JOIN, sizeof( struct PACKET_CZ_PARTY_REQ_ACK_MASTER_TO_JOIN ), clif_parse_partybooking_reply, 0 ); +#endif + #if PACKETVER_MAIN_NUM >= 20200916 || PACKETVER_RE_NUM >= 20200724 parseable_packet( HEADER_CZ_UNCONFIRMED_TSTATUS_UP, sizeof( PACKET_CZ_UNCONFIRMED_TSTATUS_UP ), clif_parse_traitstatus_up, 0 ); parseable_packet( HEADER_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT, sizeof( struct PACKET_CZ_GRADE_ENCHANT_SELECT_EQUIPMENT ), clif_parse_enchantgrade_add, 0 ); diff --git a/src/map/map.cpp b/src/map/map.cpp index 18042f68a1..f4f86b3fe8 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -91,6 +91,7 @@ char sales_table[32] = "sales"; char vendings_table[32] = "vendings"; char vending_items_table[32] = "vending_items"; char market_table[32] = "market"; +char partybookings_table[32] = "party_bookings"; char roulette_table[32] = "db_roulette"; char guild_storage_log_table[32] = "guild_storage_log"; @@ -4169,6 +4170,8 @@ int inter_config_read(const char *cfgName) safestrncpy( vendings_table, w2, sizeof(vendings_table) ); else if( strcmpi( w1, "vending_items_table" ) == 0 ) safestrncpy(vending_items_table, w2, sizeof(vending_items_table)); + else if( strcmpi( w1, "partybookings_table" ) == 0 ) + safestrncpy(partybookings_table, w2, sizeof(partybookings_table)); else if( strcmpi(w1, "roulette_table") == 0) safestrncpy(roulette_table, w2, sizeof(roulette_table)); else if (strcmpi(w1, "market_table") == 0) diff --git a/src/map/map.hpp b/src/map/map.hpp index 4a206e0f78..6c471659a6 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -1268,6 +1268,7 @@ extern char mob_skill2_table[32]; extern char vendings_table[32]; extern char vending_items_table[32]; extern char market_table[32]; +extern char partybookings_table[32]; extern char roulette_table[32]; extern char guild_storage_log_table[32]; diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 7023e8f2a1..2055fa8448 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -423,6 +423,36 @@ struct PACKET_ZC_DYNAMICNPC_CREATE_RESULT{ int32 result; } __attribute__((packed)); +struct PACKET_CZ_PARTY_REQ_MASTER_TO_JOIN{ + int16 packetType; + uint32 CID; + uint32 AID; +} __attribute__((packed)); + +struct PACKET_ZC_PARTY_REQ_MASTER_TO_JOIN{ + int16 packetType; + uint32 CID; + uint32 AID; + char name[NAME_LENGTH]; + uint16 x; + uint16 y; +} __attribute__((packed)); + +struct PACKET_CZ_PARTY_REQ_ACK_MASTER_TO_JOIN{ + int16 packetType; + uint32 CID; + uint32 AID; + uint8 accept; +} __attribute__((packed)); + +struct PACKET_ZC_PARTY_JOIN_REQ_ACK_FROM_MASTER{ + int16 packetType; + char player_name[NAME_LENGTH]; + char party_name[NAME_LENGTH]; + uint32 AID; + uint32 refused; +} __attribute__((packed)); + // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 ) #pragma pack( pop ) @@ -480,6 +510,10 @@ DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE, 0xa46) DEFINE_PACKET_HEADER(ZC_STYLE_CHANGE_RES, 0xa47) DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CLOSE, 0xa48) DEFINE_PACKET_HEADER(ZC_GROUP_ISALIVE, 0xab2) +DEFINE_PACKET_HEADER(CZ_PARTY_REQ_MASTER_TO_JOIN, 0x0ae6) +DEFINE_PACKET_HEADER(ZC_PARTY_REQ_MASTER_TO_JOIN, 0x0ae7) +DEFINE_PACKET_HEADER(CZ_PARTY_REQ_ACK_MASTER_TO_JOIN, 0x0af8) +DEFINE_PACKET_HEADER(ZC_PARTY_JOIN_REQ_ACK_FROM_MASTER, 0x0afa) DEFINE_PACKET_HEADER(CZ_REQ_STYLE_CHANGE2, 0xafc) DEFINE_PACKET_HEADER(ZC_REMOVE_EFFECT, 0x0b0d) DEFINE_PACKET_HEADER(CZ_UNCONFIRMED_TSTATUS_UP, 0x0b24) diff --git a/src/map/party.cpp b/src/map/party.cpp index db3c2898f5..96c5bed141 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -18,6 +18,7 @@ #include "achievement.hpp" #include "atcommand.hpp" //msg_txt() #include "battle.hpp" +#include "chrif.hpp" // charserver_name #include "clif.hpp" #include "instance.hpp" #include "intif.hpp" @@ -452,6 +453,105 @@ int party_invite(map_session_data *sd,map_session_data *tsd) return 1; } +bool party_isleader( map_session_data* sd ){ + if( sd == nullptr ){ + return false; + } + + if( sd->status.party_id == 0 ){ + return false; + } + + struct party_data* party = party_search( sd->status.party_id ); + + if( party == nullptr ){ + return false; + } + + for( int i = 0; i < MAX_PARTY; i++ ){ + if( party->party.member[i].char_id == sd->status.char_id ){ + return party->party.member[i].leader != 0; + } + } + + return false; +} + +void party_join( map_session_data* sd, int party_id ){ + nullpo_retv( sd ); + + // Player is in a party already now + if( sd->status.party_id != 0 ){ + return; + } + + // Player is already associated with a party + if( sd->party_creating || sd->party_joining ){ + return; + } + + struct party_data* party = party_search( party_id ); + + if( party == nullptr ){ + return; + } + + int i; + + if( battle_config.block_account_in_same_party ){ + ARR_FIND( 0, MAX_PARTY, i, party->party.member[i].account_id == sd->status.account_id ); + + if( i < MAX_PARTY ){ + // Player is in the party with a different character already + return; + } + } + + // Confirm if there is an open slot in the party + ARR_FIND( 0, MAX_PARTY, i, party->party.member[i].account_id == 0 ); + + if( i == MAX_PARTY ){ + // Party is already full + return; + } + + struct party_member member = {}; + + sd->party_joining = true; + party_fill_member( &member, sd, 0 ); + intif_party_addmember( party_id, &member ); +} + +bool party_booking_load( uint32 account_id, uint32 char_id, struct s_party_booking_requirement* booking ){ + char world_name[NAME_LENGTH * 2 + 1]; + + Sql_EscapeString( mmysql_handle, world_name, charserver_name ); + + if( Sql_Query( mmysql_handle, "SELECT `minimum_level`, `maximum_level` FROM `%s` WHERE `world_name` = '%s' AND `account_id` = '%u' AND `char_id` = '%u'", partybookings_table, world_name, account_id, char_id ) != SQL_SUCCESS) { + Sql_ShowDebug( mmysql_handle ); + + return false; + } + + if( Sql_NextRow( mmysql_handle ) != SQL_SUCCESS ){ + Sql_FreeResult( mmysql_handle ); + + return false; + } + + char* data; + + Sql_GetData( mmysql_handle, 0, &data, nullptr ); + booking->minimum_level = (uint16)strtoul( data, nullptr, 10 ); + + Sql_GetData( mmysql_handle, 1, &data, nullptr ); + booking->maximum_level = (uint16)strtoul( data, nullptr, 10 ); + + Sql_FreeResult( mmysql_handle ); + + return true; +} + int party_reply_invite(map_session_data *sd,int party_id,int flag) { map_session_data* tsd; diff --git a/src/map/party.hpp b/src/map/party.hpp index e97024d8d7..082645029a 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -48,6 +48,11 @@ struct party_booking_ad_info { struct party_booking_detail p_detail; }; +struct s_party_booking_requirement{ + uint16 minimum_level; + uint16 maximum_level; +}; + extern int party_create_byscript; void do_init_party(void); @@ -67,6 +72,9 @@ int party_leave(map_session_data *sd); int party_removemember(map_session_data *sd,uint32 account_id,char *name); int party_removemember2(map_session_data *sd,uint32 char_id,int party_id); int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id, char *name, enum e_party_member_withdraw type); +bool party_isleader( map_session_data* sd ); +void party_join( map_session_data* sd, int party_id ); +bool party_booking_load( uint32 account_id, uint32 char_id, struct s_party_booking_requirement* booking ); int party_reply_invite(map_session_data *sd,int party_id,int flag); #define party_add_member(party_id,sd) party_reply_invite(sd,party_id,1) int party_recv_noinfo(int party_id, uint32 char_id); diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 72a68b242b..c6ee17ece4 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -933,6 +933,8 @@ public: } captcha_upload; s_macro_detect macro_detect; + + std::vector party_booking_requests; }; extern struct eri *pc_sc_display_ers; /// Player's SC display table diff --git a/src/web/partybooking_controller.cpp b/src/web/partybooking_controller.cpp new file mode 100644 index 0000000000..8507f17374 --- /dev/null +++ b/src/web/partybooking_controller.cpp @@ -0,0 +1,569 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "partybooking_controller.hpp" + +#include + +#include "../common/showmsg.hpp" +#include "../common/sql.hpp" +#include "../common/strlib.hpp" + +#include "http.hpp" +#include "auth.hpp" +#include "sqllock.hpp" +#include "web.hpp" + +const size_t WORLD_NAME_LENGTH = 32; +const size_t COMMENT_LENGTH = 255; + +enum e_booking_purpose : uint16{ + BOOKING_PURPOSE_ALL = 0, + BOOKING_PURPOSE_QUEST, + BOOKING_PURPOSE_FIELD, + BOOKING_PURPOSE_DUNGEON, + BOOKING_PURPOSE_MD, + BOOKING_PURPOSE_PARADISE, + BOOKING_PURPOSE_OTHER, + BOOKING_PURPOSE_MAX +}; + +struct s_party_booking_entry{ + uint32 account_id; + uint32 char_id; + std::string char_name; + uint16 purpose; + bool assist; + bool damagedealer; + bool healer; + bool tanker; + uint16 minimum_level; + uint16 maximum_level; + std::string comment; + +public: + std::string to_json( std::string& world_name ); +}; + +std::string s_party_booking_entry::to_json( std::string& world_name ){ + return + "{ \"AID\": " + std::to_string( this->account_id ) + + ", \"GID\": " + std::to_string( this->char_id ) + + ", \"CharName\": \"" + this->char_name + "\"" + ", \"WorldName\": \"" + world_name + "\"" + ", \"Tanker\": " + ( this->tanker ? "1": "0" ) + + ", \"Healer\": " + ( this->healer ? "1": "0" ) + + ", \"Dealer\": " + ( this->damagedealer ? "1" : "0" ) + + ", \"Assist\": " + ( this->assist ? "1" : "0" ) + + ", \"MinLV\": " + std::to_string( this->minimum_level ) + + ", \"MaxLV\": " + std::to_string( this->maximum_level ) + + ", \"Memo\": \"" + this->comment + "\"" + ", \"Type\": " + std::to_string( this->purpose ) + + "}"; +} + +bool party_booking_read( std::string& world_name, std::vector& output, const std::string& condition, const std::string& order ){ + SQLLock sl(MAP_SQL_LOCK); + sl.lock(); + auto handle = sl.getHandle(); + SqlStmt* stmt = SqlStmt_Malloc( handle ); + s_party_booking_entry entry; + char world_name_escaped[WORLD_NAME_LENGTH * 2 + 1]; + char char_name[NAME_LENGTH ]; + char comment[COMMENT_LENGTH + 1]; + + Sql_EscapeString( nullptr, world_name_escaped, world_name.c_str() ); + + std::string query = "SELECT `account_id`, `char_id`, `char_name`, `purpose`, `assist`, `damagedealer`, `healer`, `tanker`, `minimum_level`, `maximum_level`, `comment` FROM `" + std::string( partybookings_table ) + "` WHERE `world_name` = ? AND " + condition + order; + + if( SQL_SUCCESS != SqlStmt_Prepare( stmt, query.c_str() ) + || SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_STRING, (void*)world_name_escaped, strlen( world_name_escaped ) ) + || SQL_SUCCESS != SqlStmt_Execute( stmt ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 0, SQLDT_UINT32, &entry.account_id, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 1, SQLDT_UINT32, &entry.char_id, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 2, SQLDT_STRING, (void*)char_name, sizeof( char_name ), NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 3, SQLDT_UINT16, &entry.purpose, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 4, SQLDT_UINT8, &entry.assist, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 5, SQLDT_UINT8, &entry.damagedealer, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 6, SQLDT_UINT8, &entry.healer, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 7, SQLDT_UINT8, &entry.tanker, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 8, SQLDT_UINT16, &entry.minimum_level, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 9, SQLDT_UINT16, &entry.maximum_level, 0, NULL, NULL ) + || SQL_SUCCESS != SqlStmt_BindColumn( stmt, 10, SQLDT_STRING, (void*)comment, sizeof( comment ), NULL, NULL ) + ){ + SqlStmt_ShowDebug( stmt ); + SqlStmt_Free( stmt ); + sl.unlock(); + return false; + } + + while( SQL_SUCCESS == SqlStmt_NextRow( stmt ) ){ + entry.char_name = char_name; + entry.comment = comment; + + output.push_back( entry ); + } + + SqlStmt_Free( stmt ); + sl.unlock(); + + return true; +} + +HANDLER_FUNC(partybooking_add){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + uint32 aid = std::stoi( req.get_file_value( "AID" ).content ); + uint32 cid = std::stoi( req.get_file_value( "GID" ).content ); + + SQLLock csl( CHAR_SQL_LOCK ); + csl.lock(); + auto chandle = csl.getHandle(); + SqlStmt* stmt = SqlStmt_Malloc( chandle ); + if( SQL_SUCCESS != SqlStmt_Prepare( stmt, "SELECT 1 FROM `%s` WHERE `leader_id` = ? AND `leader_char` = ?", party_table, aid, cid ) + || SQL_SUCCESS != SqlStmt_BindParam( stmt, 0, SQLDT_UINT32, &aid, sizeof( aid ) ) + || SQL_SUCCESS != SqlStmt_BindParam( stmt, 1, SQLDT_UINT32, &cid, sizeof( cid ) ) + || SQL_SUCCESS != SqlStmt_Execute( stmt ) + ){ + SqlStmt_ShowDebug( stmt ); + SqlStmt_Free( stmt ); + csl.unlock(); + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + if( SqlStmt_NumRows( stmt ) <= 0 ){ + // No party or not party leader + SqlStmt_Free( stmt ); + csl.unlock(); + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + SqlStmt_Free( stmt ); + csl.unlock(); + + auto world_name = req.get_file_value( "WorldName" ).content; + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + s_party_booking_entry entry = {}; + + entry.account_id = aid; + entry.char_id = cid; + entry.char_name = req.get_file_value( "CharName" ).content; + entry.purpose = std::stoi( req.get_file_value( "Type" ).content ); + entry.assist = std::stoi( req.get_file_value( "Assist" ).content ) != 0; + entry.damagedealer = std::stoi( req.get_file_value( "Dealer" ).content ) != 0; + entry.healer = std::stoi( req.get_file_value( "Healer" ).content ) != 0; + entry.tanker = std::stoi( req.get_file_value( "Tanker" ).content ) != 0; + entry.minimum_level = std::stoi( req.get_file_value( "MinLV" ).content ); + entry.maximum_level = std::stoi( req.get_file_value( "MaxLV" ).content ); + entry.comment = req.get_file_value( "Memo" ).content; + + if( entry.char_name.length() > NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + if( entry.purpose >= BOOKING_PURPOSE_MAX ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + if( entry.comment.length() > COMMENT_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + char world_name_escaped[WORLD_NAME_LENGTH * 2 + 1]; + char char_name_escaped[NAME_LENGTH * 2 + 1]; + char comment_escaped[COMMENT_LENGTH * 2 + 1]; + + Sql_EscapeString( nullptr, world_name_escaped, world_name.c_str() ); + Sql_EscapeString( nullptr, char_name_escaped, entry.char_name.c_str() ); + Sql_EscapeString( nullptr, comment_escaped, entry.comment.c_str() ); + + StringBuf buf; + + StringBuf_Init( &buf ); + + StringBuf_Printf( &buf, "REPLACE INTO `%s` ( `world_name`, `account_id`, `char_id`, `char_name`, `purpose`, `assist`, `damagedealer`, `healer`, `tanker`, `minimum_level`, `maximum_level`, `comment` ) VALUES ( ", partybookings_table ); + + StringBuf_Printf( &buf, "'%s',", world_name_escaped ); + + StringBuf_Printf( &buf, "'%u',", entry.account_id ); + StringBuf_Printf( &buf, "'%u',", entry.char_id ); + StringBuf_Printf( &buf, "'%s',", char_name_escaped ); + StringBuf_Printf( &buf, "'%hu',", entry.purpose ); + StringBuf_Printf( &buf, "'%d',", entry.assist ); + StringBuf_Printf( &buf, "'%d',", entry.damagedealer ); + StringBuf_Printf( &buf, "'%d',", entry.healer ); + StringBuf_Printf( &buf, "'%d',", entry.tanker ); + StringBuf_Printf( &buf, "'%hu',", entry.minimum_level ); + StringBuf_Printf( &buf, "'%hu',", entry.maximum_level ); + StringBuf_Printf( &buf, "'%s' );", comment_escaped ); + + SQLLock msl( MAP_SQL_LOCK ); + msl.lock(); + auto mhandle = msl.getHandle(); + + if( SQL_ERROR == Sql_QueryStr( mhandle, StringBuf_Value( &buf ) ) ){ + Sql_ShowDebug( mhandle ); + + StringBuf_Destroy( &buf ); + msl.unlock(); + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + StringBuf_Destroy( &buf ); + msl.unlock(); + + res.set_content( "{ \"Type\": 1 }", "application/json" ); +} + +HANDLER_FUNC(partybooking_delete){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + auto world_name = req.get_file_value( "WorldName" ).content; + auto account_id = std::stoi( req.get_file_value( "AID" ).content ); + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + SQLLock sl( MAP_SQL_LOCK ); + sl.lock(); + auto handle = sl.getHandle(); + + if( SQL_ERROR == Sql_Query( handle, "DELETE FROM `%s` WHERE `world_name` = '%s' AND `account_id` = '%d'", partybookings_table, world_name.c_str(), account_id ) ){ + Sql_ShowDebug( handle ); + + sl.unlock(); + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + sl.unlock(); + + res.set_content( "{ \"Type\": 1 }", "application/json" ); +} + +HANDLER_FUNC(partybooking_get){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + auto world_name = req.get_file_value( "WorldName" ).content; + auto account_id = std::stoi( req.get_file_value( "AID" ).content ); + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::vector bookings; + + if( !party_booking_read( world_name, bookings, "`account_id` = '" + std::to_string( account_id ) + "'", "" ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::string response; + + if( bookings.empty() ){ + response = "{ \"Type\": 1 }"; + }else{ + response = "{ \"Type\": 1, data: " + bookings.at( 0 ).to_json( world_name ) + " }"; + } + + res.set_content( response, "application/json" ); +} + +HANDLER_FUNC(partybooking_info){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + auto world_name = req.get_file_value( "WorldName" ).content; + auto account_id = std::stoi( req.get_file_value( "QueryAID" ).content ); + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::vector bookings; + + if( !party_booking_read( world_name, bookings, "`account_id` = '" + std::to_string( account_id ) + "'", "" ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::string response; + + if( bookings.empty() ){ + response = "{ \"Type\": 1 }"; + }else{ + response = "{ \"Type\": 1, \"data\": [" + bookings.at( 0 ).to_json( world_name ) + "] }"; + } + + res.set_content( response, "application/json" ); +} + +HANDLER_FUNC(partybooking_list){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + static const std::string condition( "1=1" ); + + auto world_name = req.get_file_value( "WorldName" ).content; + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::vector bookings; + + if( !party_booking_read( world_name, bookings, condition, " ORDER BY `created` DESC" ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::string response; + + response = "{ \"Type\": 1, \"totalPage\": "; + response += std::to_string( bookings.size() ); + response += ", \"data\": ["; + + for( size_t i = 0, max = bookings.size(); i < max; i++ ){ + s_party_booking_entry& booking = bookings.at( i ); + + response += booking.to_json( world_name ); + + if( i < ( max - 1 ) ){ + response += ", "; + } + } + + response += "] }"; + + res.set_content( response, "application/json" ); +} + +HANDLER_FUNC(partybooking_search){ + if( !isAuthorized( req, false ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + return; + } + + auto world_name = req.get_file_value( "WorldName" ).content; + + if( world_name.length() > WORLD_NAME_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + s_party_booking_entry entry; + + // Unconditional + entry.minimum_level = std::stoi( req.get_file_value( "MinLV" ).content ); + entry.maximum_level = std::stoi( req.get_file_value( "MaxLV" ).content ); + + // Conditional + if( req.files.find( "Type" ) != req.files.end() ){ + entry.purpose = std::stoi( req.get_file_value( "Type" ).content ); + + if( entry.purpose >= BOOKING_PURPOSE_MAX ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + }else{ + entry.purpose = BOOKING_PURPOSE_ALL; + } + + if( req.files.find( "Assist" ) != req.files.end() ){ + entry.assist = std::stoi( req.get_file_value( "Assist" ).content ) != 0; + }else{ + entry.assist = false; + } + + if( req.files.find( "Dealer" ) != req.files.end() ){ + entry.damagedealer = std::stoi( req.get_file_value( "Dealer" ).content ) != 0; + }else{ + entry.damagedealer = false; + } + + if( req.files.find( "Healer" ) != req.files.end() ){ + entry.healer = std::stoi( req.get_file_value( "Healer" ).content ) != 0; + }else{ + entry.healer = false; + } + + if( req.files.find( "Tanker" ) != req.files.end() ){ + entry.tanker = std::stoi( req.get_file_value( "Tanker" ).content ) != 0; + }else{ + entry.tanker = false; + } + + if( req.files.find( "Memo" ) != req.files.end() ){ + entry.comment = req.get_file_value( "Memo" ).content; + }else{ + entry.comment = ""; + } + + std::string condition; + + condition = "`minimum_level` = '" + std::to_string( entry.minimum_level ) + "'"; + condition += " AND `maximum_level` = '" + std::to_string( entry.maximum_level ) + "'"; + + if( entry.purpose != BOOKING_PURPOSE_ALL ){ + condition += " AND `purpose` = '" + std::to_string( entry.purpose ) + "'"; + } + + if( entry.assist || entry.damagedealer || entry.healer || entry.tanker ){ + bool or_required = false; + + condition += "AND ( "; + + if( entry.assist ){ + if( or_required ){ + condition += " OR "; + }else{ + or_required = true; + } + + condition += "`assist` = '1'"; + } + + if( entry.damagedealer ){ + if( or_required ){ + condition += " OR "; + }else{ + or_required = true; + } + + condition += "`damagedealer` = '1'"; + } + + if( entry.healer ){ + if( or_required ){ + condition += " OR "; + }else{ + or_required = true; + } + + condition += "`healer` = '1'"; + } + + if( entry.tanker ){ + if( or_required ){ + condition += " OR "; + }else{ + or_required = true; + } + + condition += "`tanker` = '1'"; + } + + condition += " )"; + } + + if( !entry.comment.empty() ){ + if( entry.comment.length() > COMMENT_LENGTH ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + char escaped_comment[COMMENT_LENGTH * 2 + 1]; + + Sql_EscapeString( nullptr, escaped_comment, entry.comment.c_str() ); + + condition += " AND `comment` like '%" + std::string( escaped_comment ) + "%'"; + } + + std::vector bookings; + + if( !party_booking_read( world_name, bookings, condition, " ORDER BY `created` DESC" ) ){ + res.status = HTTP_BAD_REQUEST; + res.set_content( "Error", "text/plain" ); + + return; + } + + std::string response; + + response = "{ \"Type\": 1, \"totalPage\": "; + response += std::to_string( bookings.size() ); + response += ", \"data\": ["; + + for( size_t i = 0, max = bookings.size(); i < max; i++ ){ + s_party_booking_entry& booking = bookings.at( i ); + + response += booking.to_json( world_name ); + + if( i < ( max - 1 ) ){ + response += ", "; + } + } + + response += "] }"; + + res.set_content( response, "application/json" ); +} diff --git a/src/web/partybooking_controller.hpp b/src/web/partybooking_controller.hpp new file mode 100644 index 0000000000..4df4d51a93 --- /dev/null +++ b/src/web/partybooking_controller.hpp @@ -0,0 +1,16 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef PARTYBOOKING_CONTROLLER_HPP +#define PARTYBOOKING_CONTROLLER_HPP + +#include "http.hpp" + +HANDLER_FUNC(partybooking_add); +HANDLER_FUNC(partybooking_delete); +HANDLER_FUNC(partybooking_get); +HANDLER_FUNC(partybooking_info); +HANDLER_FUNC(partybooking_list); +HANDLER_FUNC(partybooking_search); + +#endif diff --git a/src/web/sqllock.cpp b/src/web/sqllock.cpp index ef3460e8a6..94c8151104 100644 --- a/src/web/sqllock.cpp +++ b/src/web/sqllock.cpp @@ -11,6 +11,7 @@ std::mutex dbmutex; extern Sql * login_handle; extern Sql * char_handle; +extern Sql * map_handle; extern Sql * web_handle; @@ -22,6 +23,9 @@ SQLLock::SQLLock(locktype lt) : ulock(dbmutex, std::defer_lock), lt(lt) { case CHAR_SQL_LOCK: handle = char_handle; break; + case MAP_SQL_LOCK: + handle = map_handle; + break; case WEB_SQL_LOCK: handle = web_handle; break; @@ -36,6 +40,9 @@ void SQLLock::lock() { // case CHAR_SQL_LOCK: // ShowDebug("Locking char sql\n"); // break; + // case MAP_SQL_LOCK: + // ShowDebug("Locking map sql\n"); + // break; // case WEB_SQL_LOCK: // ShowDebug("Locking web sql\n"); // break; @@ -52,6 +59,9 @@ void SQLLock::unlock() { // case CHAR_SQL_LOCK: // ShowDebug("Unlocked char sql\n"); // break; + // case MAP_SQL_LOCK: + // ShowDebug("Unlocked map sql\n"); + // break; // case WEB_SQL_LOCK: // ShowDebug("Unlocked web sql\n"); // break; diff --git a/src/web/sqllock.hpp b/src/web/sqllock.hpp index 2286a437c8..d9dc759485 100644 --- a/src/web/sqllock.hpp +++ b/src/web/sqllock.hpp @@ -11,6 +11,7 @@ enum locktype { LOGIN_SQL_LOCK, CHAR_SQL_LOCK, + MAP_SQL_LOCK, WEB_SQL_LOCK }; diff --git a/src/web/web-server.vcxproj b/src/web/web-server.vcxproj index a3739985cd..e778b7c7ad 100644 --- a/src/web/web-server.vcxproj +++ b/src/web/web-server.vcxproj @@ -168,6 +168,7 @@ + @@ -179,6 +180,7 @@ + diff --git a/src/web/web-server.vcxproj.filters b/src/web/web-server.vcxproj.filters index 880307b8b0..12dc9d1f75 100644 --- a/src/web/web-server.vcxproj.filters +++ b/src/web/web-server.vcxproj.filters @@ -24,6 +24,12 @@ Source Files + + Source Files + + + Source Files + Source Files @@ -33,9 +39,6 @@ Source Files - - Source Files - Source Files @@ -53,6 +56,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -65,9 +74,6 @@ Header Files - - Header Files - Header Files diff --git a/src/web/web.cpp b/src/web/web.cpp index a030c76afa..f20b6fbaff 100644 --- a/src/web/web.cpp +++ b/src/web/web.cpp @@ -28,8 +28,9 @@ #include "charconfig_controller.hpp" #include "emblem_controller.hpp" #include "http.hpp" -#include "userconfig_controller.hpp" #include "merchantstore_controller.hpp" +#include "partybooking_controller.hpp" +#include "userconfig_controller.hpp" using namespace rathena; @@ -55,6 +56,12 @@ std::string char_server_id = "ragnarok"; std::string char_server_pw = ""; std::string char_server_db = "ragnarok"; +int map_server_port = 3306; +std::string map_server_ip = "127.0.0.1"; +std::string map_server_id = "ragnarok"; +std::string map_server_pw = ""; +std::string map_server_db = "ragnarok"; + int web_server_port = 3306; std::string web_server_ip = "127.0.0.1"; std::string web_server_id = "ragnarok"; @@ -65,6 +72,7 @@ std::string default_codepage = ""; Sql * login_handle = NULL; Sql * char_handle = NULL; +Sql * map_handle = NULL; Sql * web_handle = NULL; char login_table[32] = "login"; @@ -72,6 +80,8 @@ char guild_emblems_table[32] = "guild_emblems"; char user_configs_table[32] = "user_configs"; char char_configs_table[32] = "char_configs"; char merchant_configs_table[32] = "merchant_configs"; +char party_table[32] = "party"; +char partybookings_table[32] = "party_bookings"; char guild_db_table[32] = "guild"; char char_db_table[32] = "char"; @@ -195,6 +205,16 @@ int inter_config_read(const char* cfgName) char_server_pw = w2; else if(!strcmpi(w1,"char_server_db")) char_server_db = w2; + else if(!strcmpi(w1,"map_server_ip")) + map_server_ip = w2; + else if(!strcmpi(w1,"map_server_port")) + map_server_port = atoi(w2); + else if(!strcmpi(w1,"map_server_id")) + map_server_id = w2; + else if(!strcmpi(w1,"map_server_pw")) + map_server_pw = w2; + else if(!strcmpi(w1,"map_server_db")) + map_server_db = w2; else if(!strcmpi(w1,"web_server_ip")) web_server_ip = w2; else if(!strcmpi(w1,"web_server_port")) @@ -213,6 +233,10 @@ int inter_config_read(const char* cfgName) safestrncpy(char_configs_table, w2, sizeof(char_configs_table)); else if (!strcmpi(w1, "merchant_configs")) safestrncpy(merchant_configs_table, w2, sizeof(merchant_configs_table)); + else if (!strcmpi(w1, "party_db")) + safestrncpy(party_table, w2, sizeof(party_table)); + else if (!strcmpi(w1, "partybookings_table")) + safestrncpy(partybookings_table, w2, sizeof(partybookings_table)); else if (!strcmpi(w1, "guild_emblems")) safestrncpy(guild_emblems_table, w2, sizeof(guild_emblems_table)); else if (!strcmpi(w1, "login_server_account_db")) @@ -234,7 +258,7 @@ int inter_config_read(const char* cfgName) void web_set_defaults() { web_config.web_ip = "0.0.0.0"; - web_config.web_port = 3000; + web_config.web_port = 8888; safestrncpy(web_config.webconf_name, "conf/web_athena.conf", sizeof(web_config.webconf_name)); safestrncpy(web_config.msgconf_name, "conf/msg_conf/web_msg.conf", sizeof(web_config.msgconf_name)); web_config.print_req_res = false; @@ -252,8 +276,8 @@ int web_sql_init(void) { ShowInfo("Connecting to the Login DB server.....\n"); if (SQL_ERROR == Sql_Connect(login_handle, login_server_id.c_str(), login_server_pw.c_str(), login_server_ip.c_str(), login_server_port, login_server_db.c_str())) { - ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n", - login_server_id.c_str(), login_server_pw.c_str(), login_server_ip.c_str(), login_server_port, login_server_db.c_str()); + ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n", + login_server_id.c_str(), login_server_ip.c_str(), login_server_port, login_server_db.c_str()); Sql_ShowDebug(login_handle); Sql_Free(login_handle); exit(EXIT_FAILURE); @@ -269,8 +293,8 @@ int web_sql_init(void) { ShowInfo("Connecting to the Char DB server.....\n"); if (SQL_ERROR == Sql_Connect(char_handle, char_server_id.c_str(), char_server_pw.c_str(), char_server_ip.c_str(), char_server_port, char_server_db.c_str())) { - ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n", - char_server_id.c_str(), char_server_pw.c_str(), char_server_ip.c_str(), char_server_port, char_server_db.c_str()); + ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n", + char_server_id.c_str(), char_server_ip.c_str(), char_server_port, char_server_db.c_str()); Sql_ShowDebug(char_handle); Sql_Free(char_handle); exit(EXIT_FAILURE); @@ -282,12 +306,29 @@ int web_sql_init(void) { Sql_ShowDebug(char_handle); } + map_handle = Sql_Malloc(); + ShowInfo("Connecting to the Map DB server.....\n"); + + if (SQL_ERROR == Sql_Connect(map_handle, map_server_id.c_str(), map_server_pw.c_str(), map_server_ip.c_str(), map_server_port, map_server_db.c_str())) { + ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n", + map_server_id.c_str(), map_server_ip.c_str(), map_server_port, map_server_db.c_str()); + Sql_ShowDebug(map_handle); + Sql_Free(map_handle); + exit(EXIT_FAILURE); + } + ShowStatus("Connect success! (Map Server Connection)\n"); + + if (!default_codepage.empty()) { + if (SQL_ERROR == Sql_SetEncoding(map_handle, default_codepage.c_str())) + Sql_ShowDebug(map_handle); + } + web_handle = Sql_Malloc(); ShowInfo("Connecting to the Web DB server.....\n"); if (SQL_ERROR == Sql_Connect(web_handle, web_server_id.c_str(), web_server_pw.c_str(), web_server_ip.c_str(), web_server_port, web_server_db.c_str())) { - ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n", - web_server_id.c_str(), web_server_pw.c_str(), web_server_ip.c_str(), web_server_port, web_server_db.c_str()); + ShowError("Couldn't connect with uname='%s',host='%s',port='%d',database='%s'\n", + web_server_id.c_str(), web_server_ip.c_str(), web_server_port, web_server_db.c_str()); Sql_ShowDebug(web_handle); Sql_Free(web_handle); exit(EXIT_FAILURE); @@ -311,6 +352,9 @@ int web_sql_close(void) ShowStatus("Close Char DB Connection....\n"); Sql_Free(char_handle); char_handle = NULL; + ShowStatus("Close Map DB Connection....\n"); + Sql_Free(map_handle); + map_handle = NULL; ShowStatus("Close Web DB Connection....\n"); Sql_Free(web_handle); web_handle = NULL; @@ -319,7 +363,7 @@ int web_sql_close(void) } /** - * Login-serv destructor + * web-server destructor * dealloc..., function called at exit of the web-server */ void WebServer::finalize(){ @@ -403,14 +447,20 @@ bool WebServer::initialize( int argc, char* argv[] ){ http_server = std::make_shared(); // set up routes - http_server->Post("/emblem/download", emblem_download); - http_server->Post("/emblem/upload", emblem_upload); - http_server->Post("/userconfig/load", userconfig_load); - http_server->Post("/userconfig/save", userconfig_save); http_server->Post("/charconfig/load", charconfig_load); http_server->Post("/charconfig/save", charconfig_save); + http_server->Post("/emblem/download", emblem_download); + http_server->Post("/emblem/upload", emblem_upload); http_server->Post("/MerchantStore/load", merchantstore_load); http_server->Post("/MerchantStore/save", merchantstore_save); + http_server->Post("/party/add", partybooking_add); + http_server->Post("/party/del", partybooking_delete); + http_server->Post("/party/get", partybooking_get); + http_server->Post("/party/info", partybooking_info); + http_server->Post("/party/list", partybooking_list); + http_server->Post("/party/search", partybooking_search); + http_server->Post("/userconfig/load", userconfig_load); + http_server->Post("/userconfig/save", userconfig_save); // set up logger http_server->set_logger(logger); diff --git a/src/web/web.hpp b/src/web/web.hpp index a137a6d27a..94e5c49a45 100644 --- a/src/web/web.hpp +++ b/src/web/web.hpp @@ -66,6 +66,8 @@ extern char char_configs_table[32]; extern char guild_db_table[32]; extern char char_db_table[32]; extern char merchant_configs_table[32]; +extern char party_table[32]; +extern char partybookings_table[32]; #define msg_config_read(cfgName) web_msg_config_read(cfgName) #define msg_txt(msg_number) web_msg_txt(msg_number)