summaryrefslogtreecommitdiff
path: root/platform/www/inc/Subscriptions/SubscriberManager.php
diff options
context:
space:
mode:
authorYaco <franco@reevo.org>2022-03-08 13:08:34 +0000
committerYaco <franco@reevo.org>2022-03-08 13:08:34 +0000
commitc985c40d3f3fc6a2be3be3186df3bf2f32189475 (patch)
treecee11f5e5a7e351ee0fec36d58d72cbee4f7e49b /platform/www/inc/Subscriptions/SubscriberManager.php
first commit after acervus codebase
Diffstat (limited to 'platform/www/inc/Subscriptions/SubscriberManager.php')
-rw-r--r--platform/www/inc/Subscriptions/SubscriberManager.php290
1 files changed, 290 insertions, 0 deletions
diff --git a/platform/www/inc/Subscriptions/SubscriberManager.php b/platform/www/inc/Subscriptions/SubscriberManager.php
new file mode 100644
index 0000000..ded1390
--- /dev/null
+++ b/platform/www/inc/Subscriptions/SubscriberManager.php
@@ -0,0 +1,290 @@
+<?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');
+ }
+
+ if (empty($user)) {
+ // not logged in
+ return false;
+ }
+
+ $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);
+ }
+}