]> jfr.im git - irc/quakenet/newserv.git/blob - a4stats/nterfacer_a4stats.c
a4stats: Added DB queries for the search bar.
[irc/quakenet/newserv.git] / a4stats / nterfacer_a4stats.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include "../lib/version.h"
4 #include "../core/error.h"
5 #include "../nterfacer/library.h"
6 #include "../nterfacer/nterfacer.h"
7 #include "a4stats.h"
8
9 MODULE_VERSION("");
10
11 static struct service_node *a4stats_node;
12
13 static void a4stats_nt_query_cb(const struct DBAPIResult *result, void *uarg) {
14 struct rline *ri = uarg;
15 int i;
16
17 if (result) {
18 ri_append(ri, "%s", result->success ? "OK" : "FAILED");
19
20 if (result->success) {
21 ri_append(ri, "%d", result->fields);
22
23 while (result->next(result)) {
24 for (i = 0; i < result->fields; i++) {
25 const char *field = result->get(result, i);
26 ri_append(ri, "%s", field ? field : "");
27 }
28 }
29 }
30
31 result->clear(result);
32 } else
33 ri_append(ri, "FAILED");
34
35 ri_final(ri);
36 }
37
38 static int handle_getchannel(struct rline *ri, int argc, char **argv) {
39 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT timestamp, active, privacy, deleted FROM ? WHERE name = ?", "Ts", "channels", argv[0]);
40 return 0;
41 }
42
43 static int handle_getlines(struct rline *ri, int argc, char **argv) {
44 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11,"
45 "h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, h22, h23 "
46 "FROM ? WHERE name = ?", "Ts", "channels", argv[0]);
47
48 return 0;
49 }
50
51 static int handle_getusers(struct rline *ri, int argc, char **argv) {
52 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT users.account, users.accountid, users.seen, users.rating, users.lines, users.chars, users.words, users.h0, users.h1, users.h2, users.h3, users.h4, users.h5, users.h6, users.h7, users.h8, users.h9, users.h10, users.h11, users."
53 "h12, users.h13, users.h14, users.h15, users.h16, users.h17, users.h18, users.h19, users.h20, users.h21, users.h22, users.h23, users."
54 "last, users.quote, users.quotereset, users.mood_happy, users.mood_sad, users.questions, users.yelling, users.caps, users."
55 "slaps, users.slapped, users.highlights, users.kicks, users.kicked, users.ops, users.deops, users.actions, users.skitzo, users.foul, users."
56 "firstseen, users.curnick FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND users.quote IS NOT NULL ORDER BY lines DESC LIMIT 25", "TTs", "users", "channels", argv[0]);
57
58 return 0;
59 }
60
61 static int handle_getkicks(struct rline *ri, int argc, char **argv) {
62 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT kicks.kicker, kicks.kickerid, ukicker.seen, ukicker.curnick, kicks.victim, kicks.victimid, uvictim.seen, uvictim.curnick, kicks.timestamp, kicks.reason "
63 "FROM ? "
64 "LEFT JOIN ? ON channels.id = kicks.channelid "
65 "LEFT JOIN ? AS ukicker ON (ukicker.channelid = channels.id AND (kicks.kickerid != 0 AND kicks.kickerid = ukicker.accountid OR kicks.kickerid = 0 AND kicks.kicker = ukicker.account)) "
66 "LEFT JOIN ? AS uvictim ON (uvictim.channelid = channels.id AND (kicks.victimid != 0 AND kicks.victimid = uvictim.accountid OR kicks.victimid = 0 AND kicks.victim = uvictim.account)) "
67 "WHERE channels.name = ? ORDER BY kicks.timestamp DESC LIMIT 10", "TTTTs", "kicks", "channels", "users", "users", argv[0]);
68
69 return 0;
70 }
71
72 static int handle_gettopics(struct rline *ri, int argc, char **argv) {
73 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT topics.topic, topics.timestamp, topics.setby, topics.setbyid, users.seen, users.curnick "
74 "FROM ? "
75 "LEFT JOIN ? ON channels.id = topics.channelid "
76 "LEFT JOIN ? ON (users.channelid = channels.id AND (topics.setbyid != 0 AND topics.setbyid = users.accountid OR topics.setbyid = 0 AND topics.setby = users.account)) "
77 "WHERE channels.name = ? ORDER BY topics.timestamp DESC LIMIT 10", "TTTs", "topics", "channels", "users", argv[0]);
78
79 return 0;
80 }
81
82 static int handle_getuser(struct rline *ri, int argc, char **argv) {
83 #define USER_QUERY(a, b) a "users.account, users.accountid, users.seen, users.rating, users.lines, users.chars, users.words, " \
84 "users.h0, users.h1, users.h2, users.h3, users.h4, users.h5, users.h6, users.h7, users.h8, users.h9, " \
85 "users.h10, users.h11, users.h12, users.h13, users.h14, users.h15, users.h16, users.h17, users.h18, " \
86 "users.h19, users.h20, users.h21, users.h22, users.h23, users.last, users.quote, users.quotereset, " \
87 "users.mood_happy, users.mood_sad, users.questions, users.yelling, users.caps, users.slaps, users.slapped, " \
88 "users.highlights, users.kicks, users.kicked, users.ops, users.deops, users.actions, users.skitzo, " \
89 "users.foul, users.firstseen, users.curnick" b
90
91 /*
92 Possible cases:
93 accountid = 0, account = "username" -> new-style account, look up latest account for user
94 accountid = 0, account = "#username" -> legacy account or user not authed, look up using "username" (remove #)
95 accountid = <some value>, account = <unused> -> new-style account, look up by account id
96 */
97
98 if (argv[1][0] == '#') {
99 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("SELECT ", " FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND (users.accountid = 0 AND users.account = ?)"),
100 "TTss", "users", "channels", argv[0], &(argv[1][1]));
101 } else if (atoi(argv[2]) == 0) {
102 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("SELECT ", " FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND (users.accountid != 0 AND users.account = ?) ORDER BY users.accountid DESC LIMIT 1"),
103 "TTss", "users", "channels", argv[0], argv[1]);
104 } else {
105 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("SELECT ", " FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND users.accountid = ?"),
106 "TTss", "users", "channels", argv[0], argv[2]);
107 }
108
109 return 0;
110 }
111
112 static int handle_setprivacy(struct rline *ri, int argc, char **argv) {
113 a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE name = ?", "Tss", "channels", argv[1], argv[0]);
114 return ri_final(ri);
115 }
116
117 static int handle_finduser(struct rline *ri, int argc, char **argv) {
118 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT DISTINCT ON (curnick) * FROM "
119 "(SELECT DISTINCT ON (account, accountid) account, accountid, seen, curnick "
120 "FROM ? WHERE curnick LIKE ? OR account LIKE ? ORDER BY account, accountid, curnick DESC) "
121 "AS users ORDER BY curnick, seen DESC LIMIT 50", "Tss", "users", argv[0], argv[0]);
122
123 return 0;
124 }
125
126 static int handle_findchan(struct rline *ri, int argc, char **argv) {
127 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT name, privacy FROM ? WHERE name LIKE ?",
128 "Ts", "channels", argv[0]);
129
130 return 0;
131 }
132
133
134 static int handle_getuserchans(struct rline *ri, int argc, char **argv) {
135 #define USERCHANS_QUERY(b) "SELECT channels.name, channels.privacy FROM ? JOIN ? ON channels.id = users.channelid WHERE channels.active = 1 AND " b
136 /*
137 Possible cases:
138 accountid = 0, account = "username" -> new-style account, look up latest account for user
139 accountid = 0, account = "#username" -> legacy account or user not authed, look up using "username" (remove #)
140 accountid = <some value>, account = <unused> -> new-style account, look up by account id
141 */
142
143 if (argv[0][0] == '#') {
144 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USERCHANS_QUERY("(users.accountid = 0 AND users.account = ?)"),
145 "TTs", "users", "channels", &(argv[0][1]));
146 } else if (atoi(argv[1]) == 0) {
147 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT channels.name, channels.privacy "
148 "FROM ? JOIN ? ON channels.id = users.channelid "
149 "WHERE channels.active = 1 AND ROW(users.account, users.accountid) = "
150 "(SELECT account, accountid FROM a4stats.users WHERE users.accountid != 0 AND users.account = ? ORDER BY users.accountid DESC LIMIT 1)",
151 "TTs", "users", "channels", argv[0]);
152 } else {
153 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USERCHANS_QUERY("users.accountid = ?"),
154 "TTs", "users", "channels", argv[1]);
155 }
156
157 return 0;
158 }
159
160 void _init(void) {
161 a4stats_node = register_service("a4stats");
162 if (!a4stats_node)
163 return;
164
165 register_handler(a4stats_node, "getchannel", 1, handle_getchannel);
166 register_handler(a4stats_node, "getlines", 1, handle_getlines);
167 register_handler(a4stats_node, "getusers", 1, handle_getusers);
168 register_handler(a4stats_node, "getkicks", 1, handle_getkicks);
169 register_handler(a4stats_node, "gettopics", 1, handle_gettopics);
170 register_handler(a4stats_node, "getuser", 3, handle_getuser);
171 register_handler(a4stats_node, "setprivacy", 2, handle_setprivacy);
172 register_handler(a4stats_node, "finduser", 1, handle_finduser);
173 register_handler(a4stats_node, "findchan", 1, handle_findchan);
174 register_handler(a4stats_node, "getuserchans", 2, handle_getuserchans);
175 }
176
177 void _fini(void) {
178 if (a4stats_node)
179 deregister_service(a4stats_node);
180 }