1<?php
2
3use dokuwiki\Extension\Plugin;
4use dokuwiki\Extension\AuthPlugin;
5use dokuwiki\plugin\structpublish\meta\Assignments;
6use dokuwiki\plugin\structpublish\meta\Constants;
7use dokuwiki\plugin\structpublish\meta\Revision;
8
9/**
10 * Notification helper
11 */
12class helper_plugin_structpublish_notify extends Plugin
13{
14    /** @var helper_plugin_structpublish_db  */
15    protected $dbHelper;
16
17    public function __construct()
18    {
19        $this->dbHelper = plugin_load('helper', 'structpublish_db');
20    }
21
22    /**
23     * If activated, send emails on configured status changes.
24     *
25     * @param string $action
26     * @param Revision $newRevision
27     * @return void
28     * @throws Exception
29     */
30    public function sendEmails($action, $newRevision)
31    {
32
33        if (!$this->triggerNotification($action)) {
34            return;
35        }
36
37        // get assignees from DB
38        $assignments = Assignments::getInstance();
39        $assignees = $assignments->getPageAssignments($newRevision->getId(), false);
40
41        // get recipients for the next workflow step
42        $nextAction = Constants::workflowSteps($action)['nextAction'];
43        if (is_null($nextAction)) {
44            return;
45        }
46
47        if (empty($assignees[$nextAction])) {
48            msg($this->getLang('email_error_norecipients'), -1);
49            return;
50        }
51
52        // flatten the array and split into single user or group items
53        $assignees = implode(',', array_values($assignees[$nextAction]));
54        $assignees = explode(',', $assignees);
55
56        // get recipient emails
57        $recipients = $this->resolveRecipients($assignees);
58
59        // prepare mail text
60        $mailText = $this->prepareMailText($newRevision->getStatus());
61
62        $this->sendMail(implode(',', $recipients), $mailText);
63    }
64
65    /**
66     * @param string $recipients Comma separated list of emails
67     * @param string $mailText
68     * @return void
69     */
70    public function sendMail($recipients, $mailText)
71    {
72        $mailer = new Mailer();
73        $mailer->bcc($recipients);
74
75        $subject = $this->getLang('email_subject');
76        $mailer->subject($subject);
77
78        $mailer->setBody($mailText);
79        $mailer->send();
80    }
81
82    /**
83     * Processes an array of (comma separated) recipients
84     * and returns an array of emails
85     * with user groups resolved to individual users
86     *
87     * @param array $recipients
88     * @return array
89     * @throws Exception
90     */
91    public function resolveRecipients($recipients)
92    {
93        $resolved = [];
94
95        $recipients = array_unique($recipients);
96
97        foreach ($recipients as $recipient) {
98            $recipient = trim($recipient);
99
100            if ($recipient[0] === '@') {
101                $this->resolveGroup($resolved, $recipient);
102            } elseif (strpos($recipient, '@') === false) {
103                $this->resolveUser($resolved, $recipient);
104            } else {
105                $resolved[] = $recipient;
106            }
107        }
108        return $resolved;
109    }
110
111    /**
112     * @param array $resolved
113     * @param string $recipient
114     * @return void
115     * @throws Exception
116     */
117    protected function resolveGroup(&$resolved, $recipient)
118    {
119        /** @var AuthPlugin $auth */
120        global $auth;
121        if (!$auth->canDo('getUsers')) {
122            throw new \Exception('Auth cannot fetch users by group.');
123        }
124
125        // set arbitrary limit because not all backends interpret limit 0 as "no limit"
126        $users = $auth->retrieveUsers(0, 5000, ['grps' => substr($recipient, 1)]);
127        foreach ($users as $user) {
128            $resolved[] = $user['mail'];
129        }
130    }
131
132    /**
133     * @param array $resolved
134     * @param string $recipient
135     * @return void
136     */
137    protected function resolveUser(&$resolved, $recipient)
138    {
139        /** @var AuthPlugin $auth */
140        global $auth;
141        $user = $auth->getUserData($recipient);
142        if ($user) {
143            $resolved[] = $user['mail'];
144        }
145    }
146
147    /**
148     * Check configuration to see if a notification should be triggered.
149     *
150     * @return bool
151     */
152    private function triggerNotification($action)
153    {
154        if (!$this->getConf('email_enable')) {
155            return false;
156        }
157
158        $actions = array_map('trim', explode(',', $this->getConf('email_status')));
159        return in_array($action, $actions);
160    }
161
162    /**
163     * @return string
164     */
165    protected function prepareMailText($status)
166    {
167        global $ID;
168
169        $mailtext = file_get_contents($this->localFN('mail'));
170
171        $vars = [
172            'PAGE' => $ID,
173            'URL' => wl($ID, '', true),
174            'STATUS_CURRENT' => $status,
175        ];
176
177        foreach ($vars as $var => $val) {
178            $mailtext = str_replace('@' . $var . '@', $val, $mailtext);
179        }
180
181        return $mailtext;
182    }
183}
184