MGR = billmgr PLUGIN = ticketmgri VERSION = 5.0.1 LIB += ticketmgri ticketmgri_SOURCES = ticketmgri.cpp WRAPPER += ticketmgri_syncticket ticketmgri_syncticket_SOURCES = ticketmgri_syncticket.cpp ticketmgri_syncticket_LDADD = -lbase BASE ?= /usr/local/mgr5 include $(BASE)/src/isp.mk
<?xml version="1.0" encoding="UTF-8"?> <mgrdata> <library name="ticketmgri" /> </mgrdata>
#include <api/action.h> #include <api/module.h> #include <api/stdconfig.h> #include <billmgr/db.h> #include <mgr/mgrdb_struct.h> #include <mgr/mgrlog.h> #include <mgr/mgrtask.h> MODULE("ticketmgri"); using namespace isp_api; namespace { StringVector allowedDepartments, hideDepartments; /** * , LongTask ( ) sbin/ticketmgri_syncticket * * [in] _id */ void SyncTicket(int _id) { string id = str::Str(_id); Warning("Sync %s", id.c_str()); if (!_id) return; mgr_task::LongTask("sbin/ticketmgri_syncticket", "ticket_" + id, "ticketmgri_sync") .SetParam(id) .Start(); } /** * * * */ struct eTicketEdit : public Event { /** * * * * * ev , * elid_name . * */ eTicketEdit(const string &ev, const string &elid_name = "elid") : Event(ev, "ticketmgri_" + ev), elid_name_(elid_name) { Warning("eTicketEdit created"); } /** * * * , * [in] ses */ void AfterExecute(Session &ses) const override { Warning("subm %d cb %s elid %s", ses.IsSubmitted(), ses.Param("clicked_button").c_str(), ses.Param("elid").c_str()); string button = ses.Param("clicked_button"); string elid; if (elid_name_ == "elid_ticket2user") { elid = db->Query("SELECT ticket FROM ticket2user WHERE id='" + ses.Param("elid") + "'") ->Str(); } else { elid = ses.Param("elid"); } if ((ses.IsSubmitted() || ses.Param("sv_field") == "ok_message") && (button == "ok" || button == "" || button == "ok_message")) { if (!ses.Has(elid_name_)) { SyncTicket(db->Query("SELECT MAX(id) FROM ticket")->Int()); } else { SyncTicket(str::Int(elid)); } } } string elid_name_; }; /** * , */ struct eClientTicketEdit : public eTicketEdit { eClientTicketEdit() : eTicketEdit("clientticket.edit") {} /** * , , * * , * * [in] ses */ void AfterExecute(Session &ses) const override { eTicketEdit::AfterExecute(ses); for (auto &i : hideDepartments) { ses.xml.RemoveNodes("//slist[@name='client_department']/val[@key='" + i + "']"); } } }; /** * , */ struct aTicketintegrationSetFilter : public Action { aTicketintegrationSetFilter() : Action("ticketintegration.setfilter", MinLevel(lvAdmin)) {} /** * * * * * [in] ses */ void Execute(Session &ses) const override { InternalCall(ses, "account.setfilter", "elid=" + ses.Param("elid")); ses.Ok(ses.okTop); } }; /** * */ struct aTicketintegrationPost : public Action { aTicketintegrationPost() : Action("ticketintegration.post", MinLevel(lvAdmin)) {} void Execute(Session &ses) const override { Execute(ses, true); } /** * * * [in] ses * [in] retry , , * */ void Execute(Session &ses, bool retry) const { auto openTickets = db->Query("SELECT id FROM ticket2user WHERE ticket=" + ses.Param("elid") + " AND user IN (" + str::Join(allowedDepartments, ",") + ")"); string elid; if (openTickets->Eof()) { if (ses.Param("type") == "setstatus" && ses.Param("status") == "closed") { ses.NewNode("ok"); return; } if (retry) { InternalCall(ses, "support_tool_responsible", "set_responsible_default=off&sok=ok&set_responsible=e%5F" + allowedDepartments[0] + "&elid=" + ses.Param("elid")); Execute(ses, false); return; } else { throw mgr_err::Error("cannot_open_ticket"); } } else { elid = openTickets->Str(); } if (ses.Param("type") == "setstatus" && ses.Param("status") == "new") { return; } auto ret2 = InternalCall( ses, "ticket.edit", string() + "sok=ok&show_optional=on" + "&clicked_button=" + (ses.Param("status") == "new" ? "ok_message" : "ok") + "&" + (!ses.Checked("internal") ? "message" : "note_message") + "=" + str::url::Encode(ses.Param("message")) + "&elid=" + elid); // TODO: attachments, sender_name ses.NewNode("ok"); } }; /** * , , */ struct TicketmgriLastNote : public mgr_db::CustomTable { mgr_db::ReferenceField Ticket; mgr_db::ReferenceField LastNote; TicketmgriLastNote() : mgr_db::CustomTable("ticketmgri_last_note"), Ticket(this, "ticket", mgr_db::rtRestrict), LastNote(this, "last_note", "ticket_note", mgr_db::rtRestrict) { Ticket.info().set_primary(); } }; /** * , last_note ticketmgri_last_note */ struct aTicketintegrationLastNote : public Action { aTicketintegrationLastNote() : Action("ticketintegraion.last_note", MinLevel(lvSuper)) {} /** * , last_note * ticketmgri_last_note * * [in] ses */ void Execute(Session &ses) const override { auto t = db->Get<TicketmgriLastNote>(); if (!t->Find(ses.Param("elid"))) { t->New(); t->Ticket = str::Int(ses.Param("elid")); } if (ses.IsSubmitted()) { t->LastNote = str::Int(ses.Param("last_note")); t->Post(); ses.Ok(); } else { ses.NewNode("last_note", t->LastNote); } } }; /** * , , */ struct aTicketintegrationPushTasks : public Action { aTicketintegrationPushTasks() : Action("ticketintegraion.push_tasks", MinLevel(lvSuper)) {} /** * , * * * [in] ses */ void Execute(Session &ses) const override { mgr_xml::XPath xpath = InternalCall("longtask", "filter=yes&state=err&queue=ticketmgri_sync") .GetNodes("//elem[queue='ticketmgri_sync' and status='err']"); for (auto elem : xpath) { auto data = InternalCall("longtask.edit", "elid=" + elem.FindNode("pidfile").Str()); mgr_task::LongTask(data.GetNode("//realname"), data.GetNode("//id"), "ticketmgri_sync") .SetParam(data.GetNode("//params")) .Start(); } } }; /** * */ struct aTicketintegrationGetBalance : public Action { aTicketintegrationGetBalance() : Action("ticketintegration.getbalance", MinLevel(lvAdmin)) {} /** * * * [in] ses */ void Execute(Session &ses) const override { ses.NewNode("balance", InternalCall(ses, "account.edit", "elid=" + ses.Param("elid")) .GetNode("//balance") .Str()); } bool IsModify(const Session &) const override { return false; } }; /** * , */ struct aTicketintegrationDeduct : public Action { aTicketintegrationDeduct() : Action("ticketintegration.deduct", MinLevel(lvAdmin)) {} /** * * * SQL- . * . * , * * [in] ses */ void Execute(Session &ses) const override { auto openTickets = db->Query("SELECT id FROM ticket2user WHERE ticket=" + ses.Param("ticket") + " AND user IN (" + str::Join(allowedDepartments, ",") + ")"); if (openTickets->Eof()) { throw mgr_err::Value("ticket"); } string elid = openTickets->AsString(0); InternalCall(ses, "ticket.edit", "sok=ok&show_optional=on&elid=" + elid + "&ticket_expense=" + ses.Param("amount")); } }; } // namespace // , , // MODULE_INIT(ticketmgri, "") { Warning("Init TICKETmanager integtration"); mgr_cf::AddParam("TicketmgrUrl", "https://tickets.isplicense.ru:1500/ticketmgr"); mgr_cf::AddParam("TicketmgrLogin"); mgr_cf::AddParam("TicketmgrPassword"); mgr_cf::AddParam("TicketmgrBillmgrUrl"); mgr_cf::AddParam("TicketmgrUserId"); mgr_cf::AddParam("TicketmgrAllowedDepartments"); mgr_cf::AddParam("TicketmgrHideDepartments"); str::Split(mgr_cf::GetParam("TicketmgrAllowedDepartments"), ",", allowedDepartments); if (allowedDepartments.empty()) { allowedDepartments.push_back(0); } str::Split(mgr_cf::GetParam("TicketmgrHideDepartments"), ",", hideDepartments); db->Register<TicketmgriLastNote>(); new eClientTicketEdit; new eTicketEdit("ticket.edit", "elid_ticket2user"); new eTicketEdit("support_tool_responsible", "plid"); new aTicketintegrationSetFilter; new aTicketintegrationPost; new aTicketintegrationLastNote; new aTicketintegrationPushTasks; new aTicketintegrationGetBalance; new aTicketintegrationDeduct; }
#include <billmgr/db.h> #include <billmgr/defines.h> #include <billmgr/sbin_utils.h> #include <ispbin.h> #include <mgr/mgrclient.h> #include <mgr/mgrdb_struct.h> #include <mgr/mgrenv.h> #include <mgr/mgrlog.h> #include <mgr/mgrproc.h> #include <mgr/mgrrpc.h> MODULE("syncticket"); using sbin::DB; using sbin::GetMgrConfParam; using sbin::Client; using sbin::ClientQuery; /** * Ticketmanager * * * */ mgr_client::Client &ticketmgr() { static mgr_client::Client *ret = []() { mgr_client::Remote *ret = new mgr_client::Remote(GetMgrConfParam("TicketmgrUrl")); ret->AddParam("authinfo", GetMgrConfParam("TicketmgrLogin") + ":" + GetMgrConfParam("TicketmgrPassword")); return ret; }(); return *ret; } /** * TICKETmanager * * , xml c , * , , , */ void PostTicket(const string &elid) { // , , auto ticket = DB()->Query("SELECT * FROM ticket WHERE id=" + elid); if (ticket->Eof()) throw mgr_err::Missed("ticket"); auto account = DB()->Query("SELECT * FROM account WHERE id=" + ticket->AsString("account_client")); if (account->Eof()) throw mgr_err::Missed("account"); auto user = DB()->Query("SELECT * FROM user WHERE account=" + account->AsString("id") + " ORDER BY id LIMIT 1"); if (user->Eof()) throw mgr_err::Missed("user"); // xml- mgr_xml::Xml infoXml; auto info = infoXml.GetRoot(); auto customer = info.AppendChild("customer"); customer.AppendChild("id", account->AsString("id")); customer.AppendChild("name", account->AsString("name")); customer.AppendChild("email", user->AsString("email")); customer.AppendChild("phone", user->AsString("phone")); customer.AppendChild("link", GetMgrConfParam("TicketmgrBillmgrUrl") + "?startform=ticketintegration.setfilter&elid=" + account->AsString("id")); if (!ticket->IsNull("item")) { auto item = DB()->Query("SELECT id, name, processingmodule FROM item WHERE id=" + ticket->AsString("item")); if (item->Eof()) throw mgr_err::Missed("item"); auto iteminfo = info.AppendChild("item"); // iteminfo.SetProp("selected", "yes"); iteminfo.AppendChild("id", item->AsString("id")); iteminfo.AppendChild("name", item->AsString("name")); iteminfo.AppendChild("serverid", item->AsString("processingmodule")); // ForEachQuery(DB(), "SELECT intname, value FROM itemparam WHERE item=" + ticket->AsString("item"), i) { if (i->AsString(0) == "ip") { iteminfo.AppendChild("ip", i->AsString(1)); } else if (i->AsString(0) == "username") { iteminfo.AppendChild("login", i->AsString(1)); } else if (i->AsString(0) == "password") { iteminfo.AppendChild("password", i->AsString(1)); } else if (i->AsString(0) == "domain") { iteminfo.AppendChild("domain", i->AsString(1)); } } } // Ticketmanager StringMap args = {{"remoteid", ticket->AsString("id")}, {"department", ticket->AsString("responsible")}, {"info", infoXml.Str()}, {"subject", ticket->AsString("name")}}; ticketmgr().Query("func=clientticket.add&sok=ok", args); } int ISP_MAIN(int ac, char **av) { if (ac != 2) { fprintf(stderr, "Usage: ticketmgri_syncticket ID"); return 1; } string elid = av[1]; try { mgr_log::Init("ticketmgri"); string status = "closed"; int lastmessage = 0; // , string newStatus = DB()->Query("SELECT COUNT(*) FROM ticket2user WHERE ticket=" + elid + " AND user IN (" + GetMgrConfParam("TicketmgrAllowedDepartments") + ")") ->Int() ? "new" : "closed"; bool inDepartment = DB()->Query("SELECT COUNT(*) FROM ticket WHERE id=" + elid + " AND responsible IN (" + GetMgrConfParam("TicketmgrAllowedDepartments") + ")") ->Int(); if (newStatus != "new" && !inDepartment) { LogNote("Skip ticket %s: status=%s, inDepartment=%d", elid.c_str(), newStatus.c_str(), inDepartment); return 0; } try { // Ticketmanager auto r = ticketmgr().Query("func=clientticket.info&remoteid=?", elid); status = r.value("status"); lastmessage = str::Int(r.value("lastmessage")); } catch (mgr_err::Error &e) { if (e.type() == "missed" && e.object() == "remoteid") { // , PostTicket(elid); } else { throw; } } // last_note int lastnote = str::Int(Client() .Query("func=ticketintegraion.last_note&elid=" + elid) .value("last_note")); // auto msg = DB()->Query( string() + "SELECT ticket_message.id, user.realname AS username, user.level AS " "userlevel, message, 1 AS type, ticket_message.date_post " + "FROM ticket_message " + "JOIN user ON ticket_message.user=user.id " + "WHERE ticket_message.id > " + str::Str(lastmessage) + " " + "AND user != " + GetMgrConfParam("TicketmgrUserId") + " " + "AND ticket = " + elid + " " + "UNION " "SELECT ticket_note.id, user.realname AS username, user.level AS " "userlevel, note AS message, 2 AS type, ticket_note.date_post " + "FROM ticket_note " + "JOIN user ON ticket_note.user=user.id " + "WHERE ticket_note.id > " + str::Str(lastnote) + " " + "AND user != " + GetMgrConfParam("TicketmgrUserId") + " " + "AND ticket = " + elid + " " + "ORDER BY date_post"); // , Ticketmanager if (msg->Eof() && status != newStatus) { StringMap params = { {"remoteid", elid}, {"status", newStatus}, }; ticketmgr().Query( "func=clientticket.post&sok=ok&sender=staff&sender_name=System&type=" "setstatus", params); } else { // Ticketmanager lastnote = 0; for (msg->First(); !msg->Eof(); msg->Next()) { StringMap params = { {"remoteid", elid}, {"status", newStatus}, {"sender_name", msg->AsString("username")}, {"sender", msg->AsInt("userlevel") >= 28 ? "staff" : "client"}, {"message", msg->AsString("message")}, }; int attachments = 0; if (msg->AsInt("type") == 1) { params["messageid"] = msg->AsString("id"); // ForEachQuery( DB(), "SELECT * FROM ticket_message_attach WHERE ticket_message=" + msg->AsString("id"), attach) { string id = str::Str(attachments++); auto info = ClientQuery("func=ticket.file&elid=" + attach->AsString("id")); params["attachment_name_" + id] = info.xml.GetNode("//content/name").Str(); params["attachment_content_" + id] = str::base64::Encode( mgr_file::Read(info.xml.GetNode("//content/data").Str())); } } else { lastnote = std::max(lastnote, msg->AsInt("id")); params["internal"] = "on"; } params["attachments"] = str::Str(attachments); ticketmgr().Query("func=clientticket.post&sok=ok&type=message", params); } // last_note if (lastnote) { Client().Query("func=ticketintegraion.last_note&sok=ok&elid=" + elid + "&last_note=" + str::Str(lastnote)); } } } catch (std::exception &e) { fprintf(stderr, "%s\n", e.what()); return 1; } return 0; }
Source: https://habr.com/ru/post/314886/
All Articles