00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "module.h"
00015 #include "../extra/sql.h"
00016
00017 class MySQLInterface : public SQL::Interface
00018 {
00019 public:
00020 MySQLInterface(Module *o) : SQL::Interface(o) { }
00021
00022 void OnResult(const SQL::Result &r) anope_override
00023 {
00024 }
00025
00026 void OnError(const SQL::Result &r) anope_override
00027 {
00028 if (!r.GetQuery().query.empty())
00029 Log(LOG_DEBUG) << "Chanstats: Error executing query " << r.finished_query << ": " << r.GetError();
00030 else
00031 Log(LOG_DEBUG) << "Chanstats: Error executing query: " << r.GetError();
00032 }
00033 };
00034
00035 class CommandCSTop : public Command
00036 {
00037 public:
00038 CommandCSTop(Module *creator) : Command (creator, "chanserv/top", 0, 2)
00039 {
00040 this->SetDesc(_("Displays the top 3 users of a channel"));
00041 this->SetSyntax(_("\037channel\037"));
00042 }
00043
00044 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms);
00045 };
00046
00047 class CommandCSTop10 : public Command
00048 {
00049 public:
00050 CommandCSTop10(Module *creator) : Command (creator, "chanserv/top10", 0, 2)
00051 {
00052 this->SetDesc(_("Displays the top 10 users of a channel"));
00053 this->SetSyntax(_("\037channel\037"));
00054 }
00055
00056 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms);
00057 };
00058
00059 class CommandCSGTop : public Command
00060 {
00061 public:
00062 CommandCSGTop(Module *creator) : Command (creator, "chanserv/gtop", 0, 1)
00063 {
00064 this->SetDesc(_("Displays the top 3 users of the network"));
00065 this->SetSyntax("");
00066 }
00067
00068 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms);
00069 };
00070
00071 class CommandCSGTop10 : public Command
00072 {
00073 public:
00074 CommandCSGTop10(Module *creator) : Command (creator, "chanserv/gtop10", 0, 1)
00075 {
00076 this->SetDesc(_("Displays the top 10 users of the network"));
00077 this->SetSyntax("");
00078 }
00079
00080 void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms);
00081 };
00082
00083
00084 class CSTop;
00085 static CSTop *me;
00086 class CSTop : public Module
00087 {
00088 CommandCSTop commandcstop;
00089 CommandCSGTop commandcsgtop;
00090 CommandCSTop10 commandcstop10;
00091 CommandCSGTop10 commandcsgtop10;
00092 ServiceReference<SQL::Provider> sql;
00093 MySQLInterface sqlinterface;
00094 Anope::string prefix;
00095
00096 public:
00097 CSTop(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00098 commandcstop(this), commandcsgtop(this), commandcstop10(this), commandcsgtop10(this), sql("", ""),
00099 sqlinterface(this)
00100 {
00101 me = this;
00102 this->SetAuthor("Anope");
00103
00104 Implementation i[] = { I_OnReload };
00105 ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation));
00106 this->OnReload();
00107 }
00108
00109 void OnReload() anope_override
00110 {
00111 ConfigReader config;
00112 prefix = config.ReadValue("chanstats", "prefix", "anope_", 0);
00113 Anope::string engine = config.ReadValue("chanstats", "engine", "", 0);
00114 this->sql = ServiceReference<SQL::Provider>("SQL::Provider", engine);
00115 }
00116
00117 SQL::Result RunQuery(const SQL::Query &query)
00118 {
00119 if (!this->sql)
00120 throw SQL::Exception("Unable to locate SQL reference, is m_mysql loaded and configured correctly?");
00121
00122 SQL::Result res = sql->RunQuery(query);
00123 if (!res.GetError().empty())
00124 throw SQL::Exception(res.GetError());
00125 return res;
00126 }
00127
00128 void DoTop(CommandSource &source, const std::vector<Anope::string> ¶ms, bool is_global, int limit = 1)
00129 {
00130 if (!source.c || !source.c->ci)
00131 return;
00132
00133 Anope::string channel;
00134 if (is_global || params.empty())
00135 channel = source.c->ci->name;
00136 else if (!params.empty())
00137 channel = params[0];
00138 else
00139 {
00140 source.Reply(_("%s not found."), params[0].c_str());
00141 return;
00142 }
00143
00144 try
00145 {
00146 SQL::Query query;
00147 query = "SELECT nick, letters, words, line, actions,"
00148 "smileys_happy+smileys_sad+smileys_other as smileys "
00149 "FROM `" + prefix + "chanstats` "
00150 "WHERE `nick` != '' AND `chan` = @channel@ AND `type` = 'total' "
00151 "ORDER BY `letters` DESC LIMIT @limit@;";
00152 query.SetValue("limit", limit, false);
00153
00154 if (is_global)
00155 query.SetValue("channel", "");
00156 else
00157 query.SetValue("channel", channel.c_str());
00158
00159 SQL::Result res = this->RunQuery(query);
00160
00161 if (res.Rows() > 0)
00162 {
00163 source.Reply(_("Top %i of %s"), limit, (is_global ? "Network" : channel.c_str()));
00164 for (int i = 0; i < res.Rows(); ++i)
00165 {
00166 source.Reply(_("%2lu \002%-16s\002 letters: %s, words: %s, lines: %s, smileys %s, actions: %s"),
00167 i+1, res.Get(i, "nick").c_str(), res.Get(i, "letters").c_str(),
00168 res.Get(i, "words").c_str(), res.Get(i, "line").c_str(),
00169 res.Get(0, "smileys").c_str(), res.Get(0, "actions").c_str());
00170 }
00171 }
00172 else
00173 source.Reply(_("No stats for %s."), is_global ? "Network" : channel.c_str());
00174 }
00175 catch (const SQL::Exception &ex)
00176 {
00177 Log(LOG_DEBUG) << ex.GetReason();
00178 }
00179 }
00180 };
00181
00182 void CommandCSTop::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms)
00183 {
00184 me->DoTop(source, params, false, 3);
00185 }
00186
00187 void CommandCSTop10::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms)
00188 {
00189 me->DoTop(source, params, false, 10);
00190 }
00191
00192 void CommandCSGTop::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms)
00193 {
00194 me->DoTop(source, params, true, 3);
00195 }
00196
00197 void CommandCSGTop10::Execute(CommandSource &source, const std::vector<Anope::string> ¶ms)
00198 {
00199 me->DoTop(source, params, true, 10);
00200 }
00201
00202
00203 MODULE_INIT(CSTop)