[Commands] Add #bugs Command. (#2559)

* [Commands] Add #bugs Command.

- Adds a #bugs command for viewing bug reports.
- Remove unused bug related rules in favor of hard-coding the new system.

* Cleanup.

* Typo.

* Push.

* Lower status so it fits with message.
This commit is contained in:
Kinglykrab 2022-11-22 17:32:26 -05:00 committed by GitHub
parent dd3c76e9d2
commit 52e1bc943a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 434 additions and 269 deletions

View File

@ -135,6 +135,7 @@ namespace Logs {
PacketServerClient,
PacketClientServer,
PacketServerToServer,
Bugs,
MaxCategoryID /* Don't Remove this */
};
@ -227,7 +228,8 @@ namespace Logs {
"Faction",
"Packet-S->C",
"Packet-C->S",
"Packet-S->S"
"Packet-S->S",
"Bugs"
};
}

View File

@ -836,6 +836,16 @@
OutF(LogSys, Logs::Moderate, Logs::Expeditions, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBugs(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::General, Logs::Bugs))\
OutF(LogSys, Logs::General, Logs::Bugs, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define LogBugsDetail(message, ...) do {\
if (LogSys.IsLogEnabled(Logs::Detail, Logs::Bugs))\
OutF(LogSys, Logs::Detail, Logs::Bugs, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
if (LogSys.IsLogEnabled(debug_level, log_category))\
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
@ -1286,6 +1296,12 @@
#define LogFactionDetail(message, ...) do {\
} while (0)
#define LogBugs(message, ...) do {\
} while (0)
#define LogBugsDetail(message, ...) do {\
} while (0)
#define Log(debug_level, log_category, message, ...) do {\
} while (0)

View File

@ -742,8 +742,6 @@ RULE_CATEGORY_END()
RULE_CATEGORY(Bugs)
RULE_BOOL(Bugs, ReportingSystemActive, true, "Activates bug reporting")
RULE_BOOL(Bugs, UseOldReportingMethod, true, "Forces the use of the old bug reporting system")
RULE_BOOL(Bugs, DumpTargetEntity, false, "Dumps the target entity, if one is provided")
RULE_CATEGORY_END()
RULE_CATEGORY(Faction)

View File

