[Fusionforge-commits] FusionForge branch feature/plugin-globalactivity created. 6.0.4-944-g20adda0

Roland Mas lolando at libremir.placard.fr.eu.org
Mon Sep 26 14:36:56 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".

The branch, feature/plugin-globalactivity has been created
        at  20adda093fa83363b204ec47478ee0be09d577c7 (commit)

- Log -----------------------------------------------------------------
https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=20adda093fa83363b204ec47478ee0be09d577c7

commit 20adda093fa83363b204ec47478ee0be09d577c7
Author: Roland Mas <lolando at debian.org>
Date:   Mon Sep 26 14:30:59 2016 +0200

    Update globalactivity testsuite for master

diff --git a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
index d23d9ba..a95e6e5 100644
--- a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
+++ b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
@@ -23,7 +23,7 @@
 
 require_once dirname(dirname(__FILE__)).'/SeleniumForge.php';
 
-class Activity extends FForge_SeleniumTestCase
+class GlobalActivity extends FForge_SeleniumTestCase
 {
 	public $fixture = 'projecta';
 
@@ -90,7 +90,7 @@ class Activity extends FForge_SeleniumTestCase
 		$this->clickAndWait("addItemDocmanMenu");
 		$this->click("id=tab-new-document");
 		$this->type("title", "Doc1 Vladimir");
-		$this->type("//input[@name='description']", "Main website (the needle) - also, ZONGO");
+		$this->type("//textarea[@name='description']", "Main website (the needle) - also, ZONGO");
 		$this->click("//input[@name='type' and @value='pasteurl']");
 		$this->type("file_url", "http://fusionforge.org/");
 		$this->clickAndWait("submit");

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=b585cc55031a89f3b7d8072bede32169e5aee306

commit b585cc55031a89f3b7d8072bede32169e5aee306
Author: Roland Mas <lolando at debian.org>
Date:   Mon Sep 26 11:34:58 2016 +0200

    Fixed constructor

diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index 3707cea..f49af71f 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -23,9 +23,9 @@
 
 class globalactivityPlugin extends Plugin {
 	public function __construct($id=0) {
-		$this->Plugin($id) ;
+		parent::__construct($id);
 		$this->name = "globalactivity";
-		$this->text = "Global Activity"; // To show in the tabs, use...
+		$this->text = "Global Activity";
 
 		$this->_addHook('register_soap');
 	}

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=9558836712c3fd36abf555cab7f15783c941dfea

commit 9558836712c3fd36abf555cab7f15783c941dfea
Author: Roland Mas <lolando at debian.org>
Date:   Thu Aug 18 15:54:21 2016 +0200

    Improve test script

diff --git a/src/plugins/globalactivity/bin/test-globalactivity.py b/src/plugins/globalactivity/bin/test-globalactivity.py
index 9f7ab0f..46f1ef3 100644
--- a/src/plugins/globalactivity/bin/test-globalactivity.py
+++ b/src/plugins/globalactivity/bin/test-globalactivity.py
@@ -18,6 +18,12 @@ t1 = int(time.time())
 t0 = t1 - 864000
 results = []
 print ("Global activity")
+results = client.service.globalactivity_getActivity(session,t0,t1,[])
+project_id = 0
+for r in results:
+    print r
+
+print ("Global activity,restricted to some sections")
 results = client.service.globalactivity_getActivity(session,t0,t1,['trackeropen','trackerclose','scmgit'])
 project_id = 0
 for r in results:

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=226f629f15b19731546edaf20ac41333ca324fd2

commit 226f629f15b19731546edaf20ac41333ca324fd2
Author: Roland Mas <lolando at debian.org>
Date:   Thu Aug 18 15:50:07 2016 +0200

    Added sample SOAP client for globalactivity plugin

diff --git a/src/plugins/globalactivity/bin/test-globalactivity.py b/src/plugins/globalactivity/bin/test-globalactivity.py
new file mode 100644
index 0000000..9f7ab0f
--- /dev/null
+++ b/src/plugins/globalactivity/bin/test-globalactivity.py
@@ -0,0 +1,34 @@
+#! /usr/bin/python
+
+from suds.client import Client
+import time
+import logging
+
+logging.basicConfig(level=logging.INFO)
+logging.getLogger('suds.client').setLevel(logging.DEBUG)
+logging.getLogger('suds.transport').setLevel(logging.DEBUG)
+
+url = "https://localhost/soap/?wsdl=1"
+client = Client(url)
+session = ''
+# session = client.service.login('admin','secretpass')
+# print client
+
+t1 = int(time.time())
+t0 = t1 - 864000
+results = []
+print ("Global activity")
+results = client.service.globalactivity_getActivity(session,t0,t1,['trackeropen','trackerclose','scmgit'])
+project_id = 0
+for r in results:
+    print r
+    # print r['section']
+    # print r['description']
+    if r['section'] == 'scm':
+        project_id = r['group_id']
+
+print ("For project %d" % (project_id,))
+results = client.service.globalactivity_getActivityForProject(session,t0,t1,project_id,['trackeropen','trackerclose','scmgit'])
+project_id = 0
+for r in results:
+    print r

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=746dea3f47c85ddccd656c95fabd04a3391568b5

commit 746dea3f47c85ddccd656c95fabd04a3391568b5
Author: Roland Mas <lolando at debian.org>
Date:   Thu Aug 18 15:26:36 2016 +0200

    Fixed variable names

diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index a353967..3707cea 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -244,7 +244,7 @@ class globalactivityPlugin extends Plugin {
 			$group_id = $arr['group_id'];
 			$hookParams['group'] = $group_id;
 			$hookParams['results'] = &$results;
-			$hookParams['show'] = &$show;
+			$hookParams['show'] = &$section;
 			$hookParams['begin'] = $begin;
 			$hookParams['end'] = $end;
 			$hookParams['ids'] = &$ids;
@@ -253,7 +253,7 @@ class globalactivityPlugin extends Plugin {
 		}
 
 		if (count($show) < 1) {
-			$show = $ids;
+			$show = $section;
 		}
 
 		foreach ($show as $showthis) {
@@ -286,7 +286,8 @@ function &globalactivity_getActivity($session_ser,$begin,$end,$show=array()) {
 	$plugin = plugin_get_object('globalactivity');
 	if (!forge_get_config('use_activity')
 		|| !$plugin) {
-		return new soap_fault ('','globalactivity_getActivity','Global activity not available','Global activity not available');
+		$fault = new soap_fault ('','globalactivity_getActivity','Global activity not available','Global activity not available');
+		return $fault;
 	}
 
 	$ids = array();

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=0527a7586175cfccae19dfc210cfc3e5f38275d4

commit 0527a7586175cfccae19dfc210cfc3e5f38275d4
Author: Roland Mas <lolando at debian.org>
Date:   Wed Jun 15 13:00:51 2016 +0200

    Fixed testsuite

diff --git a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
index 762e625..d23d9ba 100644
--- a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
+++ b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
@@ -155,7 +155,7 @@ class Activity extends FForge_SeleniumTestCase
 		$this->assertTrue($found);
 		$found = False;
 		foreach ($response as $data) {
-			if ($data->description == 'Message1') {
+			if ($data->description == 'Message1 in a bottle') {
 				$found = True;
 				break;
 			}
@@ -171,7 +171,7 @@ class Activity extends FForge_SeleniumTestCase
 		$this->assertTrue($found);
 
 		// Now restrict to ProjectA only
-		$response = $soapclient->globalactivity_getActivityForProject($session,time()-3600,time(),6,array('forumpost'));
+		$response = $soapclient->globalactivity_getActivityForProject($session,time()-3600,time(),7,array('forumpost'));
 		$found = False;
 		foreach ($response as $data) {
 			if ($data->description == 'Welcome to developers-discussion') {
@@ -182,7 +182,7 @@ class Activity extends FForge_SeleniumTestCase
 		$this->assertTrue($found);
 		$found = False;
 		foreach ($response as $data) {
-			if ($data->description == 'Message1') {
+			if ($data->description == 'Message1 in a bottle') {
 				$found = True;
 				break;
 			}

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=c11e019d85810c02e39768ee7e482df9b01a06a9

commit c11e019d85810c02e39768ee7e482df9b01a06a9
Author: Roland Mas <lolando at debian.org>
Date:   Wed Jun 15 11:13:27 2016 +0200

    Fixed method name in testsuite

diff --git a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
index f9a3d2b..762e625 100644
--- a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
+++ b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
@@ -72,7 +72,7 @@ class Activity extends FForge_SeleniumTestCase
 		$this->type("body", "ninetynine of them on Charlie's wall - also, ZONGO");
 		$this->clickAndWait("submit");
 
-		$this->createAndGote('ProjectB');
+		$this->createAndGoto('ProjectB');
 		$this->clickAndWait("link=Forums");
 		$this->clickAndWait("link=open-discussion");
 		$this->click("link=Start New Thread");

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=082e2ab5fceb852dc6c48841d951a058c001aabe

commit 082e2ab5fceb852dc6c48841d951a058c001aabe
Author: Roland Mas <lolando at debian.org>
Date:   Tue Jun 14 10:07:42 2016 +0200

    Added globalactivity_getActivityForProject method

diff --git a/src/plugins/globalactivity/README b/src/plugins/globalactivity/README
index bfb0011..571b9ef 100644
--- a/src/plugins/globalactivity/README
+++ b/src/plugins/globalactivity/README
@@ -32,3 +32,8 @@ ref_id (meaning differs across sections), subref_id (ditto),
 description (title, commit number, or otherwise descriptive text),
 activity_date (as a Unix timestamp).
 
+Despite its name, the plugin also provides a non-global SOAP method
+called globalactivity_getActivityForProject, which takes a group_id as
+an extra parameter between the end date and the list of sections.  It
+returns an array of GlobalActivityEntry that only concerns the
+requested project.
diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index 8f697e1..a353967 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -69,9 +69,20 @@ class globalactivityPlugin extends Plugin {
 			array('return'=>'tns:ArrayOfGlobalActivityEntry'),
 			$uri,
 			$uri.'#globalactivity_getActivity','rpc','encoded');
+
+		$server->register(
+			'globalactivity_getActivityForProject',
+			array('session_ser'=>'xsd:string',
+				  'begin'=>'xsd:int',
+				  'end'=>'xsd:int',
+				  'group_id'=>'xsd:int',
+				  'show'=>'tns:ArrayOfstring',),
+			array('return'=>'tns:ArrayOfGlobalActivityEntry'),
+			$uri,
+			$uri.'#globalactivity_getActivityForProject','rpc','encoded');
 	}
 
-	public function getData($begin,$end,$show,&$ids,&$texts) {
+	public function getData($begin,$end,$show,&$ids,&$texts,$gid = NULL) {
 		if ($begin > $end) {
 			$tmp = $end;
 			$end = $begin;
@@ -183,11 +194,18 @@ class globalactivityPlugin extends Plugin {
 			return $cached_perms[$s][$ref];
 		}
 
-		$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
-			AND section = ANY ($3) ORDER BY activity_date DESC',
+		if ($gid) {
+			$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2 AND section = ANY ($3) AND group_id = $4 ORDER BY activity_date DESC',
+							   array($begin,
+									 $end,
+									 db_string_array_to_any_clause($section),
+									 $gid));
+		} else {
+			$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2 AND section = ANY ($3) ORDER BY activity_date DESC',
 							   array($begin,
 									 $end,
 									 db_string_array_to_any_clause($section)));
+		}
 
 		if (db_error()) {
 			exit_error(db_error(), 'home');
@@ -205,9 +223,14 @@ class globalactivityPlugin extends Plugin {
 			$results[] = $arr;
 		}
 
-		$res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
-							   array('A'));
-
+		if ($gid) {
+			$res = db_query_params('SELECT group_id FROM groups WHERE status=$1 AND group_id=$2',
+								   array('A', $gid));
+		} else {
+			$res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
+								   array('A'));
+		}
+		
 		if (db_error()) {
 			exit_error(db_error(), 'home');
 		}
@@ -299,6 +322,48 @@ function &globalactivity_getActivity($session_ser,$begin,$end,$show=array()) {
 	return $res2;
 }
 
+function &globalactivity_getActivityForProject($session_ser,$begin,$end,$group_id,$show=array()) {
+	continue_session($session_ser);
+
+	$plugin = plugin_get_object('globalactivity');
+	if (!forge_get_config('use_activity')
+		|| !$plugin) {
+		return new soap_fault ('','globalactivity_getActivity','Global activity not available','Global activity not available');
+	}
+
+	$ids = array();
+	$texts = array();
+
+	try {
+		$results = $plugin->getData($begin,$end,$show,$ids,$texts,$group_id);
+	} catch (Exception $e) {
+		$msg = "Error in global activity: ".$e->getMessage();
+		return new soap_fault ('','globalactivity_getActivity',$msg,$msg);
+	}
+
+	$keys = array(
+		'group_id',
+		'section',
+		'ref_id',
+		'subref_id',
+		'description',
+		'activity_date',
+		);
+
+
+	$res2 = array();
+	foreach ($results as $res) {
+		$r = array();
+		
+		foreach ($keys as $k) {
+			$r[$k] = $res[$k];
+		}
+		$res2[] = $r;
+	}
+
+	return $res2;
+}
+
 // Local Variables:
 // mode: php
 // c-file-style: "bsd"
diff --git a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
index dfbb6b7..f9a3d2b 100644
--- a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
+++ b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
@@ -72,6 +72,15 @@ class Activity extends FForge_SeleniumTestCase
 		$this->type("body", "ninetynine of them on Charlie's wall - also, ZONGO");
 		$this->clickAndWait("submit");
 
+		$this->createAndGote('ProjectB');
+		$this->clickAndWait("link=Forums");
+		$this->clickAndWait("link=open-discussion");
+		$this->click("link=Start New Thread");
+		$this->waitForPageToLoad("30000");
+		$this->type("subject", "Message2");
+		$this->type("body", "Forum post in project B");
+		$this->clickAndWait("submit");
+
 		// Create a document
 
 		$this->gotoProject('ProjectA');
@@ -144,6 +153,49 @@ class Activity extends FForge_SeleniumTestCase
 			}
 		}
 		$this->assertTrue($found);
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Message1') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Message2') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+
+		// Now restrict to ProjectA only
+		$response = $soapclient->globalactivity_getActivityForProject($session,time()-3600,time(),6,array('forumpost'));
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Welcome to developers-discussion') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Message1') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Message2') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertFalse($found);
 
 		$response = $soapclient->globalactivity_getActivity($session,time()-3600,time(),array('scmsvn'));
 		$found = False;

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=fed72b00ce5529e3e77f885abc992d29e50e696b

commit fed72b00ce5529e3e77f885abc992d29e50e696b
Author: Roland Mas <lolando at debian.org>
Date:   Fri Jun 3 16:17:13 2016 +0200

    Skip SCM activity by default

diff --git a/src/plugins/globalactivity/www/index.php b/src/plugins/globalactivity/www/index.php
index 92e272d..09203f0 100644
--- a/src/plugins/globalactivity/www/index.php
+++ b/src/plugins/globalactivity/www/index.php
@@ -34,7 +34,18 @@ global $HTML;
 
 $received_begin = getStringFromRequest("start_date");
 $received_end = getStringFromRequest("end_date");
-$show = getArrayFromRequest("show");
+$show = getArrayFromRequest("show",array('forumpost',
+										 'trackeropen',
+										 'trackerclose',
+										 'news',
+										 'taskopen',
+										 'taskclose',
+										 'taskdelete',
+										 'frsrelease',
+										 'docmannew',
+										 'docmanupdate',
+										 'docgroupnew'
+));
 
 $date_format = _('%Y-%m-%d');
 

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=1473a92baa9420129c90eb3d206b667c7f840ed0

commit 1473a92baa9420129c90eb3d206b667c7f840ed0
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 15:33:22 2016 +0200

    Include the globalactivity plugin in *.rpm

diff --git a/src/rpm/plugins b/src/rpm/plugins
index 784144e..6b467e7 100644
--- a/src/rpm/plugins
+++ b/src/rpm/plugins
@@ -37,6 +37,9 @@ Requires: php-pear-HTTP
 %package plugin-externalsearch
 Requires:
 
+%package plugin-globalactivity
+Requires:
+
 %package plugin-gravatar
 Requires:
 

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=6aa7289ccf27824b5eb4eee9bda0e0f880619464

commit 6aa7289ccf27824b5eb4eee9bda0e0f880619464
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 15:23:51 2016 +0200

    Include the globalactivity plugin in *.deb

diff --git a/src/debian/plugins b/src/debian/plugins
index f2a4228..1ef362e 100644
--- a/src/debian/plugins
+++ b/src/debian/plugins
@@ -62,6 +62,9 @@ Depends: libarc-php, fusionforge-plugin-compactpreview
 Package: fusionforge-plugin-foafprofiles
 Depends:
 
+Package: fusionforge-plugin-globalactivity
+Depends:
+
 Package: fusionforge-plugin-globalsearch
 Depends: libxml-rss-perl, libgetopt-mixed-perl, libdbi-perl, libwww-perl, libcrypt-ssleay-perl, libunicode-string-perl, ${perl:Depends}
 

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=c18d7386487dcb65e03f38dee5df9c25735b03ed

commit c18d7386487dcb65e03f38dee5df9c25735b03ed
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Doc for the globalactivity plugin

diff --git a/src/plugins/globalactivity/README b/src/plugins/globalactivity/README
index c8b6935..bfb0011 100644
--- a/src/plugins/globalactivity/README
+++ b/src/plugins/globalactivity/README
@@ -1 +1,34 @@
-Globalactivity plugin
\ No newline at end of file
+Globalactivity plugin
+
+This plugin provides a forge-wide view into the activities of all
+projects (modulo permissions).  It can be seen as an aggregate of all
+the project-wide "activity" pages.
+
+The relevant data is also made available through a SOAP API.
+
+The method is called globalactivity_getActivity.  It takes four
+parameters:
+
+- a session token (as for the rest of the SOAP API): string (as
+  returned from the login method), possibly empty if the API is to be
+  used anonymously;
+
+- a start date: integer (Unix timestamp: number of seconds since
+  1970-01-01 00:00:00 UTC);
+
+- an end date: integer (ditto);
+
+- a list of sections for which to list events (array of strings), to
+  be picked among: scmsvn, svngit, svnhg, trackeropen, trackerclose,
+  frsrelease, forumpost, news, taskopen, taskclose, taskdelete,
+  docmannew, docmanupdate, docgroupnew.  An empty list means no
+  filtering.
+
+The return value is an array of GlobalActivityEntry; a
+GlobalActivityEntry is a hash with the following keys: group_id
+(identifier for the project on the forge), section (see above, with a
+quirk: scmsvn, scmgit and scmhg all end up in the same "scm" section),
+ref_id (meaning differs across sections), subref_id (ditto),
+description (title, commit number, or otherwise descriptive text),
+activity_date (as a Unix timestamp).
+

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=190355a73a0a4ac2aa640e76b57923a14c1f4848

commit 190355a73a0a4ac2aa640e76b57923a14c1f4848
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Don't do HTML redirects in SOAP

diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index a09cb10..8f697e1 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -235,7 +235,7 @@ class globalactivityPlugin extends Plugin {
 
 		foreach ($show as $showthis) {
 			if (array_search($showthis, $ids) === false) {
-				exit_error(_('Invalid Data Passed to query'), 'home');
+				throw new Exception(_('Invalid Data Passed to query'));
 			}
 		}
 
@@ -268,8 +268,13 @@ function &globalactivity_getActivity($session_ser,$begin,$end,$show=array()) {
 
 	$ids = array();
 	$texts = array();
-	
-	$results = $plugin->getData($begin,$end,$show,$ids,$texts);
+
+	try {
+		$results = $plugin->getData($begin,$end,$show,$ids,$texts);
+	} catch (Exception $e) {
+		$msg = "Error in global activity: ".$e->getMessage();
+		return new soap_fault ('','globalactivity_getActivity',$msg,$msg);
+	}
 
 	$keys = array(
 		'group_id',
diff --git a/src/plugins/globalactivity/www/index.php b/src/plugins/globalactivity/www/index.php
index e13a552..92e272d 100644
--- a/src/plugins/globalactivity/www/index.php
+++ b/src/plugins/globalactivity/www/index.php
@@ -85,7 +85,11 @@ site_header(array('title'=>_('Global activity')));
 $ids = array();
 $texts = array();
 
-$results = $plugin->getData($begin,$end,$show,$ids,$texts);
+try {
+	$results = $plugin->getData($begin,$end,$show,$ids,$texts);
+} catch (Exception $e) {
+	exit_error($e->getMessage(), 'home');
+}
 
 if (count($ids) < 1) {
 	echo $HTML->information(_('No Activity Found'));

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=2f4d199f548928efaaf701d0107480ea5eab7f91

commit 2f4d199f548928efaaf701d0107480ea5eab7f91
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Testsuite for globalactivity

diff --git a/tests/func/50_PluginsScmGit/gitSSHTest.php b/tests/func/50_PluginsScmGit/gitSSHTest.php
index e1a5aa5..036d18f 100644
--- a/tests/func/50_PluginsScmGit/gitSSHTest.php
+++ b/tests/func/50_PluginsScmGit/gitSSHTest.php
@@ -81,6 +81,14 @@ class ScmGitSSHTest extends FForge_SeleniumTestCase
 		$this->assertTextPresent("Adding file");
 		$this->selectFrame("relative=top");
 
+		// Check that the changes appear in the global activity page
+
+		$this->activatePlugin('globalactivity');
+
+		$this->open(ROOT.'/plugins/globalactivity/');
+		$this->assertTextPresent("scm commit: Modifying file");
+		$this->assertTextPresent("scm commit: Adding file");
+
 		system("rm -fr $t");
 	}
 }
diff --git a/tests/func/60_PluginsGlobalactivity/globalactivityTest.php b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
new file mode 100644
index 0000000..dfbb6b7
--- /dev/null
+++ b/tests/func/60_PluginsGlobalactivity/globalactivityTest.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ * Copyright 2011, Roland Mas
+ * Copyright 2013, Franck Villaume - TrivialDev
+ * Copyright (C) 2015  Inria (Sylvain Beucler)
+ *
+ * This file is part of FusionForge.
+ *
+ * FusionForge is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * FusionForge is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+require_once dirname(dirname(__FILE__)).'/SeleniumForge.php';
+
+class Activity extends FForge_SeleniumTestCase
+{
+	public $fixture = 'projecta';
+
+	function testActivity()
+	{
+		$this->loadAndCacheFixture();
+
+		$this->activatePlugin('globalactivity');
+
+		// Open a tracker item
+
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=Tracker");
+		$this->clickAndWait("link=Bugs");
+		$this->clickAndWait("link=Submit New");
+		$this->type("summary", "Bug1 boustrophédon");
+		$this->type("details", "brebis outremanchienne");
+		$this->clickAndWait("//form[@id='trackeraddform']//input[@type='submit']");
+		$this->clickAndWait("link=Bug1 boustrophédon");
+		$this->type("details", 'Ceci était une référence au « Génie des Alpages », rien à voir avec Charlie - also, ZONGO, and needle');
+		$this->clickAndWait("submit");
+
+		// Create a task
+
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=Tasks");
+		$this->clickAndWait("link=To Do");
+		$this->clickAndWait("link=Add Task");
+		$this->type("summary", "Task1 the brain");
+		$this->type("details", "The same thing we do every night, Pinky - try to take over the world! - also, ZONGO");
+		$this->type("hours", "199");
+		$this->clickAndWait("submit");
+
+		$this->clickAndWait("link=Task1 the brain");
+		$this->type("details", 'This is the needle for tasks');
+		$this->clickAndWait("submit");
+
+		// Post a message in a forum
+
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=Forums");
+		$this->clickAndWait("link=open-discussion");
+		$this->click("link=Start New Thread");
+		$this->waitForPageToLoad("30000");
+		$this->type("subject", "Message1 in a bottle");
+		$this->type("body", "ninetynine of them on Charlie's wall - also, ZONGO");
+		$this->clickAndWait("submit");
+
+		// Create a document
+
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=Docs");
+		$this->clickAndWait("addItemDocmanMenu");
+		// ugly hack until we fix behavior in docman when no folders exist. We need to click twice on the link
+		$this->clickAndWait("addItemDocmanMenu");
+		$this->click("id=tab-new-document");
+		$this->type("title", "Doc1 Vladimir");
+		$this->type("//input[@name='description']", "Main website (the needle) - also, ZONGO");
+		$this->click("//input[@name='type' and @value='pasteurl']");
+		$this->type("file_url", "http://fusionforge.org/");
+		$this->clickAndWait("submit");
+
+		// Create some news
+
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=News");
+		$this->clickAndWait("link=Submit");
+		$this->type("summary", "News1 daily planet");
+		$this->type("details", "Clark Kent's newspaper - also, ZONGO");
+		$this->clickAndWait("submit");
+
+		// Check global activity
+
+		$this->open(ROOT.'/plugins/globalactivity/');
+		$this->assertTrue($this->isTextPresent("Bug1"));
+		$this->assertTrue($this->isTextPresent("Task1"));
+		$this->assertTrue($this->isTextPresent("Message1"));
+		$this->assertTrue($this->isTextPresent("Document http://fusionforge.org/"));
+		$this->assertTrue($this->isTextPresent("News1"));
+
+		// Also check anonymously
+
+		$this->logout();
+		$this->open(ROOT.'/plugins/globalactivity/');
+		$this->assertTrue($this->isTextPresent("Bug1"));
+		$this->assertTrue($this->isTextPresent("Task1"));
+		$this->assertTrue($this->isTextPresent("Message1"));
+		$this->assertFalse($this->isTextPresent("Document http://fusionforge.org/"));
+		$this->assertTrue($this->isTextPresent("News1"));
+
+		// Check SOAP
+
+		$soapclient = new SoapClient(WSDL_URL);
+		$this->assertNotNull($soapclient);
+		
+		$userid = FORGE_ADMIN_USERNAME;
+		$passwd = FORGE_ADMIN_PASSWORD;
+		
+		$response = $soapclient->login($userid, $passwd);
+		$session = $response;
+		
+		$response = $soapclient->globalactivity_getActivity($session,time()-3600,time(),array());
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Welcome to developers-discussion') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+
+		$response = $soapclient->globalactivity_getActivity($session,time()-3600,time(),array('forumpost'));
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Welcome to developers-discussion') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertTrue($found);
+
+		$response = $soapclient->globalactivity_getActivity($session,time()-3600,time(),array('scmsvn'));
+		$found = False;
+		foreach ($response as $data) {
+			if ($data->description == 'Welcome to developers-discussion') {
+				$found = True;
+				break;
+			}
+		}
+		$this->assertFalse($found);
+
+		// Now change permissions
+
+		$this->login(FORGE_ADMIN_USERNAME);
+		$this->gotoProject('ProjectA');
+		$this->clickAndWait("link=Admin");
+		$this->clickAndWait("link=Users and permissions");
+		$this->clickAndWait ("//td/form/div[contains(.,'Anonymous')]/../div/input[@value='Edit Permissions']") ;
+		$this->select("//select[contains(@name,'data[project_read]')]", "label=Visible");
+		$this->select("//tr/td[.='Bugs']/../td/select[contains(@name,'data[tracker]')]", "label=No Access");
+		$this->select("//tr/td[.='Patches']/../td/select[contains(@name,'data[tracker]')]", "label=No Access");
+		$this->select("//tr/td[.='To Do']/../td/select[contains(@name,'data[pm]')]", "label=No Access");
+		$this->select("//tr/td[.='Next Release']/../td/select[contains(@name,'data[pm]')]", "label=No Access");
+		$this->select("//tr/td[.='open-discussion']/../td/select[contains(@name,'data[forum]')]", "label=No Access");
+		$this->select("//tr/td[.='developers-discussion']/../td/select[contains(@name,'data[forum]')]", "label=No Access");
+		$this->select("//select[contains(@name,'data[docman]')]", "label=Read only");
+		$this->clickAndWait ("//input[@value='Submit']") ;
+
+		// Recheck perms on anonymous global activity page
+
+		$this->logout();
+		$this->open(ROOT.'/plugins/globalactivity/');
+		$this->assertFalse($this->isTextPresent("Bug1"));
+		$this->assertFalse($this->isTextPresent("Task1"));
+		$this->assertFalse($this->isTextPresent("Message1"));
+		$this->assertTrue($this->isTextPresent("Document http://fusionforge.org/"));
+		$this->assertTrue($this->isTextPresent("News1"));
+
+	}
+}

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=9d3887a2b73502b668e9e8e4d0b8ea16884ec3bc

commit 9d3887a2b73502b668e9e8e4d0b8ea16884ec3bc
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    SOAP for globalactivity

diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index 3565e30..a09cb10 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -26,9 +26,49 @@ class globalactivityPlugin extends Plugin {
 		$this->Plugin($id) ;
 		$this->name = "globalactivity";
 		$this->text = "Global Activity"; // To show in the tabs, use...
+
+		$this->_addHook('register_soap');
 	}
 
-	function CallHook ($hookname, &$params) {
+	public function register_soap(&$params) {
+		$server = &$params['server'];
+		$uri = 'http://'.forge_get_config('web_host');
+
+		$server->wsdl->addComplexType(
+			'GlobalActivityEntry',
+			'complexType',
+			'struct',
+			'sequence',
+			'',
+			array(
+				'group_id' => array('name'=>'group_id', 'type' => 'xsd:int'),
+				'section' => array('name'=>'section', 'type' => 'xsd:string'),
+				'ref_id' => array('name'=>'ref_id', 'type' => 'xsd:string'),
+				'subref_id' => array('name'=>'subref_id', 'type' => 'xsd:string'),
+				'description' => array('name'=>'description', 'type' => 'xsd:string'),
+				'activity_date' => array('name'=>'activity_date', 'type' => 'xsd:int')
+				)
+			);
+
+		$server->wsdl->addComplexType(
+			'ArrayOfGlobalActivityEntry',
+			'complexType',
+			'array',
+			'',
+			'SOAP-ENC:Array',
+			array(),
+			array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:GlobalActivityEntry[]')),
+			'tns:GlobalActivityEntry');
+		
+		$server->register(
+			'globalactivity_getActivity',
+			array('session_ser'=>'xsd:string',
+				  'begin'=>'xsd:int',
+				  'end'=>'xsd:int',
+				  'show'=>'tns:ArrayOfstring',),
+			array('return'=>'tns:ArrayOfGlobalActivityEntry'),
+			$uri,
+			$uri.'#globalactivity_getActivity','rpc','encoded');
 	}
 
 	public function getData($begin,$end,$show,&$ids,&$texts) {
@@ -87,7 +127,7 @@ class globalactivityPlugin extends Plugin {
 			$section = $show;
 		}
 
-		function date_compare($a, $b) {
+		function activity_date_compare($a, $b) {
 			if ($a['activity_date'] == $b['activity_date']) {
 				return 0;
 			}
@@ -174,6 +214,7 @@ class globalactivityPlugin extends Plugin {
 
 		// If plugins wants to add activities.
 		while ($arr = db_fetch_array($res)) {
+			$group_id = $arr['group_id'];
 			if (!forge_check_perm('project_read', $group_id)) {
 				continue;
 			}
@@ -210,12 +251,49 @@ class globalactivityPlugin extends Plugin {
 			$res2[] = $arr;
 		}
 
-		usort($res2, 'date_compare');
+		usort($res2, 'activity_date_compare');
 
 		return $res2;
 	}
 }
 
+function &globalactivity_getActivity($session_ser,$begin,$end,$show=array()) {
+	continue_session($session_ser);
+
+	$plugin = plugin_get_object('globalactivity');
+	if (!forge_get_config('use_activity')
+		|| !$plugin) {
+		return new soap_fault ('','globalactivity_getActivity','Global activity not available','Global activity not available');
+	}
+
+	$ids = array();
+	$texts = array();
+	
+	$results = $plugin->getData($begin,$end,$show,$ids,$texts);
+
+	$keys = array(
+		'group_id',
+		'section',
+		'ref_id',
+		'subref_id',
+		'description',
+		'activity_date',
+		);
+
+
+	$res2 = array();
+	foreach ($results as $res) {
+		$r = array();
+		
+		foreach ($keys as $k) {
+			$r[$k] = $res[$k];
+		}
+		$res2[] = $r;
+	}
+
+	return $res2;
+}
+
 // Local Variables:
 // mode: php
 // c-file-style: "bsd"

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=d34e1aaa2626a309c9ffcaaf11ef928218c5114c

commit d34e1aaa2626a309c9ffcaaf11ef928218c5114c
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Factor gathering of data into plugin class

diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
index 14ca531..3565e30 100644
--- a/src/plugins/globalactivity/include/globalactivityPlugin.class.php
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -25,100 +25,194 @@ class globalactivityPlugin extends Plugin {
 	public function __construct($id=0) {
 		$this->Plugin($id) ;
 		$this->name = "globalactivity";
-		$this->text = "HelloWorld!"; // To show in the tabs, use...
-		$this->_addHook("user_personal_links");//to make a link to the user's personal part of the plugin
-		$this->_addHook("usermenu");
-		$this->_addHook("groupmenu");	// To put into the project tabs
-		$this->_addHook("groupisactivecheckbox"); // The "use ..." checkbox in editgroupinfo
-		$this->_addHook("groupisactivecheckboxpost"); //
-		$this->_addHook("userisactivecheckbox"); // The "use ..." checkbox in user account
-		$this->_addHook("userisactivecheckboxpost"); //
-		$this->_addHook("project_admin_plugins"); // to show up in the admin page fro group
+		$this->text = "Global Activity"; // To show in the tabs, use...
 	}
 
 	function CallHook ($hookname, &$params) {
-		global $use_helloworldplugin,$G_SESSION,$HTML;
-		if ($hookname == "usermenu") {
-			$text = $this->text; // this is what shows in the tab
-			if ($G_SESSION->usesPlugin("helloworld")) {
-				$param = '?type=user&id=' . $G_SESSION->getId() . '&pluginname=' . $this->name; // we indicate the part we're calling is the user one
-				echo $HTML->PrintSubMenu (array ($text),
-						  array ('/plugins/helloworld/index.php' . $param ));
+	}
 
+	public function getData($begin,$end,$show,&$ids,&$texts) {
+		if ($begin > $end) {
+			$tmp = $end;
+			$end = $begin;
+			$begin = $tmp;
+			$tmp = $rendered_end;
+			$rendered_end = $rendered_begin;
+			$rendered_begin = $tmp;
+		}
+		
+		if (forge_get_config('use_forum')) {
+			$ids[]		= 'forumpost';
+			$texts[]	= _('Forum Post');
+		}
+
+		if (forge_get_config('use_tracker')) {
+			$ids[]		= 'trackeropen';
+			$texts[]	= _('Tracker Opened');
+			$ids[]		= 'trackerclose';
+			$texts[]	= _('Tracker Closed');
+		}
+
+		if (forge_get_config('use_news')) {
+			$ids[]		= 'news';
+			$texts[]	= _('News');
+		}
+
+		if (forge_get_config('use_pm')) {
+			$ids[]		= 'taskopen';
+			$texts[]	= _('Tasks Opened');
+			$ids[]		= 'taskclose';
+			$texts[]	= _('Tasks Closed');
+			$ids[]		= 'taskdelete';
+			$texts[]	= _('Tasks Deleted');
+		}
+
+		if (forge_get_config('use_frs')) {
+			$ids[]		= 'frsrelease';
+			$texts[]	= _('FRS Release');
+		}
+
+		if (forge_get_config('use_docman')) {
+			$ids[]		= 'docmannew';
+			$texts[]	= _('New Documents');
+			$ids[]		= 'docmanupdate';
+			$texts[]	= _('Updated Documents');
+			$ids[]		= 'docgroupnew';
+			$texts[]	= _('New Directories');
+		}
+
+		if (count($show) < 1) {
+			$section = $ids;
+		} else {
+			$section = $show;
+		}
+
+		function date_compare($a, $b) {
+			if ($a['activity_date'] == $b['activity_date']) {
+				return 0;
 			}
-		} elseif ($hookname == "groupmenu") {
-			$group_id=$params['group'];
-			$project = group_get_object($group_id);
-			if (!$project || !is_object($project)) {
-				return;
-			}
-			if ($project->isError()) {
-				return;
+			return ($a['activity_date'] > $b['activity_date']) ? -1 : 1;
+		}
+
+		global $cached_perms;
+		$cached_perms = array();
+		function check_perm_for_activity($arr) {
+			global $cached_perms;
+			$s = $arr['section'];
+			$ref = $arr['ref_id'];
+			$group_id = $arr['group_id'];
+
+			if (!isset($cached_perms[$s][$ref])) {
+				switch ($s) {
+					case 'scm': {
+						$cached_perms[$s][$ref] = forge_check_perm('scm', $group_id, 'read');
+						break;
+					}
+					case 'trackeropen':
+					case 'trackerclose': {
+						$cached_perms[$s][$ref] = forge_check_perm('tracker', $ref, 'read');
+						break;
+					}
+					case 'frsrelease': {
+						$cached_perms[$s][$ref] = forge_check_perm('frs', $ref, 'read');
+						break;
+					}
+					case 'forumpost':
+					case 'news': {
+						$cached_perms[$s][$ref] = forge_check_perm('forum', $ref, 'read');
+						break;
+					}
+					case 'taskopen':
+					case 'taskclose':
+					case 'taskdelete': {
+						$cached_perms[$s][$ref] = forge_check_perm('pm', $ref, 'read');
+						break;
+					}
+					case 'docmannew':
+					case 'docmanupdate':
+					case 'docgroupnew': {
+						$cached_perms[$s][$ref] = forge_check_perm('docman', $group_id, 'read');
+						break;
+					}
+					default: {
+						// Must be a bug somewhere, we're supposed to handle all types
+						$cached_perms[$s][$ref] = false;
+					}
+				}
 			}
-			if (!$project->isProject()) {
-				return;
+			return $cached_perms[$s][$ref];
+		}
+
+		$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
+			AND section = ANY ($3) ORDER BY activity_date DESC',
+							   array($begin,
+									 $end,
+									 db_string_array_to_any_clause($section)));
+
+		if (db_error()) {
+			exit_error(db_error(), 'home');
+		}
+
+		$results = array();
+		while ($arr = db_fetch_array($res)) {
+			$group_id = $arr['group_id'];
+			if (!forge_check_perm('project_read', $group_id)) {
+				continue;
 			}
-			if ( $project->usesPlugin ( $this->name ) ) {
-				$params['TITLES'][]=$this->text;
-				$params['DIRS'][]=util_make_url ('/plugins/helloworld/index.php?type=group&id=' . $group_id . "&pluginname=" . $this->name) ; // we indicate the part we're calling is the project one
-			} else {
-				$params['TITLES'][]=$this->text." is [Off]";
-				$params['DIRS'][]='';
+			if (!check_perm_for_activity($arr)) {
+				continue;
 			}
-			(($params['toptab'] == $this->name) ? $params['selected']=(count($params['TITLES'])-1) : '' );
-		} elseif ($hookname == "groupisactivecheckbox") {
-			//Check if the group is active
-			// this code creates the checkbox in the project edit public info page to activate/deactivate the plugin
-			$group_id=$params['group'];
-			$group = group_get_object($group_id);
-			echo "<tr>";
-			echo "<td>";
-			echo ' <input type="checkbox" name="use_helloworldplugin" value="1" ';
-			// checked or unchecked?
-			if ( $group->usesPlugin ( $this->name ) ) {
-				echo "checked";
+			$results[] = $arr;
+		}
+
+		$res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
+							   array('A'));
+
+		if (db_error()) {
+			exit_error(db_error(), 'home');
+		}
+
+		// If plugins wants to add activities.
+		while ($arr = db_fetch_array($res)) {
+			if (!forge_check_perm('project_read', $group_id)) {
+				continue;
 			}
-			echo " /><br/>";
-			echo "</td>";
-			echo "<td>";
-			echo "<strong>Use ".$this->text." Plugin</strong>";
-			echo "</td>";
-			echo "</tr>";
-		} elseif ($hookname == "groupisactivecheckboxpost") {
-			// this code actually activates/deactivates the plugin after the form was submitted in the project edit public info page
-			$group_id=$params['group'];
-			$group = group_get_object($group_id);
-			$use_helloworldplugin = getStringFromRequest('use_helloworldplugin');
-			if ( $use_helloworldplugin == 1 ) {
-				$group->setPluginUse ( $this->name );
-			} else {
-				$group->setPluginUse ( $this->name, false );
+			$group_id = $arr['group_id'];
+			$hookParams['group'] = $group_id;
+			$hookParams['results'] = &$results;
+			$hookParams['show'] = &$show;
+			$hookParams['begin'] = $begin;
+			$hookParams['end'] = $end;
+			$hookParams['ids'] = &$ids;
+			$hookParams['texts'] = &$texts;
+			plugin_hook("activity", $hookParams);
+		}
+
+		if (count($show) < 1) {
+			$show = $ids;
+		}
+
+		foreach ($show as $showthis) {
+			if (array_search($showthis, $ids) === false) {
+				exit_error(_('Invalid Data Passed to query'), 'home');
 			}
-		} elseif ($hookname == "user_personal_links") {
-			// this displays the link in the user's profile page to it's personal HelloWorld (if you want other sto access it, youll have to change the permissions in the index.php
-			$userid = $params['user_id'];
-			$user = user_get_object($userid);
-			$text = $params['text'];
-			//check if the user has the plugin activated
-			if ($user->usesPlugin($this->name)) {
-				echo '	<p>' ;
-				echo util_make_link ("/plugins/helloworld/index.php?id=$userid&type=user&pluginname=".$this->name,
-						     _('View Personal HelloWorld')
-					);
-				echo '</p>';
+		}
+
+		$res2 = array();
+		foreach ($results as $arr) {
+			$group_id = $arr['group_id'];
+			if (!forge_check_perm('project_read', $group_id)) {
+				continue;
 			}
-		} elseif ($hookname == "project_admin_plugins") {
-			// this displays the link in the project admin options page to it's  HelloWorld administration
-			$group_id = $params['group_id'];
-			$group = group_get_object($group_id);
-			if ( $group->usesPlugin ( $this->name ) ) {
-				echo '<p>'.util_make_link ("/plugins/helloworld/admin/index.php?id=".$group->getID().'&type=admin&pluginname='.$this->name,
-						     _('HelloWorld Admin')).'</p>' ;
+			if (!check_perm_for_activity($arr)) {
+				continue;
 			}
+			$res2[] = $arr;
 		}
-		elseif ($hookname == "blahblahblah") {
-			// ...
-		}
+
+		usort($res2, 'date_compare');
+
+		return $res2;
 	}
 }
 
diff --git a/src/plugins/globalactivity/www/index.php b/src/plugins/globalactivity/www/index.php
index 9663aff..e13a552 100644
--- a/src/plugins/globalactivity/www/index.php
+++ b/src/plugins/globalactivity/www/index.php
@@ -70,114 +70,22 @@ if (!$received_end || $received_end == 0) {
 	}
 }
 
-if ($begin > $end) {
-	$tmp = $end;
-	$end = $begin;
-	$begin = $tmp;
-	$tmp = $rendered_end;
-	$rendered_end = $rendered_begin;
-	$rendered_begin = $tmp;
-}
+$plugin = plugin_get_object('globalactivity');
 
 if (!forge_get_config('use_activity')) {
 	exit_disabled();
 }
+if (!$plugin) {
+	exit_disabled();
+}
+	
 
 site_header(array('title'=>_('Global activity')));
 
 $ids = array();
 $texts = array();
 
-if (forge_get_config('use_forum')) {
-	$ids[]		= 'forumpost';
-	$texts[]	= _('Forum Post');
-}
-
-if (forge_get_config('use_tracker')) {
-	$ids[]		= 'trackeropen';
-	$texts[]	= _('Tracker Opened');
-	$ids[]		= 'trackerclose';
-	$texts[]	= _('Tracker Closed');
-}
-
-if (forge_get_config('use_news')) {
-	$ids[]		= 'news';
-	$texts[]	= _('News');
-}
-
-if (forge_get_config('use_pm')) {
-	$ids[]		= 'taskopen';
-	$texts[]	= _('Tasks Opened');
-	$ids[]		= 'taskclose';
-	$texts[]	= _('Tasks Closed');
-	$ids[]		= 'taskdelete';
-	$texts[]	= _('Tasks Deleted');
-}
-
-if (forge_get_config('use_frs')) {
-	$ids[]		= 'frsrelease';
-	$texts[]	= _('FRS Release');
-}
-
-if (forge_get_config('use_docman')) {
-	$ids[]		= 'docmannew';
-	$texts[]	= _('New Documents');
-	$ids[]		= 'docmanupdate';
-	$texts[]	= _('Updated Documents');
-	$ids[]		= 'docgroupnew';
-	$texts[]	= _('New Directories');
-}
-
-if (count($show) < 1) {
-	$section = $ids;
-} else {
-	$section = $show;
-}
-
-$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
-			AND section = ANY ($3) ORDER BY activity_date DESC',
-			array($begin,
-				$end,
-				db_string_array_to_any_clause($section)));
-
-if (db_error()) {
-	exit_error(db_error(), 'home');
-}
-
-$results = array();
-while ($arr = db_fetch_array($res)) {
-	$results[] = $arr;
-}
-
-$res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
-    array('A'));
-
-if (db_error()) {
-	exit_error(db_error(), 'home');
-}
-
-// If plugins wants to add activities.
-while ($arr = db_fetch_array($res)) {
-	$group_id = $arr['group_id'];
-	$hookParams['group'] = $group_id;
-	$hookParams['results'] = &$results;
-	$hookParams['show'] = &$show;
-	$hookParams['begin'] = $begin;
-	$hookParams['end'] = $end;
-	$hookParams['ids'] = &$ids;
-	$hookParams['texts'] = &$texts;
-	plugin_hook("activity", $hookParams);
-}
-
-if (count($show) < 1) {
-	$show = $ids;
-}
-
-foreach ($show as $showthis) {
-	if (array_search($showthis, $ids) === false) {
-		exit_error(_('Invalid Data Passed to query'), 'home');
-	}
-}
+$results = $plugin->getData($begin,$end,$show,$ids,$texts);
 
 if (count($ids) < 1) {
 	echo $HTML->information(_('No Activity Found'));
@@ -217,77 +125,12 @@ if (count($ids) < 1) {
 		echo $HTML->information(_('No Activity Found'));
 	} else {
 
-		function date_compare($a, $b)
-		{
-			if ($a['activity_date'] == $b['activity_date']) {
-				return 0;
-			}
-			return ($a['activity_date'] > $b['activity_date']) ? -1 : 1;
-		}
-
-		$cached_perms = array();
-		function check_perm_for_activity($arr) {
-			global $cached_perms;
-			$s = $arr['section'];
-			$ref = $arr['ref_id'];
-			$group_id = $arr['group_id'];
-
-			if (!isset($cached_perms[$s][$ref])) {
-				switch ($s) {
-					case 'scm': {
-						$cached_perms[$s][$ref] = forge_check_perm('scm', $group_id, 'read');
-						break;
-					}
-					case 'trackeropen':
-					case 'trackerclose': {
-						$cached_perms[$s][$ref] = forge_check_perm('tracker', $ref, 'read');
-						break;
-					}
-					case 'frsrelease': {
-						$cached_perms[$s][$ref] = forge_check_perm('frs', $ref, 'read');
-						break;
-					}
-					case 'forumpost':
-					case 'news': {
-						$cached_perms[$s][$ref] = forge_check_perm('forum', $ref, 'read');
-						break;
-					}
-					case 'taskopen':
-					case 'taskclose':
-					case 'taskdelete': {
-						$cached_perms[$s][$ref] = forge_check_perm('pm', $ref, 'read');
-						break;
-					}
-					case 'docmannew':
-					case 'docmanupdate':
-					case 'docgroupnew': {
-						$cached_perms[$s][$ref] = forge_check_perm('docman', $group_id, 'read');
-						break;
-					}
-					default: {
-						// Must be a bug somewhere, we're supposed to handle all types
-						$cached_perms[$s][$ref] = false;
-					}
-				}
-			}
-			return $cached_perms[$s][$ref];
-		}
-
-		usort($results, 'date_compare');
 
 		$displayTableTop = 0;
 		$j = 0;
 		$last_day = 0;
 		foreach ($results as $arr) {
-
 			$group_id = $arr['group_id'];
-			if (!forge_check_perm('project_read', $group_id)) {
-				continue;
-			}
-
-			if (!check_perm_for_activity($arr)) {
-				continue;
-			}
 			if (!$displayTableTop) {
 				$theader = array();
 				$theader[] = _('Project');

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=250841388a34e59b0b9e652dc6208099891cecee

commit 250841388a34e59b0b9e652dc6208099891cecee
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Global activity plugin: new plugin
    
    New page at /plugins/globalactivity/ aggregating activities for all
    projects (modulo permissions)

diff --git a/autoinstall/install-src.sh b/autoinstall/install-src.sh
index b75eca5..b1e476e 100755
--- a/autoinstall/install-src.sh
+++ b/autoinstall/install-src.sh
@@ -56,6 +56,7 @@ fi
     make install-base install-shell install-scm \
         install-plugin-scmsvn install-plugin-scmgit \
         install-plugin-blocks install-plugin-moinmoin \
-        install-plugin-online_help install-plugin-taskboard install-plugin-message
+        install-plugin-online_help install-plugin-taskboard install-plugin-message \
+	install-plugin-globalactivity
     make post-install
 )
diff --git a/autoinstall/install.sh b/autoinstall/install.sh
index 39c256b..e3dc82d 100755
--- a/autoinstall/install.sh
+++ b/autoinstall/install.sh
@@ -43,7 +43,7 @@ if [ -e /etc/debian_version ]; then
 	    fusionforge-plugin-scmgit fusionforge-plugin-scmsvn fusionforge-plugin-scmbzr \
 	    fusionforge-plugin-moinmoin \
 	    fusionforge-plugin-blocks fusionforge-plugin-taskboard \
-	    fusionforge-plugin-message
+	    fusionforge-plugin-message fusionforge-plugin-globalactivity
 	if ! dpkg-vendor --is Ubuntu; then
 	    apt-get install locales-all  # https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1394929
 	fi
@@ -58,6 +58,6 @@ else
 	yum --enablerepo=epel install -y fusionforge fusionforge-shell fusionforge-scm \
 	    fusionforge-plugin-scmgit fusionforge-plugin-scmsvn \
 	    fusionforge-plugin-blocks fusionforge-plugin-online_help fusionforge-plugin-taskboard \
-	    fusionforge-plugin-message
+	    fusionforge-plugin-message fusionforge-plugin-globalactivity
     fi
 fi
diff --git a/src/plugins/globalactivity/INSTALL b/src/plugins/globalactivity/INSTALL
new file mode 100644
index 0000000..4b3b059
--- /dev/null
+++ b/src/plugins/globalactivity/INSTALL
@@ -0,0 +1,13 @@
+0. INSTALLATION of Globalactivity Plugin
+
+i.e. : if the directory where the plugins are is  /srv/www/gforge/plugins you should end up 
+	with /srv/www/gforge/plugins/globalactivity and all the files in it
+
+1. CONFIGURATION
+
+A) Make the symbolic links for each section
+
+(this is just an example, you should change the variables for what you have on your installation)
+
+/$GFORGEDIR/www/plugins/globalactivity -> /$GFORGEPLUGINSDIR/globalactivity/www
+/$ETC/gforge ->  /$GFORGEPLUGINSDIR/globalactivity/etc/plugins/globalactivity
diff --git a/src/plugins/globalactivity/README b/src/plugins/globalactivity/README
new file mode 100644
index 0000000..c8b6935
--- /dev/null
+++ b/src/plugins/globalactivity/README
@@ -0,0 +1 @@
+Globalactivity plugin
\ No newline at end of file
diff --git a/src/plugins/globalactivity/common/globalactivity-init.php b/src/plugins/globalactivity/common/globalactivity-init.php
new file mode 100644
index 0000000..8429e92
--- /dev/null
+++ b/src/plugins/globalactivity/common/globalactivity-init.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * This file is part of FusionForge.
+ *
+ * FusionForge is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FusionForge is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+global $gfplugins;
+require_once $gfplugins.'globalactivity/include/globalactivityPlugin.class.php' ;
+
+$globalactivityPluginObject = new globalactivityPlugin ;
+
+register_plugin ($globalactivityPluginObject) ;
+
+// Local Variables:
+// mode: php
+// c-file-style: "bsd"
+// End:
diff --git a/src/plugins/globalactivity/etc/globalactivity.ini b/src/plugins/globalactivity/etc/globalactivity.ini
new file mode 100644
index 0000000..591c0b5
--- /dev/null
+++ b/src/plugins/globalactivity/etc/globalactivity.ini
@@ -0,0 +1,7 @@
+[globalactivity]
+
+; plugin_status is a string.
+; valid means : production ready.
+; Any other strings means it's under work or broken and plugin
+; is available in installation_environment = development only.
+plugin_status = 'valid'
diff --git a/src/plugins/globalactivity/include/GlobalactivityPluginDescriptor.class.php b/src/plugins/globalactivity/include/GlobalactivityPluginDescriptor.class.php
new file mode 100644
index 0000000..9d0286c
--- /dev/null
+++ b/src/plugins/globalactivity/include/GlobalactivityPluginDescriptor.class.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
+ *
+ * This file is a part of Codendi.
+ *
+ * Codendi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Codendi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Codendi. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Portions Copyright 2010 (c) Mélanie Le Bail
+ * Portions Copyright 2011 (c) France Telecom, Coclico project
+ */
+
+require_once 'common/plugin/PluginDescriptor.class.php';
+
+class GlobalactivityPluginDescriptor extends PluginDescriptor {
+
+    function GlobalactivityPluginDescriptor() {
+        $this->PluginDescriptor(_('Globalactivity'), 'v1.0', _('Global activity in the forge'));
+    }
+}
diff --git a/src/plugins/globalactivity/include/GlobalactivityPluginInfo.class.php b/src/plugins/globalactivity/include/GlobalactivityPluginInfo.class.php
new file mode 100644
index 0000000..88f233e
--- /dev/null
+++ b/src/plugins/globalactivity/include/GlobalactivityPluginInfo.class.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
+ *
+ * This file is a part of Codendi.
+ *
+ * Codendi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Codendi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Codendi. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2010 (c) Mélanie Le Bail
+ * Copyright 2011 (c) France Telecom, Coclico project
+ */
+require_once 'common/plugin/PluginInfo.class.php';
+require_once 'GlobalactivityPluginDescriptor.class.php';
+
+class GlobalactivityPluginInfo extends PluginInfo {
+
+    function GlobalactivityPluginInfo(&$plugin) {
+        $this->PluginInfo($plugin);
+        $this->setPluginDescriptor(new GlobalactivityPluginDescriptor());
+    }
+
+}
diff --git a/src/plugins/globalactivity/include/globalactivityPlugin.class.php b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
new file mode 100644
index 0000000..14ca531
--- /dev/null
+++ b/src/plugins/globalactivity/include/globalactivityPlugin.class.php
@@ -0,0 +1,128 @@
+<?php
+
+/**
+ * globalactivityPlugin Class
+ *
+ *
+ * This file is part of FusionForge.
+ *
+ * FusionForge is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FusionForge is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+class globalactivityPlugin extends Plugin {
+	public function __construct($id=0) {
+		$this->Plugin($id) ;
+		$this->name = "globalactivity";
+		$this->text = "HelloWorld!"; // To show in the tabs, use...
+		$this->_addHook("user_personal_links");//to make a link to the user's personal part of the plugin
+		$this->_addHook("usermenu");
+		$this->_addHook("groupmenu");	// To put into the project tabs
+		$this->_addHook("groupisactivecheckbox"); // The "use ..." checkbox in editgroupinfo
+		$this->_addHook("groupisactivecheckboxpost"); //
+		$this->_addHook("userisactivecheckbox"); // The "use ..." checkbox in user account
+		$this->_addHook("userisactivecheckboxpost"); //
+		$this->_addHook("project_admin_plugins"); // to show up in the admin page fro group
+	}
+
+	function CallHook ($hookname, &$params) {
+		global $use_helloworldplugin,$G_SESSION,$HTML;
+		if ($hookname == "usermenu") {
+			$text = $this->text; // this is what shows in the tab
+			if ($G_SESSION->usesPlugin("helloworld")) {
+				$param = '?type=user&id=' . $G_SESSION->getId() . '&pluginname=' . $this->name; // we indicate the part we're calling is the user one
+				echo $HTML->PrintSubMenu (array ($text),
+						  array ('/plugins/helloworld/index.php' . $param ));
+
+			}
+		} elseif ($hookname == "groupmenu") {
+			$group_id=$params['group'];
+			$project = group_get_object($group_id);
+			if (!$project || !is_object($project)) {
+				return;
+			}
+			if ($project->isError()) {
+				return;
+			}
+			if (!$project->isProject()) {
+				return;
+			}
+			if ( $project->usesPlugin ( $this->name ) ) {
+				$params['TITLES'][]=$this->text;
+				$params['DIRS'][]=util_make_url ('/plugins/helloworld/index.php?type=group&id=' . $group_id . "&pluginname=" . $this->name) ; // we indicate the part we're calling is the project one
+			} else {
+				$params['TITLES'][]=$this->text." is [Off]";
+				$params['DIRS'][]='';
+			}
+			(($params['toptab'] == $this->name) ? $params['selected']=(count($params['TITLES'])-1) : '' );
+		} elseif ($hookname == "groupisactivecheckbox") {
+			//Check if the group is active
+			// this code creates the checkbox in the project edit public info page to activate/deactivate the plugin
+			$group_id=$params['group'];
+			$group = group_get_object($group_id);
+			echo "<tr>";
+			echo "<td>";
+			echo ' <input type="checkbox" name="use_helloworldplugin" value="1" ';
+			// checked or unchecked?
+			if ( $group->usesPlugin ( $this->name ) ) {
+				echo "checked";
+			}
+			echo " /><br/>";
+			echo "</td>";
+			echo "<td>";
+			echo "<strong>Use ".$this->text." Plugin</strong>";
+			echo "</td>";
+			echo "</tr>";
+		} elseif ($hookname == "groupisactivecheckboxpost") {
+			// this code actually activates/deactivates the plugin after the form was submitted in the project edit public info page
+			$group_id=$params['group'];
+			$group = group_get_object($group_id);
+			$use_helloworldplugin = getStringFromRequest('use_helloworldplugin');
+			if ( $use_helloworldplugin == 1 ) {
+				$group->setPluginUse ( $this->name );
+			} else {
+				$group->setPluginUse ( $this->name, false );
+			}
+		} elseif ($hookname == "user_personal_links") {
+			// this displays the link in the user's profile page to it's personal HelloWorld (if you want other sto access it, youll have to change the permissions in the index.php
+			$userid = $params['user_id'];
+			$user = user_get_object($userid);
+			$text = $params['text'];
+			//check if the user has the plugin activated
+			if ($user->usesPlugin($this->name)) {
+				echo '	<p>' ;
+				echo util_make_link ("/plugins/helloworld/index.php?id=$userid&type=user&pluginname=".$this->name,
+						     _('View Personal HelloWorld')
+					);
+				echo '</p>';
+			}
+		} elseif ($hookname == "project_admin_plugins") {
+			// this displays the link in the project admin options page to it's  HelloWorld administration
+			$group_id = $params['group_id'];
+			$group = group_get_object($group_id);
+			if ( $group->usesPlugin ( $this->name ) ) {
+				echo '<p>'.util_make_link ("/plugins/helloworld/admin/index.php?id=".$group->getID().'&type=admin&pluginname='.$this->name,
+						     _('HelloWorld Admin')).'</p>' ;
+			}
+		}
+		elseif ($hookname == "blahblahblah") {
+			// ...
+		}
+	}
+}
+
+// Local Variables:
+// mode: php
+// c-file-style: "bsd"
+// End:
diff --git a/src/plugins/globalactivity/www/admin/index.php b/src/plugins/globalactivity/www/admin/index.php
new file mode 100644
index 0000000..c246739
--- /dev/null
+++ b/src/plugins/globalactivity/www/admin/index.php
@@ -0,0 +1,110 @@
+<?php
+
+/*
+ * HelloWorld plugin
+ *
+ * Daniel Perez <danielperez.arg at gmail.com>
+ *
+ * This is an example to watch things in action. You can obviously modify things and logic as you see fit
+ */
+
+require_once '../../../env.inc.php';
+require_once $gfwww.'include/pre.php';
+require_once $gfconfig.'plugins/helloworld/config.php';
+
+// the header that displays for the user portion of the plugin
+function helloworld_Project_Header($params) {
+	global $DOCUMENT_ROOT,$HTML,$id;
+	$params['toptab']='helloworld';
+	$params['group']=$id;
+	/*
+		Show horizontal links
+	*/
+	site_project_header($params);
+}
+
+// the header that displays for the project portion of the plugin
+function helloworld_User_Header($params) {
+	global $DOCUMENT_ROOT,$HTML,$user_id;
+	$params['toptab']='helloworld';
+	$params['user']=$user_id;
+	/*
+	 Show horizontal links
+	 */
+	site_user_header($params);
+}
+
+	$user = session_get_user(); // get the session user
+
+	if (!$user || !is_object($user) || $user->isError() || !$user->isActive()) {
+		exit_error("Invalid User", "Cannot Process your request for this user.");
+	}
+
+	$type = getStringFromRequest('type');
+	$id = getStringFromRequest('id');
+	$pluginname = getStringFromRequest('pluginname');
+
+	if (!$type) {
+		exit_error("Cannot Process your request","No TYPE specified"); // you can create items in Base.tab and customize this messages
+	} elseif (!$id) {
+		exit_error("Cannot Process your request","No ID specified");
+	} else {
+		if ($type == 'group') {
+			$group = group_get_object($id);
+			if ( !$group) {
+				exit_error("Invalid Project", "Inexistent Project");
+			}
+			if ( ! ($group->usesPlugin ( $pluginname )) ) {//check if the group has the HelloWorld plugin active
+				exit_error("Error", "First activate the $pluginname plugin through the Project's Admin Interface");
+			}
+			$userperm = $group->getPermission();//we'll check if the user belongs to the group (optional)
+			if ( !$userperm->IsMember()) {
+				exit_error("Access Denied", "You are not a member of this project");
+			}
+			// other perms checks here...
+			helloworld_Project_Header(array('title'=>$pluginname . ' Project Plugin!','pagename'=>"$pluginname",'sectionvals'=>array(group_getname($id))));
+			// DO THE STUFF FOR THE PROJECT PART HERE
+			echo "We are in the Project HelloWorld plugin <br>";
+			echo "Greetings from planet " . $world; // $world comes from the config file in /etc
+		} elseif ($type == 'user') {
+			$realuser = user_get_object($id);//
+			if (!($realuser) || !($realuser->usesPlugin($pluginname))) {
+				exit_error("Error", "First activate the User's $pluginname plugin through Account Manteinance Page");
+			}
+			if ( (!$user) || ($user->getID() != $id)) { // if someone else tried to access the private HelloWorld part of this user
+				exit_error("Access Denied", "You cannot access other user's personal $pluginname");
+			}
+			helloworld_User_Header(array('title'=>'My '.$pluginname,'pagename'=>"$pluginname",'sectionvals'=>array($realuser->getUnixName())));
+			// DO THE STUFF FOR THE USER PART HERE
+			echo "We are in the User HelloWorld plugin <br>";
+			echo "Greetings from planet " . $world; // $world comes from the config file in /etc
+		} elseif ($type == 'admin') {
+			$group = group_get_object($id);
+			if ( !$group) {
+				exit_error("Invalid Project", "Inexistent Project");
+			}
+			if ( ! ($group->usesPlugin ( $pluginname )) ) {//check if the group has the HelloWorld plugin active
+				exit_error("Error", "First activate the $pluginname plugin through the Project's Admin Interface");
+			}
+			$userperm = $group->getPermission();//we'll check if the user belongs to the group
+			if ( !$userperm->IsMember()) {
+				exit_error("Access Denied", "You are not a member of this project");
+			}
+			//only project admin can access here
+			if ( $userperm->isAdmin() ) {
+				helloworld_Project_Header(array('title'=>$pluginname . ' Project Plugin!','pagename'=>"$pluginname",'sectionvals'=>array(group_getname($id))));
+				// DO THE STUFF FOR THE PROJECT ADMINISTRATION PART HERE
+				echo "We are in the Project HelloWorld plugin <font color=\"#ff0000\">ADMINISTRATION</font> <br>";
+				echo "Greetings from planet " . $world; // $world comes from the config file in /etc
+			} else {
+				exit_error("Access Denied", "You are not a project Admin");
+			}
+		}
+	}
+
+	site_project_footer();
+
+// Local Variables:
+// mode: php
+// c-file-style: "bsd"
+// End:
diff --git a/src/plugins/globalactivity/www/index.php b/src/plugins/globalactivity/www/index.php
new file mode 100644
index 0000000..9663aff
--- /dev/null
+++ b/src/plugins/globalactivity/www/index.php
@@ -0,0 +1,394 @@
+<?php
+/**
+ * Global Activity Page
+ *
+ * Copyright 1999 dtype
+ * Copyright 2006 (c) GForge, LLC
+ * Copyright 2010-2011, Franck Villaume - Capgemini
+ * Copyright 2012-2014, Franck Villaume - TrivialDev
+ * Copyright (C) 2012 Alain Peyrat - Alcatel-Lucent
+ * Copyright 2014, Benoit Debaenst - TrivialDev
+ * Copyright 2016, Roland Mas
+ * http://fusionforge.org/
+ *
+ * This file is part of FusionForge. FusionForge is free software;
+ * you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the Licence, or (at your option)
+ * any later version.
+ *
+ * FusionForge is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with FusionForge; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+require_once '../../env.inc.php';
+require_once $gfcommon.'include/pre.php';
+
+global $HTML;
+
+$received_begin = getStringFromRequest("start_date");
+$received_end = getStringFromRequest("end_date");
+$show = getArrayFromRequest("show");
+
+$date_format = _('%Y-%m-%d');
+
+if (!$received_begin || $received_begin==0) {
+	$begin = (time()-(30*86400));
+	$rendered_begin = strftime($date_format, $begin);
+} else {
+	$tmp = strptime($received_begin, $date_format);
+	if (!$tmp) {
+		$begin = (time()-(7*86400));
+		$rendered_begin = strftime($date_format, $begin);
+	} else {
+		$begin = mktime(0, 0, 0, $tmp['tm_mon']+1, $tmp['tm_mday'], $tmp['tm_year'] + 1900);
+		$rendered_begin = $received_begin;
+	}
+}
+if ($begin < 0) {
+    $begin = 0;
+    $rendered_begin = strftime($date_format, $begin);
+}
+
+if (!$received_end || $received_end == 0) {
+	$end = time();
+	$rendered_end = strftime($date_format, $end);
+} else {
+	$tmp = strptime($received_end, $date_format);
+	if (!$tmp) {
+		$end = time();
+		$rendered_end = strftime($date_format, $end);
+	} else {
+		$end = mktime(23, 59, 59, $tmp['tm_mon']+1, $tmp['tm_mday'], $tmp['tm_year'] + 1900);
+		$rendered_end = $received_end;
+	}
+}
+
+if ($begin > $end) {
+	$tmp = $end;
+	$end = $begin;
+	$begin = $tmp;
+	$tmp = $rendered_end;
+	$rendered_end = $rendered_begin;
+	$rendered_begin = $tmp;
+}
+
+if (!forge_get_config('use_activity')) {
+	exit_disabled();
+}
+
+site_header(array('title'=>_('Global activity')));
+
+$ids = array();
+$texts = array();
+
+if (forge_get_config('use_forum')) {
+	$ids[]		= 'forumpost';
+	$texts[]	= _('Forum Post');
+}
+
+if (forge_get_config('use_tracker')) {
+	$ids[]		= 'trackeropen';
+	$texts[]	= _('Tracker Opened');
+	$ids[]		= 'trackerclose';
+	$texts[]	= _('Tracker Closed');
+}
+
+if (forge_get_config('use_news')) {
+	$ids[]		= 'news';
+	$texts[]	= _('News');
+}
+
+if (forge_get_config('use_pm')) {
+	$ids[]		= 'taskopen';
+	$texts[]	= _('Tasks Opened');
+	$ids[]		= 'taskclose';
+	$texts[]	= _('Tasks Closed');
+	$ids[]		= 'taskdelete';
+	$texts[]	= _('Tasks Deleted');
+}
+
+if (forge_get_config('use_frs')) {
+	$ids[]		= 'frsrelease';
+	$texts[]	= _('FRS Release');
+}
+
+if (forge_get_config('use_docman')) {
+	$ids[]		= 'docmannew';
+	$texts[]	= _('New Documents');
+	$ids[]		= 'docmanupdate';
+	$texts[]	= _('Updated Documents');
+	$ids[]		= 'docgroupnew';
+	$texts[]	= _('New Directories');
+}
+
+if (count($show) < 1) {
+	$section = $ids;
+} else {
+	$section = $show;
+}
+
+$res = db_query_params('SELECT * FROM activity_vw WHERE activity_date BETWEEN $1 AND $2
+			AND section = ANY ($3) ORDER BY activity_date DESC',
+			array($begin,
+				$end,
+				db_string_array_to_any_clause($section)));
+
+if (db_error()) {
+	exit_error(db_error(), 'home');
+}
+
+$results = array();
+while ($arr = db_fetch_array($res)) {
+	$results[] = $arr;
+}
+
+$res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
+    array('A'));
+
+if (db_error()) {
+	exit_error(db_error(), 'home');
+}
+
+// If plugins wants to add activities.
+while ($arr = db_fetch_array($res)) {
+	$group_id = $arr['group_id'];
+	$hookParams['group'] = $group_id;
+	$hookParams['results'] = &$results;
+	$hookParams['show'] = &$show;
+	$hookParams['begin'] = $begin;
+	$hookParams['end'] = $end;
+	$hookParams['ids'] = &$ids;
+	$hookParams['texts'] = &$texts;
+	plugin_hook("activity", $hookParams);
+}
+
+if (count($show) < 1) {
+	$show = $ids;
+}
+
+foreach ($show as $showthis) {
+	if (array_search($showthis, $ids) === false) {
+		exit_error(_('Invalid Data Passed to query'), 'home');
+	}
+}
+
+if (count($ids) < 1) {
+	echo $HTML->information(_('No Activity Found'));
+} else {
+?>
+
+<div id="activity">
+<div id="activity_left">
+
+<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
+
+<div id="activity_select" >
+<div id="activity_label"><?php echo _('Activity')._(':'); ?></div>
+<?php echo html_build_multiple_select_box_from_arrays($ids, $texts, 'show[]', $show, count($texts), false); ?>
+</div>
+
+<div id="activity_startdate" >
+<div id="activity_label_startdate"><?php echo _('Start Date')._(':'); ?></div>
+<input name="start_date" value="<?php echo $rendered_begin; ?>" size="10" maxlength="10" />
+</div>
+
+<div id="activity_enddate" >
+<div id="activity_label_enddate"><?php echo _('End Date')._(':'); ?></div>
+<input name="end_date" value="<?php echo $rendered_end; ?>" size="10" maxlength="10" />
+</div>
+
+<div id="activity_submit" >
+<input type="submit" name="submit" value="<?php echo _('Refresh'); ?>" />
+</div>
+
+</form>
+</div>
+
+<div id="activity_right">
+<?php
+	if (count($results) < 1) {
+		echo $HTML->information(_('No Activity Found'));
+	} else {
+
+		function date_compare($a, $b)
+		{
+			if ($a['activity_date'] == $b['activity_date']) {
+				return 0;
+			}
+			return ($a['activity_date'] > $b['activity_date']) ? -1 : 1;
+		}
+
+		$cached_perms = array();
+		function check_perm_for_activity($arr) {
+			global $cached_perms;
+			$s = $arr['section'];
+			$ref = $arr['ref_id'];
+			$group_id = $arr['group_id'];
+
+			if (!isset($cached_perms[$s][$ref])) {
+				switch ($s) {
+					case 'scm': {
+						$cached_perms[$s][$ref] = forge_check_perm('scm', $group_id, 'read');
+						break;
+					}
+					case 'trackeropen':
+					case 'trackerclose': {
+						$cached_perms[$s][$ref] = forge_check_perm('tracker', $ref, 'read');
+						break;
+					}
+					case 'frsrelease': {
+						$cached_perms[$s][$ref] = forge_check_perm('frs', $ref, 'read');
+						break;
+					}
+					case 'forumpost':
+					case 'news': {
+						$cached_perms[$s][$ref] = forge_check_perm('forum', $ref, 'read');
+						break;
+					}
+					case 'taskopen':
+					case 'taskclose':
+					case 'taskdelete': {
+						$cached_perms[$s][$ref] = forge_check_perm('pm', $ref, 'read');
+						break;
+					}
+					case 'docmannew':
+					case 'docmanupdate':
+					case 'docgroupnew': {
+						$cached_perms[$s][$ref] = forge_check_perm('docman', $group_id, 'read');
+						break;
+					}
+					default: {
+						// Must be a bug somewhere, we're supposed to handle all types
+						$cached_perms[$s][$ref] = false;
+					}
+				}
+			}
+			return $cached_perms[$s][$ref];
+		}
+
+		usort($results, 'date_compare');
+
+		$displayTableTop = 0;
+		$j = 0;
+		$last_day = 0;
+		foreach ($results as $arr) {
+
+			$group_id = $arr['group_id'];
+			if (!forge_check_perm('project_read', $group_id)) {
+				continue;
+			}
+
+			if (!check_perm_for_activity($arr)) {
+				continue;
+			}
+			if (!$displayTableTop) {
+				$theader = array();
+				$theader[] = _('Project');
+				$theader[] = _('Time');
+				$theader[] = _('Activity');
+				$theader[] = _('By');
+
+				echo $HTML->listTableTop($theader);
+				$displayTableTop = 1;
+			}
+			if ($last_day != strftime($date_format, $arr['activity_date'])) {
+				//	echo $HTML->listTableBottom($theader);
+				echo '<tr class="tableheading"><td colspan="4">'.strftime($date_format, $arr['activity_date']).'</td></tr>';
+				//	echo $HTML->listTableTop($theader);
+				$last_day=strftime($date_format, $arr['activity_date']);
+			}
+			switch (@$arr['section']) {
+				case 'scm': {
+					$icon = html_image('ic/cvs16b.png','','',array('alt'=>_('Source Code')));
+					$url = util_make_link('/scm/'.$arr['ref_id'].$arr['subref_id'],_('scm commit')._(': ').$arr['description']);
+					break;
+				}
+				case 'trackeropen': {
+					$icon = html_image('ic/tracker20g.png','','',array('alt'=>_('Trackers')));
+					$url = util_make_link('/tracker/?func=detail&atid='.$arr['ref_id'].'&aid='.$arr['subref_id'].'&group_id='.$arr['group_id'],_('Tracker Item').' [#'.$arr['subref_id'].'] '.$arr['description'].' '._('Opened'));
+					break;
+				}
+				case 'trackerclose': {
+					$icon = html_image('ic/tracker20g.png','','',array('alt'=>_('Trackers')));
+					$url = util_make_link('/tracker/?func=detail&atid='.$arr['ref_id'].'&aid='.$arr['subref_id'].'&group_id='.$arr['group_id'],_('Tracker Item').' [#'.$arr['subref_id'].'] '.$arr['description'].' '._('Closed'));
+					break;
+				}
+				case 'frsrelease': {
+					$icon = html_image('ic/cvs16b.png','','',array('alt'=>_('Files')));
+					$url = util_make_link('/frs/?release_id='.$arr['subref_id'].'&group_id='.$arr['group_id'],_('FRS Release').' '.$arr['description']);
+					break;
+				}
+				case 'forumpost': {
+					$icon = html_image('ic/forum20g.png','','',array('alt'=>_('Forum')));
+					$url = util_make_link('/forum/message.php?msg_id='.$arr['subref_id'].'&group_id='.$arr['group_id'],_('Forum Post').' '.$arr['description']);
+					break;
+				}
+				case 'news': {
+					$icon = html_image('ic/write16w.png','','',array('alt'=>_('News')));
+					$url = util_make_link('/forum/forum.php?forum_id='.$arr['subref_id'],_('News').' '.$arr['description']);
+					break;
+				}
+				case 'taskopen': {
+					$icon = html_image('ic/taskman20w.png','','',array('alt'=>_('Tasks')));
+					$url = util_make_link('/pm/task.php?func=detailtask&project_task_id='.$arr['subref_id'].'&group_id='.$arr['group_id'].'&group_project_id='.$arr['ref_id'],_('Tasks').' '.$arr['description']);
+					break;
+				}
+				case 'taskclose': {
+					$icon = html_image('ic/taskman20w.png','','',array('alt'=>_('Tasks')));
+					$url = util_make_link('/pm/task.php?func=detailtask&project_task_id='.$arr['subref_id'].'&group_id='.$arr['group_id'].'&group_project_id='.$arr['ref_id'],_('Tasks').' '.$arr['description']);
+					break;
+				}
+
+				case 'taskdelete': {
+					$icon = html_image('ic/taskman20w.png','','',array('alt'=>_('Tasks')));
+					$url = util_make_link('/pm/task.php?func=detailtask&project_task_id='.$arr['subref_id'].'&group_id='.$arr['group_id'].'&group_project_id='.$arr['ref_id'],_('Tasks').' '.$arr['description']);
+					break;
+				}
+				case 'docmannew':
+				case 'docmanupdate': {
+					$icon = html_image('ic/docman16b.png', '', '', array('alt'=>_('Documents')));
+					$url = util_make_link('docman/?group_id='.$arr['group_id'].'&view=listfile&dirid='.$arr['ref_id'],_('Document').' '.$arr['description']);
+					break;
+				}
+				case 'docgroupnew': {
+					$icon = html_image('ic/cfolder15.png', '', '', array("alt"=>_('Directory')));
+					$url = util_make_link('docman/?group_id='.$arr['group_id'].'&view=listfile&dirid='.$arr['subref_id'],_('Directory').' '.$arr['description']);
+					break;
+				}
+				default: {
+					$icon = isset($arr['icon']) ? $arr['icon'] : '';
+					$url = '<a href="'.$arr['link'].'">'.$arr['title'].'</a>';
+				}
+			}
+			$cells = array();
+			$cells[][] = util_make_link_g(group_get_object($group_id)->getUnixName(),$group_id,group_get_object($group_id)->getPublicName());
+			$cells[][] = date('H:i:s',$arr['activity_date']);
+			$cells[][] = $icon .' '.$url;
+			if (isset($arr['user_name']) && $arr['user_name']) {
+				$cells[][] = util_display_user($arr['user_name'], $arr['user_id'],$arr['realname']);
+			} else {
+				$cells[][] = $arr['realname'];
+			}
+			echo $HTML->multiTableRow(array('class' => $HTML->boxGetAltRowStyle($j++, true)), $cells);
+		}
+		if ($displayTableTop) {
+			echo $HTML->listTableBottom($theader);
+		}
+		if (!$displayTableTop) {
+			echo $HTML->information(_('No Activity Found'));
+		}
+	}
+
+	echo '</div>';
+	echo '</div>';
+}
+
+
+site_project_footer();

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=8e231804a4607cc3ab80e1d6aea22612a2b58ce3

commit 8e231804a4607cc3ab80e1d6aea22612a2b58ce3
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    Activity: avoid duplicate sections
    
    This change is harmless in the standard case but avoids duplicate
    sections in the globalactivity plugin.

diff --git a/src/plugins/scmgit/common/GitPlugin.class.php b/src/plugins/scmgit/common/GitPlugin.class.php
index 5a6bca6..a89c069 100644
--- a/src/plugins/scmgit/common/GitPlugin.class.php
+++ b/src/plugins/scmgit/common/GitPlugin.class.php
@@ -1044,8 +1044,10 @@ control over it to the project's administrator.");
 				}
 			}
 		}
-		$params['ids'][] = $this->name;
-		$params['texts'][] = _('Git Commits');
+		if (!in_array($this->name, $params['ids'])) {
+			$params['ids'][] = $this->name;
+			$params['texts'][] = _('Git Commits');
+		}
 		return true;
 	}
 
diff --git a/src/plugins/scmhg/common/HgPlugin.class.php b/src/plugins/scmhg/common/HgPlugin.class.php
index d258bb2..9d96eaa 100644
--- a/src/plugins/scmhg/common/HgPlugin.class.php
+++ b/src/plugins/scmhg/common/HgPlugin.class.php
@@ -645,8 +645,10 @@ Offer DAV or SSH access.");
 				}
 			}
 		}
-		$params['ids'][] = $this->name;
-		$params['texts'][] = _('Hg Commits');
+		if (!in_array($this->name, $params['ids'])) {
+			$params['ids'][] = $this->name;
+			$params['texts'][] = _('Hg Commits');
+		}
 		return true;
 	}
 
diff --git a/src/plugins/scmsvn/common/SVNPlugin.class.php b/src/plugins/scmsvn/common/SVNPlugin.class.php
index e718661..bebfe14 100644
--- a/src/plugins/scmsvn/common/SVNPlugin.class.php
+++ b/src/plugins/scmsvn/common/SVNPlugin.class.php
@@ -644,8 +644,10 @@ some control over it to the project's administrator.");
 				}
 			}
 		}
-		$params['ids'][] = $this->name;
-		$params['texts'][] = _('Subversion Commits');
+		if (!in_array($this->name, $params['ids'])) {
+			$params['ids'][] = $this->name;
+			$params['texts'][] = _('Subversion Commits');
+		}
 		return true;
 	}
 

https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=b6327fc92af44bde8f5fb2759838df96e759f518

commit b6327fc92af44bde8f5fb2759838df96e759f518
Author: Roland Mas <lolando at debian.org>
Date:   Tue May 31 13:47:57 2016 +0200

    New hook to allow plugins to register SOAP methods

diff --git a/src/www/soap/index.php b/src/www/soap/index.php
index 7c18edd..9b5c7f8 100644
--- a/src/www/soap/index.php
+++ b/src/www/soap/index.php
@@ -150,6 +150,11 @@ require_once $gfwww.'soap/frs/frs.php';
 //
 require_once $gfwww.'soap/scm/scm.php';
 
+// Include methods defined by plugins
+$params = array();
+$params['server'] = &$server;
+plugin_hook('register_soap',$params);
+
 $wsdl_data = $server->wsdl->serialize();
 
 if (isset($wsdl)) {

-----------------------------------------------------------------------


hooks/post-receive
-- 
FusionForge



More information about the Fusionforge-commits mailing list