1 #**************************************************************************
2 # Copyright (C) 2009 by Michael Andreen <harvATruinDOTnu> *
4 # This program is free software; you can redistribute it and/or modify *
5 # it under the terms of the GNU General Public License as published by *
6 # the Free Software Foundation; either version 2 of the License, or *
7 # (at your option) any later version. *
9 # This program is distributed in the hope that it will be useful, *
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 # GNU General Public License for more details. *
14 # You should have received a copy of the GNU General Public License *
15 # along with this program; if not, write to the *
16 # Free Software Foundation, Inc., *
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 #**************************************************************************/
25 use NDIRC::Dispatcher;
28 help => q(syntax: .+user username id | username must be alphanum characters, assumes discord id if it ends with #XXXX otherwise pnick),
31 }, class extends NDIRC::Command {
32 method execute ($c,$msg) {
33 my ($nick,$id) = $msg =~ /^(\w+) (.+)$/ or die 'ARGS';
37 my $discordid = undef;
40 if ($id =~ /.+#\d+/) {
44 $host = "$pnick.users.netgamers.org";
46 my ($username,$hostname,$p_nick,$discord_id) = $dbh->selectrow_array(q{
47 SELECT username, hostmask,pnick,discord_id
48 FROM users WHERE username = $1 OR hostmask = $2 OR pnick = $3 OR discord_id = $4
49 },undef,$nick,$host,$pnick,$discordid);
51 if (defined $username){
52 $c->reply("<b>$username ($p_nick, $discord_id)</b> already exists with host: <b>$hostname</b>");
55 INSERT INTO users (username,hostmask,pnick,discord_id) VALUES($1,$2,$3,$4)
56 },undef,$nick,$host,$pnick,$discordid);
57 $c->reply("Added <b>$nick(/$id)</b>");
63 help => q(syntax: .-user nick | nick must be alphanum characters, if no pnick is given then it will be set to nick),
65 acl => 'irc_deactivateuser'
66 }, class extends NDIRC::Command {
67 method execute ($c,$msg) {
68 my ($nick) = $msg =~ /^(\S+)$/ or die 'ARGS';
71 my $f = $dbh->prepare(q{SELECT uid,username FROM users WHERE username ILIKE ?});
73 my ($uid,$username) = $f->fetchrow();
76 my $updated = $dbh->do(q{
77 UPDATE users SET hostmask = $1, password = NULL WHERE uid = $2
78 },undef,$username,$uid);
80 my $groups = $dbh->do(q{DELETE FROM groupmembers WHERE uid = ?},undef,$uid);
82 $c->reply("<b>$username</b> has been deactivated. Removed from $groups groups.");
84 $c->reply("Something went wrong when trying to modify <b>$username</b>");
86 }elsif ($f->rows == 0){
87 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
89 $c->reply("More than 1 user matched, please refine the search");
96 help => q(syntax: .chattr username [-]flags | % can be used for wildcards \%arro% will match barrow, if a - is given then flags will be removed, otherwise added),
99 }, class extends NDIRC::Command {
100 method execute ($c,$msg) {
101 my ($nick, $mode, $flags) = $msg =~ /^(\S+) (\+|-)?(\w+)$/ or die 'ARGS';
104 my $f = $dbh->prepare(q{SELECT uid,username FROM users WHERE username ILIKE ?});
106 my $user = $f->fetchrow_hashref;
110 $update = $dbh->prepare(q{
111 DELETE FROM groupmembers WHERE uid = $1 AND gid = ANY($2)
114 $update = $dbh->prepare(q{
115 INSERT INTO groupmembers (uid,gid)
116 (SELECT $1,gid FROM unnest($2::text[]) gid WHERE
117 gid NOT IN (SELECT gid FROM groupmembers WHERE uid = $1)
118 AND gid IN (SELECT gid FROM groups))
121 my @flags = split /\W*/,$flags;
122 $update->execute($user->{uid},\@flags);
123 $update = $dbh->prepare(q{
124 SELECT array_to_string(array_agg(gid),'')
125 FROM (SELECT uid,gid FROM groupmembers ORDER BY uid,gid ) g
128 $flags = $dbh->selectrow_array($update,undef,$user->{uid});
129 $c->reply("Flags for <b>$user->{username}</b> are now: $flags");
130 }elsif ($f->rows == 0){
131 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
133 $c->reply("More than 1 user matched, please refine the search");
140 help => q(Lists all the available flags),
142 }, class extends NDIRC::Command {
143 method execute ($c,$msg) {
145 my ($flags) = $dbh->selectrow_array(q{
146 SELECT array_to_string(array_agg(gid||':'||groupname),', ') FROM groups
148 $c->reply("Current flags: $flags");
153 help => q(syntax: .whois username | % can be used for wildcards \%arro% will match barrow.),
155 }, class extends NDIRC::Command {
156 method execute ($c,$msg) {
157 my ($nick) = $msg =~ /^(\S+)$/ or die 'ARGS';
161 my $f = $dbh->prepare(q{
162 SELECT username, pnick, hostmask, array_to_string(array_agg(gid),'') AS flags
164 LEFT OUTER JOIN (SELECT uid,gid FROM groupmembers ORDER BY uid,gid
166 WHERE username ILIKE ?
167 GROUP BY username,pnick,hostmask LIMIT 5
170 while (my $user = $f->fetchrow_hashref){
171 $c->reply("<b>$user->{username} (/$user->{pnick})</b> flags: ($user->{flags}) host: $user->{hostmask}");
174 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
180 help => q(syntax: .flag flag [-noflags] | Lists all users with the given flag. Can specify a second argument to remove members that has any of those flags. .flag M -C lists all members that doesn't have community flag),
182 }, class extends NDIRC::Command {
183 method execute ($c,$msg) {
184 my ($flag,$noflag) = $msg =~ /^(\w)(?: -(\w+))?$/ or die 'ARGS';
187 my $f = $c->model->prepare(q{
188 SELECT array_to_string(array_agg(username),', '),count(username)
189 FROM (SELECT uid, username FROM users ORDER BY username) u
190 JOIN groupmembers gm USING (uid)
191 WHERE gid = $1 AND uid NOT IN (SELECT uid FROM groupmembers WHERE gid = ANY($2))
193 my @noflag = split //, $noflag;
194 my ($users,$count) = $c->model->selectrow_array($f,undef,$flag,\@noflag);
195 $c->reply("<b>$count</b> Users with flag <b>$flag</b>: $users");
200 help => q(syntax: .laston flag [days] | lists users and the number of days since they were last seen (irc|forum|claim). If days is specified it will only list users with at least that amount of idle time. Days can also specify forum and claim with irc|forum|claim syntax),
202 }, class extends NDIRC::Command {
203 method execute ($c,$msg) {
204 my ($flag,$min,$forum,$claim) = $msg =~ /^(\w)(?: (\d+)(?:\|(\d+)\|(\d+))?)?$/
208 my $f = $c->model->prepare(q{
209 SELECT username, COALESCE(last::text,'?') AS last
210 ,COALESCE(lastforum::text,'?') AS lastforum
211 ,COALESCE(lastclaim::text,'?') AS lastclaim
212 FROM (SELECT username
213 ,date_part('day',now() - laston)::int AS last
214 ,date_part('day',now() -
215 (SELECT max(time) FROM forum_thread_visits WHERE uid = u.uid)) AS lastforum
216 ,date_part('day',now() -
217 (SELECT max(timestamp) FROM raid_claims WHERE uid = u.uid)) AS lastclaim
219 NATURAL JOIN groupmembers
222 WHERE COALESCE(last >= $2,TRUE) AND COALESCE(lastforum >= $3,TRUE)
223 AND COALESCE(lastclaim >= $4,TRUE)
224 ORDER BY a.last DESC, a.lastforum DESC, a.lastclaim DESC
226 $f->execute($flag,$min,$forum,$claim);
230 while (my $user = $f->fetchrow_hashref){
231 $text .= "$user->{username}($user->{last}|$user->{lastforum}|$user->{lastclaim}) ";
234 $c->reply("<b>$i</b> Users(days) with flag <b>$flag</b>: $text");
239 command lastseen => {
240 help => q(syntax: .lastseen username | Shows the number of days since the user(s) last visited irc, forum and raids),
241 acl => 'irc_lastseen'
242 }, class extends NDIRC::Command {
243 method execute ($c,$msg) {
244 my ($username) = $msg =~ /^(\S+)$/ or die 'ARGS';
246 my $f = $c->model->prepare(q{
247 SELECT username, COALESCE(date_part('day',now() - laston)::text,'?') AS last
248 ,COALESCE(date_part('day',now() - (SELECT max(time)
249 FROM forum_thread_visits WHERE uid = u.uid))::text,'?') AS lastforum
250 ,COALESCE(date_part('day',now() - (SELECT max(timestamp)
251 FROM raid_claims WHERE uid = u.uid))::text,'?') AS lastclaim
253 WHERE username ILIKE $1 ORDER BY username
255 $f->execute($username);
259 while (my $user = $f->fetchrow_hashref){
260 $text .= "$user->{username}($user->{last}|$user->{lastforum}|$user->{lastclaim}) ";
263 $c->reply("<b>$i</b> Users(days): $text");
267 command getships => {
268 help => q(Usage: .getships ship | % can be used as wildcard, e.g. beet%, shipshome shows the number of ships currently home),
269 alias => 'shipshome',
270 acl => 'irc_getships'
271 }, class extends NDIRC::Command {
272 method execute ($c,$msg) {
273 my ($ship) = $msg =~ /^(\S+)$/ or die 'ARGS';
276 my $f = $dbh->prepare(q{
277 SELECT username,SUM(fs.amount) AS amount
279 JOIN (SELECT DISTINCT ON (pid) pid,fid FROM fleets
280 WHERE mission = 'Full fleet' AND name <> 'Unit'
281 ORDER BY pid,tick DESC,fid DESC
283 JOIN fleet_ships fs USING (fid)
284 WHERE ship ILIKE $1 AND uid IN (SELECT uid FROM groupmembers WHERE gid = 'M')
285 GROUP BY username ORDER BY amount DESC
287 if ($self->name eq 'shipshome'){
288 $f = $dbh->prepare(q{
289 SELECT username,SUM(amount) AS amount
291 WHERE ship ILIKE ? AND uid IN (SELECT uid FROM groupmembers WHERE gid = 'M')
292 GROUP BY username ORDER BY amount DESC
299 while (my $user = $f->fetchrow_hashref){
300 $text .= "$user->{username}: $user->{amount} ";
302 $total += $user->{amount};
305 $c->reply("<b>$i</b> Users with <b>$total $ship</b>: $text");
307 $c->reply("Couldn't find any user with <b>$ship</b>");
312 command getfleet => {
313 help => q(Usage: .getfleet username | % can be used as wildcard, e.g. barr%),
314 acl => q(irc_getfleet)
315 }, class extends NDIRC::Command {
316 method execute ($c,$msg) {
317 my ($nick) = $msg =~ /^(\S+)$/ or die 'ARGS';
320 my $f = $dbh->prepare(q{
321 SELECT fs.ship, fs.amount, username
323 JOIN (SELECT fid,username
325 JOIN users u USING (pid)
326 WHERE mission = 'Full fleet' AND name <> 'Unit'
327 AND username ILIKE $1
328 ORDER BY pid,tick DESC,fid DESC
336 while (my $ship = $f->fetchrow_hashref){
337 unless (defined $username) {
338 $username = $ship->{username};
339 $text = "<b>$username</b> has: "
341 $text .= "$ship->{ship} $ship->{amount} ";
346 $c->reply("Couldn't find any fleet for $nick");
352 help => q(Usage: .sethost username [host] | if host isn't given then it resets to netgamers host),
353 acl => q(irc_sethost)
354 }, class extends NDIRC::Command {
355 method execute ($c,$msg) {
356 my ($nick,$host) = $msg =~ /^(\S+)(?: (\S+))?$/ or die 'ARGS';
359 my $f = $dbh->prepare(q{
360 SELECT uid,username,pnick,hostmask FROM users WHERE username ILIKE ?
363 my $user = $f->fetchrow_hashref;
365 $host //= "$user->{pnick}.users.netgamers.org";
367 $dbh->do(q{UPDATE users SET hostmask = ? WHERE uid = ?}
368 ,undef,$host,$user->{uid});
369 $c->reply("Updated <b>$user->{username}</b>'s host to: <b>$host</b>");
372 if ($@ =~ /duplicate key value violates unique constraint/){
373 my ($username, $hostname) = $dbh->selectrow_array(q{
374 SELECT username,hostmask FROM users WHERE hostmask = $1
376 $c->reply("<c04>Problem</c>, <b>$username</b> already uses host <b>$hostname</b>.");
381 }elsif ($f->rows == 0){
382 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
384 $c->reply("More than 1 user matched, please refine the search");
390 command setpnick => {
391 help => q(Usage: .setpnick username pnick | Changes a user's pnick),
392 acl => q(irc_setpnick)
393 }, class extends NDIRC::Command {
394 method execute ($c,$msg) {
395 my ($nick,$pnick) = $msg =~ /^(\S+) (\S+)$/ or die 'ARGS';
398 my $f = $dbh->prepare(q{SELECT uid,username FROM users WHERE username ILIKE ?});
400 my $user = $f->fetchrow_hashref;
402 my $hostname = "$pnick.users.netgamers.org";
404 $dbh->do(q{UPDATE users SET pnick = ?, hostmask = ? WHERE uid = ?}
405 ,undef,$pnick,$hostname,$user->{uid});
406 $c->reply("Updated <b>$user->{username}</b>'s pnick to: <b>$pnick</b> and hostname to <b>$hostname</b>");
409 if ($@ =~ /duplicate key value violates unique constraint/){
410 my ($username, $hostname, $pnick) = $dbh->selectrow_array(q{
411 SELECT username,hostmask,pnick FROM users WHERE hostmask = $1 OR pnick = $2
412 },undef,$hostname, $pnick);
413 $c->reply("<c04>Problem</c>, <b>$username</b> already uses host <b>$hostname</b> and pnick <b>$pnick</b>.");
418 }elsif ($f->rows == 0){
419 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
421 $c->reply("More than 1 user matched, please refine the search");
427 command setdiscordid => {
428 help => q(Usage: .setdiscordid username discordid | Changes a user's discord id/tag Nick#id),
429 acl => q(bot_setdiscordid)
430 }, class extends NDIRC::Command {
431 method execute ($c,$msg) {
432 my ($nick,$discordid) = $msg =~ /^(\S+) (\S+)$/ or die 'ARGS';
435 my $f = $dbh->prepare(q{SELECT uid,username FROM users WHERE username ILIKE ?});
437 my $user = $f->fetchrow_hashref;
440 $dbh->do(q{UPDATE users SET discord_id = NULLIF($1, 'NULL') WHERE uid = $2}
441 ,undef,$discordid,$user->{uid});
442 $c->reply("Updated <b>$user->{username}</b>'s discord id to: <b>$discordid</b>");
445 if ($@ =~ /duplicate key value violates unique constraint/){
446 my ($username, $discordid) = $dbh->selectrow_array(q{
447 SELECT username,discord_id FROM users WHERE discord_id = $1
449 $c->reply("<c04>Problem</c>, <b>$username</b> already uses discord id <b>$discordid</b>.");
454 }elsif ($f->rows == 0){
455 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
457 $c->reply("More than 1 user matched, please refine the search");
463 my $points = class extends NDIRC::Command {
469 method execute ($c,$msg) {
470 my ($nick,$points) = $msg =~ /^(\S+)(?: (-?(:?\d+|\d*\.\d+)))?$/ or die 'ARGS';
474 return unless $self->check($c,$nick,$points);
478 if ($points*$points > 400){
479 $c->reply("Values between -20 and 20 please");
483 my $f = $dbh->prepare(q{SELECT uid,username FROM users WHERE username ILIKE ?});
485 my $user = $f->fetchrow_hashref;
487 my $type .= $self->point . "_points";
488 $dbh->do(qq{UPDATE users SET $type = $type + ? WHERE uid = ?}
489 ,undef,$points,$user->{uid});
490 $c->reply("$user->{username} has been given $points $type");
491 }elsif ($f->rows == 0){
492 $c->reply("No hit, maybe spelling mistake, or add % as wildcard");
494 $c->reply("More than 1 user matched, please refine the search");
498 method check ($c,$nick,$points) {
504 help => q(Usage: .a username [points] | % can be used for wildcards %arro% will match barrow, if the number of points isn't specified, then 1 will be assumed.),
508 extends $points->name;
509 method check ($c,$nick,$points) {
510 my ($fleets) = $c->model->selectrow_array(q{
511 SELECT count(*) FROM raids r
512 JOIN raid_targets rt ON r.id = rt.raid
513 JOIN raid_claims rc ON rt.id = rc.target
514 WHERE not launched AND tick + 24 > tick()
515 AND uid = (SELECT uid FROM users WHERE username ILIKE $1);
518 if ($fleets > 0 && $points > 0){
519 $c->reply("$nick has $fleets claimed waves the last 24 ticks that aren't marked as launched, so no points.");
527 help => q(Usage: .d username [points] | % can be used for wildcards %arro% will match barrow, if the number of points isn't specified, then 1 will be assumed.),
534 help => q(Usage: .s username [points] | % can be used for wildcards %arro% will match barrow, if the number of points isn't specified, then 1 will be assumed.),
540 help => q(Usage: .h username [points] | % can be used for wildcards %arro% will match barrow, if the number of points isn't specified, then 1 will be assumed.),
546 help => q(Usage: .getanti class [eta] | class is the target class, like fi or bs, eta is optional max eta for the ships.),
547 acl => q(irc_getships),
548 }, class extends NDIRC::Command {
549 method execute ($c,$msg) {
550 my ($class,$eta) = $msg =~ /^(\S+)(?: (\d+))?$/ or die 'ARGS';
555 my @classes = qw/Fi Co Fr De Cr Bs/;
557 if (lc $class eq lc $_){
569 my $f = $dbh->prepare(q{
570 SELECT username, ship, amount, CASE WHEN $1 = t1 THEN 't1' ELSE 't2' END AS t
571 FROM available_ships a
572 JOIN ship_stats s USING (ship)
573 WHERE uid IN (SELECT uid FROM groupmembers WHERE gid = 'M')
576 ORDER BY amount*(metal+crystal+eonium)*CASE WHEN $1 = t1 THEN 1.0 ELSE 0.6 END DESC
578 $f->execute($class,\@classes);
582 while (my $user = $f->fetchrow_hashref){
583 $text .= "($user->{username}: $user->{ship} $user->{amount} $user->{t}) ";
585 $total += $user->{amount};
588 $c->reply("<b>$i</b> fleets with anti-<b>$class</b>: $text");
590 $c->reply("Couldn't find any user with anti-<b>$class</b>");
596 help => q(Gives new users a random password.),
598 }, class extends NDIRC::Command {
600 ###########################################################
601 # Written by Guy Malachi http://guymal.com
603 ###########################################################
604 sub generate_random_string
606 my $length_of_randomstring=shift;# the length of
607 # the random string to generate
609 my @chars=('a'..'z','A'..'Z','0'..'9','_');
611 foreach (1..$length_of_randomstring)
613 # rand @chars will generate a random
614 # number between 0 and scalar @chars
615 $random_string .= $chars[rand @chars];
617 return $random_string;
620 method execute ($c,$msg) {
623 my $password = generate_random_string 16;
624 my $update = $dbh->do(q{
625 UPDATE users SET password = $1
626 WHERE uid = $2 AND password IS NULL
627 },undef,$password,$c->uid);
629 $c->reply("Password set to: $password (you can change it on webbie)");
631 $c->reply("Couldn't set password. Either it has already been set or you don't have an account");