@ -63,6 +63,7 @@ extern volatile bool RunLoops;
#include "../common/expedition_lockout_timer.h"
#include "cheat_manager.h"
#include "../common/repositories/bug_reports_repository.h"
#include "../common/repositories/char_recipe_list_repository.h"
#include "../common/repositories/character_spells_repository.h"
#include "../common/repositories/character_disciplines_repository.h"
@ -11811,6 +11812,67 @@ bool Client::SendGMCommand(std::string message, bool ignore_status) {
return command_dispatch(this, message, ignore_status) >= 0 ? true : false;
}
void Client::RegisterBug(BugReport_Struct* r) {
if (!r) {
return;
};
auto b = BugReportsRepository::NewEntity();
b.zone = zone->GetShortName();
b.client_version_id = static_cast<uint32_t>(ClientVersion());
b.client_version_name = EQ::versions::ClientVersionName(ClientVersion());
b.account_id = AccountID();
b.character_id = CharacterID();
b.character_name = GetName();
b.reporter_spoof = (strcmp(GetCleanName(), r->reporter_name) != 0 ? 1 : 0);
b.category_id = r->category_id;
b.category_name = r->category_name;
b.reporter_name = r->reporter_name;
b.ui_path = r->ui_path;
b.pos_x = r->pos_x;
b.pos_y = r->pos_y;
b.pos_z = r->pos_z;
b.heading = r->heading;
b.time_played = r->time_played;
b.target_id = r->target_id;
b.target_name = r->target_name;
b.optional_info_mask = r->optional_info_mask;
b._can_duplicate = ((r->optional_info_mask & EQ::bug::infoCanDuplicate) != 0 ? 1 : 0);
b._crash_bug = ((r->optional_info_mask & EQ::bug::infoCrashBug) != 0 ? 1 : 0);
b._target_info = ((r->optional_info_mask & EQ::bug::infoTargetInfo) != 0 ? 1 : 0);
b._character_flags = ((r->optional_info_mask & EQ::bug::infoCharacterFlags) != 0 ? 1 : 0);
b._unknown_value = ((r->optional_info_mask & EQ::bug::infoUnknownValue) != 0 ? 1 : 0);
b.bug_report = r->bug_report;
b.system_info = r->system_info;
auto n = BugReportsRepository::InsertOne(database, b);
if (!n.id) {
Message(Chat::White, "Failed to created your bug report."); // Client sends success message
return;
}
LogBugs("id [{}] report [{}] account [{}] name [{}] charid [{}] zone [{}]", n.id, r->bug_report, AccountID(), GetCleanName(), CharacterID(), zone->GetShortName());
worldserver.SendEmoteMessage(
0,
0,
AccountStatus::QuestTroupe,
Chat::Yellow,
fmt::format(
"{} has created a new bug report, would you like to {} it?",
GetCleanName(),
Saylink::Silent(
fmt::format(
"#bugs view {}",
n.id
),
"view"
)
).c_str()
);
}
std::vector<Mob*> Client::GetApplySpellList(
ApplySpellType apply_type,
bool allow_pets,

View File

@ -910,6 +910,8 @@ public:
bool SendGMCommand(std::string message, bool ignore_status = false);
void RegisterBug(BugReport_Struct* r);
std::vector<Mob*> GetApplySpellList(
ApplySpellType apply_type,
bool allow_pets,

View File

@ -3936,23 +3936,17 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app)
void Client::Handle_OP_Bug(const EQApplicationPacket *app)
{
if (!RuleB(Bugs, ReportingSystemActive)) {
Message(0, "Bug reporting is disabled on this server.");
Message(Chat::White, "Bug reporting is disabled on this server.");
return;
}
if (app->size != sizeof(BugReport_Struct)) {
printf("Wrong size of BugReport_Struct got %d expected %zu!\n", app->size, sizeof(BugReport_Struct));
}
else {
BugReport_Struct* bug_report = (BugReport_Struct*)app->pBuffer;
if (RuleB(Bugs, UseOldReportingMethod))
database.RegisterBug(bug_report);
else
database.RegisterBug(this, bug_report);
LogError("Wrong size of BugReport_Struct got {} expected {}!", app->size, sizeof(BugReport_Struct));
return;
}
return;
auto *r = (BugReport_Struct *) app->pBuffer;
RegisterBug(r);
}
void Client::Handle_OP_Camp(const EQApplicationPacket *app)

View File

@ -100,6 +100,7 @@ int command_init(void)
command_add("augmentitem", "Force augments an item. Must have the augment item window open.", AccountStatus::GMImpossible, command_augmentitem) ||
command_add("ban", "[Character Name] [Reason] - Ban by character name", AccountStatus::GMLeadAdmin, command_ban) ||
command_add("bind", "Sets your targets bind spot to their current location", AccountStatus::GMMgmt, command_bind) ||
command_add("bugs", "[Close|Delete|Review|Search|View] - Handles player bug reports", AccountStatus::QuestTroupe, command_bugs) ||
#ifdef BOTS
command_add("bot", "Type \"#bot help\" or \"^help\" to the see the list of available commands for bots.", AccountStatus::Player, command_bot) ||
@ -942,6 +943,7 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/augmentitem.cpp"
#include "gm_commands/ban.cpp"
#include "gm_commands/bind.cpp"
#include "gm_commands/bugs.cpp"
#include "gm_commands/camerashake.cpp"
#include "gm_commands/castspell.cpp"
#include "gm_commands/chat.cpp"

View File

@ -45,6 +45,7 @@ void command_attack(Client *c, const Seperator *sep);
void command_augmentitem(Client *c, const Seperator *sep);
void command_ban(Client *c, const Seperator *sep);
void command_bind(Client *c, const Seperator *sep);
void command_bugs(Client *c, const Seperator *sep);
void command_camerashake(Client *c, const Seperator *sep);
void command_castspell(Client *c, const Seperator *sep);
void command_chat(Client *c, const Seperator *sep);

343
zone/gm_commands/bugs.cpp Executable file
View File

@ -0,0 +1,343 @@
#include "../client.h"
#include "../../common/repositories/bug_reports_repository.h"
void command_bugs(Client *c, const Seperator *sep)
{
auto arguments = sep->argnum;
if (!arguments) {
c->Message(Chat::White, "Usage: #bugs close [Bug ID] - Close a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs delete [Bug ID] - Delete a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs review [Bug ID] [Review] - Review a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs search [Search Criteria] - Search for Bug Reports");
c->Message(Chat::White, "Usage: #bugs view [Bug ID] - View a Bug Report by ID");
return;
}
bool is_close = !strcasecmp(sep->arg[1], "close");
bool is_delete = !strcasecmp(sep->arg[1], "delete");
bool is_review = !strcasecmp(sep->arg[1], "review");
bool is_search = !strcasecmp(sep->arg[1], "search");
bool is_view = !strcasecmp(sep->arg[1], "view");
if (
!is_close &&
!is_delete &&
!is_review &&
!is_search &&
!is_view
) {
c->Message(Chat::White, "Usage: #bugs close [Bug ID] - Close a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs delete [Bug ID] - Delete a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs review [Bug ID] [Review] - Review a Bug Report by ID");
c->Message(Chat::White, "Usage: #bugs search [Search Criteria] - Search for Bug Reports");
c->Message(Chat::White, "Usage: #bugs view [Bug ID] - View a Bug Report by ID");
return;
}
if (is_close) {
if (!sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #bugs close [Bug ID] - Close a Bug Report by ID");
return;
}
auto bug_id = std::stoul(sep->arg[2]);
auto r = BugReportsRepository::FindOne(content_db, bug_id);
if (!r.id) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} does not exist or is invalid.",
bug_id
).c_str()
);
return;
}
r.bug_status = 1;
if (!BugReportsRepository::UpdateOne(content_db, r)) {
c->Message(
Chat::White,
fmt::format(
"Failed to close Bug ID {}.",
bug_id
).c_str()
);
return;
}
c->Message(
Chat::White,
fmt::format(
"Successfully closed Bug ID {}.",
bug_id
).c_str()
);
} else if (is_delete) {
if (!sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #bugs delete [Bug ID] - Delete a Bug Report by ID");
return;
}
auto bug_id = std::stoul(sep->arg[2]);
auto deleted_count = BugReportsRepository::DeleteOne(content_db, bug_id);
if (!deleted_count) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} does not exist or is invalid.",
bug_id
).c_str()
);
return;
}
c->Message(
Chat::White,
fmt::format(
"Bug ID {} successfully deleted.",
bug_id
).c_str()
);
} else if (is_review) {
if (
arguments < 3 ||
!sep->IsNumber(2)
) {
c->Message(Chat::White, "Usage: #bugs review [Bug ID] [Review] - Review a Bug Report by ID");
return;
}
auto bug_id = std::stoul(sep->arg[2]);
auto bug_review = sep->argplus[3];
auto r = BugReportsRepository::FindOne(content_db, bug_id);
if (!r.id) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} does not exist or is invalid.",
bug_id
).c_str()
);
return;
}
r.last_review = std::time(nullptr);
r.last_reviewer = c->GetCleanName();
r.reviewer_notes = bug_review;
if (!BugReportsRepository::UpdateOne(content_db, r)) {
c->Message(
Chat::White,
fmt::format(
"Failed to add a review on Bug ID {}.",
bug_id
).c_str()
);
return;
}
c->Message(
Chat::White,
fmt::format(
"Successfully added a review on Bug ID {}.",
bug_id
).c_str()
);
} else if (is_search) {
if (arguments < 2) {
c->Message(Chat::White, "Usage: #bugs search [Search Criteria] - Search for Bug Reports");
return;
}
auto search_criteria = sep->argplus[2];
auto l = BugReportsRepository::GetWhere(
content_db,
fmt::format(
"bug_status = 0 AND (character_name LIKE '%%{}%%' OR bug_report LIKE '%%{}%%')",
Strings::Escape(search_criteria),
Strings::Escape(search_criteria)
)
);
if (l.empty()) {
c->Message(
Chat::White,
fmt::format(
"No Bug Reports were found matching '{}'.",
search_criteria
).c_str()
);
return;
}
for (const auto& r : l) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Character: {} Report: {} | {} | {}",
r.id,
r.character_name,
r.bug_report,
Saylink::Silent(
fmt::format(
"#bugs view {}",
r.id
),
"View"
),
Saylink::Silent(
fmt::format(
"#bugs close {}",
r.id
),
"Close"
)
).c_str()
);
}
} else if (is_view) {
if (!sep->IsNumber(2)) {
c->Message(Chat::White, "Usage: #bugs view [Bug ID] - View a Bug Report by ID");
return;
}
auto bug_id = std::stoul(sep->arg[2]);
auto r = BugReportsRepository::FindOne(content_db, bug_id);
if (!r.id) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} does not exist or is invalid.",
bug_id
).c_str()
);
return;
}
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Character: {} ({}) Category: {} ({})",
r.id,
r.character_name,
r.character_id,
r.category_name,
r.category_id
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Zone: {} ({})",
r.id,
ZoneLongName(ZoneID(r.zone)),
r.zone
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Position: {:.2f}, {:.2f}, {:.2f}, {}",
r.id,
r.pos_x,
r.pos_y,
r.pos_z,
r.heading
).c_str()
);
if (r._target_info) {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Target: {} ({})",
r.id,
r.target_name,
r.target_id
).c_str()
);
}
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Can Duplicate: {} Crash Bug: {}",
r.id,
r._can_duplicate ? "Yes" : "No",
r._crash_bug ? "Yes" : "No"
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Character Flags: {} Unknown Value: {}",
r.id,
r._character_flags ? "Yes" : "No",
r._unknown_value ? "Yes" : "No"
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Report: {} Reported: {}",
r.id,
r.bug_report,
r.report_datetime
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Client: {} ({}) UI Path: {}",
r.id,
r.client_version_name,
r.client_version_id,
r.ui_path
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | System Info: {}",
r.id,
r.system_info
).c_str()
);
if (r.last_reviewer != "None") {
c->Message(
Chat::White,
fmt::format(
"Bug ID {} | Last Reviewer: {} Last Reviewed: {} Reviewer Notes: {}",
r.id,
r.last_reviewer,
r.last_review,
r.reviewer_notes
).c_str()
);
}
c->Message(
Chat::White,
fmt::format(
"Would you like to {} this bug?",
Saylink::Silent(
fmt::format(
"#bugs close {}",
r.id
),
"close"
)
).c_str()
);
}
}

