mangos/src/game/Object/GMTicketMgr.cpp
Olion17 2f17dbe017 [GM] .ticket command rework
Including ticket numbering fix (now real ticket IDs throughout)
Closing tickets for offline players
2016-03-19 22:23:37 +00:00

221 lines
7.2 KiB
C++

/**
* MaNGOS is a full featured server for World of Warcraft, supporting
* the following clients: 1.12.x, 2.4.3, 3.3.5a, 4.3.4a and 5.4.8
*
* Copyright (C) 2005-2016 MaNGOS project <http://getmangos.eu>
*
* 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; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* World of Warcraft, and all World of Warcraft or Warcraft art, images,
* and lore are copyrighted by Blizzard Entertainment, Inc.
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "SQLStorages.h"
#include "GMTicketMgr.h"
#include "ObjectMgr.h"
#include "ObjectGuid.h"
#include "ProgressBar.h"
#include "Policies/Singleton.h"
#include "Player.h"
INSTANTIATE_SINGLETON_1(GMTicketMgr);
void GMTicket::SaveSurveyData(WorldPacket& recvData) const
{
uint32 x;
recvData >> x; // answer range? (6 = 0-5?)
DEBUG_LOG("SURVEY: X = %u", x);
uint8 result[10];
memset(result, 0, sizeof(result));
for (int i = 0; i < 10; ++i)
{
uint32 questionID;
recvData >> questionID; // GMSurveyQuestions.dbc
if (!questionID)
break;
uint8 value;
std::string unk_text;
recvData >> value; // answer
recvData >> unk_text; // always empty?
result[i] = value;
DEBUG_LOG("SURVEY: ID %u, value %u, text %s", questionID, value, unk_text.c_str());
}
std::string comment;
recvData >> comment; // addional comment
DEBUG_LOG("SURVEY: comment %s", comment.c_str());
// TODO: chart this data in some way in DB
}
void GMTicket::Init(ObjectGuid guid, const std::string& text, const std::string& responseText, time_t update, uint32 ticketId)
{
m_guid = guid;
m_ticketId = ticketId;
m_text = text;
m_responseText = responseText;
m_lastUpdate = update;
}
void GMTicket::SetText(const char* text)
{
m_text = text ? text : "";
m_lastUpdate = time(NULL);
std::string escapedString = m_text;
CharacterDatabase.escape_string(escapedString);
CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' "
"WHERE guid = '%u'",
escapedString.c_str(), m_guid.GetCounter());
}
void GMTicket::SetResponseText(const char* text)
{
m_responseText = text ? text : "";
m_lastUpdate = time(NULL);
std::string escapedString = m_responseText;
CharacterDatabase.escape_string(escapedString);
CharacterDatabase.PExecute("UPDATE character_ticket SET response_text = '%s' "
"WHERE guid = '%u'",
escapedString.c_str(), m_guid.GetCounter());
}
void GMTicket::CloseWithSurvey() const
{
_Close(GM_TICKET_STATUS_SURVEY);
}
void GMTicket::CloseByClient() const
{
_Close(GM_TICKET_STATUS_DO_NOTHING);
}
void GMTicket::Close() const
{
_Close(GM_TICKET_STATUS_CLOSE);
}
void GMTicket::_Close(GMTicketStatus statusCode) const
{
Player* pPlayer = sObjectMgr.GetPlayer(m_guid);
CharacterDatabase.PExecute("UPDATE character_ticket "
"SET resolved = 1 "
"WHERE guid = %u AND resolved = 0",
m_guid.GetCounter());
if (pPlayer && statusCode != GM_TICKET_STATUS_DO_NOTHING)
{ pPlayer->GetSession()->SendGMTicketStatusUpdate(statusCode); }
}
void GMTicketMgr::LoadGMTickets()
{
m_GMTicketMap.clear(); // For reload case
QueryResult* result = CharacterDatabase.Query(
// 0 1 2 3 4
"SELECT guid, ticket_text, response_text, UNIX_TIMESTAMP(ticket_lastchange), ticket_id "
"FROM character_ticket "
"WHERE resolved = 0 "
"ORDER BY ticket_id ASC");
if (!result)
{
BarGoLink bar(1);
bar.step();
sLog.outString(">> Loaded `character_ticket`, table is empty.");
sLog.outString();
return;
}
BarGoLink bar(result->GetRowCount());
do
{
bar.step();
Field* fields = result->Fetch();
uint32 guidlow = fields[0].GetUInt32();
if (!guidlow)
{ continue; }
ObjectGuid guid = ObjectGuid(HIGHGUID_PLAYER, guidlow);
GMTicket& ticket = m_GMTicketMap[guid];
ticket.Init(guid, fields[1].GetCppString(), fields[2].GetCppString(), time_t(fields[3].GetUInt64()), fields[4].GetUInt32());
m_GMTicketIdMap[ticket.GetId()] = &ticket;
}
while (result->NextRow());
delete result;
sLog.outString(">> Loaded " SIZEFMTD " GM tickets", GetTicketCount());
sLog.outString();
}
void GMTicketMgr::Create(ObjectGuid guid, const char* text)
{
std::string escapedText = text;
CharacterDatabase.escape_string(escapedText);
CharacterDatabase.BeginTransaction();
//This needs to be Direct (not placed in queue) as we need the id of it soon afterwards
CharacterDatabase.DirectPExecute("INSERT INTO character_ticket "
"(guid, ticket_text) "
"VALUES "
"(%u, '%s')",
guid.GetCounter(), escapedText.c_str());
//Get the id of the ticket, needed for logging whispers
QueryResult* result = CharacterDatabase.PQuery("SELECT ticket_id, guid, resolved "
"FROM character_ticket "
"WHERE guid = %u AND resolved = 0;",
guid.GetCounter());
CharacterDatabase.CommitTransaction();
if (!result)
return;
Field* fields = result->Fetch();
uint32 ticketId = fields[0].GetUInt32();
//This implicitly creates a new instance since we're using operator[]
GMTicket& ticket = m_GMTicketMap[guid];
if (ticket.GetPlayerGuid())
m_GMTicketIdMap.erase(ticketId);
//Lets reinitialize with new data
ticket.Init(guid, text, "", time(NULL), ticketId);
m_GMTicketIdMap[ticketId] = &ticket;
}
void GMTicketMgr::DeleteAll()
{
for (GMTicketMap::const_iterator itr = m_GMTicketMap.begin(); itr != m_GMTicketMap.end(); ++itr)
{
if (Player* owner = sObjectMgr.GetPlayer(itr->first))
{ owner->GetSession()->SendGMTicketGetTicket(0x0A); }
}
CharacterDatabase.Execute("DELETE FROM character_ticket");
m_GMTicketIdMap.clear();
m_GMTicketMap.clear();
}