1<?php
2
3use splitbrain\phpcli\Options;
4use dokuwiki\plugin\structtasks\meta\Utilities;
5use dokuwiki\plugin\structtasks\meta\ReminderNotifier;
6use dokuwiki\plugin\structtasks\meta\TodayNotifier;
7use dokuwiki\plugin\structtasks\meta\OverdueNotifier;
8
9/**
10 * DokuWiki Plugin structtasks (CLI Component)
11 *
12 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
13 * @author  Chris MacMackin <cmacmackin@gmail.com>
14 */
15class cli_plugin_structtasks extends \dokuwiki\Extension\CLIPlugin
16{
17
18    private $schema;
19    private $struct;
20    private $util;
21    private $dateformat;
22    public $testing = false;
23    public $notifiers = [];
24
25    /** @inheritDoc */
26    protected function setup(Options $options)
27    {
28        $options->setHelp('Send emails to users that have been assigned to tasks.');
29        $options->registerOption('verbose', 'Show progress information', 'v', false);
30    }
31
32    /** @inheritDoc */
33    public function main(Options $options)
34    {
35        $this->notify($options->getOpt('verbose'));
36    }
37
38    /**
39     * Function to run CLI algorithm.
40     */
41    public function notify($verbose = true) {
42        if (!$this->initialise($verbose)) {
43            exit(-1);
44        }
45
46        $notifiers = $this->createNotifiers(
47            array_map('intval', explode(',', $this->getConf('reminder'))),
48            (bool)$this->getConf('overdue_reminder'),
49            $verbose
50        );
51
52        $tasks = $this->struct->getPages($this->schema);
53        foreach (array_keys($tasks) as $task) {
54            if ($verbose) $this->notice(sprintf($this->getLang('msg_processing'), $task));
55            $this->processTask($task, $notifiers);
56        }
57    }
58
59    /**
60     * Sets up useful properties for the class. Returns true if
61     * initialises successfully (e.g., all configurations are valid,
62     * necessary plugins available, etc.), false otherwise.
63     */
64    public function initialise($verbose = false) : bool {
65        if (!auth_setup()) {
66            if ($verbose) $this->error($this->getLang('msg_no_auth'));
67            return false;
68        }
69        $this->schema = $this->getConf('schema');
70        if ($this->schema == '') return false;
71        $this->struct = $this->loadHelper('struct', true);
72        if (is_null($this->struct)) return false;
73        $this->util = new Utilities($this->struct);
74        if (!$this->util->isValidSchema($this->schema)) {
75            if ($verbose) $this->error(
76                sprintf($this->getLang('msg_invalid_schema'), $this->schema));
77            return false;
78        }
79        if ($verbose) $this->success(
80            sprintf($this->getLang('msg_handling_schema'), $this->schema));
81        $this->dateformat = $this->util->dateFormat($this->schema);
82        return true;
83    }
84
85    /**
86     * Create an array of notifiers based on structtask configurations.
87     *
88     * @param array<int> $reminder_days  On which days before the due-date
89     *                                   to send reminders
90     * @param bool       $overdue        Whether to send reminders for
91     *                                   overdue tasks
92     * @param bool       $verbose        Whether to print status messages
93     * @return array<AbstractNotifier>
94     */
95    function createNotifiers($reminder_days, $overdue, $verbose = false) : array {
96        if ($this->testing) return $this->notifiers;
97        $notifiers = [];
98        $getConf = [$this, 'getConf'];
99        $getLang = [$this, 'getLang'];
100        if (($key = array_search(0, $reminder_days)) !== false) {
101            unset($reminder_days[$key]);
102            $notifiers[] = new TodayNotifier($getConf, $getLang);
103            if ($verbose) $this->notice($this->getLang('msg_today_notifier'));
104        }
105        if (count($reminder_days) != 0) {
106            $notifiers[] = new ReminderNotifier($getConf, $getLang, $reminder_days);
107            if ($verbose) {
108                $days = '';
109                $c = count($reminder_days);
110                if ($c > 1) $days .= implode(
111                    ', ', array_slice($reminder_days, 0, -1)) . ' or ';
112                $days .= $reminder_days[$c - 1];
113                $this->notice(
114                sprintf($this->getLang('msg_reminder_notifier'), $days)
115            );
116            }
117        }
118        if ($overdue) {
119            $notifiers[] = new OverdueNotifier($getConf, $getLang);
120            if ($verbose) $this->notice($this->getLang('msg_overdue_notifier'));
121        }
122        return $notifiers;
123    }
124
125    /**
126     * Apply notifiers to the specified task
127     *
128     * @param string                  $task       ID for the task page being processed
129     * @param array<AbstractNotifier> $notifiers  Notifiers to use with this task
130     */
131    function processTask($task, $notifiers) : void {
132        $filename = wikiFN($task);
133        $rev = @filemtime($filename);
134        $content = rawWiki($task);
135        $structdata = $this->struct->getData($task, $this->schema)[$this->schema];
136        $data = $this->util->formatData($structdata, $this->dateformat);
137        $data['content'] = $content;
138        $title = p_get_first_heading($task, METADATA_RENDER_USING_SIMPLE_CACHE);
139        // Doesn't seem to be a simple way to get editor info for
140        // arbitrary pages, so will just leave that blank. It
141        // doesn't actually get used in any of the reminder emails
142        // anyway.
143        $editor_name = '';
144        $editor_email = '';
145        foreach ($notifiers as $n) {
146            $n->sendMessage($task, $title, $editor_name, $editor_email, $data, $data);
147        }
148    }
149}
150
151