3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-10-04 18:38:47 +02:00

Improve recall command with better capabilities

The nick field is now optional and Getopt::Long is used to accept targeted
options for channel/history, allowing recalls by text/channel for any nick
which is useful when you know what text the message contained but not who
said it.
This commit is contained in:
Pragmatic Software 2014-05-14 21:23:59 +00:00
parent dad69fb0c8
commit 92b4ef00cf
4 changed files with 120 additions and 35 deletions

View File

@ -12,6 +12,7 @@ package PBot::MessageHistory;
use warnings;
use strict;
use Getopt::Long qw(GetOptionsFromString);
use Time::HiRes qw(gettimeofday tv_interval);
use Time::Duration;
use Carp ();
@ -62,50 +63,110 @@ sub recall_message {
return "";
}
my $usage = 'Usage: recall [nick [history [channel]]] [-c,channel <channel>] [-t,text,h,history <history>] [+ ...]';
if(not defined $arguments or not length $arguments) {
return "Usage: recall <nick> [history [channel]] -- where [history] is an optional argument that is either an integral number of recent messages or a regex (without whitespace) of the text within the message; e.g., to recall the 3rd most recent message for nick, use `recall nick 3` or to recall a message containing 'pizza', use `recall nick pizza`; and [channel] is an optional channel, so you can use it from /msg (you will need to also specify [history] in this case)";
return $usage;
}
$arguments = lc $arguments;
my @recalls = split /\s\+\s/, $arguments;
my ($recall_nick, $recall_history, $channel, $recall_nicks, $recall_text);
my $getopt_error;
local $SIG{__WARN__} = sub {
$getopt_error = shift;
chomp $getopt_error;
};
my $recall_text;
foreach my $recall (@recalls) {
($recall_nick, $recall_history, $channel) = split(/\s+/, $recall, 3);
my ($recall_nick, $recall_history, $recall_channel);
$recall_history = $nick eq $recall_nick ? 2 : 1 if not defined $recall_history; # skip recall command if recalling self without arguments
$channel = $from if not defined $channel;
my ($ret, $args) = GetOptionsFromString($recall,
'channel|c=s' => \$recall_channel,
'text|t|history|h=s' => \$recall_history);
my ($account, $found_nick) = $self->{database}->find_message_account_by_nick($recall_nick);
return "$getopt_error -- $usage" if defined $getopt_error;
if(not defined $account) {
return "I don't know anybody named $recall_nick.";
my $channel_arg = 1 if defined $recall_channel;
my $history_arg = 1 if defined $recall_history;
$recall_nick = shift @$args;
$recall_history = shift @$args if not defined $recall_history;
$recall_channel = shift @$args if not defined $recall_channel;
# swap nick and channel if recall nick looks like channel and channel wasn't specified
if(not $channel_arg and $recall_nick =~ m/^#/) {
my $temp = $recall_nick;
$recall_nick = $recall_channel;
$recall_channel = $temp;
}
# swap history and channel if history looks like a channel and neither history or channel were specified
if(not $channel_arg and not $history_arg and $recall_history =~ m/^#/) {
my $temp = $recall_history;
$recall_history = $recall_channel;
$recall_channel = $temp;
}
# skip recall command if recalling self without arguments
$recall_history = $nick eq $recall_nick ? 2 : 1 if defined $recall_nick and not defined $recall_history;
# set history to most recent message if not specified
$recall_history = '1' if not defined $recall_history;
# set channel to current channel if not specified
$recall_channel = $from if not defined $recall_channel;
my ($account, $found_nick);
if(defined $recall_nick) {
($account, $found_nick) = $self->{database}->find_message_account_by_nick($recall_nick);
if(not defined $account) {
return "I don't know anybody named $recall_nick.";
}
}
my $message;
if($recall_history =~ /^\d+$/) {
# integral history
my $max_messages = $self->{database}->get_max_messages($account, $channel);
if($recall_history < 1 || $recall_history > $max_messages) {
return "Please choose a history between 1 and $max_messages";
if(defined $account) {
my $max_messages = $self->{database}->get_max_messages($account, $recall_channel);
if($recall_history < 1 || $recall_history > $max_messages) {
return "Please choose a history between 1 and $max_messages";
}
}
$recall_history--;
$message = $self->{database}->recall_message_by_count($account, $recall_channel, $recall_history, 'recall');
$message = $self->{database}->recall_message_by_count($account, $channel, $recall_history, 'recall');
if(not defined $message) {
return "No message found at index $recall_history in channel $recall_channel.";
}
} else {
# regex history
$message = $self->{database}->recall_message_by_text($account, $channel, $recall_history, 'recall');
$message = $self->{database}->recall_message_by_text($account, $recall_channel, $recall_history, 'recall');
if(not defined $message) {
return "No such message for nick $found_nick in channel $channel containing text '$recall_history'";
if(defined $account) {
return "No such message for nick $found_nick in channel $recall_channel containing text '$recall_history'";
} else {
return "No such message in channel $recall_channel containing text '$recall_history'";
}
}
}
$self->{pbot}->logger->log("$nick ($from) recalled <$recall_nick/$channel> $message->{msg}\n");
if(defined $message->{id}) {
my $hostmask = $self->{database}->find_most_recent_hostmask($message->{id});
($found_nick) = $hostmask =~ m/^([^!]+)/;
$recall_nick = $found_nick;
}
$self->{pbot}->logger->log("$nick ($from) recalled <$recall_nick/$recall_channel> $message->{msg}\n");
my $text = $message->{msg};
my $ago = ago(gettimeofday - $message->{timestamp});

View File

@ -409,14 +409,26 @@ SQL
sub recall_message_by_count {
my ($self, $id, $channel, $count, $ignore_command) = @_;
my $messages = eval {
my $sth = $self->{dbh}->prepare('SELECT msg, mode, timestamp FROM Messages WHERE id = ? AND channel = ? ORDER BY timestamp DESC LIMIT 10 OFFSET ?');
$sth->bind_param(1, $id);
$sth->bind_param(2, $channel);
$sth->bind_param(3, $count);
$sth->execute();
return $sth->fetchall_arrayref({});
};
my $messages;
if(defined $id) {
$messages = eval {
my $sth = $self->{dbh}->prepare('SELECT msg, mode, timestamp FROM Messages WHERE id = ? AND channel = ? ORDER BY timestamp DESC LIMIT 10 OFFSET ?');
$sth->bind_param(1, $id);
$sth->bind_param(2, $channel);
$sth->bind_param(3, $count);
$sth->execute();
return $sth->fetchall_arrayref({});
};
} else {
$messages = eval {
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp FROM Messages WHERE channel = ? ORDER BY timestamp DESC LIMIT 10 OFFSET ?');
$sth->bind_param(1, $channel);
$sth->bind_param(2, $count);
$sth->execute();
return $sth->fetchall_arrayref({});
};
}
$self->{pbot}->logger->log($@) if $@;
@ -438,14 +450,26 @@ sub recall_message_by_text {
$text =~ s/\*/%/g;
$text =~ s/\?/_/g;
my $messages = eval {
my $sth = $self->{dbh}->prepare('SELECT msg,mode,timestamp FROM Messages WHERE id = ? AND channel = ? AND msg LIKE ? ORDER BY timestamp DESC LIMIT 10');
$sth->bind_param(1, $id);
$sth->bind_param(2, $channel);
$sth->bind_param(3, "%$text%");
$sth->execute();
return $sth->fetchall_arrayref({});
};
my $messages;
if(defined $id) {
$messages = eval {
my $sth = $self->{dbh}->prepare('SELECT msg,mode,timestamp FROM Messages WHERE id = ? AND channel = ? AND msg LIKE ? ORDER BY timestamp DESC LIMIT 10');
$sth->bind_param(1, $id);
$sth->bind_param(2, $channel);
$sth->bind_param(3, "%$text%");
$sth->execute();
return $sth->fetchall_arrayref({});
};
} else {
$messages = eval {
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp FROM Messages WHERE channel = ? AND msg LIKE ? ORDER BY timestamp DESC LIMIT 10');
$sth->bind_param(1, $channel);
$sth->bind_param(2, "%$text%");
$sth->execute();
return $sth->fetchall_arrayref({});
};
}
$self->{pbot}->logger->log($@) if $@;

View File

@ -315,7 +315,7 @@ sub show_random_quotegrab {
return "";
}
my $usage = 'Usage: rq [nick regex] [-c,--channel <channel regex>] [-t,--text <text regex>]';
my $usage = 'Usage: rq [nick [channel [text]]] [-c,--channel <channel>] [-t,--text <text>]';
if(defined $arguments) {
my $getopt_error;

View File

@ -13,8 +13,8 @@ use warnings;
# These are set automatically by the build/commit script
use constant {
BUILD_NAME => "PBot",
BUILD_REVISION => 572,
BUILD_DATE => "2014-05-13",
BUILD_REVISION => 573,
BUILD_DATE => "2014-05-14",
};
1;