Add ability to get surrounding message context in recall command

Add the -b/-before and -a/-after flags to the `recall` command to display
that many lines of surrounding context.

For example, `recall -c ##c -b 100` will show the last 100 messages in the ##c
channel.

Another example, `recall pragma- 50 -b 5 -a 5` will show the 5 messages before the 50th
most recent message spoken by pragma- and then show that 50th message and finally show
the 5 messages after it.
This commit is contained in:
Pragmatic Software 2015-01-23 07:36:39 -08:00
parent 8810605691
commit b806a473d2
2 changed files with 78 additions and 25 deletions

View File

@ -123,7 +123,7 @@ sub recall_message {
return "";
}
my $usage = 'Usage: recall [nick [history [channel]]] [-c,channel <channel>] [-t,text,h,history <history>] [+ ...]';
my $usage = 'Usage: recall [nick [history [channel]]] [-c,channel <channel>] [-t,text,h,history <history>] [-b,before <context before>] [-a,after <context after>] [+ ...]';
if(not defined $arguments or not length $arguments) {
return $usage;
@ -142,11 +142,13 @@ sub recall_message {
my $recall_text;
foreach my $recall (@recalls) {
my ($recall_nick, $recall_history, $recall_channel);
my ($recall_nick, $recall_history, $recall_channel, $recall_before, $recall_after);
my ($ret, $args) = GetOptionsFromString($recall,
'channel|c=s' => \$recall_channel,
'text|t|history|h=s' => \$recall_history);
'channel|c=s' => \$recall_channel,
'text|t|history|h=s' => \$recall_history,
'before|b=s' => \$recall_before,
'after|a=s' => \$recall_after);
return "$getopt_error -- $usage" if defined $getopt_error;
@ -156,6 +158,8 @@ sub recall_message {
$recall_nick = shift @$args;
$recall_history = shift @$args if not defined $recall_history;
$recall_channel = shift @$args if not defined $recall_channel;
$recall_before = 0 if not defined $recall_before;
$recall_after = 0 if not defined $recall_after;
# swap nick and channel if recall nick looks like channel and channel wasn't specified
if(not $channel_arg and $recall_nick =~ m/^#/) {
@ -220,28 +224,30 @@ sub recall_message {
}
}
if(defined $message->{id}) {
my $hostmask = $self->{database}->find_most_recent_hostmask($message->{id});
($found_nick) = $hostmask =~ m/^([^!]+)/;
$recall_nick = $found_nick;
if ($recall_before + $recall_after > 200) {
return "You may only select 200 lines of surrounding context.";
}
$self->{pbot}->{logger}->log("$nick ($from) recalled <$recall_nick/$recall_channel> $message->{msg}\n");
my $messages = $self->{database}->get_message_context($message, $recall_before, $recall_after);
my $text = $message->{msg};
my $ago = ago(gettimeofday - $message->{timestamp});
foreach my $msg (@$messages) {
$self->{pbot}->{logger}->log("$nick ($from) recalled <$msg->{nick}/$msg->{channel}> $msg->{msg}\n");
if(not defined $recall_text) {
if($text =~ s/^\/me\s+// or $text =~ m/^KICKED /) {
$recall_text = "[$ago] * $found_nick $text";
my $text = $msg->{msg};
my $ago = ago(gettimeofday - $msg->{timestamp});
if(not defined $recall_text) {
if($text =~ s/^\/me\s+// or $text =~ m/^KICKED /) {
$recall_text = "[$ago] * $msg->{nick} $text\n";
} else {
$recall_text = "[$ago] <$msg->{nick}> $text\n";
}
} else {
$recall_text = "[$ago] <$found_nick> $text";
}
} else {
if($text =~ s/^\/me\s+// or $text =~ m/^KICKED /) {
$recall_text .= " [$ago] * $found_nick $text";
} else {
$recall_text .= " [$ago] <$found_nick> $text";
if($text =~ s/^\/me\s+// or $text =~ m/^KICKED /) {
$recall_text .= "[$ago] * $msg->{nick} $text\n";
} else {
$recall_text .= "[$ago] <$msg->{nick}> $text\n";
}
}
}
}

View File

@ -441,6 +441,53 @@ SQL
return $messages;
}
sub get_message_context {
my ($self, $message, $before, $after) = @_;
my ($messages_before, $messages_after);
if (defined $before and $before > 0) {
$messages_before = eval {
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel FROM Messages WHERE channel = ? AND timestamp < ? AND mode != 1 ORDER BY timestamp DESC LIMIT ?');
$sth->bind_param(1, $message->{channel});
$sth->bind_param(2, $message->{timestamp});
$sth->bind_param(3, $before);
$sth->execute();
return [reverse @{$sth->fetchall_arrayref({})}];
};
$self->{pbot}->{logger}->log($@) if $@;
}
if (defined $after and $after > 0) {
$messages_after = eval {
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel FROM Messages WHERE channel = ? AND timestamp > ? AND mode != 1 LIMIT ?');
$sth->bind_param(1, $message->{channel});
$sth->bind_param(2, $message->{timestamp});
$sth->bind_param(3, $after);
$sth->execute();
return $sth->fetchall_arrayref({});
};
$self->{pbot}->{logger}->log($@) if $@;
}
my @messages;
push(@messages, @$messages_before) if defined $messages_before;
push(@messages, $message);
push(@messages, @$messages_after) if defined $messages_after;
my %nicks;
foreach my $msg (@messages) {
if (not exists $nicks{$msg->{id}}) {
my $hostmask = $self->find_most_recent_hostmask($msg->{id});
my ($nick) = $hostmask =~ m/^([^!]+)/;
$nicks{$msg->{id}} = $nick;
}
$msg->{nick} = $nicks{$msg->{id}};
}
return \@messages;
}
sub recall_message_by_count {
my ($self, $id, $channel, $count, $ignore_command) = @_;
@ -448,7 +495,7 @@ sub recall_message_by_count {
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 ?');
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel 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);
@ -457,7 +504,7 @@ sub recall_message_by_count {
};
} else {
$messages = eval {
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp FROM Messages WHERE channel = ? ORDER BY timestamp DESC LIMIT 10 OFFSET ?');
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel FROM Messages WHERE channel = ? ORDER BY timestamp DESC LIMIT 10 OFFSET ?');
$sth->bind_param(1, $channel);
$sth->bind_param(2, $count);
$sth->execute();
@ -489,7 +536,7 @@ sub recall_message_by_text {
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');
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel 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%");
@ -498,7 +545,7 @@ sub recall_message_by_text {
};
} 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');
my $sth = $self->{dbh}->prepare('SELECT id, msg, mode, timestamp, channel 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();