mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-02 18:19:33 +01:00
Plugins/RemindMe: reminders set to an absolute time now repeat at correct intervals
This commit is contained in:
parent
fe37658d97
commit
726cb06963
@ -57,11 +57,11 @@ sub cmd_remindme {
|
|||||||
return "Internal error.";
|
return "Internal error.";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $usage = "Usage: remindme -t time message [-c channel] [-r repeat count] | remindme -l [nick] | remindme -d id";
|
my $usage = "Usage: remindme -t <time> <message> [-r <repeat count>] [-c <channel>] | remindme -l [nick] | remindme -d <id>";
|
||||||
|
|
||||||
return $usage if not length $context->{arguments};
|
return $usage if not length $context->{arguments};
|
||||||
|
|
||||||
my ($channel, $repeats, $text, $alarm, $list_reminders, $delete_id);
|
my ($channel, $repeats, $text, $time, $list_reminders, $delete_id);
|
||||||
|
|
||||||
my $getopt_error;
|
my $getopt_error;
|
||||||
local $SIG{__WARN__} = sub {
|
local $SIG{__WARN__} = sub {
|
||||||
@ -75,7 +75,7 @@ sub cmd_remindme {
|
|||||||
GetOptionsFromArray(
|
GetOptionsFromArray(
|
||||||
\@opt_args,
|
\@opt_args,
|
||||||
'r:i' => \$repeats,
|
'r:i' => \$repeats,
|
||||||
't:s' => \$alarm,
|
't:s' => \$time,
|
||||||
'c:s' => \$channel,
|
'c:s' => \$channel,
|
||||||
'm:s' => \$text,
|
'm:s' => \$text,
|
||||||
'l:s' => \$list_reminders,
|
'l:s' => \$list_reminders,
|
||||||
@ -86,13 +86,16 @@ sub cmd_remindme {
|
|||||||
|
|
||||||
# option -l was provided; list reminders
|
# option -l was provided; list reminders
|
||||||
if (defined $list_reminders) {
|
if (defined $list_reminders) {
|
||||||
my $nick_override = $list_reminders if length $list_reminders;
|
# unique internal account id for a hostmask
|
||||||
my $account;
|
my $account;
|
||||||
|
|
||||||
|
# if arg was provided to -l, list reminders belonging to args
|
||||||
|
my $nick_override = $list_reminders if length $list_reminders;
|
||||||
|
|
||||||
if ($nick_override) {
|
if ($nick_override) {
|
||||||
|
# look up account id and hostmask for -l argument
|
||||||
my $hostmask;
|
my $hostmask;
|
||||||
|
|
||||||
# look up account id and hostmask by nickname
|
|
||||||
($account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($nick_override);
|
($account, $hostmask) = $self->{pbot}->{messagehistory}->{database}->find_message_account_by_nick($nick_override);
|
||||||
|
|
||||||
if (not $account) {
|
if (not $account) {
|
||||||
@ -102,13 +105,17 @@ sub cmd_remindme {
|
|||||||
# capture nick portion of hostmask
|
# capture nick portion of hostmask
|
||||||
($nick_override) = $hostmask =~ m/^([^!]+)!/;
|
($nick_override) = $hostmask =~ m/^([^!]+)!/;
|
||||||
} else {
|
} else {
|
||||||
|
# look up caller's account id
|
||||||
$account = $self->{pbot}->{messagehistory}->{database}->get_message_account($context->{nick}, $context->{user}, $context->{host});
|
$account = $self->{pbot}->{messagehistory}->{database}->get_message_account($context->{nick}, $context->{user}, $context->{host});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# get the root parent account id (consolidates nick-changes, etc)
|
||||||
$account = $self->{pbot}->{messagehistory}->{database}->get_ancestor_id($account);
|
$account = $self->{pbot}->{messagehistory}->{database}->get_ancestor_id($account);
|
||||||
|
|
||||||
|
# get the reminders
|
||||||
my $reminders = $self->get_reminders($account);
|
my $reminders = $self->get_reminders($account);
|
||||||
|
|
||||||
|
# list the reminders
|
||||||
my $count = 0;
|
my $count = 0;
|
||||||
my $text = '';
|
my $text = '';
|
||||||
my $now = time;
|
my $now = time;
|
||||||
@ -125,7 +132,7 @@ sub cmd_remindme {
|
|||||||
$text .= "$reminder->{id}) $interval";
|
$text .= "$reminder->{id}) $interval";
|
||||||
|
|
||||||
if ($reminder->{repeats}) {
|
if ($reminder->{repeats}) {
|
||||||
$text .= " ($reminder->{repeats} repeat" . ($reminder->{repeats} == 1 ? '' : 's') . " left)";
|
$text .= " (repeats every $reminder->{interval}, $reminder->{repeats} more time" . ($reminder->{repeats} == 1 ? '' : 's') . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
$text .= ": $reminder->{text}\n";
|
$text .= ": $reminder->{text}\n";
|
||||||
@ -186,7 +193,7 @@ sub cmd_remindme {
|
|||||||
$text .= join ' ', @opt_args;
|
$text .= join ' ', @opt_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Please use -t to specify a time for this reminder." if not $alarm;
|
return "Please use -t to specify a time for this reminder." if not $time;
|
||||||
return "Please specify a reminder message." if not $text;
|
return "Please specify a reminder message." if not $text;
|
||||||
|
|
||||||
# option -c was provided; ensure bot is in channel
|
# option -c was provided; ensure bot is in channel
|
||||||
@ -195,7 +202,7 @@ sub cmd_remindme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# parse "5 minutes", "next week", "3pm", etc into seconds
|
# parse "5 minutes", "next week", "3pm", etc into seconds
|
||||||
my ($seconds, $error) = $self->{pbot}->{parsedate}->parsedate($alarm);
|
my ($seconds, $error) = $self->{pbot}->{parsedate}->parsedate($time);
|
||||||
return $error if $error;
|
return $error if $error;
|
||||||
|
|
||||||
if ($seconds > 31536000 * 10) {
|
if ($seconds > 31536000 * 10) {
|
||||||
@ -218,7 +225,7 @@ sub cmd_remindme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# set timestamp for alarm
|
# set timestamp for alarm
|
||||||
$alarm = time + $seconds;
|
my $alarm = time + $seconds;
|
||||||
|
|
||||||
my $account = $self->{pbot}->{messagehistory}->{database}->get_message_account($context->{nick}, $context->{user}, $context->{host});
|
my $account = $self->{pbot}->{messagehistory}->{database}->get_message_account($context->{nick}, $context->{user}, $context->{host});
|
||||||
$account = $self->{pbot}->{messagehistory}->{database}->get_ancestor_id($account);
|
$account = $self->{pbot}->{messagehistory}->{database}->get_ancestor_id($account);
|
||||||
@ -236,7 +243,8 @@ sub cmd_remindme {
|
|||||||
channel => $channel,
|
channel => $channel,
|
||||||
text => $text,
|
text => $text,
|
||||||
alarm => $alarm,
|
alarm => $alarm,
|
||||||
interval => $seconds,
|
interval => $time,
|
||||||
|
seconds => $seconds,
|
||||||
repeats => $repeats,
|
repeats => $repeats,
|
||||||
owner => $context->{hostmask},
|
owner => $context->{hostmask},
|
||||||
);
|
);
|
||||||
@ -293,28 +301,67 @@ sub do_reminder {
|
|||||||
$self->{pbot}->{conn}->privmsg($target, $text);
|
$self->{pbot}->{conn}->privmsg($target, $text);
|
||||||
|
|
||||||
# log event
|
# log event
|
||||||
$self->{pbot}->{logger}->log("Reminded $target about \"$text\"\n");
|
$self->{pbot}->{logger}->log("Reminded $target about \"$text\"; interval: $reminder->{interval}\n");
|
||||||
|
|
||||||
# update repeats or delete reminder
|
# update repeats or delete reminder
|
||||||
if ($reminder->{repeats} > 0) {
|
if ($reminder->{repeats} > 0) {
|
||||||
# update reminder
|
# update reminder
|
||||||
$reminder->{repeats}--;
|
$reminder->{repeats}--;
|
||||||
$reminder->{alarm} = time + $reminder->{interval};
|
|
||||||
|
# parse interval again to get correct offset in seconds
|
||||||
|
# e.g., if it's 12 pm and they set a repeating reminder for 3 pm then
|
||||||
|
# the interval would be 3h. we don't want the reminder to repeat every
|
||||||
|
# 3h but instead every day at 3 pm. so when this reminder fires at 3 pm,
|
||||||
|
# we reparse the interval "3 pm" again to get 24h, instead of storing 3h.
|
||||||
|
my ($seconds) = $self->{pbot}->{parsedate}->parsedate($reminder->{interval});
|
||||||
|
|
||||||
|
# if timeout is 0 or less, prepend "next" and try again.
|
||||||
|
# e.g., if interval is "10 pm" then at 10:00:00 pm the interval will
|
||||||
|
# parse to 0 seconds, i.e. right now, until it is 10:00:01 pm. we really
|
||||||
|
# want the next 10 pm, 24 hours from right now.
|
||||||
|
if ($seconds <= 0) {
|
||||||
|
my $override;
|
||||||
|
if ($reminder->{interval} =~ m/^\d/) {
|
||||||
|
$override = "tomorrow ";
|
||||||
|
} else {
|
||||||
|
$override = "next ";
|
||||||
|
}
|
||||||
|
|
||||||
|
($seconds) = $self->{pbot}->{parsedate}->parsedate("$override $reminder->{interval}");
|
||||||
|
}
|
||||||
|
|
||||||
|
# update alarm timestamp
|
||||||
|
$reminder->{alarm} = time + $seconds;
|
||||||
|
|
||||||
# update reminder in SQLite database
|
# update reminder in SQLite database
|
||||||
my $data = { repeats => $reminder->{repeats}, alarm => $reminder->{alarm} };
|
my $data = { repeats => $reminder->{repeats}, alarm => $reminder->{alarm} };
|
||||||
$self->update_reminder($reminder->{id}, $data);
|
$self->update_reminder($reminder->{id}, $data);
|
||||||
|
|
||||||
# update reminder event in PBot event queue
|
# update reminder event in PBot event queue
|
||||||
$event->{interval} = $reminder->{interval};
|
$event->{interval} = $seconds;
|
||||||
$event->{repeating} = 1;
|
$event->{repeating} = 1;
|
||||||
} else {
|
} else {
|
||||||
# delete reminder
|
# delete reminder from SQLite database
|
||||||
$self->delete_reminder($reminder->{id});
|
$self->delete_reminder($reminder->{id});
|
||||||
|
|
||||||
|
# tell PBot event queue not to reschedule this reminder
|
||||||
$event->{repeating} = 0;
|
$event->{repeating} = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# add a single reminder to the PBot event queue
|
||||||
|
sub enqueue_reminder {
|
||||||
|
my ($self, $reminder, $timeout) = @_;
|
||||||
|
|
||||||
|
$self->{pbot}->{event_queue}->enqueue_event(
|
||||||
|
sub {
|
||||||
|
my ($event) = @_;
|
||||||
|
$self->do_reminder($reminder->{id}, $event);
|
||||||
|
},
|
||||||
|
$timeout, "reminder $reminder->{id}", $reminder->{repeats}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
# load all reminders from SQLite database and add them
|
# load all reminders from SQLite database and add them
|
||||||
# to PBot's event queue. typically used once at PBot start-up.
|
# to PBot's event queue. typically used once at PBot start-up.
|
||||||
sub enqueue_reminders {
|
sub enqueue_reminders {
|
||||||
@ -338,18 +385,12 @@ sub enqueue_reminders {
|
|||||||
|
|
||||||
# delete this reminder if it's expired by approximately 1 year
|
# delete this reminder if it's expired by approximately 1 year
|
||||||
if ($timeout <= -(86400 * 31 * 12)) {
|
if ($timeout <= -(86400 * 31 * 12)) {
|
||||||
$self->{pbot}->{logger}->log("Deleting expired reminder: $reminder->{id}) $reminder->{text} set by $reminder->{created_by}; alarm: $reminder->{alarm} - current time: " . (scalar time) . " = timeout: $timeout\n");
|
$self->{pbot}->{logger}->log("Deleting expired reminder: $reminder->{id}) $reminder->{text} set by $reminder->{created_by}\n");
|
||||||
$self->delete_reminder($reminder->{id});
|
$self->delete_reminder($reminder->{id});
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{pbot}->{event_queue}->enqueue_event(
|
$self->enqueue_reminder($reminder, $timeout);
|
||||||
sub {
|
|
||||||
my ($event) = @_;
|
|
||||||
$self->do_reminder($reminder->{id}, $event);
|
|
||||||
},
|
|
||||||
$timeout, "reminder $reminder->{id}", $reminder->{repeats}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +408,7 @@ CREATE TABLE IF NOT EXISTS Reminders (
|
|||||||
text TEXT,
|
text TEXT,
|
||||||
alarm NUMERIC,
|
alarm NUMERIC,
|
||||||
repeats INTEGER,
|
repeats INTEGER,
|
||||||
interval NUMERIC,
|
interval TEXT,
|
||||||
created_on NUMERIC,
|
created_on NUMERIC,
|
||||||
created_by TEXT
|
created_by TEXT
|
||||||
)
|
)
|
||||||
@ -400,10 +441,11 @@ sub dbi_end {
|
|||||||
delete $self->{dbh};
|
delete $self->{dbh};
|
||||||
}
|
}
|
||||||
|
|
||||||
# add a reminder
|
# add a reminder, to SQLite and the PBot event queue
|
||||||
sub add_reminder {
|
sub add_reminder {
|
||||||
my ($self, %args) = @_;
|
my ($self, %args) = @_;
|
||||||
|
|
||||||
|
# add reminder to SQLite database
|
||||||
my $id = eval {
|
my $id = eval {
|
||||||
my $sth = $self->{dbh}->prepare('INSERT INTO Reminders (account, channel, text, alarm, interval, repeats, created_on, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
my $sth = $self->{dbh}->prepare('INSERT INTO Reminders (account, channel, text, alarm, interval, repeats, created_on, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
|
||||||
|
|
||||||
@ -421,43 +463,50 @@ sub add_reminder {
|
|||||||
return $self->{dbh}->sqlite_last_insert_rowid;
|
return $self->{dbh}->sqlite_last_insert_rowid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# check for exception
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$self->{pbot}->{logger}->log("Add reminder failed: $@");
|
$self->{pbot}->{logger}->log("Add reminder failed: $@");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{pbot}->{event_queue}->enqueue_event(
|
my $reminder = {
|
||||||
sub {
|
id => $id,
|
||||||
my ($event) = @_;
|
repeats => $args{repeats},
|
||||||
$self->do_reminder($id, $event);
|
};
|
||||||
},
|
|
||||||
$args{interval}, "reminder $id", $args{repeats}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
# add reminder to event queue.
|
||||||
|
$self->enqueue_reminder($reminder, $args{seconds});
|
||||||
|
|
||||||
|
# return reminder id
|
||||||
return $id;
|
return $id;
|
||||||
}
|
}
|
||||||
|
|
||||||
# delete a reminder by its id
|
# delete a reminder by its id, from SQLite and the PBot event queue
|
||||||
sub delete_reminder {
|
sub delete_reminder {
|
||||||
my ($self, $id) = @_;
|
my ($self, $id) = @_;
|
||||||
|
|
||||||
return if not $self->{dbh};
|
return if not $self->{dbh};
|
||||||
|
|
||||||
|
# remove from SQLite database
|
||||||
eval {
|
eval {
|
||||||
my $sth = $self->{dbh}->prepare('DELETE FROM Reminders WHERE id = ?');
|
my $sth = $self->{dbh}->prepare('DELETE FROM Reminders WHERE id = ?');
|
||||||
$sth->execute($id);
|
$sth->execute($id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# check for exeption
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$self->{pbot}->{logger}->log("Delete reminder $id failed: $@");
|
$self->{pbot}->{logger}->log("Delete reminder $id failed: $@");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{pbot}->{event_queue}->dequeue_event("reminder $id");
|
# remove from event queue
|
||||||
|
my $removed = $self->{pbot}->{event_queue}->dequeue_event("reminder $id");
|
||||||
|
|
||||||
|
$self->{pbot}->{logger}->log("RemindMe: dequeued events: $removed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# update a reminder's metadata
|
# update a reminder's data, in SQLite
|
||||||
sub update_reminder {
|
sub update_reminder {
|
||||||
my ($self, $id, $data) = @_;
|
my ($self, $id, $data) = @_;
|
||||||
|
|
||||||
@ -488,7 +537,7 @@ sub update_reminder {
|
|||||||
$self->{pbot}->{logger}->log($@) if $@;
|
$self->{pbot}->{logger}->log($@) if $@;
|
||||||
}
|
}
|
||||||
|
|
||||||
# get a single reminder by its id
|
# get a single reminder by its id, from SQLite
|
||||||
sub get_reminder {
|
sub get_reminder {
|
||||||
my ($self, $id) = @_;
|
my ($self, $id) = @_;
|
||||||
|
|
||||||
@ -506,7 +555,7 @@ sub get_reminder {
|
|||||||
return $reminder;
|
return $reminder;
|
||||||
}
|
}
|
||||||
|
|
||||||
# get all reminders belonging to a user
|
# get all reminders belonging to an account id, from SQLite
|
||||||
sub get_reminders {
|
sub get_reminders {
|
||||||
my ($self, $account) = @_;
|
my ($self, $account) = @_;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user