4 namespace dokuwiki\Subscriptions
;
7 use dokuwiki\ChangeLog\PageChangeLog
;
8 use dokuwiki\Extension\AuthPlugin
;
9 use dokuwiki\Input\Input
;
12 class BulkSubscriptionSender
extends SubscriptionSender
16 * Send digest and list subscriptions
18 * This sends mails to all subscribers that have a subscription for namespaces above
19 * the given page if the needed $conf['subscribe_time'] has passed already.
21 * This function is called form lib/exe/indexer.php
24 * @return int number of sent mails
27 public function sendBulk($page)
29 $subscriberManager = new SubscriberManager();
30 if (!$subscriberManager->isenabled()) {
34 /** @var AuthPlugin $auth */
38 /** @var Input $INPUT */
42 $subscriptions = $subscriberManager->subscribers($page, null, ['digest', 'list']);
44 // remember current user info
45 $olduinfo = $USERINFO;
46 $olduser = $INPUT->server
->str('REMOTE_USER');
48 foreach ($subscriptions as $target => $users) {
49 if (!$this->lock($target)) {
53 foreach ($users as $user => $info) {
54 [$style, $lastupdate] = $info;
56 $lastupdate = (int)$lastupdate;
57 if ($lastupdate +
$conf['subscribe_time'] > time()) {
58 // Less than the configured time period passed since last
63 // Work as the user to make sure ACLs apply correctly
64 $USERINFO = $auth->getUserData($user);
65 $INPUT->server
->set('REMOTE_USER', $user);
66 if ($USERINFO === false) {
69 if (!$USERINFO['mail']) {
73 if (substr($target, -1, 1) === ':') {
74 // subscription target is a namespace, get all changes within
75 $changes = getRecentsSince($lastupdate, null, getNS($target));
77 // single page subscription, check ACL ourselves
78 if (auth_quickaclcheck($target) < AUTH_READ
) {
81 $meta = p_get_metadata($target);
82 $changes = [$meta['last_change']];
85 // Filter out pages only changed in small and own edits
87 foreach ($changes as $rev) {
89 $pagelog = new PageChangeLog($rev['id']);
90 while (!is_null($rev) && $rev['date'] >= $lastupdate &&
91 ($INPUT->server
->str('REMOTE_USER') === $rev['user'] ||
92 $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT
)
94 $revisions = $pagelog->getRevisions($n++
, 1);
95 $rev = ($revisions !== []) ?
$pagelog->getRevisionInfo($revisions[0]) : null;
98 if (!is_null($rev) && $rev['date'] >= $lastupdate) {
99 // Some change was not a minor one and not by myself
100 $change_ids[] = $rev['id'];
105 if ($style === 'digest') {
106 foreach ($change_ids as $change_id) {
114 } elseif ($style === 'list') {
115 $this->sendList($USERINFO['mail'], $change_ids, $target);
118 // TODO: Handle duplicate subscriptions.
120 // Update notification time.
121 $subscriberManager->add($target, $user, $style, time());
123 $this->unlock($target);
126 // restore current user info
127 $USERINFO = $olduinfo;
128 $INPUT->server
->set('REMOTE_USER', $olduser);
133 * Lock subscription info
135 * We don't use io_lock() her because we do not wait for the lock and use a larger stale time
137 * @param string $id The target page or namespace, specified by id; Namespaces
138 * are identified by appending a colon.
140 * @return bool true, if you got a succesful lock
141 * @author Adrian Lang <lang@cosmocode.de>
143 protected function lock($id)
147 $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
149 if (is_dir($lock) && time() - @filemtime
($lock) > 60 * 5) {
150 // looks like a stale lock - remove it
154 // try creating the lock directory
155 if (!@mkdir
($lock)) {
159 if ($conf['dperm']) {
160 chmod($lock, $conf['dperm']);
166 * Unlock subscription info
168 * @param string $id The target page or namespace, specified by id; Namespaces
169 * are identified by appending a colon.
172 * @author Adrian Lang <lang@cosmocode.de>
174 protected function unlock($id)
177 $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
178 return @rmdir
($lock);
184 * Sends a digest mail showing a bunch of changes of a single page. Basically the same as sendPageDiff()
185 * but determines the last known revision first
187 * @param string $subscriber_mail The target mail address
188 * @param string $id The ID
189 * @param int $lastupdate Time of the last notification
192 * @author Adrian Lang <lang@cosmocode.de>
195 protected function sendDigest($subscriber_mail, $id, $lastupdate)
197 $pagelog = new PageChangeLog($id);
200 $rev = $pagelog->getRevisions($n++
, 1);
201 $rev = ($rev !== []) ?
$rev[0] : null;
202 } while (!is_null($rev) && $rev > $lastupdate);
204 // TODO I'm not happy with the following line and passing $this->mailer around. Not sure how to solve it better
205 $pageSubSender = new PageSubscriptionSender($this->mailer
);
206 return $pageSubSender->sendPageDiff(
217 * Sends a list mail showing a list of changed pages.
219 * @param string $subscriber_mail The target mail address
220 * @param array $ids Array of ids
221 * @param string $ns_id The id of the namespace
223 * @return bool true if a mail was sent
224 * @author Adrian Lang <lang@cosmocode.de>
227 protected function sendList($subscriber_mail, $ids, $ns_id)
235 foreach ($ids as $id) {
236 $link = wl($id, [], true);
237 $tlist .= '* ' . $link . NL
;
238 $hlist .= '<li><a href="' . $link . '">' . hsc($id) . '</a></li>' . NL
;
242 $id = prettyprint_id($ns_id);
244 'DIFF' => rtrim($tlist),
246 'SUBSCRIBE' => wl($id, ['do' => 'subscribe'], true, '&'),