diff options
author | Andreas Gohr <gohr@cosmocode.de> | 2019-10-10 09:55:14 +0200 |
---|---|---|
committer | Andreas Gohr <gohr@cosmocode.de> | 2019-10-10 09:55:14 +0200 |
commit | 31a58aba4c24b34c34ad5764d1a35b7c398c3a2c (patch) | |
tree | 7f4d1546fbb69863a7d366fc1ff647f784853b68 /inc/Subscriptions/SubscriberManager.php | |
parent | af7ba5aa0bd10fc0ad9ef983006305b4c5a8ed42 (diff) | |
parent | c0c77cd20b23921c9e893bb70b99f38be153875a (diff) | |
download | dokuwiki-31a58aba4c24b34c34ad5764d1a35b7c398c3a2c.tar.gz dokuwiki-31a58aba4c24b34c34ad5764d1a35b7c398c3a2c.zip |
Merge branch 'psr2'
* psr2: (160 commits)
fixed merge error
Moved parts of the Asian word handling to its own class
ignore snake_case error of substr_replace
fixed some line length errors
ignore PSR2 in the old form class
fix PSR2 error in switch statement
replaced deprecated utf8 functions
formatting cleanup
mark old utf8 functions deprecated
some more PSR2 cleanup
Some cleanup for the UTF-8 stuff
Moved all utf8 methods to their own namespaced classes
Create separate table files for UTF-8 handling
Ignore mixed concerns in loader
Use type safe comparisons in loader
Remove obsolete include
adjust phpcs exclude patterns for new plugin classes
đźšš Move Subscription class to deprecated.php
♻️ Split up ChangesSubscriptionSender into multiple classes
Minor optimizations in PluginController
...
Diffstat (limited to 'inc/Subscriptions/SubscriberManager.php')
-rw-r--r-- | inc/Subscriptions/SubscriberManager.php | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/inc/Subscriptions/SubscriberManager.php b/inc/Subscriptions/SubscriberManager.php new file mode 100644 index 000000000..138176fe9 --- /dev/null +++ b/inc/Subscriptions/SubscriberManager.php @@ -0,0 +1,285 @@ +<?php + +namespace dokuwiki\Subscriptions; + +use dokuwiki\Input\Input; +use DokuWiki_Auth_Plugin; +use Exception; + +class SubscriberManager +{ + + /** + * Check if subscription system is enabled + * + * @return bool + */ + public function isenabled() + { + return actionOK('subscribe'); + } + + /** + * Adds a new subscription for the given page or namespace + * + * This will automatically overwrite any existent subscription for the given user on this + * *exact* page or namespace. It will *not* modify any subscription that may exist in higher namespaces. + * + * @throws Exception when user or style is empty + * + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * @param string $user + * @param string $style + * @param string $data + * + * @return bool + */ + public function add($id, $user, $style, $data = '') + { + if (!$this->isenabled()) { + return false; + } + + // delete any existing subscription + $this->remove($id, $user); + + $user = auth_nameencode(trim($user)); + $style = trim($style); + $data = trim($data); + + if (!$user) { + throw new Exception('no subscription user given'); + } + if (!$style) { + throw new Exception('no subscription style given'); + } + if (!$data) { + $data = time(); + } //always add current time for new subscriptions + + $line = "$user $style $data\n"; + $file = $this->file($id); + return io_saveFile($file, $line, true); + } + + + /** + * Removes a subscription for the given page or namespace + * + * This removes all subscriptions matching the given criteria on the given page or + * namespace. It will *not* modify any subscriptions that may exist in higher + * namespaces. + * + * @param string $id The target object’s (namespace or page) id + * @param string|array $user + * @param string|array $style + * @param string|array $data + * + * @return bool + */ + public function remove($id, $user = null, $style = null, $data = null) + { + if (!$this->isenabled()) { + return false; + } + + $file = $this->file($id); + if (!file_exists($file)) { + return true; + } + + $regexBuilder = new SubscriberRegexBuilder(); + $re = $regexBuilder->buildRegex($user, $style, $data); + return io_deleteFromFile($file, $re, true); + } + + /** + * Get data for $INFO['subscribed'] + * + * $INFO['subscribed'] is either false if no subscription for the current page + * and user is in effect. Else it contains an array of arrays with the fields + * “target”, “style”, and optionally “data”. + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $id Page ID, defaults to global $ID + * @param string $user User, defaults to $_SERVER['REMOTE_USER'] + * + * @return array|false + */ + public function userSubscription($id = '', $user = '') + { + if (!$this->isenabled()) { + return false; + } + + global $ID; + /** @var Input $INPUT */ + global $INPUT; + if (!$id) { + $id = $ID; + } + if (!$user) { + $user = $INPUT->server->str('REMOTE_USER'); + } + + $subs = $this->subscribers($id, $user); + if (!count($subs)) { + return false; + } + + $result = []; + foreach ($subs as $target => $info) { + $result[] = [ + 'target' => $target, + 'style' => $info[$user][0], + 'data' => $info[$user][1], + ]; + } + + return $result; + } + + /** + * Recursively search for matching subscriptions + * + * This function searches all relevant subscription files for a page or + * namespace. + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $page The target object’s (namespace or page) id + * @param string|array $user + * @param string|array $style + * @param string|array $data + * + * @return array + */ + public function subscribers($page, $user = null, $style = null, $data = null) + { + if (!$this->isenabled()) { + return []; + } + + // Construct list of files which may contain relevant subscriptions. + $files = [':' => $this->file(':')]; + do { + $files[$page] = $this->file($page); + $page = getNS(rtrim($page, ':')) . ':'; + } while ($page !== ':'); + + $regexBuilder = new SubscriberRegexBuilder(); + $re = $regexBuilder->buildRegex($user, $style, $data); + + // Handle files. + $result = []; + foreach ($files as $target => $file) { + if (!file_exists($file)) { + continue; + } + + $lines = file($file); + foreach ($lines as $line) { + // fix old style subscription files + if (strpos($line, ' ') === false) { + $line = trim($line) . " every\n"; + } + + // check for matching entries + if (!preg_match($re, $line, $m)) { + continue; + } + + $u = rawurldecode($m[1]); // decode the user name + if (!isset($result[$target])) { + $result[$target] = []; + } + $result[$target][$u] = [$m[2], $m[3]]; // add to result + } + } + return array_reverse($result); + } + + /** + * Default callback for COMMON_NOTIFY_ADDRESSLIST + * + * Aggregates all email addresses of user who have subscribed the given page with 'every' style + * + * @author Adrian Lang <lang@cosmocode.de> + * @author Steven Danz <steven-danz@kc.rr.com> + * + * @todo move the whole functionality into this class, trigger SUBSCRIPTION_NOTIFY_ADDRESSLIST instead, + * use an array for the addresses within it + * + * @param array &$data Containing the entries: + * - $id (the page id), + * - $self (whether the author should be notified, + * - $addresslist (current email address list) + * - $replacements (array of additional string substitutions, @KEY@ to be replaced by value) + */ + public function notifyAddresses(&$data) + { + if (!$this->isenabled()) { + return; + } + + /** @var DokuWiki_Auth_Plugin $auth */ + global $auth; + global $conf; + /** @var \Input $INPUT */ + global $INPUT; + + $id = $data['id']; + $self = $data['self']; + $addresslist = $data['addresslist']; + + $subscriptions = $this->subscribers($id, null, 'every'); + + $result = []; + foreach ($subscriptions as $target => $users) { + foreach ($users as $user => $info) { + $userinfo = $auth->getUserData($user); + if ($userinfo === false) { + continue; + } + if (!$userinfo['mail']) { + continue; + } + if (!$self && $user == $INPUT->server->str('REMOTE_USER')) { + continue; + } //skip our own changes + + $level = auth_aclcheck($id, $user, $userinfo['grps']); + if ($level >= AUTH_READ) { + if (strcasecmp($userinfo['mail'], $conf['notify']) != 0) { //skip user who get notified elsewhere + $result[$user] = $userinfo['mail']; + } + } + } + } + $data['addresslist'] = trim($addresslist . ',' . implode(',', $result), ','); + } + + /** + * Return the subscription meta file for the given ID + * + * @author Adrian Lang <lang@cosmocode.de> + * + * @param string $id The target page or namespace, specified by id; Namespaces + * are identified by appending a colon. + * + * @return string + */ + protected function file($id) + { + $meta_fname = '.mlist'; + if ((substr($id, -1, 1) === ':')) { + $meta_froot = getNS($id); + $meta_fname = '/' . $meta_fname; + } else { + $meta_froot = $id; + } + return metaFN((string)$meta_froot, $meta_fname); + } +} |