summaryrefslogtreecommitdiff
path: root/platform/www/inc/Subscriptions/BulkSubscriptionSender.php
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www/inc/Subscriptions/BulkSubscriptionSender.php')
-rw-r--r--platform/www/inc/Subscriptions/BulkSubscriptionSender.php261
1 files changed, 261 insertions, 0 deletions
diff --git a/platform/www/inc/Subscriptions/BulkSubscriptionSender.php b/platform/www/inc/Subscriptions/BulkSubscriptionSender.php
new file mode 100644
index 0000000..672ef90
--- /dev/null
+++ b/platform/www/inc/Subscriptions/BulkSubscriptionSender.php
@@ -0,0 +1,261 @@
+<?php
+
+
+namespace dokuwiki\Subscriptions;
+
+
+use dokuwiki\ChangeLog\PageChangeLog;
+use dokuwiki\Input\Input;
+use DokuWiki_Auth_Plugin;
+
+class BulkSubscriptionSender extends SubscriptionSender
+{
+
+ /**
+ * Send digest and list subscriptions
+ *
+ * This sends mails to all subscribers that have a subscription for namespaces above
+ * the given page if the needed $conf['subscribe_time'] has passed already.
+ *
+ * This function is called form lib/exe/indexer.php
+ *
+ * @param string $page
+ *
+ * @return int number of sent mails
+ */
+ public function sendBulk($page)
+ {
+ $subscriberManager = new SubscriberManager();
+ if (!$subscriberManager->isenabled()) {
+ return 0;
+ }
+
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+ global $conf;
+ global $USERINFO;
+ /** @var Input $INPUT */
+ global $INPUT;
+ $count = 0;
+
+ $subscriptions = $subscriberManager->subscribers($page, null, ['digest', 'list']);
+
+ // remember current user info
+ $olduinfo = $USERINFO;
+ $olduser = $INPUT->server->str('REMOTE_USER');
+
+ foreach ($subscriptions as $target => $users) {
+ if (!$this->lock($target)) {
+ continue;
+ }
+
+ foreach ($users as $user => $info) {
+ list($style, $lastupdate) = $info;
+
+ $lastupdate = (int)$lastupdate;
+ if ($lastupdate + $conf['subscribe_time'] > time()) {
+ // Less than the configured time period passed since last
+ // update.
+ continue;
+ }
+
+ // Work as the user to make sure ACLs apply correctly
+ $USERINFO = $auth->getUserData($user);
+ $INPUT->server->set('REMOTE_USER', $user);
+ if ($USERINFO === false) {
+ continue;
+ }
+ if (!$USERINFO['mail']) {
+ continue;
+ }
+
+ if (substr($target, -1, 1) === ':') {
+ // subscription target is a namespace, get all changes within
+ $changes = getRecentsSince($lastupdate, null, getNS($target));
+ } else {
+ // single page subscription, check ACL ourselves
+ if (auth_quickaclcheck($target) < AUTH_READ) {
+ continue;
+ }
+ $meta = p_get_metadata($target);
+ $changes = [$meta['last_change']];
+ }
+
+ // Filter out pages only changed in small and own edits
+ $change_ids = [];
+ foreach ($changes as $rev) {
+ $n = 0;
+ while (!is_null($rev) && $rev['date'] >= $lastupdate &&
+ ($INPUT->server->str('REMOTE_USER') === $rev['user'] ||
+ $rev['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT)) {
+ $pagelog = new PageChangeLog($rev['id']);
+ $rev = $pagelog->getRevisions($n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ }
+
+ if (!is_null($rev) && $rev['date'] >= $lastupdate) {
+ // Some change was not a minor one and not by myself
+ $change_ids[] = $rev['id'];
+ }
+ }
+
+ // send it
+ if ($style === 'digest') {
+ foreach ($change_ids as $change_id) {
+ $this->sendDigest(
+ $USERINFO['mail'],
+ $change_id,
+ $lastupdate
+ );
+ $count++;
+ }
+ } else {
+ if ($style === 'list') {
+ $this->sendList($USERINFO['mail'], $change_ids, $target);
+ $count++;
+ }
+ }
+ // TODO: Handle duplicate subscriptions.
+
+ // Update notification time.
+ $subscriberManager->add($target, $user, $style, time());
+ }
+ $this->unlock($target);
+ }
+
+ // restore current user info
+ $USERINFO = $olduinfo;
+ $INPUT->server->set('REMOTE_USER', $olduser);
+ return $count;
+ }
+
+ /**
+ * Lock subscription info
+ *
+ * We don't use io_lock() her because we do not wait for the lock and use a larger stale time
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ *
+ * @return bool true, if you got a succesful lock
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ protected function lock($id)
+ {
+ global $conf;
+
+ $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
+
+ if (is_dir($lock) && time() - @filemtime($lock) > 60 * 5) {
+ // looks like a stale lock - remove it
+ @rmdir($lock);
+ }
+
+ // try creating the lock directory
+ if (!@mkdir($lock, $conf['dmode'])) {
+ return false;
+ }
+
+ if (!empty($conf['dperm'])) {
+ chmod($lock, $conf['dperm']);
+ }
+ return true;
+ }
+
+ /**
+ * Unlock subscription info
+ *
+ * @param string $id The target page or namespace, specified by id; Namespaces
+ * are identified by appending a colon.
+ *
+ * @return bool
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ protected function unlock($id)
+ {
+ global $conf;
+ $lock = $conf['lockdir'] . '/_subscr_' . md5($id) . '.lock';
+ return @rmdir($lock);
+ }
+
+ /**
+ * Send a digest mail
+ *
+ * Sends a digest mail showing a bunch of changes of a single page. Basically the same as sendPageDiff()
+ * but determines the last known revision first
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param string $id The ID
+ * @param int $lastupdate Time of the last notification
+ *
+ * @return bool
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ */
+ protected function sendDigest($subscriber_mail, $id, $lastupdate)
+ {
+ $pagelog = new PageChangeLog($id);
+ $n = 0;
+ do {
+ $rev = $pagelog->getRevisions($n++, 1);
+ $rev = (count($rev) > 0) ? $rev[0] : null;
+ } while (!is_null($rev) && $rev > $lastupdate);
+
+ // TODO I'm not happy with the following line and passing $this->mailer around. Not sure how to solve it better
+ $pageSubSender = new PageSubscriptionSender($this->mailer);
+ return $pageSubSender->sendPageDiff(
+ $subscriber_mail,
+ 'subscr_digest',
+ $id,
+ $rev
+ );
+ }
+
+ /**
+ * Send a list mail
+ *
+ * Sends a list mail showing a list of changed pages.
+ *
+ * @param string $subscriber_mail The target mail address
+ * @param array $ids Array of ids
+ * @param string $ns_id The id of the namespace
+ *
+ * @return bool true if a mail was sent
+ * @author Adrian Lang <lang@cosmocode.de>
+ *
+ */
+ protected function sendList($subscriber_mail, $ids, $ns_id)
+ {
+ if (count($ids) === 0) {
+ return false;
+ }
+
+ $tlist = '';
+ $hlist = '<ul>';
+ foreach ($ids as $id) {
+ $link = wl($id, [], true);
+ $tlist .= '* ' . $link . NL;
+ $hlist .= '<li><a href="' . $link . '">' . hsc($id) . '</a></li>' . NL;
+ }
+ $hlist .= '</ul>';
+
+ $id = prettyprint_id($ns_id);
+ $trep = [
+ 'DIFF' => rtrim($tlist),
+ 'PAGE' => $id,
+ 'SUBSCRIBE' => wl($id, ['do' => 'subscribe'], true, '&'),
+ ];
+ $hrep = [
+ 'DIFF' => $hlist,
+ ];
+
+ return $this->send(
+ $subscriber_mail,
+ 'subscribe_list',
+ $ns_id,
+ 'subscr_list',
+ $trep,
+ $hrep
+ );
+ }
+}