From bfdae229962cc11c7d1fbc23b57876d99ae913b0 Mon Sep 17 00:00:00 2001
From: Lari Taskula <lari.taskula@hypernova.fi>
Date: Tue, 17 May 2022 23:19:58 +0000
Subject: [PATCH] Bug 3935: Add support for recurring scheduled tasks

Tools->Task scheduler lacked the ability to repeatedly execute tasks.

This patch adds such functionality.

It adds a new parameter "--recurring" to misc/cronjobs/runreport.pl

After runreport.pl is executed and if --recurring is provided, we will now
schedule a new task with the same parameters.

To test:
1. Navigate to Tools->Task scheduler
2. Observe there is nothing that allows you to repeatedly execute the task
3. Apply patch
4. Refresh Tools->Task scheduler page
5. Observe new field "Recurring every" ... "minutes/hours/days..."
6. Check current server time
7. Add current server time + 1 minute to "Time" field
8. Add "1 minutes" to "Recurring every" field
9. Select a saved report (if you don't have one, create a new one)
10. Add your email address to "Email"
11. Click "Save"
12. Observe new row at "Jobs already entered" section and note down given
    datetime
13. Wait one minute
14. Refresh Tools->Task scheduler page
15. Observe updated row at "Jobs already entered" section, it should now
    have datetime + 1 minute of what you observed at step 12
---
 .../prog/en/modules/tools/scheduler.tt        | 13 ++++++
 misc/cronjobs/runreport.pl                    | 44 +++++++++++++++++++
 tools/scheduler.pl                            | 20 +++++----
 3 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/scheduler.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/scheduler.tt
index 918ed0ce56..b58408ab4c 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/scheduler.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/scheduler.tt
@@ -51,6 +51,19 @@
         <input type="text" size="10" id="startdate" name="startdate" class="flatpickr" data-flatpickr-futuredate="true" value="" />
         <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
     </li>
+<li>
+    <label for="frequency">Recurring every:</label>
+    <input type="text" name="frequency" id="frequency" value="" maxlength="10" size="10" />
+    <select name="frequency_unit" id="frequency_unit">
+        <option value="minutes">minutes</option>
+        <option value="hours">hours</option>
+        <option value="days">days</option>
+        <option value="weeks">weeks</option>
+        <option value="months">months</option>
+        <option value="years">years</option>
+    </select>
+    <div class="hint">(optional)</div>
+</li>
 <li><label for="report">Report:</label>
 <select name="report" id="report">
 [% FOREACH savedreport IN savedreports %]
diff --git a/misc/cronjobs/runreport.pl b/misc/cronjobs/runreport.pl
index bc3c85c5d8..e35f703705 100755
--- a/misc/cronjobs/runreport.pl
+++ b/misc/cronjobs/runreport.pl
@@ -22,6 +22,7 @@ use Modern::Perl;
 
 use Koha::Script -cron;
 use C4::Reports::Guided qw( store_results execute_query );
+use C4::Scheduler qw( add_at_job );
 use Koha::Reports;
 use C4::Context;
 use C4::Log qw( cronlogaction );
@@ -64,6 +65,7 @@ runreport.pl [ -h | -m ] [ -v ] reportID [ reportID ... ]
    --param=s      parameters for the report
    --store-results store the result of the report
    --csv-header    add column names as first line of csv output
+   --recurring     optional, duration at which this script is repeated, in format "integer-unit", e.g. 15-minutes.
 
 
  Arguments:
@@ -129,6 +131,17 @@ Store the result of the report into the saved_reports DB table.
 
 To access the results, go on Reports > Guided reports > Saved report.
 
+=item B<--recurring>
+
+Duration at which this script is repeated.
+
+Format for this parameter is "integer-unit" (without quotes)
+Example: 15-minutes.
+
+Regex: [1-9][0-9]*-(years|months|weeks|days|hours|minutes)
+
+Optional.
+
 =back
 
 =head1 DESCRIPTION
@@ -181,6 +194,7 @@ my $separator = ',';
 my $quote = '"';
 my $store_results = 0;
 my $csv_header = 0;
+my $recurring;
 
 my $username = undef;
 my $password = undef;
@@ -202,6 +216,7 @@ GetOptions(
     'method:s'          => \$method,
     'store-results'     => \$store_results,
     'csv-header'        => \$csv_header,
+    'recurring:s'       => \$recurring,
 
 ) or pod2usage(2);
 pod2usage( -verbose => 2 ) if ($man);
@@ -226,6 +241,11 @@ if ($to or $from or $send_email) {
     $to   or $to   = C4::Context->preference('KohaAdminEmailAddress');
 }
 
+if ($recurring and $recurring !~ /^[1-9][0-9]*-(years|months|weeks|days|hours|minutes)$/) {
+    print STDERR "ERROR: Invalid --recurring format, format is: \d+-(years|months|weeks|days|hours|minutes)\n";
+    pod2usage(1);
+}
+
 unless (scalar(@ARGV)) {
     print STDERR "ERROR: No reportID(s) specified\n";
     pod2usage(1);
@@ -358,4 +378,28 @@ foreach my $report_id (@ARGV) {
     else {
         print $message;
     }
+
+    if ( $recurring ) {
+        my ( $frequency, $frequency_unit ) = split( '-', $recurring );
+        my $base;
+        if ( C4::Context->config('supportdir') ) {
+            $base = C4::Context->config('supportdir');
+        }
+        else {
+            $base = "/usr/share/koha/bin";
+        }
+        my $CONFIG_NAME = $ENV{'KOHA_CONF'};
+        my $command =
+        "export KOHA_CONF=\"$CONFIG_NAME\"; " .
+        "$base/cronjobs/runreport.pl " . $report->id . " --format=$format --to=$to --recurring=$recurring";
+
+        my $start = DateTime->now->add( $frequency_unit => $frequency )->truncate( to => 'minute' );
+        $start = $start->ymd('') . substr($start->hms(''), 0, 4);
+
+        unless ( add_at_job( $start, $command ) ) {
+            print STDERR "ERROR: Adding recurring job failed\n";
+        }
+
+        print STDOUT "Recurring job added\n";
+    }
 }
diff --git a/tools/scheduler.pl b/tools/scheduler.pl
index 53d4b641c4..0c1f660201 100755
--- a/tools/scheduler.pl
+++ b/tools/scheduler.pl
@@ -68,15 +68,17 @@ if ( $mode eq 'job_add' ) {
         "export KOHA_CONF=\"$CONFIG_NAME\"; " .
         "$base/cronjobs/runreport.pl $report --format=$format --to=$email";
 
-#FIXME commit ea899bc55933cd74e4665d70b1c48cab82cd1257 added recurring parameter (it is not in template) and call to add_cron_job (undefined)
-#    my $recurring = $input->param('recurring');
-#    if ($recurring) {
-#        my $frequency = $input->param('frequency');
-#        add_cron_job( $start, $command );
-#    }
-#    else {
-#        #here was the the unless ( add_at_job
-#    }
+    my $recurring = $input->param('frequency');
+    if ( $recurring ) {
+        my $frequency = $recurring;
+        $frequency =~ s/^\s+|\s+$//g;
+        my $frequency_unit = $input->param('frequency_unit');
+
+        my @allowed_units = qw( years months weeks days hours minutes );
+        if ( $frequency =~ /^[1-9][0-9]*$/ and grep( /^$frequency_unit$/, @allowed_units ) ) {
+            $command = $command . ' --recurring=' . $frequency . '-' . $frequency_unit;
+        }
+    }
 
     unless ( add_at_job( $start, $command ) ) {
         $template->param( job_add_failed => 1 );
-- 
2.25.1