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