View File

@ -196,259 +196,7 @@ bool ZoneDatabase::logevents(const char* accountname,uint32 accountid,uint8 stat
return true;
}
void ZoneDatabase::RegisterBug(BugReport_Struct* bug_report) {
if (!bug_report)
return;
size_t len = 0;
char* name_ = nullptr;
char* ui_ = nullptr;
char* type_ = nullptr;
char* target_ = nullptr;
char* bug_ = nullptr;
len = strlen(bug_report->reporter_name);
if (len) {
if (len > 63) // check against db column size
len = 63;
name_ = new char[(2 * len + 1)];
memset(name_, 0, (2 * len + 1));
DoEscapeString(name_, bug_report->reporter_name, len);
}
len = strlen(bug_report->ui_path);
if (len) {
if (len > 127)
len = 127;
ui_ = new char[(2 * len + 1)];
memset(ui_, 0, (2 * len + 1));
DoEscapeString(ui_, bug_report->ui_path, len);
}
len = strlen(bug_report->category_name);
if (len) {
if (len > 63)
len = 63;
type_ = new char[(2 * len + 1)];
memset(type_, 0, (2 * len + 1));
DoEscapeString(type_, bug_report->category_name, len);
}
len = strlen(bug_report->target_name);
if (len) {
if (len > 63)
len = 63;
target_ = new char[(2 * len + 1)];
memset(target_, 0, (2 * len + 1));
DoEscapeString(target_, bug_report->target_name, len);
}
len = strlen(bug_report->bug_report);
if (len) {
if (len > 1023)
len = 1023;
bug_ = new char[(2 * len + 1)];
memset(bug_, 0, (2 * len + 1));
DoEscapeString(bug_, bug_report->bug_report, len);
}
//x and y are intentionally swapped because eq is inversexy coords //is this msg out-of-date or are the parameters wrong?
std::string query = StringFormat(
"INSERT INTO `bugs` (`zone`, `name`, `ui`, `x`, `y`, `z`, `type`, `flag`, `target`, `bug`, `date`) "
"VALUES('%s', '%s', '%s', '%.2f', '%.2f', '%.2f', '%s', %d, '%s', '%s', CURDATE())",
zone->GetShortName(),
(name_ ? name_ : ""),
(ui_ ? ui_ : ""),
bug_report->pos_x,
bug_report->pos_y,
bug_report->pos_z,
(type_ ? type_ : ""),
bug_report->optional_info_mask,
(target_ ? target_ : "Unknown Target"),
(bug_ ? bug_ : "")
);
safe_delete_array(name_);
safe_delete_array(ui_);
safe_delete_array(type_);
safe_delete_array(target_);
safe_delete_array(bug_);
QueryDatabase(query);
}
void ZoneDatabase::RegisterBug(Client* client, BugReport_Struct* bug_report) {
if (!client || !bug_report)
return;
size_t len = 0;
char* category_name_ = nullptr;
char* reporter_name_ = nullptr;
char* ui_path_ = nullptr;
char* target_name_ = nullptr;
char* bug_report_ = nullptr;
char* system_info_ = nullptr;
len = strlen(bug_report->category_name);
if (len) {
if (len > 63) // check against db column size
len = 63;
category_name_ = new char[(2 * len + 1)];
memset(category_name_, 0, (2 * len + 1));
DoEscapeString(category_name_, bug_report->category_name, len);
}
len = strlen(bug_report->reporter_name);
if (len) {
if (len > 63)
len = 63;
reporter_name_ = new char[(2 * len + 1)];
memset(reporter_name_, 0, (2 * len + 1));
DoEscapeString(reporter_name_, bug_report->reporter_name, len);
}
len = strlen(bug_report->ui_path);
if (len) {
if (len > 127)
len = 127;
ui_path_ = new char[(2 * len + 1)];
memset(ui_path_, 0, (2 * len + 1));
DoEscapeString(ui_path_, bug_report->ui_path, len);
}
len = strlen(bug_report->target_name);
if (len) {
if (len > 63)
len = 63;
target_name_ = new char[(2 * len + 1)];
memset(target_name_, 0, (2 * len + 1));
DoEscapeString(target_name_, bug_report->target_name, len);
}
len = strlen(bug_report->bug_report);
if (len) {
if (len > 1023)
len = 1023;
bug_report_ = new char[(2 * len + 1)];
memset(bug_report_, 0, (2 * len + 1));
DoEscapeString(bug_report_, bug_report->bug_report, len);
}
len = strlen(bug_report->system_info);
if (len) {
if (len > 1023)
len = 1023;
system_info_ = new char[(2 * len + 1)];
memset(system_info_, 0, (2 * len + 1));
DoEscapeString(system_info_, bug_report->system_info, len);
}
std::string query = StringFormat(
"INSERT INTO `bug_reports` "
"(`zone`,"
" `client_version_id`,"
" `client_version_name`,"
" `account_id`,"
" `character_id`,"
" `character_name`,"
" `reporter_spoof`,"
" `category_id`,"
" `category_name`,"
" `reporter_name`,"
" `ui_path`,"
" `pos_x`,"
" `pos_y`,"
" `pos_z`,"
" `heading`,"
" `time_played`,"
" `target_id`,"
" `target_name`,"
" `optional_info_mask`,"
" `_can_duplicate`,"
" `_crash_bug`,"
" `_target_info`,"
" `_character_flags`,"
" `_unknown_value`,"
" `bug_report`,"
" `system_info`) "
"VALUES "
"('%s',"
" '%u',"
" '%s',"
" '%u',"
" '%u',"
" '%s',"
" '%u',"
" '%u',"
" '%s',"
" '%s',"
" '%s',"
" '%1.1f',"
" '%1.1f',"
" '%1.1f',"
" '%u',"
" '%u',"
" '%u',"
" '%s',"
" '%u',"
" '%u',"
" '%u',"
" '%u',"
" '%u',"
" '%u',"
" '%s',"
" '%s')",
zone->GetShortName(),
client->ClientVersion(),
EQ::versions::ClientVersionName(client->ClientVersion()),
client->AccountID(),
client->CharacterID(),
client->GetName(),
(strcmp(client->GetName(), reporter_name_) != 0 ? 1 : 0),
bug_report->category_id,
(category_name_ ? category_name_ : ""),
(reporter_name_ ? reporter_name_ : ""),
(ui_path_ ? ui_path_ : ""),
bug_report->pos_x,
bug_report->pos_y,
bug_report->pos_z,
bug_report->heading,
bug_report->time_played,
bug_report->target_id,
(target_name_ ? target_name_ : ""),
bug_report->optional_info_mask,
((bug_report->optional_info_mask & EQ::bug::infoCanDuplicate) != 0 ? 1 : 0),
((bug_report->optional_info_mask & EQ::bug::infoCrashBug) != 0 ? 1 : 0),
((bug_report->optional_info_mask & EQ::bug::infoTargetInfo) != 0 ? 1 : 0),
((bug_report->optional_info_mask & EQ::bug::infoCharacterFlags) != 0 ? 1 : 0),
((bug_report->optional_info_mask & EQ::bug::infoUnknownValue) != 0 ? 1 : 0),
(bug_report_ ? bug_report_ : ""),
(system_info_ ? system_info_ : "")
);
safe_delete_array(category_name_);
safe_delete_array(reporter_name_);
safe_delete_array(ui_path_);
safe_delete_array(target_name_);
safe_delete_array(bug_report_);
safe_delete_array(system_info_);
auto result = QueryDatabase(query);
// TODO: Entity dumping [RuleB(Bugs, DumpTargetEntity)]
}
//void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug) {
//
// uint32 len = strlen(bug->text);
// auto bugtext = new char[2 * len + 1];
// memset(bugtext, 0, 2 * len + 1);
// DoEscapeString(bugtext, bug->text, len);
//
// std::string query = StringFormat("INSERT INTO bugs (type, name, bugtext, flag) "
// "VALUES('%s', '%s', '%s', %i)",
// "Petition", bug->name, bugtext, 25);
// safe_delete_array(bugtext);
// QueryDatabase(query);
//}
bool ZoneDatabase::SetSpecialAttkFlag(uint8 id, const char* flag) {

View File

@ -547,9 +547,6 @@ public:
bool DeleteMerc(uint32 merc_id);
/* Petitions */
void RegisterBug(BugReport_Struct* bug_report); // old method
void RegisterBug(Client* client, BugReport_Struct* bug_report); // new method
//void UpdateBug(PetitionBug_Struct* bug);
void DeletePetitionFromDB(Petition* wpet);
void UpdatePetitionToDB(Petition* wpet);
void InsertPetitionToDB(Petition* wpet);