diff options
Diffstat (limited to 'whine.pl')
-rwxr-xr-x | whine.pl | 901 |
1 files changed, 459 insertions, 442 deletions
@@ -37,38 +37,35 @@ my @seen_schedules = (); # These statement handles should live outside of their functions in order to # allow the database to keep their SQL compiled. -my $sth_run_queries = - $dbh->prepare("SELECT " . - "query_name, title, onemailperbug " . - "FROM whine_queries " . - "WHERE eventid=? " . - "ORDER BY sortkey"); -my $sth_get_query = - $dbh->prepare("SELECT query FROM namedqueries " . - "WHERE userid = ? AND name = ?"); +my $sth_run_queries + = $dbh->prepare("SELECT " + . "query_name, title, onemailperbug " + . "FROM whine_queries " + . "WHERE eventid=? " + . "ORDER BY sortkey"); +my $sth_get_query = $dbh->prepare( + "SELECT query FROM namedqueries " . "WHERE userid = ? AND name = ?"); # get the event that's scheduled with the lowest run_next value -my $sth_next_scheduled_event = $dbh->prepare( - "SELECT " . - " whine_schedules.eventid, " . - " whine_events.owner_userid, " . - " whine_events.subject, " . - " whine_events.body, " . - " whine_events.mailifnobugs " . - "FROM whine_schedules " . - "LEFT JOIN whine_events " . - " ON whine_events.id = whine_schedules.eventid " . - "WHERE run_next <= NOW() " . - "ORDER BY run_next " . - $dbh->sql_limit(1) -); +my $sth_next_scheduled_event + = $dbh->prepare("SELECT " + . " whine_schedules.eventid, " + . " whine_events.owner_userid, " + . " whine_events.subject, " + . " whine_events.body, " + . " whine_events.mailifnobugs " + . "FROM whine_schedules " + . "LEFT JOIN whine_events " + . " ON whine_events.id = whine_schedules.eventid " + . "WHERE run_next <= NOW() " + . "ORDER BY run_next " + . $dbh->sql_limit(1)); # get all pending schedules matching an eventid -my $sth_schedules_by_event = $dbh->prepare( - "SELECT id, mailto_type, mailto " . - "FROM whine_schedules " . - "WHERE eventid=? AND run_next <= NOW()" -); +my $sth_schedules_by_event + = $dbh->prepare("SELECT id, mailto_type, mailto " + . "FROM whine_schedules " + . "WHERE eventid=? AND run_next <= NOW()"); ################################################################################ @@ -88,20 +85,25 @@ my $sth_schedules_by_event = $dbh->prepare( my $fromaddress = Bugzilla->params->{'mailfrom'}; # get the current date and time -my ($now_sec, $now_minute, $now_hour, $now_day, $now_month, $now_year, - $now_weekday) = localtime; +my ( + $now_sec, $now_minute, $now_hour, $now_day, + $now_month, $now_year, $now_weekday +) = localtime; + # Convert year to two digits $now_year = sprintf("%02d", $now_year % 100); + # Convert the month to January being "1" instead of January being "0". $now_month++; my @daysinmonth = qw(0 31 28 31 30 31 30 31 31 30 31 30 31); + # Alter February in case of a leap year. This simple way to do it only # applies if you won't be looking at February of next year, which whining # doesn't need to do. -if (($now_year % 4 == 0) && - (($now_year % 100 != 0) || ($now_year % 400 == 0))) { - $daysinmonth[2] = 29; +if (($now_year % 4 == 0) && (($now_year % 100 != 0) || ($now_year % 400 == 0))) +{ + $daysinmonth[2] = 29; } # run_day can contain either a calendar day (1, 2, 3...), a day of the week @@ -113,67 +115,79 @@ if (($now_year % 4 == 0) && # # We go over each uninitialized schedule record and use its settings to # determine what the next time it runs should be -my $sched_h = $dbh->prepare("SELECT id, run_day, run_time " . - "FROM whine_schedules " . - "WHERE run_next IS NULL" ); +my $sched_h + = $dbh->prepare("SELECT id, run_day, run_time " + . "FROM whine_schedules " + . "WHERE run_next IS NULL"); $sched_h->execute(); while (my ($schedule_id, $day, $time) = $sched_h->fetchrow_array) { - # fill in some defaults in case they're blank - $day ||= '0'; - $time ||= '0'; - - # If this schedule is supposed to run today, we see if it's supposed to be - # run at a particular hour. If so, we set it for that hour, and if not, - # it runs at an interval over the course of a day, which means we should - # set it to run immediately. - if (&check_today($day)) { - # Values that are not entirely numeric are intervals, like "30min" - if ($time !~ /^\d+$/) { - # set it to now - $sth = $dbh->prepare( "UPDATE whine_schedules " . - "SET run_next=NOW() " . - "WHERE id=?"); - $sth->execute($schedule_id); - } - # A time greater than now means it still has to run today - elsif ($time >= $now_hour) { - # set it to today + number of hours - $sth = $dbh->prepare( - "UPDATE whine_schedules " . - "SET run_next = " . - $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'HOUR') . - " WHERE id = ?"); - $sth->execute($time, $schedule_id); - } - # the target time is less than the current time - else { # set it for the next applicable day - $day = &get_next_date($day); - my $run_next = $dbh->sql_date_math('(' - . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') - . ')', '+', '?', 'HOUR'); - $sth = $dbh->prepare("UPDATE whine_schedules " . - "SET run_next = $run_next - WHERE id = ?"); - $sth->execute($day, $time, $schedule_id); - } + # fill in some defaults in case they're blank + $day ||= '0'; + $time ||= '0'; + + # If this schedule is supposed to run today, we see if it's supposed to be + # run at a particular hour. If so, we set it for that hour, and if not, + # it runs at an interval over the course of a day, which means we should + # set it to run immediately. + if (&check_today($day)) { + + # Values that are not entirely numeric are intervals, like "30min" + if ($time !~ /^\d+$/) { + + # set it to now + $sth = $dbh->prepare( + "UPDATE whine_schedules " . "SET run_next=NOW() " . "WHERE id=?"); + $sth->execute($schedule_id); } - # If the schedule is not supposed to run today, we set it to run on the - # appropriate date and time - else { - my $target_date = &get_next_date($day); - # If configured for a particular time, set it to that, otherwise - # midnight - my $target_time = ($time =~ /^\d+$/) ? $time : 0; - - my $run_next = $dbh->sql_date_math('(' - . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') - . ')', '+', '?', 'HOUR'); - $sth = $dbh->prepare("UPDATE whine_schedules " . - "SET run_next = $run_next - WHERE id = ?"); - $sth->execute($target_date, $target_time, $schedule_id); + + # A time greater than now means it still has to run today + elsif ($time >= $now_hour) { + + # set it to today + number of hours + $sth + = $dbh->prepare("UPDATE whine_schedules " + . "SET run_next = " + . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'HOUR') + . " WHERE id = ?"); + $sth->execute($time, $schedule_id); } + + # the target time is less than the current time + else { # set it for the next applicable day + $day = &get_next_date($day); + my $run_next + = $dbh->sql_date_math( + '(' . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') . ')', + '+', '?', 'HOUR'); + $sth = $dbh->prepare( + "UPDATE whine_schedules " . "SET run_next = $run_next + WHERE id = ?" + ); + $sth->execute($day, $time, $schedule_id); + } + + } + + # If the schedule is not supposed to run today, we set it to run on the + # appropriate date and time + else { + my $target_date = &get_next_date($day); + + # If configured for a particular time, set it to that, otherwise + # midnight + my $target_time = ($time =~ /^\d+$/) ? $time : 0; + + my $run_next + = $dbh->sql_date_math( + '(' . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') . ')', + '+', '?', 'HOUR'); + $sth = $dbh->prepare( + "UPDATE whine_schedules " . "SET run_next = $run_next + WHERE id = ?" + ); + $sth->execute($target_date, $target_time, $schedule_id); + } } $sched_h->finish(); @@ -187,7 +201,7 @@ $sched_h->finish(); # 5. Return an event hashref # # The event hashref consists of: -# eventid - ID of the event +# eventid - ID of the event # author - user object for the event's creator # users - array of user objects for recipients # subject - Subject line for the email @@ -195,91 +209,85 @@ $sched_h->finish(); # mailifnobugs - send message even if there are no query or query results sub get_next_event { - my $event = {}; - - # Loop until there's something to return - until (scalar keys %{$event}) { - - $dbh->bz_start_transaction(); - - # Get the event ID for the first pending schedule - $sth_next_scheduled_event->execute; - my $fetched = $sth_next_scheduled_event->fetch; - $sth_next_scheduled_event->finish; - return undef unless $fetched; - my ($eventid, $owner_id, $subject, $body, $mailifnobugs) = @{$fetched}; - - my $owner = Bugzilla::User->new($owner_id); - - my $whineatothers = $owner->in_group('bz_canusewhineatothers'); - - my %user_objects; # Used for keeping track of who has been added - - # Get all schedules that match that event ID and are pending - $sth_schedules_by_event->execute($eventid); - - # Add the users from those schedules to the list - while (my $row = $sth_schedules_by_event->fetch) { - my ($sid, $mailto_type, $mailto) = @{$row}; - - # Only bother doing any work if this user has whine permission - if ($owner->in_group('bz_canusewhines')) { - - if ($mailto_type == MAILTO_USER) { - if (not defined $user_objects{$mailto}) { - if ($mailto == $owner_id) { - $user_objects{$mailto} = $owner; - } - elsif ($whineatothers) { - $user_objects{$mailto} = Bugzilla::User->new($mailto); - } - } - } - elsif ($mailto_type == MAILTO_GROUP) { - my $sth = $dbh->prepare("SELECT name FROM groups " . - "WHERE id=?"); - $sth->execute($mailto); - my $groupname = $sth->fetch->[0]; - my $group_id = Bugzilla::Group::ValidateGroupName( - $groupname, $owner); - if ($group_id) { - my $glist = join(',', - @{Bugzilla::Group->flatten_group_membership( - $group_id)}); - $sth = $dbh->prepare("SELECT user_id FROM " . - "user_group_map " . - "WHERE group_id IN ($glist)"); - $sth->execute(); - for my $row (@{$sth->fetchall_arrayref}) { - if (not defined $user_objects{$row->[0]}) { - $user_objects{$row->[0]} = - Bugzilla::User->new($row->[0]); - } - } - } - } + my $event = {}; - } + # Loop until there's something to return + until (scalar keys %{$event}) { - reset_timer($sid); - } + $dbh->bz_start_transaction(); + + # Get the event ID for the first pending schedule + $sth_next_scheduled_event->execute; + my $fetched = $sth_next_scheduled_event->fetch; + $sth_next_scheduled_event->finish; + return undef unless $fetched; + my ($eventid, $owner_id, $subject, $body, $mailifnobugs) = @{$fetched}; + + my $owner = Bugzilla::User->new($owner_id); + + my $whineatothers = $owner->in_group('bz_canusewhineatothers'); - $dbh->bz_commit_transaction(); - - # Only set $event if the user is allowed to do whining - if ($owner->in_group('bz_canusewhines')) { - my @users = values %user_objects; - $event = { - 'eventid' => $eventid, - 'author' => $owner, - 'mailto' => \@users, - 'subject' => $subject, - 'body' => $body, - 'mailifnobugs' => $mailifnobugs, - }; + my %user_objects; # Used for keeping track of who has been added + + # Get all schedules that match that event ID and are pending + $sth_schedules_by_event->execute($eventid); + + # Add the users from those schedules to the list + while (my $row = $sth_schedules_by_event->fetch) { + my ($sid, $mailto_type, $mailto) = @{$row}; + + # Only bother doing any work if this user has whine permission + if ($owner->in_group('bz_canusewhines')) { + + if ($mailto_type == MAILTO_USER) { + if (not defined $user_objects{$mailto}) { + if ($mailto == $owner_id) { + $user_objects{$mailto} = $owner; + } + elsif ($whineatothers) { + $user_objects{$mailto} = Bugzilla::User->new($mailto); + } + } } + elsif ($mailto_type == MAILTO_GROUP) { + my $sth = $dbh->prepare("SELECT name FROM groups " . "WHERE id=?"); + $sth->execute($mailto); + my $groupname = $sth->fetch->[0]; + my $group_id = Bugzilla::Group::ValidateGroupName($groupname, $owner); + if ($group_id) { + my $glist = join(',', @{Bugzilla::Group->flatten_group_membership($group_id)}); + $sth = $dbh->prepare( + "SELECT user_id FROM " . "user_group_map " . "WHERE group_id IN ($glist)"); + $sth->execute(); + for my $row (@{$sth->fetchall_arrayref}) { + if (not defined $user_objects{$row->[0]}) { + $user_objects{$row->[0]} = Bugzilla::User->new($row->[0]); + } + } + } + } + + } + + reset_timer($sid); } - return $event; + + $dbh->bz_commit_transaction(); + + # Only set $event if the user is allowed to do whining + if ($owner->in_group('bz_canusewhines')) { + my @users = values %user_objects; + $event = { + 'eventid' => $eventid, + 'author' => $owner, + 'mailto' => \@users, + 'subject' => $subject, + 'body' => $body, + 'mailifnobugs' => $mailifnobugs, + }; + } + } + return $event; } # Run the queries for each event @@ -293,38 +301,38 @@ sub get_next_event { # mailifnobugs (send message even if there are no query or query results) while (my $event = get_next_event) { - my $eventid = $event->{'eventid'}; - - # We loop for each target user because some of the queries will be using - # subjective pronouns - $dbh = Bugzilla->switch_to_shadow_db(); - for my $target (@{$event->{'mailto'}}) { - my $args = { - 'subject' => $event->{'subject'}, - 'body' => $event->{'body'}, - 'eventid' => $event->{'eventid'}, - 'author' => $event->{'author'}, - 'recipient' => $target, - 'from' => $fromaddress, - }; - - # run the queries for this schedule - my $queries = run_queries($args); - - # If mailifnobugs is false, make sure there is something to output - if (!$event->{'mailifnobugs'}) { - my $there_are_bugs = 0; - for my $query (@{$queries}) { - $there_are_bugs = 1 if scalar @{$query->{'bugs'}}; - } - next unless $there_are_bugs; - } + my $eventid = $event->{'eventid'}; + + # We loop for each target user because some of the queries will be using + # subjective pronouns + $dbh = Bugzilla->switch_to_shadow_db(); + for my $target (@{$event->{'mailto'}}) { + my $args = { + 'subject' => $event->{'subject'}, + 'body' => $event->{'body'}, + 'eventid' => $event->{'eventid'}, + 'author' => $event->{'author'}, + 'recipient' => $target, + 'from' => $fromaddress, + }; + + # run the queries for this schedule + my $queries = run_queries($args); + + # If mailifnobugs is false, make sure there is something to output + if (!$event->{'mailifnobugs'}) { + my $there_are_bugs = 0; + for my $query (@{$queries}) { + $there_are_bugs = 1 if scalar @{$query->{'bugs'}}; + } + next unless $there_are_bugs; + } - $args->{'queries'} = $queries; + $args->{'queries'} = $queries; - mail($args); - } - $dbh = Bugzilla->switch_to_main_db(); + mail($args); + } + $dbh = Bugzilla->switch_to_main_db(); } ################################################################################ @@ -347,111 +355,114 @@ while (my $event = get_next_event) { # - recipient user object for the recipient # - author user object of the person who created the whine event sub mail { - my $args = shift; - # Don't send mail to someone whose bugmail notification is disabled. - return if $args->{recipient}->email_disabled; - - $args->{to_user} = $args->{recipient}; - MessageToMTA(generate_email( - $args, - { - header => 'whine/header.txt.tmpl', - text => 'whine/mail.txt.tmpl', - html => 'whine/mail.html.tmpl', - } - )); + my $args = shift; + + # Don't send mail to someone whose bugmail notification is disabled. + return if $args->{recipient}->email_disabled; + + $args->{to_user} = $args->{recipient}; + MessageToMTA(generate_email( + $args, + { + header => 'whine/header.txt.tmpl', + text => 'whine/mail.txt.tmpl', + html => 'whine/mail.html.tmpl', + } + )); } # run_queries runs all of the queries associated with a schedule ID, adding # the results to $args or mailing off the template if a query wants individual # messages for each bug sub run_queries { - my $args = shift; - - my $return_queries = []; - - $sth_run_queries->execute($args->{'eventid'}); - my @queries = (); - for (@{$sth_run_queries->fetchall_arrayref}) { - push(@queries, - { - 'name' => $_->[0], - 'title' => $_->[1], - 'onemailperbug' => $_->[2], - 'columnlist' => [], - 'bugs' => [], - } - ); + my $args = shift; + + my $return_queries = []; + + $sth_run_queries->execute($args->{'eventid'}); + my @queries = (); + for (@{$sth_run_queries->fetchall_arrayref}) { + push( + @queries, + { + 'name' => $_->[0], + 'title' => $_->[1], + 'onemailperbug' => $_->[2], + 'columnlist' => [], + 'bugs' => [], + } + ); + } + + foreach my $thisquery (@queries) { + next unless $thisquery->{'name'}; # named query is blank + + my $savedquery = get_query($thisquery->{'name'}, $args->{'author'}); + next unless $savedquery; # silently ignore missing queries + + # Execute the saved query + my @searchfields = ('bug_id', DEFAULT_COLUMN_LIST); + + # A new Bugzilla::CGI object needs to be created to allow + # Bugzilla::Search to execute a saved query. It's exceedingly weird, + # but that's how it works. + my $searchparams = new Bugzilla::CGI($savedquery); + + # Use the columnlist for the saved query, if it exists, and make + # sure bug_id is always in the list. + if (my $columnlist = $searchparams->param('columnlist')) { + @searchfields = split(/[\s,]+/, $columnlist); + unshift(@searchfields, 'bug_id') unless grep { $_ eq 'bug_id' } @searchfields; + } + push @{$thisquery->{'columnlist'}}, @searchfields; + + my @orderstrings = split(/,\s*/, $searchparams->param('order') || ''); + my $search = new Bugzilla::Search( + 'fields' => \@searchfields, + 'params' => scalar $searchparams->Vars, + 'user' => $args->{'recipient'}, # the search runs as the recipient + 'order' => \@orderstrings + ); + + # If a query fails for whatever reason, it shouldn't kill the script. + my $data = eval { $search->data }; + if ($@) { + print STDERR get_text('whine_query_failed', + {query_name => $thisquery->{'name'}, author => $args->{'author'}, reason => $@}) + . "\n"; + next; } - foreach my $thisquery (@queries) { - next unless $thisquery->{'name'}; # named query is blank - - my $savedquery = get_query($thisquery->{'name'}, $args->{'author'}); - next unless $savedquery; # silently ignore missing queries - - # Execute the saved query - my @searchfields = ('bug_id', DEFAULT_COLUMN_LIST); - - # A new Bugzilla::CGI object needs to be created to allow - # Bugzilla::Search to execute a saved query. It's exceedingly weird, - # but that's how it works. - my $searchparams = new Bugzilla::CGI($savedquery); - - # Use the columnlist for the saved query, if it exists, and make - # sure bug_id is always in the list. - if (my $columnlist = $searchparams->param('columnlist')) { - @searchfields = split(/[\s,]+/, $columnlist); - unshift(@searchfields, 'bug_id') unless grep { $_ eq 'bug_id' } @searchfields; - } - push @{$thisquery->{'columnlist'}}, @searchfields; - - my @orderstrings = split(/,\s*/, $searchparams->param('order') || ''); - my $search = new Bugzilla::Search( - 'fields' => \@searchfields, - 'params' => scalar $searchparams->Vars, - 'user' => $args->{'recipient'}, # the search runs as the recipient - 'order' => \@orderstrings - ); - # If a query fails for whatever reason, it shouldn't kill the script. - my $data = eval { $search->data }; - if ($@) { - print STDERR get_text('whine_query_failed', { query_name => $thisquery->{'name'}, - author => $args->{'author'}, - reason => $@ }) . "\n"; - next; - } - - foreach my $row (@$data) { - my $bug = {}; - for my $field (@searchfields) { - my $fieldname = $field; - $fieldname =~ s/^bugs\.//; # No need for bugs.whatever - $bug->{$fieldname} = shift @$row; - } - - if ($thisquery->{'onemailperbug'}) { - $args->{'queries'} = [ - { - 'name' => $thisquery->{'name'}, - 'title' => $thisquery->{'title'}, - 'columnlist' => $thisquery->{'columnlist'}, - 'bugs' => [ $bug ], - }, - ]; - mail($args); - delete $args->{'queries'}; - } - else { # It belongs in one message with any other lists - push @{$thisquery->{'bugs'}}, $bug; - } - } - if (!$thisquery->{'onemailperbug'} && @{$thisquery->{'bugs'}}) { - push @{$return_queries}, $thisquery; - } + foreach my $row (@$data) { + my $bug = {}; + for my $field (@searchfields) { + my $fieldname = $field; + $fieldname =~ s/^bugs\.//; # No need for bugs.whatever + $bug->{$fieldname} = shift @$row; + } + + if ($thisquery->{'onemailperbug'}) { + $args->{'queries'} = [ + { + 'name' => $thisquery->{'name'}, + 'title' => $thisquery->{'title'}, + 'columnlist' => $thisquery->{'columnlist'}, + 'bugs' => [$bug], + }, + ]; + mail($args); + delete $args->{'queries'}; + } + else { # It belongs in one message with any other lists + push @{$thisquery->{'bugs'}}, $bug; + } + } + if (!$thisquery->{'onemailperbug'} && @{$thisquery->{'bugs'}}) { + push @{$return_queries}, $thisquery; } + } - return $return_queries; + return $return_queries; } # get_query gets the namedquery. It's similar to LookupNamedQuery (in @@ -459,12 +470,12 @@ sub run_queries { # individual named queries might go away without the whine_queries that point # to them being removed. sub get_query { - my ($name, $user) = @_; - my $qname = $name; - $sth_get_query->execute($user->id, $qname); - my $fetched = $sth_get_query->fetch; - $sth_get_query->finish; - return $fetched ? $fetched->[0] : ''; + my ($name, $user) = @_; + my $qname = $name; + $sth_get_query->execute($user->id, $qname); + my $fetched = $sth_get_query->fetch; + $sth_get_query->finish; + return $fetched ? $fetched->[0] : ''; } # check_today gets a run day from the schedule and sees if it matches today @@ -476,25 +487,23 @@ sub get_query { # - 'MF' for every weekday sub check_today { - my $run_day = shift; - - if (($run_day eq 'MF') - && ($now_weekday > 0) - && ($now_weekday < 6)) { - return 1; - } - elsif ( - length($run_day) == 3 && - index("SunMonTueWedThuFriSat", $run_day)/3 == $now_weekday) { - return 1; - } - elsif (($run_day eq 'All') - || (($run_day eq 'last') && - ($now_day == $daysinmonth[$now_month] )) - || ($run_day eq $now_day)) { - return 1; - } - return 0; + my $run_day = shift; + + if (($run_day eq 'MF') && ($now_weekday > 0) && ($now_weekday < 6)) { + return 1; + } + elsif (length($run_day) == 3 + && index("SunMonTueWedThuFriSat", $run_day) / 3 == $now_weekday) + { + return 1; + } + elsif (($run_day eq 'All') + || (($run_day eq 'last') && ($now_day == $daysinmonth[$now_month])) + || ($run_day eq $now_day)) + { + return 1; + } + return 0; } # reset_timer sets the next time a whine is supposed to run, assuming it just @@ -503,95 +512,101 @@ sub check_today { # reset_timer does not lock the whine_schedules table. Anything that calls it # should do that itself. sub reset_timer { - my $schedule_id = shift; - - # Schedules may not be executed more than once for each invocation of - # whine.pl -- there are legitimate circumstances that can cause this, like - # a set of whines that take a very long time to execute, so it's done - # quietly. - if (grep($_ == $schedule_id, @seen_schedules)) { - null_schedule($schedule_id); - return; + my $schedule_id = shift; + + # Schedules may not be executed more than once for each invocation of + # whine.pl -- there are legitimate circumstances that can cause this, like + # a set of whines that take a very long time to execute, so it's done + # quietly. + if (grep($_ == $schedule_id, @seen_schedules)) { + null_schedule($schedule_id); + return; + } + push @seen_schedules, $schedule_id; + + $sth = $dbh->prepare( + "SELECT run_day, run_time FROM whine_schedules " . "WHERE id=?"); + $sth->execute($schedule_id); + my ($run_day, $run_time) = $sth->fetchrow_array; + + # It may happen that the run_time field is NULL or blank due to + # a bug in editwhines.cgi when this field was initially 0. + $run_time ||= 0; + + my $run_today = 0; + my $minute_offset = 0; + + # If the schedule is to run today, and it runs many times per day, + # it shall be set to run immediately. + $run_today = &check_today($run_day); + if (($run_today) && ($run_time !~ /^\d+$/)) { + + # The default of 60 catches any bad value + my $minute_interval = 60; + if ($run_time =~ /^(\d+)min$/i) { + $minute_interval = $1; } - push @seen_schedules, $schedule_id; - - $sth = $dbh->prepare( "SELECT run_day, run_time FROM whine_schedules " . - "WHERE id=?" ); - $sth->execute($schedule_id); - my ($run_day, $run_time) = $sth->fetchrow_array; - - # It may happen that the run_time field is NULL or blank due to - # a bug in editwhines.cgi when this field was initially 0. - $run_time ||= 0; - - my $run_today = 0; - my $minute_offset = 0; - - # If the schedule is to run today, and it runs many times per day, - # it shall be set to run immediately. - $run_today = &check_today($run_day); - if (($run_today) && ($run_time !~ /^\d+$/)) { - # The default of 60 catches any bad value - my $minute_interval = 60; - if ($run_time =~ /^(\d+)min$/i) { - $minute_interval = $1; - } - # set the minute offset to the next interval point - $minute_offset = $minute_interval - ($now_minute % $minute_interval); - } - elsif (($run_today) && ($run_time > $now_hour)) { - # timed event for later today - # (This should only happen if, for example, an 11pm scheduled event - # didn't happen until after midnight) - $minute_offset = (60 * ($run_time - $now_hour)) - $now_minute; - } - else { - # it's not something that runs later today. - $minute_offset = 0; - - # Set the target time if it's a specific hour - my $target_time = ($run_time =~ /^\d+$/) ? $run_time : 0; - - my $nextdate = &get_next_date($run_day); - my $run_next = $dbh->sql_date_math('(' - . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') - . ')', '+', '?', 'HOUR'); - $sth = $dbh->prepare("UPDATE whine_schedules " . - "SET run_next = $run_next - WHERE id = ?"); - $sth->execute($nextdate, $target_time, $schedule_id); - return; - } - - if ($minute_offset > 0) { - # Scheduling is done in terms of whole minutes. - - my $next_run = $dbh->selectrow_array( - 'SELECT ' . $dbh->sql_date_math('NOW()', '+', '?', 'MINUTE'), - undef, $minute_offset); - $next_run = format_time($next_run, "%Y-%m-%d %R"); - - $sth = $dbh->prepare("UPDATE whine_schedules " . - "SET run_next = ? WHERE id = ?"); - $sth->execute($next_run, $schedule_id); - } else { - # The minute offset is zero or less, which is not supposed to happen. - # complain to STDERR - null_schedule($schedule_id); - print STDERR "Error: bad minute_offset for schedule ID $schedule_id\n"; - } + # set the minute offset to the next interval point + $minute_offset = $minute_interval - ($now_minute % $minute_interval); + } + elsif (($run_today) && ($run_time > $now_hour)) { + + # timed event for later today + # (This should only happen if, for example, an 11pm scheduled event + # didn't happen until after midnight) + $minute_offset = (60 * ($run_time - $now_hour)) - $now_minute; + } + else { + # it's not something that runs later today. + $minute_offset = 0; + + # Set the target time if it's a specific hour + my $target_time = ($run_time =~ /^\d+$/) ? $run_time : 0; + + my $nextdate = &get_next_date($run_day); + my $run_next + = $dbh->sql_date_math( + '(' . $dbh->sql_date_math('CURRENT_DATE', '+', '?', 'DAY') . ')', + '+', '?', 'HOUR'); + $sth = $dbh->prepare( + "UPDATE whine_schedules " . "SET run_next = $run_next + WHERE id = ?" + ); + $sth->execute($nextdate, $target_time, $schedule_id); + return; + } + + if ($minute_offset > 0) { + + # Scheduling is done in terms of whole minutes. + + my $next_run + = $dbh->selectrow_array( + 'SELECT ' . $dbh->sql_date_math('NOW()', '+', '?', 'MINUTE'), + undef, $minute_offset); + $next_run = format_time($next_run, "%Y-%m-%d %R"); + + $sth + = $dbh->prepare("UPDATE whine_schedules " . "SET run_next = ? WHERE id = ?"); + $sth->execute($next_run, $schedule_id); + } + else { + # The minute offset is zero or less, which is not supposed to happen. + # complain to STDERR + null_schedule($schedule_id); + print STDERR "Error: bad minute_offset for schedule ID $schedule_id\n"; + } } # null_schedule is used to safeguard against infinite loops. Schedules with # run_next set to NULL will not be available to get_next_event until they are # rescheduled, which only happens when whine.pl starts. sub null_schedule { - my $schedule_id = shift; - $sth = $dbh->prepare("UPDATE whine_schedules " . - "SET run_next = NULL " . - "WHERE id=?"); - $sth->execute($schedule_id); + my $schedule_id = shift; + $sth = $dbh->prepare( + "UPDATE whine_schedules " . "SET run_next = NULL " . "WHERE id=?"); + $sth->execute($schedule_id); } # get_next_date determines the difference in days between now and the next @@ -600,56 +615,58 @@ sub null_schedule { # It takes a run_day argument (see check_today, above, for an explanation), # and returns an integer, representing a number of days. sub get_next_date { - my $day = shift; + my $day = shift; + + my $add_days = 0; - my $add_days = 0; + if ($day eq 'All') { + $add_days = 1; + } + elsif ($day eq 'last') { - if ($day eq 'All') { - $add_days = 1; + # next_date should contain the last day of this month, or next month + # if it's today + if ($daysinmonth[$now_month] == $now_day) { + my $month = $now_month + 1; + $month = 1 if $month > 12; + $add_days = $daysinmonth[$month] + 1; } - elsif ($day eq 'last') { - # next_date should contain the last day of this month, or next month - # if it's today - if ($daysinmonth[$now_month] == $now_day) { - my $month = $now_month + 1; - $month = 1 if $month > 12; - $add_days = $daysinmonth[$month] + 1; - } - else { - $add_days = $daysinmonth[$now_month] - $now_day; - } + else { + $add_days = $daysinmonth[$now_month] - $now_day; } - elsif ($day eq 'MF') { # any day Monday through Friday - if ($now_weekday < 5) { # Sun-Thurs - $add_days = 1; - } - elsif ($now_weekday == 5) { # Friday - $add_days = 3; - } - else { # it's 6, Saturday - $add_days = 2; - } + } + elsif ($day eq 'MF') { # any day Monday through Friday + if ($now_weekday < 5) { # Sun-Thurs + $add_days = 1; + } + elsif ($now_weekday == 5) { # Friday + $add_days = 3; + } + else { # it's 6, Saturday + $add_days = 2; } - elsif ($day !~ /^\d+$/) { # A specific day of the week + } + elsif ($day !~ /^\d+$/) { # A specific day of the week # The default is used if there is a bad value in the database, in # which case we mark it to a less-popular day (Sunday) - my $day_num = 0; + my $day_num = 0; - if (length($day) == 3) { - $day_num = (index("SunMonTueWedThuFriSat", $day)/3) or 0; - } + if (length($day) == 3) { + $day_num = (index("SunMonTueWedThuFriSat", $day) / 3) or 0; + } - $add_days = $day_num - $now_weekday; - if ($add_days <= 0) { # it's next week - $add_days += 7; - } + $add_days = $day_num - $now_weekday; + if ($add_days <= 0) { # it's next week + $add_days += 7; } - else { # it's a number, so we set it for that calendar day - $add_days = $day - $now_day; - # If it's already beyond that day this month, set it to the next one - if ($add_days <= 0) { - $add_days += $daysinmonth[$now_month]; - } + } + else { # it's a number, so we set it for that calendar day + $add_days = $day - $now_day; + + # If it's already beyond that day this month, set it to the next one + if ($add_days <= 0) { + $add_days += $daysinmonth[$now_month]; } - return $add_days; + } + return $add_days; } |