summaryrefslogtreecommitdiff
path: root/platform/www/lib/plugins/popularity
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www/lib/plugins/popularity')
-rw-r--r--platform/www/lib/plugins/popularity/action.php66
-rw-r--r--platform/www/lib/plugins/popularity/admin.php157
-rw-r--r--platform/www/lib/plugins/popularity/admin.svg1
-rw-r--r--platform/www/lib/plugins/popularity/helper.php292
-rw-r--r--platform/www/lib/plugins/popularity/lang/en/intro.txt11
-rw-r--r--platform/www/lib/plugins/popularity/lang/en/lang.php9
-rw-r--r--platform/www/lib/plugins/popularity/lang/en/submitted.txt3
-rw-r--r--platform/www/lib/plugins/popularity/plugin.info.txt7
8 files changed, 546 insertions, 0 deletions
diff --git a/platform/www/lib/plugins/popularity/action.php b/platform/www/lib/plugins/popularity/action.php
new file mode 100644
index 0000000..fac6107
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/action.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Popularity Feedback Plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ */
+
+class action_plugin_popularity extends DokuWiki_Action_Plugin
+{
+
+ /**
+ * @var helper_plugin_popularity
+ */
+ protected $helper;
+
+ public function __construct()
+ {
+ $this->helper = $this->loadHelper('popularity', false);
+ }
+
+ /** @inheritdoc */
+ public function register(Doku_Event_Handler $controller)
+ {
+ $controller->register_hook('INDEXER_TASKS_RUN', 'AFTER', $this, 'autosubmit', array());
+ }
+
+ /**
+ * Event handler
+ *
+ * @param Doku_Event $event
+ * @param $param
+ */
+ public function autosubmit(Doku_Event &$event, $param)
+ {
+ //Do we have to send the data now
+ if (!$this->helper->isAutosubmitEnabled() || $this->isTooEarlyToSubmit()) {
+ return;
+ }
+
+ //Actually send it
+ $status = $this->helper->sendData($this->helper->gatherAsString());
+
+ if ($status !== '') {
+ //If an error occured, log it
+ io_saveFile($this->helper->autosubmitErrorFile, $status);
+ } else {
+ //If the data has been sent successfully, previous log of errors are useless
+ @unlink($this->helper->autosubmitErrorFile);
+ //Update the last time we sent data
+ touch($this->helper->autosubmitFile);
+ }
+
+ $event->stopPropagation();
+ $event->preventDefault();
+ }
+
+ /**
+ * Check if it's time to send autosubmit data
+ * (we should have check if autosubmit is enabled first)
+ */
+ protected function isTooEarlyToSubmit()
+ {
+ $lastSubmit = $this->helper->lastSentTime();
+ return $lastSubmit + 24*60*60*30 > time();
+ }
+}
diff --git a/platform/www/lib/plugins/popularity/admin.php b/platform/www/lib/plugins/popularity/admin.php
new file mode 100644
index 0000000..61d8cc3
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/admin.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * Popularity Feedback Plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+class admin_plugin_popularity extends DokuWiki_Admin_Plugin
+{
+
+ /** @var helper_plugin_popularity */
+ protected $helper;
+ protected $sentStatus = null;
+
+ /**
+ * admin_plugin_popularity constructor.
+ */
+ public function __construct()
+ {
+ $this->helper = $this->loadHelper('popularity', false);
+ }
+
+ /**
+ * return prompt for admin menu
+ * @param $language
+ * @return string
+ */
+ public function getMenuText($language)
+ {
+ return $this->getLang('name');
+ }
+
+ /**
+ * return sort order for position in admin menu
+ */
+ public function getMenuSort()
+ {
+ return 2000;
+ }
+
+ /**
+ * Accessible for managers
+ */
+ public function forAdminOnly()
+ {
+ return false;
+ }
+
+
+ /**
+ * handle user request
+ */
+ public function handle()
+ {
+ global $INPUT;
+
+ //Send the data
+ if ($INPUT->has('data')) {
+ $this->sentStatus = $this->helper->sendData($INPUT->str('data'));
+ if ($this->sentStatus === '') {
+ //Update the last time we sent the data
+ touch($this->helper->popularityLastSubmitFile);
+ }
+ //Deal with the autosubmit option
+ $this->enableAutosubmit($INPUT->has('autosubmit'));
+ }
+ }
+
+ /**
+ * Enable or disable autosubmit
+ * @param bool $enable If TRUE, it will enable autosubmit. Else, it will disable it.
+ */
+ protected function enableAutosubmit($enable)
+ {
+ if ($enable) {
+ io_saveFile($this->helper->autosubmitFile, ' ');
+ } else {
+ @unlink($this->helper->autosubmitFile);
+ }
+ }
+
+ /**
+ * Output HTML form
+ */
+ public function html()
+ {
+ global $INPUT;
+
+ if (! $INPUT->has('data')) {
+ echo $this->locale_xhtml('intro');
+
+ //If there was an error the last time we tried to autosubmit, warn the user
+ if ($this->helper->isAutoSubmitEnabled()) {
+ if (file_exists($this->helper->autosubmitErrorFile)) {
+ echo $this->getLang('autosubmitError');
+ echo io_readFile($this->helper->autosubmitErrorFile);
+ }
+ }
+
+ flush();
+ echo $this->buildForm('server');
+
+ //Print the last time the data was sent
+ $lastSent = $this->helper->lastSentTime();
+ if ($lastSent !== 0) {
+ echo $this->getLang('lastSent') . ' ' . datetime_h($lastSent);
+ }
+ } else {
+ //If we just submitted the form
+ if ($this->sentStatus === '') {
+ //If we successfully sent the data
+ echo $this->locale_xhtml('submitted');
+ } else {
+ //If we failed to submit the data, try directly with the browser
+ echo $this->getLang('submissionFailed') . $this->sentStatus . '<br />';
+ echo $this->getLang('submitDirectly');
+ echo $this->buildForm('browser', $INPUT->str('data'));
+ }
+ }
+ }
+
+
+ /**
+ * Build the form which presents the data to be sent
+ * @param string $submissionMode How is the data supposed to be sent? (may be: 'browser' or 'server')
+ * @param string $data The popularity data, if it has already been computed. NULL otherwise.
+ * @return string The form, as an html string
+ */
+ protected function buildForm($submissionMode, $data = null)
+ {
+ $url = ($submissionMode === 'browser' ? $this->helper->submitUrl : script());
+ if (is_null($data)) {
+ $data = $this->helper->gatherAsString();
+ }
+
+ $form = '<form method="post" action="'. $url .'" accept-charset="utf-8">'
+ .'<fieldset style="width: 60%;">'
+ .'<textarea class="edit" rows="10" cols="80" readonly="readonly" name="data">'
+ .$data
+ .'</textarea><br />';
+
+ //If we submit via the server, we give the opportunity to suscribe to the autosubmission option
+ if ($submissionMode !== 'browser') {
+ $form .= '<label for="autosubmit">'
+ .'<input type="checkbox" name="autosubmit" id="autosubmit" '
+ .($this->helper->isAutosubmitEnabled() ? 'checked' : '' )
+ .'/> ' . $this->getLang('autosubmit') .'<br />'
+ .'</label>'
+ .'<input type="hidden" name="do" value="admin" />'
+ .'<input type="hidden" name="page" value="popularity" />';
+ }
+ $form .= '<button type="submit">'.$this->getLang('submit').'</button>'
+ .'</fieldset>'
+ .'</form>';
+ return $form;
+ }
+}
diff --git a/platform/www/lib/plugins/popularity/admin.svg b/platform/www/lib/plugins/popularity/admin.svg
new file mode 100644
index 0000000..820fc8c
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/admin.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M2 21l21-9L2 3v7l15 2-15 2v7z"/></svg> \ No newline at end of file
diff --git a/platform/www/lib/plugins/popularity/helper.php b/platform/www/lib/plugins/popularity/helper.php
new file mode 100644
index 0000000..4537976
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/helper.php
@@ -0,0 +1,292 @@
+<?php
+
+use dokuwiki\HTTP\DokuHTTPClient;
+use dokuwiki\Extension\Event;
+
+/**
+ * Popularity Feedback Plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ */
+class helper_plugin_popularity extends Dokuwiki_Plugin
+{
+ /**
+ * The url where the data should be sent
+ */
+ public $submitUrl = 'http://update.dokuwiki.org/popularity.php';
+
+ /**
+ * Name of the file which determine if the the autosubmit is enabled,
+ * and when it was submited for the last time
+ */
+ public $autosubmitFile;
+
+ /**
+ * File where the last error which happened when we tried to autosubmit, will be log
+ */
+ public $autosubmitErrorFile;
+
+ /**
+ * Name of the file which determine when the popularity data was manually
+ * submitted for the last time
+ * (If this file doesn't exist, the data has never been sent)
+ */
+ public $popularityLastSubmitFile;
+
+ /**
+ * helper_plugin_popularity constructor.
+ */
+ public function __construct()
+ {
+ global $conf;
+ $this->autosubmitFile = $conf['cachedir'].'/autosubmit.txt';
+ $this->autosubmitErrorFile = $conf['cachedir'].'/autosubmitError.txt';
+ $this->popularityLastSubmitFile = $conf['cachedir'].'/lastSubmitTime.txt';
+ }
+
+ /**
+ * Check if autosubmit is enabled
+ *
+ * @return boolean TRUE if we should send data once a month, FALSE otherwise
+ */
+ public function isAutoSubmitEnabled()
+ {
+ return file_exists($this->autosubmitFile);
+ }
+
+ /**
+ * Send the data, to the submit url
+ *
+ * @param string $data The popularity data
+ * @return string An empty string if everything worked fine, a string describing the error otherwise
+ */
+ public function sendData($data)
+ {
+ $error = '';
+ $httpClient = new DokuHTTPClient();
+ $status = $httpClient->sendRequest($this->submitUrl, array('data' => $data), 'POST');
+ if (! $status) {
+ $error = $httpClient->error;
+ }
+ return $error;
+ }
+
+ /**
+ * Compute the last time the data was sent. If it has never been sent, we return 0.
+ *
+ * @return int
+ */
+ public function lastSentTime()
+ {
+ $manualSubmission = @filemtime($this->popularityLastSubmitFile);
+ $autoSubmission = @filemtime($this->autosubmitFile);
+
+ return max((int) $manualSubmission, (int) $autoSubmission);
+ }
+
+ /**
+ * Gather all information
+ *
+ * @return string The popularity data as a string
+ */
+ public function gatherAsString()
+ {
+ $data = $this->gather();
+ $string = '';
+ foreach ($data as $key => $val) {
+ if (is_array($val)) foreach ($val as $v) {
+ $string .= hsc($key)."\t".hsc($v)."\n";
+ } else {
+ $string .= hsc($key)."\t".hsc($val)."\n";
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * Gather all information
+ *
+ * @return array The popularity data as an array
+ */
+ protected function gather()
+ {
+ global $conf;
+ /** @var $auth DokuWiki_Auth_Plugin */
+ global $auth;
+ $data = array();
+ $phptime = ini_get('max_execution_time');
+ @set_time_limit(0);
+ $pluginInfo = $this->getInfo();
+
+ // version
+ $data['anon_id'] = md5(auth_cookiesalt());
+ $data['version'] = getVersion();
+ $data['popversion'] = $pluginInfo['date'];
+ $data['language'] = $conf['lang'];
+ $data['now'] = time();
+ $data['popauto'] = (int) $this->isAutoSubmitEnabled();
+
+ // some config values
+ $data['conf_useacl'] = $conf['useacl'];
+ $data['conf_authtype'] = $conf['authtype'];
+ $data['conf_template'] = $conf['template'];
+
+ // number and size of pages
+ $list = array();
+ search($list, $conf['datadir'], array($this, 'searchCountCallback'), array('all'=>false), '');
+ $data['page_count'] = $list['file_count'];
+ $data['page_size'] = $list['file_size'];
+ $data['page_biggest'] = $list['file_max'];
+ $data['page_smallest'] = $list['file_min'];
+ $data['page_nscount'] = $list['dir_count'];
+ $data['page_nsnest'] = $list['dir_nest'];
+ if ($list['file_count']) $data['page_avg'] = $list['file_size'] / $list['file_count'];
+ $data['page_oldest'] = $list['file_oldest'];
+ unset($list);
+
+ // number and size of media
+ $list = array();
+ search($list, $conf['mediadir'], array($this, 'searchCountCallback'), array('all'=>true));
+ $data['media_count'] = $list['file_count'];
+ $data['media_size'] = $list['file_size'];
+ $data['media_biggest'] = $list['file_max'];
+ $data['media_smallest'] = $list['file_min'];
+ $data['media_nscount'] = $list['dir_count'];
+ $data['media_nsnest'] = $list['dir_nest'];
+ if ($list['file_count']) $data['media_avg'] = $list['file_size'] / $list['file_count'];
+ unset($list);
+
+ // number and size of cache
+ $list = array();
+ search($list, $conf['cachedir'], array($this, 'searchCountCallback'), array('all'=>true));
+ $data['cache_count'] = $list['file_count'];
+ $data['cache_size'] = $list['file_size'];
+ $data['cache_biggest'] = $list['file_max'];
+ $data['cache_smallest'] = $list['file_min'];
+ if ($list['file_count']) $data['cache_avg'] = $list['file_size'] / $list['file_count'];
+ unset($list);
+
+ // number and size of index
+ $list = array();
+ search($list, $conf['indexdir'], array($this, 'searchCountCallback'), array('all'=>true));
+ $data['index_count'] = $list['file_count'];
+ $data['index_size'] = $list['file_size'];
+ $data['index_biggest'] = $list['file_max'];
+ $data['index_smallest'] = $list['file_min'];
+ if ($list['file_count']) $data['index_avg'] = $list['file_size'] / $list['file_count'];
+ unset($list);
+
+ // number and size of meta
+ $list = array();
+ search($list, $conf['metadir'], array($this, 'searchCountCallback'), array('all'=>true));
+ $data['meta_count'] = $list['file_count'];
+ $data['meta_size'] = $list['file_size'];
+ $data['meta_biggest'] = $list['file_max'];
+ $data['meta_smallest'] = $list['file_min'];
+ if ($list['file_count']) $data['meta_avg'] = $list['file_size'] / $list['file_count'];
+ unset($list);
+
+ // number and size of attic
+ $list = array();
+ search($list, $conf['olddir'], array($this, 'searchCountCallback'), array('all'=>true));
+ $data['attic_count'] = $list['file_count'];
+ $data['attic_size'] = $list['file_size'];
+ $data['attic_biggest'] = $list['file_max'];
+ $data['attic_smallest'] = $list['file_min'];
+ if ($list['file_count']) $data['attic_avg'] = $list['file_size'] / $list['file_count'];
+ $data['attic_oldest'] = $list['file_oldest'];
+ unset($list);
+
+ // user count
+ if ($auth && $auth->canDo('getUserCount')) {
+ $data['user_count'] = $auth->getUserCount();
+ }
+
+ // calculate edits per day
+ $list = @file($conf['metadir'].'/_dokuwiki.changes');
+ $count = count($list);
+ if ($count > 2) {
+ $first = (int) substr(array_shift($list), 0, 10);
+ $last = (int) substr(array_pop($list), 0, 10);
+ $dur = ($last - $first)/(60*60*24); // number of days in the changelog
+ $data['edits_per_day'] = $count/$dur;
+ }
+ unset($list);
+
+ // plugins
+ $data['plugin'] = plugin_list();
+
+ // pcre info
+ if (defined('PCRE_VERSION')) $data['pcre_version'] = PCRE_VERSION;
+ $data['pcre_backtrack'] = ini_get('pcre.backtrack_limit');
+ $data['pcre_recursion'] = ini_get('pcre.recursion_limit');
+
+ // php info
+ $data['os'] = PHP_OS;
+ $data['webserver'] = $_SERVER['SERVER_SOFTWARE'];
+ $data['php_version'] = phpversion();
+ $data['php_sapi'] = php_sapi_name();
+ $data['php_memory'] = php_to_byte(ini_get('memory_limit'));
+ $data['php_exectime'] = $phptime;
+ $data['php_extension'] = get_loaded_extensions();
+
+ // plugin usage data
+ $this->addPluginUsageData($data);
+
+ return $data;
+ }
+
+ /**
+ * Triggers event to let plugins add their own data
+ *
+ * @param $data
+ */
+ protected function addPluginUsageData(&$data)
+ {
+ $pluginsData = array();
+ Event::createAndTrigger('PLUGIN_POPULARITY_DATA_SETUP', $pluginsData);
+ foreach ($pluginsData as $plugin => $d) {
+ if (is_array($d)) {
+ foreach ($d as $key => $value) {
+ $data['plugin_' . $plugin . '_' . $key] = $value;
+ }
+ } else {
+ $data['plugin_' . $plugin] = $d;
+ }
+ }
+ }
+
+ /**
+ * Callback to search and count the content of directories in DokuWiki
+ *
+ * @param array &$data Reference to the result data structure
+ * @param string $base Base usually $conf['datadir']
+ * @param string $file current file or directory relative to $base
+ * @param string $type Type either 'd' for directory or 'f' for file
+ * @param int $lvl Current recursion depht
+ * @param array $opts option array as given to search()
+ * @return bool
+ */
+ public function searchCountCallback(&$data, $base, $file, $type, $lvl, $opts)
+ {
+ // traverse
+ if ($type == 'd') {
+ if ($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl;
+ $data['dir_count']++;
+ return true;
+ }
+
+ //only search txt files if 'all' option not set
+ if ($opts['all'] || substr($file, -4) == '.txt') {
+ $size = filesize($base.'/'.$file);
+ $date = filemtime($base.'/'.$file);
+ $data['file_count']++;
+ $data['file_size'] += $size;
+ if (!isset($data['file_min']) || $data['file_min'] > $size) $data['file_min'] = $size;
+ if ($data['file_max'] < $size) $data['file_max'] = $size;
+ if (!isset($data['file_oldest']) || $data['file_oldest'] > $date) $data['file_oldest'] = $date;
+ }
+
+ return false;
+ }
+}
diff --git a/platform/www/lib/plugins/popularity/lang/en/intro.txt b/platform/www/lib/plugins/popularity/lang/en/intro.txt
new file mode 100644
index 0000000..e1d6d94
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/lang/en/intro.txt
@@ -0,0 +1,11 @@
+====== Popularity Feedback ======
+
+This [[doku>popularity|tool]] gathers anonymous data about your wiki and allows you to send it back to the DokuWiki developers. This helps them to understand them how DokuWiki is used by its users and makes sure future development decisions are backed up by real world usage statistics.
+
+You are encouraged to repeat this step from time to time to keep developers informed when your wiki grows. Your repeated data sets will be identified by an anonymous ID.
+
+Data collected contains information like your DokuWiki version, the number and size of your pages and files, installed plugins and information about your PHP install.
+
+The raw data that will be send is shown below. Please use the "Send Data" button to transfer the information.
+
+
diff --git a/platform/www/lib/plugins/popularity/lang/en/lang.php b/platform/www/lib/plugins/popularity/lang/en/lang.php
new file mode 100644
index 0000000..af6797c
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/lang/en/lang.php
@@ -0,0 +1,9 @@
+<?php
+
+$lang['name'] = 'Popularity Feedback (may take some time to load)';
+$lang['submit'] = 'Send Data';
+$lang['autosubmit'] = 'Automatically send data once a month';
+$lang['submissionFailed'] = 'The data couldn\'t be sent due to the following error:';
+$lang['submitDirectly'] = 'You can send the data manually by submitting the following form.';
+$lang['autosubmitError'] = 'The last autosubmit failed, because of the following error: ';
+$lang['lastSent'] = 'The data has been sent';
diff --git a/platform/www/lib/plugins/popularity/lang/en/submitted.txt b/platform/www/lib/plugins/popularity/lang/en/submitted.txt
new file mode 100644
index 0000000..30f2784
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/lang/en/submitted.txt
@@ -0,0 +1,3 @@
+====== Popularity Feedback ======
+
+The data has been sent succesfully.
diff --git a/platform/www/lib/plugins/popularity/plugin.info.txt b/platform/www/lib/plugins/popularity/plugin.info.txt
new file mode 100644
index 0000000..8ffc136
--- /dev/null
+++ b/platform/www/lib/plugins/popularity/plugin.info.txt
@@ -0,0 +1,7 @@
+base popularity
+author Andreas Gohr
+email andi@splitbrain.org
+date 2015-07-15
+name Popularity Feedback Plugin
+desc Send anonymous data about your wiki to the DokuWiki developers
+url http://www.dokuwiki.org/plugin:popularity