[Fusionforge-commits] r11827 - in branches/Branch_5_1: src src/common/docman src/common/frs src/common/include src/common/tracker src/db src/deb-specific src/debian src/packaging/install src/plugins/extratabs/common src/plugins/mediawiki/common src/utils/fixscripts src/www src/www/admin src/www/project/admin src/www/register tests/func/Docs tests/func/Forums tests/func/News tests/func/PluginsBlocks tests/func/RBAC tests/func/Site tests/func/Tasks tests/func/Testing tests/func/Trackers

Roland Mas lolando at libremir.placard.fr.eu.org
Fri Dec 17 15:32:05 CET 2010


Author: lolando
Date: 2010-12-17 15:32:04 +0100 (Fri, 17 Dec 2010)
New Revision: 11827

Added:
   branches/Branch_5_1/src/db/20101213-project-template.sql
   branches/Branch_5_1/src/utils/fixscripts/populate_template_project.php
Modified:
   branches/Branch_5_1/src/CHANGES
   branches/Branch_5_1/src/common/docman/DocumentGroup.class.php
   branches/Branch_5_1/src/common/docman/DocumentGroupFactory.class.php
   branches/Branch_5_1/src/common/frs/FRSPackage.class.php
   branches/Branch_5_1/src/common/include/Group.class.php
   branches/Branch_5_1/src/common/include/RBAC.php
   branches/Branch_5_1/src/common/include/config-vars.php
   branches/Branch_5_1/src/common/tracker/ArtifactTypes.class.php
   branches/Branch_5_1/src/deb-specific/db-upgrade.pl
   branches/Branch_5_1/src/debian/changelog
   branches/Branch_5_1/src/packaging/install/db-postgresql
   branches/Branch_5_1/src/plugins/extratabs/common/ExtraTabsPlugin.class.php
   branches/Branch_5_1/src/plugins/mediawiki/common/MediaWikiPlugin.class.php
   branches/Branch_5_1/src/www/admin/approve-pending.php
   branches/Branch_5_1/src/www/admin/groupedit.php
   branches/Branch_5_1/src/www/admin/grouplist.php
   branches/Branch_5_1/src/www/index_std.php
   branches/Branch_5_1/src/www/project/admin/users.php
   branches/Branch_5_1/src/www/register/index.php
   branches/Branch_5_1/tests/func/Docs/createDocURLTest.php
   branches/Branch_5_1/tests/func/Forums/forumsTest.php
   branches/Branch_5_1/tests/func/News/newsTest.php
   branches/Branch_5_1/tests/func/PluginsBlocks/blocksTest.php
   branches/Branch_5_1/tests/func/RBAC/rbacTest.php
   branches/Branch_5_1/tests/func/Site/projectsTest.php
   branches/Branch_5_1/tests/func/Tasks/createTaskTest.php
   branches/Branch_5_1/tests/func/Testing/SeleniumGforge.php
   branches/Branch_5_1/tests/func/Trackers/relationTest.php
   branches/Branch_5_1/tests/func/Trackers/trackersTest.php
   branches/Branch_5_1/tests/func/Trackers/workflowTest.php
Log:
Template projects reworked, see [#225]

Modified: branches/Branch_5_1/src/CHANGES
===================================================================
--- branches/Branch_5_1/src/CHANGES	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/CHANGES	2010-12-17 14:32:04 UTC (rev 11827)
@@ -11,7 +11,7 @@
 * Trackers: Sorting improved to allow text & select fields (Alcatel-Lucent)
 * [#127] Patch to auto approve projects.
 * scmgit plugin now allows project members to request a personal git
-  repository as a clone of the current project's one
+  repository as a clone of the current project's one (AdaCore)
 * New blocks plugin, to add free HTML blocks on top of each tools of
   the project allowing admins to add free descriptions
   (Alcatel-Lucent), (better with fckeditor plugin).
@@ -23,6 +23,9 @@
   (Roland Mas, Coclico)
 * Unified configuration system, now using standard *.ini files (Roland
   Mas)
+* Template projects: there can be several of them, and users
+  registering new projects can pick which template to clone from for
+  their new projects (Roland Mas, Coclico)
 * Reorganised, modular Apache configuration (Roland Mas)
 * New User Widget : documents monitoring (Capgemini)
 * RPM packages for Red Hat (and derived) distributions

Modified: branches/Branch_5_1/src/common/docman/DocumentGroup.class.php
===================================================================
--- branches/Branch_5_1/src/common/docman/DocumentGroup.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/docman/DocumentGroup.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -299,6 +299,7 @@
 							$this->Group->getID())
 					);
 		if ($result && db_affected_rows($result) > 0) {
+			$this->fetchData($this->getID()) ;
 			return true;
 		} else {
 			$this->setOnUpdateError(_('DocumentGroup:').' '.db_error());

Modified: branches/Branch_5_1/src/common/docman/DocumentGroupFactory.class.php
===================================================================
--- branches/Branch_5_1/src/common/docman/DocumentGroupFactory.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/docman/DocumentGroupFactory.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -113,13 +113,14 @@
 			return $this->flat_groups;
 		}
 
+		$this->flat_groups = array () ;
+
 		$result = db_query_params('SELECT * FROM doc_groups WHERE group_id=$1 AND stateid=$2 ORDER BY groupname ASC',
 						array($this->Group->getID(), $stateid));
 		$rows = db_numrows($result);
 
 		if (!$result || $rows < 1) {
 			$this->setError(_('No Document Directory Found').' '.db_error());
-			return false;
 		} else {
 			while ($arr = db_fetch_array($result)) {
 				$this->flat_groups[] = new DocumentGroup($this->Group, $arr);

Modified: branches/Branch_5_1/src/common/frs/FRSPackage.class.php
===================================================================
--- branches/Branch_5_1/src/common/frs/FRSPackage.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/frs/FRSPackage.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -27,15 +27,14 @@
 require_once $gfcommon.'frs/FRSRelease.class.php';
 
 function &get_frs_packages($Group) {
+	$ps = array();
 	$res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
 				array ($Group->getID())) ;
-	if (db_numrows($res) < 1) {
-		return false;
+	if (db_numrows($res) > 0) {
+		while($arr = db_fetch_array($res)) {
+			$ps[]=new FRSPackage($Group,$arr['package_id'],$arr);
+		}
 	}
-	$ps = array();
-	while($arr = db_fetch_array($res)) {
-		$ps[]=new FRSPackage($Group,$arr['package_id'],$arr);
-	}
 	return $ps;
 }
 

Modified: branches/Branch_5_1/src/common/include/Group.class.php
===================================================================
--- branches/Branch_5_1/src/common/include/Group.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/include/Group.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -3,7 +3,7 @@
  * FusionForge groups
  *
  * Copyright 1999-2001, VA Linux Systems, Inc.
- * Copyright 2009, Roland Mas
+ * Copyright 2009-2010, Roland Mas
  * Copyright 2010, Franck Villaume - Capgemini
  *
  * This file is part of FusionForge.
@@ -33,12 +33,14 @@
 require_once $gfcommon.'include/Role.class.php';
 require_once $gfcommon.'frs/FRSPackage.class.php';
 require_once $gfcommon.'docman/DocumentGroup.class.php';
+require_once $gfcommon.'docman/DocumentGroupFactory.class.php';
 require_once $gfcommon.'mail/MailingList.class.php';
 require_once $gfcommon.'mail/MailingListFactory.class.php';
 require_once $gfcommon.'survey/SurveyFactory.class.php';
 require_once $gfcommon.'survey/SurveyQuestionFactory.class.php';
 require_once $gfcommon.'include/gettext.php';
 require_once $gfcommon.'include/GroupJoinRequest.class.php';
+require_once $gfcommon.'widget/WidgetLayoutManager.class.php';
 
 //the license_id of "Other/proprietary" license
 define('GROUP_LICENSE_OTHER',126);
@@ -146,6 +148,12 @@
 	return group_get_objects (util_result_column_to_array($res,0)) ;
 }
 
+function &group_get_template_projects() {
+	$res=db_query_params ('SELECT group_id FROM groups WHERE is_template=1 AND status != $1',
+			      array ('D')) ;
+	return group_get_objects (util_result_column_to_array($res,0)) ;
+}
+
 function &group_get_object_by_name($groupname) {
 	$res=db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array ($groupname)) ;
 	return group_get_object(db_result($res,0,'group_id'),$res);
@@ -276,8 +284,9 @@
 	 *  @param	string	The new group description.
 	 *  @param	string	The purpose of the group.
 	 *  @param	bool	Whether to send an email or not
+	 *  @param      int     The id of the project this new project is based on
 	 */
-	function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true) {
+	function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true, $built_from_template=0) {
 		// $user is ignored - anyone can create pending group
 
 		global $SYS;
@@ -329,9 +338,10 @@
 					register_purpose,
 					register_time,
                                         enable_anonscm,
-					rand_hash
+					rand_hash,
+                                        built_from_template
 				)
-				VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
+				VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)',
 						array (htmlspecialchars ($group_name),
 						       $is_public,
 						       $unix_name,
@@ -344,7 +354,8 @@
 						       htmlspecialchars($purpose),
 						       time(),
 						       $is_public,
-						       md5($random_num)	)) ;
+						       md5($random_num),
+						       $built_from_template)) ;
 			if (!$res || db_affected_rows($res) < 1) {
 				$this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
 				db_rollback();
@@ -795,6 +806,44 @@
 	}
 
 	/**
+	 *	isTemplate - Simply returns the is_template flag from the database.
+	 *
+	 *	@return	boolean	is_template.
+	 */
+	function isTemplate() {
+		return $this->data_array['is_template'];
+	}
+
+	/**
+	 *	setAsTemplate - Set the template status of a project
+	 *
+	 *	@param	boolean	is_template.
+	 */
+	function setAsTemplate ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET is_template=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['is_template']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
+	 *	getTemplateProject - Return the project template this project is built from
+	 *
+	 *	@return	object	The template project
+	 */
+	function getTemplateProject() {
+		return group_get_object($this->data_array['built_from_template']);
+	}
+
+	/**
 	 *  getUnixName - the unix_name
 	 *
 	 *  @return	string	unix_name.
@@ -1076,6 +1125,26 @@
 	}
 
 	/**
+	 *	setUseSCM - Set the SCM usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseSCM ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_scm']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *	usesMail - whether or not this group has opted to use mailing lists.
 	 *
 	 *	@return	boolean uses_mail.
@@ -1090,6 +1159,26 @@
 	}
 
 	/**
+	 *	setUseMail - Set the mailing-list usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseMail ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_mail=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_mail']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 * 	usesNews - whether or not this group has opted to use news.
 	 *
 	 *	@return	boolean	uses_news.
@@ -1118,6 +1207,26 @@
 	}	   
 
 	/**
+	 *	setUseForum - Set the forum usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseForum ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_forum=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_forum']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *  usesStats - whether or not this group has opted to use stats.
 	 *
 	 *  @return	boolean	uses_stats.
@@ -1141,6 +1250,26 @@
 	}
 
 	/**
+	 *	setUseFRS - Set the FRS usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseFRS ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_frs=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_frs']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *  usesTracker - whether or not this group has opted to use tracker.
 	 *
 	 *  @return	boolean	uses_tracker.
@@ -1155,6 +1284,26 @@
 	}
 
 	/**
+	 *	setUseTracker - Set the tracker usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseTracker ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_tracker=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_tracker']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *  useCreateOnline - whether or not this group has opted to use create online documents option.
 	 *
 	 *  @return	boolean	use_docman_create_online.
@@ -1183,6 +1332,26 @@
 	}
 
 	/**
+	 *	setUseDocman - Set the docman usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUseDocman ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_docman=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_docman']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *  useDocmanSearch - whether or not this group has opted to use docman search engine.
 	 *
 	 *  @return	boolean	use_docman_search.
@@ -1253,6 +1422,26 @@
 	}
 
 	/**
+	 *	setUsePM - Set the PM usage
+	 *
+	 *	@param	boolean	enabled/disabled
+	 */
+	function setUsePM ($booleanparam) {
+		db_begin () ;
+		$booleanparam = $booleanparam ? 1 : 0 ;
+		$res = db_query_params ('UPDATE groups SET use_pm=$1 WHERE group_id=$2',
+					array ($booleanparam, $this->getID()));
+		if ($res) {
+			$this->data_array['use_pm']=$booleanparam;
+			db_commit () ;
+			return true ;
+		} else {
+			db_rollback () ;
+			return false ;
+		}
+	}
+
+	/**
 	 *  getPlugins -  get a list of all available group plugins
 	 *
 	 *  @return	array	array containing plugin_id => plugin_name
@@ -2183,6 +2372,19 @@
 	}
 
 	/**
+	 *	replaceTemplateStrings - fill-in some blanks with project name
+	 *
+	 *	@param	string	Template string
+	 *	@return	string	String after replacements
+	 */
+	function replaceTemplateStrings($string) {
+		$string = str_replace ('UNIXNAME', $this->getUnixName(), $string) ;
+		$string = str_replace ('PUBLICNAME', $this->getPublicName(), $string) ;
+		$string = str_replace ('DESCRIPTION', $this->getDescription(), $string) ;
+		return $string ;
+	}
+
+	/**
 	 *	approve - Approve pending project.
 	 *
 	 *	@param	object	The User object who is doing the updating.
@@ -2231,21 +2433,34 @@
 			}
 		}
 
-		$role = new Role($this);
-		$todo = array_keys($role->defaults);
-		for ($c=0; $c<count($todo); $c++) {
-			$role = new Role($this);
-			if (! ($role_id = $role->createDefault($todo[$c]))) {
-				$this->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+		$template = $this->getTemplateProject() ;
+		$id_mappings = array ();
+		$seen_local_roles = false ;
+		if ($template) {
+			// Copy roles from template project
+			foreach ($template->getRoles() as $oldrole) {
+				if ($oldrole->getHomeProject() != NULL) {
+					$role = new Role ($this) ;
+					$data = array () ;
+					// Need to use a different role name so that the permissions aren't set from the hardcoded defaults
+					$role->create ('TEMPORARY ROLE NAME', $data, true) ;
+					$role->setName ($oldrole->getName()) ;
+					$seen_local_roles = true ;
+				} else {
+					$role = $oldrole ;
+					$role->linkProject ($this) ;
+				}
+				$id_mappings['role'][$oldrole->getID()] = $role->getID() ;
+				// Reuse the project_admin permission
+				$role->setSetting ('project_admin', $this->getID(), $oldrole->getSetting ('project_admin', $template->getID())) ;
 			}
-			$role = new Role($this, $role_id);
-			if ($role->getVal('projectadmin',0)=='A') {
-				$role->setUser($idadmin_group);
-			}
 		}
+
+		if (!$seen_local_roles) {
+			$role = new Role($this);
+			$adminperms = array ('project_admin' => array ($this->getID() => 1)) ;
+			$role_id = $role->create ('Admin', $adminperms, true) ;
+		}
 		
 		if (USE_PFO_RBAC) {
 			$roles = $this->getRoles() ;
@@ -2260,188 +2475,133 @@
 		$saved_session = session_get_user () ;
 		session_set_internal ($idadmin_group) ;
 
-		//
-		//
-		//	Tracker Integration
-		//
-		//
-		if (forge_get_config ('use_tracker')) {
-			$ats = new ArtifactTypes($this);
-			if (!$ats || !is_object($ats)) {
-				$this->setError(_('Error creating ArtifactTypes object'));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
-			} else if ($ats->isError()) {
-				$this->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+		if ($template) {
+			if (forge_get_config ('use_tracker')) {
+				$this->setUseTracker ($template->usesTracker()) ;
+				if ($template->usesTracker()) {
+					$oldatf = new ArtifactTypeFactory ($template) ;
+					foreach ($oldatf->getArtifactTypes() as $o) {
+						$t = new ArtifactType ($this) ;
+						$t->create ($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->isPublic(),$o->allowsAnon(),$o->emailAll(),$o->getEmailAddress(),$o->getDuePeriod()/86400,0,$o->getSubmitInstructions(),$o->getBrowseInstructions()) ;
+						$id_mappings['tracker'][$o->getID()] = $t->getID() ;
+						$t->cloneFieldsFrom ($o->getID()) ;
+					}
+				}
 			}
-			if (!$ats->createTrackers()) {
-				$this->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+
+			if (forge_get_config ('use_pm')) {
+				$this->setUsePM ($template->usesPM()) ;
+				if ($template->usesPM()) {
+					$oldpgf = new ProjectGroupFactory ($template) ;
+					foreach ($oldpgf->getProjectGroups() as $o) {
+						$pg = new ProjectGroup ($this) ;
+						$pg->create ($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->isPublic(),$o->getSendAllPostsTo()) ;
+						$id_mappings['pm'][$o->getID()] = $pg->getID() ;
+					}
+				}
 			}
-		}
 
-		//
-		//
-		//	Forum Integration
-		//
-		//
-		if (forge_get_config ('use_forum')) {
-			$f = new Forum($this);
-			if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
-				$this->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+			if (forge_get_config ('use_forum')) {
+				$this->setUseForum ($template->usesForum()) ;
+				if ($template->usesForum()) {
+					$oldff = new ForumFactory ($template) ;
+					foreach ($oldff->getForums() as $o) {
+						$f = new Forum ($this) ;
+						$f->create ($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->isPublic(),$o->getSendAllPostsTo(),1,$o->allowAnonymous(),$o->getModerationLevel()) ;
+						$id_mappings['forum'][$o->getID()] = $f->getID() ;
+					}
+				}
 			}
-			$f = new Forum($this);
-			if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
-				$this->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+			
+			if (forge_get_config ('use_docman')) {
+				$this->setUseDocman ($template->usesDocman()) ;
+				if ($template->usesDocman()) {
+					$olddgf = new DocumentGroupFactory ($template) ;
+					// First pass: create all docgroups
+					$id_mappings['docman_docgroup'][0] = 0 ;
+					foreach ($olddgf->getDocumentGroups() as $o) {
+						$ndgf = new DocumentGroup ($this) ;
+						$ndgf->create($this->replaceTemplateStrings($o->getName())) ;
+						$id_mappings['docman_docgroup'][$o->getID()] = $ndgf->getID() ;
+					}
+					// Second pass: restore hierarchy links
+					foreach ($olddgf->getDocumentGroups() as $o) {
+						$ndgf = new DocumentGroup ($this) ;
+						$ndgf->fetchData ($id_mappings['docman_docgroup'][$o->getID()]) ;
+						$ndgf->update ($ndgf->getName(),$id_mappings['docman_docgroup'][$o->getParentID()]) ;
+					}
+				}
 			}
-			$f = new Forum($this);
-			if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
-				$this->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+			
+			if (forge_get_config ('use_frs')) {
+				$this->setUseFRS ($template->usesFRS()) ;
+				if ($template->usesFRS()) {
+					foreach (get_frs_packages ($template) as $o) {
+						$newp = new FRSPackage ($this) ;
+						$nname = $this->replaceTemplateStrings($o->getName()) ;
+						$newp->create ($nname, $o->isPublic()) ;
+					}
+				}
 			}
-		}
-		
-		//
-		//
-		//	Doc Mgr Integration
-		//
-		//
-		if (forge_get_config('use_docman')) {
-			$dg = new DocumentGroup($this);
-			if (!$dg->create(_('Uncategorized Submissions'))) {
-				$this->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
-			}
-		}
 
-		//
-		//
-		//	FRS integration
-		//
-		//
-		if (forge_get_config ('use_frs')) {
-			$frs = new FRSPackage($this);
-			if (!$frs->create($this->getUnixName())) {
-				$this->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
-			}
-		}
+			if (forge_get_config ('use_mail')) {
+				$this->setUseMail ($template->usesMail()) ;
+				if ($template->usesMail()) {
+					$oldmlf = new MailingListFactory ($template) ;
+					foreach ($oldmlf->getMailingLists() as $o) {
+						$ml = new MailingList ($this) ;
+						$nname = preg_replace ('/^'.$template->getUnixName().'-/','',$o->getName()) ;
 
-		//
-		//
-		//	PM Integration
-		//
-		//
-		if (forge_get_config ('use_pm')) {
-			$pg = new ProjectGroup($this);
-			if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
-				$this->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
+						$ndescription = $this->replaceTemplateStrings($o->getDescription()) ;
+						$ml->create ($nname, $ndescription, $o->isPublic()) ;
+					}
+				}
 			}
-			$pg = new ProjectGroup($this);
-			if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
-				$this->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
-			}
-		}
 
-		// Set permissions for roles
-		if (USE_PFO_RBAC) {
-			if ($this->isPublic()) {
-				$ra = RoleAnonymous::getInstance() ;
-				$rl = RoleLoggedIn::getInstance() ;
-				$ra->linkProject ($this) ;
-				$rl->linkProject ($this) ;
+			$this->setUseSCM ($template->usesSCM()) ;
 
-				$ra->setSetting ('project_read', $this->getID(), 1) ;
-				$rl->setSetting ('project_read', $this->getID(), 1) ;
+			foreach ($template->getPlugins() as $plugin_id => $plugin_name) {
+				$this->setPluginUse ($plugin_name) ;
+			}
 
-				$ra->setSetting ('frs', $this->getID(), 1) ;
-				$rl->setSetting ('frs', $this->getID(), 1) ;
+			foreach ($template->getRoles() as $oldrole) {
+				$newrole = RBACEngine::getInstance()->getRoleById ($id_mappings['role'][$oldrole->getID()]) ;
+				if ($oldrole->getHomeProject() != NULL
+				    && $oldrole->getHomeProject()->getID() == $template->getID()) {
+					$newrole->setPublic ($oldrole->isPublic()) ;
+				}
+				$oldsettings = $oldrole->getSettingsForProject ($template) ;
+				
+				$sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
+				foreach ($sections as $section) {
+					$newrole->setSetting ($section, $this->getID(), $oldsettings[$section][$template->getID()]) ;
+				}
 
-				$ra->setSetting ('docman', $this->getID(), 1) ;
-				$rl->setSetting ('docman', $this->getID(), 1) ;
-
-				$ff = new ForumFactory ($this) ;
-				foreach ($ff->getAllForumIds() as $fid) {
-					$f = forum_get_object ($fid) ;
-					if ($f->isPublic()) {
-						$l = $f->getModerationLevel() ;
-						if ($l == 0) {
-							$rl->setSetting ('forum', $fid, 3) ;
-						} else {
-							$rl->setSetting ('forum', $fid, 2) ;
+				$sections = array ('tracker', 'pm', 'forum') ;
+				foreach ($sections as $section) {
+					if (isset ($oldsettings[$section])) {
+						foreach ($oldsettings[$section] as $k => $v) {
+							$newrole->setSetting ($section,
+									      $id_mappings[$section][$k],
+									      $v) ;
 						}
-						if ($f->allowAnonymous()) {
-							if ($l == 0) {
-								$ra->setSetting ('forum', $fid, 3) ;
-							} else {
-								$ra->setSetting ('forum', $fid, 2) ;
-							}
-						} else {
-							$ra->setSetting ('forum', $fid, 1) ;
-						}
 					}
 				}
+			}	
 
-				$pgf = new ProjectGroupFactory ($this) ;
-				foreach ($pgf->getAllProjectGroupIds() as $pgid) {
-					$pg = projectgroup_get_object ($pgid) ;
-					if ($pg->isPublic()) {
-						$ra->setSetting ('pm', $pgid, 1) ;
-						$rl->setSetting ('pm', $pgid, 1) ;
-					}
-				}
+			$lm = new WidgetLayoutManager();
+			$lm->createDefaultLayoutForProject ($this->getID(), $template->getID()) ;
 
-				$atf = new ArtifactTypeFactory ($this) ;
-				foreach ($atf->getAllArtifactTypeIds() as $atid) {
-					$at = artifactType_get_object ($atid) ;
-					if ($at->isPublic()) {
-						$ra->setSetting ('tracker', $atid, 1) ;
-						$rl->setSetting ('tracker', $atid, 1) ;
-					}
-				}
-			}
-			foreach (get_group_join_requests ($this) as $gjr) {
-				$gjr->delete (true) ;
-			}
-		}
+			$params = array () ;
+			$params['template'] = $template ;
+			$params['project'] = $this ;
+			$params['id_mappings'] = $id_mappings ;
+			plugin_hook_by_reference ('clone_project_from_template', $params) ;
+		} else {
+			// Disable everything
+			$res = db_query_params ('UPDATE groups SET use_mail=0, use_survey=0, use_forum=0, use_pm=0, use_pm_depend_box=0, use_scm=0, use_news=0, use_docman=0, is_public=0, use_ftp=0, use_tracker=0, use_frs=0, use_stats=0 WHERE group_id=$1',
 
-		//
-		//
-		//	Create MailingList
-		//
-		//
-		if (forge_get_config('use_mail')) {
-			$mlist = new MailingList($this);
-			if (!$mlist->create('commits',_('Commits'),1,$idadmin_group)) {
-				$this->setError(sprintf(_('ML: %s'),$mlist->getErrorMessage()));
-				db_rollback();
-				setup_gettext_from_context();
-				return false;
-			}
+						array ($this->getID())) ;
 		}
 
 		$this->normalizeAllRoles () ;

Modified: branches/Branch_5_1/src/common/include/RBAC.php
===================================================================
--- branches/Branch_5_1/src/common/include/RBAC.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/include/RBAC.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -524,7 +524,7 @@
 		$group_id = $project->getID() ;
 
 		if (USE_PFO_RBAC) {
-			$sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'webcal') ;
+			$sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
 			foreach ($sections as $section) {
 				$result[$section][$group_id] = $this->getVal ($section, $group_id) ;
 			}
@@ -540,18 +540,21 @@
 		foreach ($tids as $tid) {
 			$result['tracker'][$tid] = $this->getVal ('tracker', $tid) ;
 		}
+		$sections[] = 'tracker' ;
 
 		$ff = new ForumFactory ($project) ;
 		$fids = $ff->getAllForumIds () ;
 		foreach ($fids as $fid) {
 			$result['forum'][$fid] = $this->getVal ('forum', $fid) ;
 		}
+		$sections[] = 'forum' ;
 
 		$pgf = new ProjectGroupFactory ($project) ;
 		$pgids = $pgf->getAllProjectGroupIds () ;
 		foreach ($pgids as $pgid) {
 			$result['pm'][$pgid] = $this->getVal ('pm', $pgid) ;
 		}
+		$sections[] = 'pm' ;
 
 
 		if (USE_PFO_RBAC) {

Modified: branches/Branch_5_1/src/common/include/config-vars.php
===================================================================
--- branches/Branch_5_1/src/common/include/config-vars.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/include/config-vars.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -32,6 +32,8 @@
 forge_define_config_item ('project_auto_approval', 'core', false) ;
 forge_set_config_item_bool ('project_auto_approval', 'core') ;
 forge_define_config_item ('project_auto_approval_user', 'core', 'admin') ;
+forge_define_config_item ('allow_project_without_template', 'core', true) ;
+forge_set_config_item_bool ('allow_project_without_template', 'core') ;
 forge_define_config_item ('web_host', 'core', $GLOBALS['sys_default_domain']) ;
 forge_define_config_item ('http_port', 'core', 80) ;
 forge_define_config_item ('https_port', 'core', 443) ;

Modified: branches/Branch_5_1/src/common/tracker/ArtifactTypes.class.php
===================================================================
--- branches/Branch_5_1/src/common/tracker/ArtifactTypes.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/common/tracker/ArtifactTypes.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -137,6 +137,7 @@
 			}
 
 		}
+
 		db_commit();
 		return true;
 	}

Added: branches/Branch_5_1/src/db/20101213-project-template.sql
===================================================================
--- branches/Branch_5_1/src/db/20101213-project-template.sql	                        (rev 0)
+++ branches/Branch_5_1/src/db/20101213-project-template.sql	2010-12-17 14:32:04 UTC (rev 11827)
@@ -0,0 +1,4 @@
+ALTER TABLE groups ADD COLUMN is_template INTEGER DEFAULT 0 NOT NULL;
+ALTER TABLE groups ADD COLUMN built_from_template INTEGER DEFAULT 0 NOT NULL;
+
+UPDATE groups SET is_template=1 WHERE unix_group_name='template';

Modified: branches/Branch_5_1/src/deb-specific/db-upgrade.pl
===================================================================
--- branches/Branch_5_1/src/deb-specific/db-upgrade.pl	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/deb-specific/db-upgrade.pl	2010-12-17 14:32:04 UTC (rev 11827)
@@ -1941,6 +1941,7 @@
     &update_with_sql("20101029-docman-monitoring","5.0.51-7");
     &update_with_sql("20100402_add_query_options","5.0.51-8");
     &update_with_sql("20101024-docman-createonline","5.0.51-9");
+    &update_with_sql("20101213-project-template","5.0.51-10");
 
     ########################### INSERT HERE #################################
 

Modified: branches/Branch_5_1/src/debian/changelog
===================================================================
--- branches/Branch_5_1/src/debian/changelog	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/debian/changelog	2010-12-17 14:32:04 UTC (rev 11827)
@@ -1,3 +1,10 @@
+fusionforge (5.0.51+templateengine-1) UNRELEASED; urgency=low
+
+  * Started branch to bring "template project" feature up to the level of
+    functionality offered by Codendi.
+
+ -- Roland Mas <roland at gnurandal.com>  Thu, 25 Nov 2010 16:53:47 +0100
+
 fusionforge (5.0.51-1) UNRELEASED; urgency=low
 
   * Snapshot from upstream SVN.

Modified: branches/Branch_5_1/src/packaging/install/db-postgresql
===================================================================
--- branches/Branch_5_1/src/packaging/install/db-postgresql	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/packaging/install/db-postgresql	2010-12-17 14:32:04 UTC (rev 11827)
@@ -66,4 +66,5 @@
 utils/inject-files.php usr/share/@OLDPACKAGE@/bin/
 #
 utils/fixscripts/normalize_roles.php	usr/share/@OLDPACKAGE@/bin/
+utils/fixscripts/populate_template_project.php	usr/share/@OLDPACKAGE@/bin/
 utils/forge_set_password                usr/share/@OLDPACKAGE@/bin/

Modified: branches/Branch_5_1/src/plugins/extratabs/common/ExtraTabsPlugin.class.php
===================================================================
--- branches/Branch_5_1/src/plugins/extratabs/common/ExtraTabsPlugin.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/plugins/extratabs/common/ExtraTabsPlugin.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -31,6 +31,7 @@
 		$this->text = "Extra tabs";
 		$this->hooks[] = "project_admin_plugins" ;
 		$this->hooks[] = "groupmenu" ;  // To put into the project tabs
+		$this->hooks[] = "clone_project_from_template" ;
 	}
 
 	function CallHook ($hookname, &$params) {
@@ -55,6 +56,25 @@
 				$params['DIRS'][] = $row_tab['tab_url'];
 				$params['TITLES'][] = $row_tab['tab_name'];
 			}
+		} elseif ($hookname == "clone_project_from_template") {
+			$tabs = array () ;
+			$res = db_query_params ('SELECT tab_name, tab_url, index FROM plugin_extratabs_main WHERE group_id=$1 ORDER BY index',
+						     array ($params['template']->getID())) ;
+			while ($row = db_fetch_array($res)) {
+				$data = array () ;
+				$data['tab_url'] = $params['project']->replaceTemplateStrings ($row['tab_url']) ;
+				$data['tab_name'] = $params['project']->replaceTemplateStrings ($row['tab_name']) ;
+				$data['index'] = $row['index'] ;
+				$tabs[] = $data ;
+			}			 
+
+			foreach ($tabs as $tab) {
+				db_query_params ('INSERT INTO plugin_extratabs_main (tab_url, tab_name, index, group_id) VALUES ($1,$2,$3,$4)',
+						 array ($data['tab_url'],
+							$data['tab_name'],
+							$data['index'],
+							$params['project']->getID())) ;
+			}
 		}
 	}
 }

Modified: branches/Branch_5_1/src/plugins/mediawiki/common/MediaWikiPlugin.class.php
===================================================================
--- branches/Branch_5_1/src/plugins/mediawiki/common/MediaWikiPlugin.class.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/plugins/mediawiki/common/MediaWikiPlugin.class.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -49,6 +49,7 @@
 		$this->hooks[] = "role_get_setting";
 		$this->hooks[] = "list_roles_by_permission";
 		$this->hooks[] = "project_admin_plugins"; // to show up in the admin page for group
+		$this->hooks[] = "clone_project_from_template" ;
 	}
 
 	function CallHook ($hookname, &$params) {
@@ -340,6 +341,23 @@
 				    "/plugins/mediawiki/plugin_admin.php?group_id=" .
 				    $group->getID(), _("MediaWiki Plugin admin")) .
 				    "<br />";
+		} elseif ($hookname == "clone_project_from_template") {
+			$template = $params['template'] ;
+			$project = $params['project'] ;
+			$id_mappings = $params['id_mappings'] ;
+			
+			$sections = array ('plugin_mediawiki_read', 'plugin_mediawiki_edit', 'plugin_mediawiki_upload', 'plugin_mediawiki_admin') ;
+
+			foreach ($template->getRoles() as $oldrole) {
+				$newrole = RBACEngine::getInstance()->getRoleById ($id_mappings['role'][$oldrole->getID()]) ;
+				$oldsettings = $oldrole->getSettingsForProject ($template) ;
+				
+				foreach ($sections as $section) {
+					if (isset ($oldsettings[$section][$template->getID()])) {
+						$newrole->setSetting ($section, $project->getID(), $oldsettings[$section][$template->getID()]) ;
+					}
+				}
+			}
 		}
 	}
   }

Added: branches/Branch_5_1/src/utils/fixscripts/populate_template_project.php
===================================================================
--- branches/Branch_5_1/src/utils/fixscripts/populate_template_project.php	                        (rev 0)
+++ branches/Branch_5_1/src/utils/fixscripts/populate_template_project.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -0,0 +1,209 @@
+#! /usr/bin/php
+<?php
+/**
+ * Copyright 2010 Roland Mas
+ *
+ * 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 FusionForge; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  US
+ */
+
+require (dirname(__FILE__).'/../www/env.inc.php');
+require_once $gfcommon.'include/pre.php';
+			 
+$err='';
+
+// Plugins subsystem
+require_once('common/include/Plugin.class.php') ;
+require_once('common/include/PluginManager.class.php') ;
+
+setup_plugin_manager () ;
+session_set_admin () ;
+
+function populateProject($project) {
+	db_begin();
+	$role = new Role($project);
+	$todo = array_keys($role->defaults);
+	for ($c=0; $c<count($todo); $c++) {
+		if (! ($role_id = $role->createDefault($todo[$c]))) {
+			$project->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+		$role = new Role($project, $role_id);
+		if ($role->getVal('projectadmin',0)=='A') {
+			$role->setUser(session_get_user()->getID());
+		}
+	}
+
+	if (forge_get_config ('use_tracker')) {
+		$ats = new ArtifactTypes($project);
+		if (!$ats || !is_object($ats)) {
+			$project->setError(_('Error creating ArtifactTypes object'));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		} else if ($ats->isError()) {
+			$project->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+		if (!$ats->createTrackers()) {
+			$project->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+
+	if (forge_get_config ('use_forum')) {
+		$f = new Forum($project);
+		if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
+			$project->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+		$f = new Forum($project);
+		if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
+			$project->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+		$f = new Forum($project);
+		if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
+			$project->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+               
+	if (forge_get_config('use_docman')) {
+		$dg = new DocumentGroup($project);
+		if (!$dg->create(_('Uncategorized Submissions'))) {
+			$project->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+
+	if (forge_get_config ('use_frs')) {
+		$frs = new FRSPackage($project);
+		if (!$frs->create("UNIXNAME")) {
+			$project->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+
+	if (forge_get_config ('use_pm')) {
+		$pg = new ProjectGroup($project);
+		if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
+			$project->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+		$pg = new ProjectGroup($project);
+		if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
+			$project->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+
+	$ra = RoleAnonymous::getInstance() ;
+	$rl = RoleLoggedIn::getInstance() ;
+	$ra->linkProject ($project) ;
+	$rl->linkProject ($project) ;
+	
+	$ra->setSetting ('project_read', $project->getID(), 1) ;
+	$rl->setSetting ('project_read', $project->getID(), 1) ;
+	
+	$ra->setSetting ('frs', $project->getID(), 1) ;
+	$rl->setSetting ('frs', $project->getID(), 1) ;
+	
+	$ra->setSetting ('docman', $project->getID(), 1) ;
+	$rl->setSetting ('docman', $project->getID(), 1) ;
+	
+	$ff = new ForumFactory ($project) ;
+	foreach ($ff->getAllForumIds() as $fid) {
+		$f = forum_get_object ($fid) ;
+		if ($f->isPublic()) {
+			$l = $f->getModerationLevel() ;
+			if ($l == 0) {
+				$rl->setSetting ('forum', $fid, 3) ;
+			} else {
+				$rl->setSetting ('forum', $fid, 2) ;
+			}
+			if ($f->allowAnonymous()) {
+				if ($l == 0) {
+					$ra->setSetting ('forum', $fid, 3) ;
+				} else {
+					$ra->setSetting ('forum', $fid, 2) ;
+				}
+			} else {
+				$ra->setSetting ('forum', $fid, 1) ;
+			}
+		}
+	}
+	$pgf = new ProjectGroupFactory ($project) ;
+	foreach ($pgf->getAllProjectGroupIds() as $pgid) {
+		$pg = projectgroup_get_object ($pgid) ;
+		if ($pg->isPublic()) {
+			$ra->setSetting ('pm', $pgid, 1) ;
+			$rl->setSetting ('pm', $pgid, 1) ;
+		}
+	}
+
+	$atf = new ArtifactTypeFactory ($project) ;
+	foreach ($atf->getAllArtifactTypeIds() as $atid) {
+		$at = artifactType_get_object ($atid) ;
+		if ($at->isPublic()) {
+			$ra->setSetting ('tracker', $atid, 1) ;
+			$rl->setSetting ('tracker', $atid, 1) ;
+		}
+	}
+
+	if (forge_get_config('use_mail')) {
+		$mlist = new MailingList($project);
+		if (!$mlist->create('commits',_('Commits'),1,session_get_user()->getID())) {
+			$project->setError(sprintf(_('ML: %s'),$mlist->getErrorMessage()));
+			db_rollback();
+			setup_gettext_from_context();
+			return false;
+		}
+	}
+	$project->normalizeAllRoles () ;
+
+	db_commit();
+
+	return true;
+}
+ 
+$project = group_get_object(5);
+
+if (!populateProject($project)) {
+	echo "Error when populating template project!\n";
+	exit(1);
+}
+?>


Property changes on: branches/Branch_5_1/src/utils/fixscripts/populate_template_project.php
___________________________________________________________________
Added: svn:executable
   + *

Modified: branches/Branch_5_1/src/www/admin/approve-pending.php
===================================================================
--- branches/Branch_5_1/src/www/admin/approve-pending.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/admin/approve-pending.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -221,6 +221,11 @@
 	}
 	}
 	
+	if ($row_grp['built_from_template']) {
+		$templateproject = group_get_object ($row_grp['built_from_template']) ;
+		print "<p>" .sprintf(_('Based on template project: %s (%s)'),$templateproject->getPublicName(),$templateproject->getUnixName())."</p>";
+	}
+
 	echo "<hr />";
 }
 

Modified: branches/Branch_5_1/src/www/admin/groupedit.php
===================================================================
--- branches/Branch_5_1/src/www/admin/groupedit.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/admin/groupedit.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -38,7 +38,7 @@
 }
 
 // This function performs very update
-function do_update(&$group, $is_public, $status, $group_type, $unix_box, $http_domain, $scm_box='') {
+function do_update(&$group, $is_public, $is_template, $status, $group_type, $unix_box, $http_domain, $scm_box='') {
 	global $feedback;
     global $error_msg;
 
@@ -56,6 +56,12 @@
 		return false;
 	}
 
+	if (!$group->setAsTemplate($is_template)) {
+		$error_msg .= $group->getErrorMessage();
+		db_rollback();
+		return false;
+	}
+
 	if($group->usesSCM() && !$group->setSCMBox($scm_box)) {
 		$error_msg .= $group->getErrorMessage();
 		db_rollback();
@@ -71,12 +77,13 @@
 
 if (getStringFromRequest('submit')) {
 	$form_public = getStringFromRequest('form_public');
+	$form_template = getStringFromRequest('form_template');
 	$form_status = getStringFromRequest('form_status');
 	$form_box = getStringFromRequest('form_box');
 	$form_domain = getStringFromRequest('form_domain');
 	$form_scm_box = getStringFromRequest('form_scm_box');
 
-	do_update($group, $form_public, $form_status, 1, $form_box, $form_domain, $form_scm_box);
+	do_update($group, $form_public, $form_template, $form_status, 1, $form_box, $form_domain, $form_scm_box);
 
 } else if (getStringFromRequest('resend')) {
 
@@ -147,6 +154,26 @@
 
 <tr>
 <td>
+<?php echo _('Template?') ?>:
+</td>
+<td>
+<?php
+	echo html_build_select_box_from_arrays(
+	array(
+		'0',
+		'1'
+	),
+	array(
+		_('No'),
+		_('Yes')
+),
+	'form_template', $group->isTemplate(), false
+); ?>
+</td>
+</tr>
+
+<tr>
+<td>
 <?php echo _('Unix Project Name:'); ?>
 </td>
 <td>

Modified: branches/Branch_5_1/src/www/admin/grouplist.php
===================================================================
--- branches/Branch_5_1/src/www/admin/grouplist.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/admin/grouplist.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -39,44 +39,47 @@
 					      'status',
 					      'is_public',
 					      'license_name',
-					      'members')) ;
+					      'members',
+					      'is_template')) ;
 
+if ($sortorder == 'is_template') {
+	$sortorder = 'is_template DESC' ;
+}
+
 if (isset($group_name_search)) {
 	echo "<p>"._('Projects that begin with'). " <strong>".$group_name_search."</strong></p>\n";
 	if (USE_PFO_RBAC) {
-		$res = db_query_params ('SELECT group_name,register_time,unix_group_name,groups.group_id,groups.is_public,status,license_name,COUNT(DISTINCT(pfo_user_role.user_id)) AS members
-FROM groups, pfo_user_role, pfo_role, licenses
-WHERE pfo_user_role.role_id=pfo_role.role_id
-AND pfo_role.home_group_id=groups.group_id
+		$res = db_query_params ('SELECT group_name,register_time,unix_group_name,groups.group_id,groups.is_public,groups.is_template,status,license_name,COUNT(DISTINCT(pfo_user_role.user_id)) AS members
+FROM groups, pfo_user_role RIGHT OUTER JOIN pfo_role ON pfo_user_role.role_id=pfo_role.role_id, licenses
+WHERE pfo_role.home_group_id=groups.group_id
 AND license_id=license
 AND lower(group_name) LIKE $1
-GROUP BY group_name,register_time,unix_group_name,groups.group_id,groups.is_public,status,license_name
+GROUP BY group_name,register_time,unix_group_name,groups.group_id,groups.is_public,groups.is_template,status,license_name
 ORDER BY '.$sortorder,
 					array (strtolower ("$group_name_search%"))) ;
 	} else {
-	$res = db_query_params ('SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name,COUNT(user_group.group_id) AS members
+	$res = db_query_params ('SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name,COUNT(user_group.group_id) AS members
 FROM groups
 LEFT JOIN user_group ON user_group.group_id=groups.group_id, licenses
 WHERE license_id=license
 AND lower(group_name) LIKE $1
-GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name
+GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name
 ORDER BY '.$sortorder,
 				array (strtolower ("$group_name_search%"))) ;
 	}
 } else {
 	if (USE_PFO_RBAC) {
-		$qpa = db_construct_qpa (false, 'SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name,COUNT(DISTINCT(pfo_user_role.user_id)) AS members
-FROM groups, pfo_user_role, pfo_role, licenses
-WHERE pfo_user_role.role_id=pfo_role.role_id
-AND pfo_role.home_group_id=groups.group_id
+		$qpa = db_construct_qpa (false, 'SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name,COUNT(DISTINCT(pfo_user_role.user_id)) AS members
+FROM groups, pfo_user_role RIGHT OUTER JOIN pfo_role ON pfo_user_role.role_id=pfo_role.role_id, licenses
+WHERE pfo_role.home_group_id=groups.group_id
 AND license_id=license') ;
 		if ($status) {
 			$qpa = db_construct_qpa ($qpa, ' AND status=$1', array ($status)) ;
 		}
-		$qpa = db_construct_qpa ($qpa, ' GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name ORDER BY '.$sortorder) ;
+		$qpa = db_construct_qpa ($qpa, ' GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name ORDER BY '.$sortorder) ;
 		$res = db_query_qpa ($qpa) ;
 	} else {
-		$qpa = db_construct_qpa (false, 'SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name,COUNT(user_group.group_id) AS members
+		$qpa = db_construct_qpa (false, 'SELECT group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name,COUNT(user_group.group_id) AS members
 FROM groups
 LEFT JOIN user_group ON user_group.group_id=groups.group_id, licenses
 WHERE license_id=license',
@@ -84,7 +87,7 @@
 		if ($status) {
 			$qpa = db_construct_qpa ($qpa, ' AND status=$1', array ($status)) ;
 		}
-		$qpa = db_construct_qpa ($qpa, ' GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,status,license_name ORDER BY '.$sortorder) ;
+		$qpa = db_construct_qpa ($qpa, ' GROUP BY group_name,register_time,unix_group_name,groups.group_id,is_public,groups.is_template,status,license_name ORDER BY '.$sortorder) ;
 		$res = db_query_qpa ($qpa) ;
 	}
 }
@@ -96,7 +99,8 @@
 	_('Status'),
 	_('Public?'),
 	_('License'),
-	_('Members')
+	_('Members'),
+	_('Template?')
 );
 
 $headerLinks = array(
@@ -106,7 +110,8 @@
 	'/admin/grouplist.php?sortorder=status',
 	'/admin/grouplist.php?sortorder=is_public',
 	'/admin/grouplist.php?sortorder=license_name',
-	'/admin/grouplist.php?sortorder=members'
+	'/admin/grouplist.php?sortorder=members',
+	'/admin/grouplist.php?sortorder=is_template'
 );
 
 echo $HTML->listTableTop($headers, $headerLinks);
@@ -136,6 +141,7 @@
 	echo '<td>'.$grp['is_public'].'</td>';
 	echo '<td>'.$grp['license_name'].'</td>';
 	echo '<td>'.$grp['members'].'</td>';
+	echo '<td>'.$grp['is_template'].'</td>';
 	echo '</tr>';
 	$i++;
 }

Modified: branches/Branch_5_1/src/www/index_std.php
===================================================================
--- branches/Branch_5_1/src/www/index_std.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/index_std.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -26,14 +26,15 @@
 
 <h3><?php print _("What's new in FusionForge 5.1"); ?></h3>
 <ul>
-<li><?php print _('New Funky Theme.'); ?></li>
-<li><?php print _('New UI and features for the document manager (download as zip, locking, referencing documents by URL).'); ?></li>
+<li><?php print _('New Funky Theme (Capgemini).'); ?></li>
+<li><?php print _('New UI and features for the document manager (download as zip, locking, referencing documents by URL) (Capgemini).'); ?></li>
 <li><?php print _('New progress bar displaying completion state of trackers using a custom status field.'); ?></li>
-<li><?php print _('Improved sorting in trackers.'); ?></li>
-<li><?php print _('More flexible and more powerful role-based access control system (Roland Mas, Coclico)'); ?></li>
+<li><?php print _('Improved sorting in trackers (Alcatel-Lucent).'); ?></li>
+<li><?php print _('More flexible and more powerful role-based access control system (Coclico).'); ?></li>
 <li><?php print _('New unobtrusive tooltip system based on jquery and tipsy to replace old help window (Alcatel-Lucent)'); ?></li>
 <li><?php print _('New plugins: Blocks, to add free HTML blocks on top of each tool of the project; Gravatar, to display user faces; OSLC, implementing the OSLC-CM API for tracker interoperability with external tools.'); ?></li>
-<li><?php print _('scmgit plugin: Personal Git repositories for project members.'); ?></li>
+<li><?php print _('scmgit plugin: Personal Git repositories for project members (AdaCore).'); ?></li>
+<li><?php print _('Template projects: there can be several of them, and users registering new projects can pick which template to clone from for their new projects (Coclico).'); ?></li>
 <li><?php print _('Simplified configuration system, using standard *.ini files.'); ?></li>
 <li><?php print _('Reorganised, modular Apache configuration.'); ?></li>
 <li><?php print _('RPM packages for Red Hat (and derived) distributions.'); ?></li>

Modified: branches/Branch_5_1/src/www/project/admin/users.php
===================================================================
--- branches/Branch_5_1/src/www/project/admin/users.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/project/admin/users.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -250,7 +250,7 @@
 					name="form_unix_name" value="<?php echo $user->getUnixName(); ?>" /><a
 					href="/users/<?php echo $user->getUnixName(); ?>"><?php echo $user->getRealName(); ?></a>
 				</td>
-				<td style="white-space: nowrap; text-align: right;"><?php echo role_box($group_id,'role_id',$row_memb['role_id']); ?>
+				<td style="white-space: nowrap; text-align: right;"><?php echo role_box($group_id,'role_id'); ?>
 				<input type="submit" name="acceptpending"
 					value="<?php echo _("Accept") ?>" />
 				<input type="submit" name="rejectpending"

Modified: branches/Branch_5_1/src/www/register/index.php
===================================================================
--- branches/Branch_5_1/src/www/register/index.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/src/www/register/index.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -51,6 +51,9 @@
 	exit_not_logged_in();
 }
 
+$template_projects = group_get_template_projects() ;
+sortProjectList ($template_projects) ;
+
 if (getStringFromRequest('submit')) {
 	if (!form_key_is_valid(getStringFromRequest('form_key'))) {
 		exit_form_double_submit('my');
@@ -62,6 +65,7 @@
 	$unix_name = trim(strtolower(getStringFromRequest('unix_name')));
 	$scm = getStringFromRequest('scm');
 	$is_public = getIntFromRequest('is_public');
+	$built_from_template = getIntFromRequest('built_from_template');
 	$feedback = "";
 	$error_msg = "";
 
@@ -69,6 +73,22 @@
 		$scm = 'noscm' ;
 	}
 
+	$template_project = group_get_object ($built_from_template) ;
+	if ($template_project
+	    && !$template_project->isError()
+	    && $template_project->isTemplate()) {
+		// Valid template selected, nothing to do
+	} elseif (forge_get_config('allow_project_without_template')) {
+		// Empty projects allowed
+		$built_from_template = 0 ;
+	} elseif (count($template_projects) == 0) {
+		// No empty projects allowed, but no template available
+		$built_from_template = 0 ;
+	} else {
+		// No empty projects allowed, picking the first available template
+		$built_from_template = $template_projects[0]->getID() ;
+	}
+
 	if (forge_get_config('use_scm')) {
 		$scm_host = '';
 		$plugin = false ;
@@ -96,7 +116,8 @@
 			'shell1',
 			$scm_host,
 			$is_public,
-			$send_mail
+			$send_mail,
+			$built_from_template
 		);
 		if ($res && forge_get_config('use_scm') && $plugin) {
 			$group->setUsesSCM (true) ;
@@ -205,6 +226,54 @@
 	echo '</tr></tbody></table>'."\n";
 }
 
+$index++;
+echo '<h3>'.$index.'. '._('Project template'). '</h3>';
+
+if (count ($template_projects) > 1) {
+	$tpv_arr = array () ;
+	$tpn_arr = array () ;
+	echo '<p>';
+	if (forge_get_config('allow_project_without_template')) {
+		printf(_('You can either start from an empty project, or pick a project that will act as a template for yours.  Your project will initially have the same configuration as the template (same roles and permissions, same trackers, same set of enabled plugins, and so on).')) ;
+		$tpv_arr[] = 0 ;
+		$tpn_arr[] = _('Start from empty project') ;
+	} else {
+		printf(_('Please pick a project that will act as a template for yours.  Your project will initially have the same configuration as the template (same roles and permissions, same trackers, same set of enabled plugins, and so on).')) ;
+	}
+	echo '</p>' ;
+	foreach ($template_projects as $tp) {
+		$tpv_arr[] = $tp->getID() ;
+		$tpn_arr[] = $tp->getPublicName() ;
+	}
+	echo html_build_select_box_from_arrays ($tpv_arr, $tpn_arr, 'built_from_template', $template_projects[0]->getID(),
+						false, '', false, '') ;
+} elseif (count ($template_projects) == 1) {
+	echo '<p>';
+	if (forge_get_config('allow_project_without_template')) {
+		printf(_('You can either start from an empty project, or use the %s project as a template for yours.  Your project will initially have the same configuration as the template (same roles and permissions, same trackers, same set of enabled plugins, and so on).'),
+		       $template_projects[0]->getPublicName()) ;
+		echo '</p>' ;
+		$tpv_arr = array () ;
+		$tpn_arr = array () ;
+		$tpv_arr[] = 0 ;
+		$tpn_arr[] = _('Start from empty project') ;
+		$tpv_arr[] = $template_projects[0]->getID() ;
+		$tpn_arr[] = $template_projects[0]->getPublicName() ;
+		echo html_build_select_box_from_arrays ($tpv_arr, $tpn_arr, 'built_from_template', $template_projects[0]->getID(),
+							false, '', false, '') ;
+	} else {
+		printf(_('Your project will initially have the same configuration as the %s project (same roles and permissions, same trackers, same set of enabled plugins, and so on).'),
+		       $template_projects[0]->getPublicName()) ;
+		echo '<input type="hidden" name="built_from_template" value="'.$template_projects[0]->getID().'" />' ;
+	echo '</p>' ;
+	}
+} else {
+	echo '<p>';
+	printf(_('Since no template project is available, your project will start empty.')) ;
+	echo '<input type="hidden" name="built_from_template" value="0" />' ;
+	echo '</p>';
+}
+
 if ($sys_use_private_project) {
 	$index++;
 	echo '<h3>'.$index.'. '._('Visibility'). '</h3>';

Modified: branches/Branch_5_1/tests/func/Docs/createDocURLTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Docs/createDocURLTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Docs/createDocURLTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -48,6 +48,7 @@
 {
 	function testCreateDocURL()
 	{
+		$this->populateStandardTemplate('docs');
 		$this->init();
 		$this->clickAndWait("link=Docs");
 		$this->clickAndWait("link=Submit new documentation");

Modified: branches/Branch_5_1/tests/func/Forums/forumsTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Forums/forumsTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Forums/forumsTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -47,9 +47,10 @@
 
 class CreateForum extends FForge_SeleniumTestCase
 {
-	function testSimplePost()
+	function skiptestSimplePost()
 	{
 		// Create the first message (Message1/Text1).
+		$this->populateStandardTemplate('forums');
 		$this->init();
 		$this->click("link=Forums");
 		$this->waitForPageToLoad("30000");
@@ -81,18 +82,19 @@
 	 */
 	function testSimpleAccessWhenPrivate()
 	{
+		$this->populateStandardTemplate('forums');
 		$this->init();
 
-		$this->open( ROOT.'/forum/message.php?msg_id=3' );
+		$this->open( ROOT.'/forum/message.php?msg_id=6' );
 		$this->waitForPageToLoad("30000");
-		$this->assertTrue($this->isTextPresent("Welcome to Developers"));
+		$this->assertTrue($this->isTextPresent("Welcome to developers"));
 
 		$this->logout();
-		$this->open( ROOT.'/forum/message.php?msg_id=3' );
+		$this->open( ROOT.'/forum/message.php?msg_id=6' );
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isLoginRequired());
 		$this->triggeredLogin('admin');
-		$this->assertTrue($this->isTextPresent("Welcome to Developers"));
+		$this->assertTrue($this->isTextPresent("Welcome to developers"));
 	}
 
 	/*
@@ -101,8 +103,9 @@
 	 * to the login page, then will reply and then
 	 * we check that his reply is present in the thread.
 	 */
-	function testReplyToMessage()
+	function skiptestReplyToMessage()
 	{
+		$this->populateStandardTemplate('forums');
 		$this->init();
 		$this->logout();
 
@@ -111,7 +114,7 @@
 		$this->waitForPageToLoad("30000");
 		$this->click("link=open-discussion");
 		$this->waitForPageToLoad("30000");
-		$this->click("link=Welcome to Open-Discussion");
+		$this->click("link=Welcome to open-discussion");
 		$this->waitForPageToLoad("30000");
 		$this->click("link=[ reply ]");
 		$this->waitForPageToLoad("30000");
@@ -121,7 +124,7 @@
 		$this->click("submit");
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("Message Posted Successfully"));
-		$this->click("link=Welcome to Open-Discussion");
+		$this->click("link=Welcome to open-discussion");
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("Here is my 19823 reply"));
 
@@ -130,7 +133,8 @@
 	/*
 	 * Verify that it is imposible to use name already used by a mailing list
 	 */
-	function testEmailAddressNotAlreadyUsed() {
+	function skiptestEmailAddressNotAlreadyUsed() {
+		$this->populateStandardTemplate('forums');
 		$this->init();
 		$this->click("link=Mailing Lists");
 		$this->waitForPageToLoad("30000");

Modified: branches/Branch_5_1/tests/func/News/newsTest.php
===================================================================
--- branches/Branch_5_1/tests/func/News/newsTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/News/newsTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -49,6 +49,7 @@
 {
 	function testMyTestCase()
 	{
+		$this->populateStandardTemplate(array());
 		$this->init();
 
 		// Create a simple news.

Modified: branches/Branch_5_1/tests/func/PluginsBlocks/blocksTest.php
===================================================================
--- branches/Branch_5_1/tests/func/PluginsBlocks/blocksTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/PluginsBlocks/blocksTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -52,6 +52,7 @@
   {
   	$this->_activateBlocksPlugin();
 	
+    $this->populateStandardTemplate('empty');
     $this->init();
 
     $this->click("link=Admin");

Modified: branches/Branch_5_1/tests/func/RBAC/rbacTest.php
===================================================================
--- branches/Branch_5_1/tests/func/RBAC/rbacTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/RBAC/rbacTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -204,7 +204,7 @@
 
 	function testProjectRolesAndPermissions()
 	{
-		$this->login("admin");
+		$this->populateStandardTemplate('trackers');
 
 		$this->createUser ("bigboss") ;
 		$this->createUser ("guru") ;
@@ -254,15 +254,34 @@
 		$this->registerProject ("SubProject", "bigboss") ;
 		$this->approveProject ("SubProject", "bigboss") ;
 
+		// Create roles
+		$this->gotoProject ("MetaProject") ;
+		$this->click("link=Admin");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Users and permissions");
+		$this->waitForPageToLoad("30000");
+		$this->type ("//form[contains(@action,'roleedit.php')]/..//input[@name='role_name']", "Senior Developer") ;
+		$this->click ("//input[@value='Create Role']") ;
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Users and permissions");
+		$this->waitForPageToLoad("30000");
+		$this->type ("//form[contains(@action,'roleedit.php')]/..//input[@name='role_name']", "Junior Developer") ;
+		$this->click ("//input[@value='Create Role']") ;
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Users and permissions");
+		$this->waitForPageToLoad("30000");
+		$this->type ("//form[contains(@action,'roleedit.php')]/..//input[@name='role_name']", "Doc Writer") ;
+		$this->click ("//input[@value='Create Role']") ;
+		$this->waitForPageToLoad("30000");
+
 		// Add users
 		$this->gotoProject ("MetaProject") ;
 		$this->click("link=Admin");
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Users and permissions");
 		$this->waitForPageToLoad("30000");
-
-		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name']", "guru") ;
-		$this->select("//select[@name='role_id']", "label=Senior Developer");
+		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name' and @type='text']", "guru") ;
+		$this->select("//input[@value='Add Member']/../select[@name='role_id']", "label=Senior Developer");
 		$this->click ("//input[@value='Add Member']") ;
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("guru Lastname"));
@@ -272,8 +291,8 @@
 ]
 /../td[.='Senior Developer']")) ;
 
-		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name']", "trainee") ;
-		$this->select("//select[@name='role_id']", "label=Junior Developer");
+		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name' and @type='text']", "trainee") ;
+		$this->select("//input[@value='Add Member']/../select[@name='role_id']", "label=Junior Developer");
 		$this->click ("//input[@value='Add Member']") ;
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("trainee Lastname"));
@@ -283,8 +302,8 @@
 ]
 /../td[.='Junior Developer']")) ;
 
-		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name']", "docmaster") ;
-		$this->select("//select[@name='role_id']", "label=Doc Writer");
+		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name' and @type='text']", "docmaster") ;
+		$this->select("//input[@value='Add Member']/../select[@name='role_id']", "label=Doc Writer");
 		$this->click ("//input[@value='Add Member']") ;
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("docmaster Lastname"));
@@ -294,8 +313,8 @@
 ]
 /../td[.='Doc Writer']")) ;
 
-		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name']", "bigboss") ;
-		$this->select("//select[@name='role_id']", "label=Senior Developer");
+		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name' and @type='text']", "bigboss") ;
+		$this->select("//input[@value='Add Member']/../select[@name='role_id']", "label=Senior Developer");
 		$this->click ("//input[@value='Add Member']") ;
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("bigboss Lastname"));
@@ -327,8 +346,8 @@
 		$this->waitForPageToLoad("30000");
 		$this->assertFalse($this->isTextPresent("trainee Lastname"));
 
-		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name']", "trainee") ;
-		$this->select("//select[@name='role_id']", "label=Junior Developer");
+		$this->type ("//form[contains(@action,'users.php')]//input[@name='form_unix_name' and @type='text']", "trainee") ;
+		$this->select("//input[@value='Add Member']/../select[@name='role_id']", "label=Junior Developer");
 		$this->click ("//input[@value='Add Member']") ;
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("trainee Lastname"));

Modified: branches/Branch_5_1/tests/func/Site/projectsTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Site/projectsTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Site/projectsTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -80,20 +80,6 @@
 		$this->waitForPageToLoad("30000");
 		$this->assertTrue($this->isTextPresent("This is the public description for ProjectA."));
 		$this->assertTrue($this->isTextPresent("This project has not yet categorized itself"));
-		
-		// Also test our high-level functions (testing the test-suite)
-		$this->createProject ('ProjectB');
-		$this->click("link=Home");
-		$this->waitForPageToLoad("30000");
-		$this->assertTrue($this->isTextPresent("ProjectB"));
-		$this->click("link=ProjectB");
-		$this->waitForPageToLoad("30000");
-		$this->assertTrue($this->isTextPresent("This is the public description for ProjectB."));
-		$this->assertTrue($this->isTextPresent("This project has not yet categorized itself"));
-		$this->gotoProject ('ProjectB');
-		$this->assertTrue($this->isTextPresent("This is the public description for ProjectB."));
-		$this->createAndGoto ('ProjectC');
-		$this->assertTrue($this->isTextPresent("This is the public description for ProjectC."));
 	}
 
 	function testCharsCreateTestCase()
@@ -137,6 +123,90 @@
 		$this->assertFalse($this->isTextPresent("Project ' &amp; B"));
 	}
 
+	function testHighLevelFunctions()
+	{
+		// Test our high-level functions (testing the test-suite)
+		$this->createProject ('ProjectB');
+		$this->click("link=Home");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("ProjectB"));
+		$this->click("link=ProjectB");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("This is the public description for ProjectB."));
+		$this->assertTrue($this->isTextPresent("This project has not yet categorized itself"));
+		$this->gotoProject ('ProjectB');
+		$this->assertTrue($this->isTextPresent("This is the public description for ProjectB."));
+		$this->createAndGoto ('ProjectC');
+		$this->assertTrue($this->isTextPresent("This is the public description for ProjectC."));
+		$this->init ();
+		$this->assertTrue($this->isTextPresent("This is the public description for ProjectA."));
+	}
+
+	function testTemplateProject()
+	{
+		$this->populateStandardTemplate('trackers');
+
+		$this->open( ROOT . '/projects/template') ;
+		$this->waitForPageToLoad("30000");
+
+		$this->click("link=Admin");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Tools");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Trackers Admin");
+		$this->waitForPageToLoad("30000");
+		$this->type("name", "Local tracker for UNIXNAME");
+		$this->type("description", "Tracker for PUBLICNAME (UNIXNAME)");
+		$this->click("post_changes");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("Tracker created successfully"));
+
+		$this->init();
+		$this->assertTrue($this->isElementPresent("//a[.='Tracker']"));
+		$this->assertTrue($this->isElementPresent("//a[.='Forums']"));
+		$this->assertTrue($this->isElementPresent("//a[.='Tasks']"));
+		$this->click("link=Tracker");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("Tracker for ProjectA (projecta)"));
+	}
+
+	function testEmptyProject()
+	{
+		// Create an empty project despite the template being full
+		$this->populateStandardTemplate('all');
+
+		$this->click("link=My Page");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Register Project");
+		$this->waitForPageToLoad("30000");
+		$this->type("full_name", "ProjectA");
+		$this->type("purpose", "This is a simple description for ProjectA");
+		$this->type("description", "This is the public description for ProjectA.");
+		$this->type("unix_name", "projecta");
+		$this->select("//select[@name='built_from_template']", "label=Start from empty project");
+		$this->click("//input[@name='scm' and @value='scmsvn']");
+		$this->click("submit");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("Your project has been submitted"));
+		$this->assertTrue($this->isTextPresent("you will receive notification of their decision and further instructions"));
+		$this->click("link=Site Admin");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Pending projects (new project approval)");
+		$this->waitForPageToLoad("30000");
+		$this->click("document.forms['approve.projecta'].submit");
+		$this->waitForPageToLoad("60000");
+		$this->click("link=Home");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("ProjectA"));
+		$this->click("link=ProjectA");
+		$this->waitForPageToLoad("30000");
+		$this->assertTrue($this->isTextPresent("This is the public description for ProjectA."));
+		$this->assertTrue($this->isTextPresent("This project has not yet categorized itself"));
+		$this->assertFalse($this->isElementPresent("//a[.='Tracker']"));
+		$this->assertFalse($this->isElementPresent("//a[.='Forums']"));
+		$this->assertFalse($this->isElementPresent("//a[.='Tasks']"));
+	}
+
 	// Test removal of project.
 	// TODO: Test not finished as removal does not work.
 	function testRemoveProject()

Modified: branches/Branch_5_1/tests/func/Tasks/createTaskTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Tasks/createTaskTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Tasks/createTaskTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -68,6 +68,7 @@
 
     function setUpTasks()
     {
+	$this->populateStandardTemplate(array('tasks'));
         $this->init();
 
         // Initialize "rep_time_tracking" table
@@ -353,7 +354,12 @@
 
     function assignTask()
     {
-        $this->open("/pm/task.php?group_id=6&group_project_id=2");
+	$this->gotoProject("ProjectA");
+	$this->waitForPageToLoad("30000");
+	$this->click("link=Tasks");
+	$this->waitForPageToLoad("30000");	    
+        $this->click("link=To Do: Browse tasks");
+        $this->waitForPageToLoad("30000");
         $this->click("link=exact:Task1: Hello Paris");
         $this->waitForPageToLoad("30000");
         $this->addSelection("assigned_to[]", "label=ucontrib Lastname");
@@ -387,7 +393,8 @@
 
     function createSubproject()
     {
-        $this->open("/pm/task.php?group_id=6");
+	$this->gotoProject("ProjectA");
+	$this->waitForPageToLoad("30000");
         $this->click("link=Project Admin");
         $this->waitForPageToLoad("30000");
         $this->click("link=Tools");
@@ -408,7 +415,8 @@
 
     function createPrivateSubproject()
     {
-        $this->open("/pm/task.php?group_id=6");
+	$this->gotoProject("ProjectA");
+	$this->waitForPageToLoad("30000");
         $this->click("link=Project Admin");
         $this->waitForPageToLoad("30000");
         $this->click("link=Tools");

Modified: branches/Branch_5_1/tests/func/Testing/SeleniumGforge.php
===================================================================
--- branches/Branch_5_1/tests/func/Testing/SeleniumGforge.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Testing/SeleniumGforge.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -81,6 +81,148 @@
 		$this->createAndGoto('ProjectA');
 	}
 
+	protected function populateStandardTemplate($what='all')
+	{
+		if ($what == 'all') {
+			$what = array('trackers','tasks','forums','docs');
+		} elseif ($what == 'empty') {
+			$what = array();
+		} elseif (!is_array($what)) {
+			$what = array($what) ;
+		}
+		$this->switchUser ('admin') ;
+
+		$this->approveProject ('Template', 'admin');
+		$this->open( ROOT . '/projects/template') ;
+		$this->waitForPageToLoad("30000");
+
+		$this->click("link=Admin");
+		$this->waitForPageToLoad("30000");
+		$this->click("link=Tools");
+		$this->waitForPageToLoad("30000");
+		$this->click("//input[@name='use_forum']") ;
+		$this->click("//input[@name='use_tracker']") ;
+		$this->click("//input[@name='use_mail']") ;
+		$this->click("//input[@name='use_pm']") ;
+		$this->click("//input[@name='use_docman']") ;
+		$this->click("//input[@name='use_news']") ;
+		$this->click("//input[@name='use_frs']") ;
+		$this->click("submit");
+		$this->waitForPageToLoad("30000");
+
+		if (in_array ('trackers', $what)) {
+			$this->click("link=Trackers Admin");
+			$this->waitForPageToLoad("30000");
+			$this->type("name", "Bugs");
+			$this->type("description", "Tracker for bug reports");
+			$this->click("post_changes");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Tracker created successfully"));
+			$this->click("link=Bugs");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Manage Custom Fields");
+			$this->waitForPageToLoad("30000");
+			$this->type("name", "URL");
+			$this->type("alias", "url");
+			$this->click("document.forms[2].field_type[3]");
+			$this->click("post_changes");
+			$this->waitForPageToLoad("30000");
+			
+			$this->click("link=Admin");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Tools");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Trackers Admin");
+			$this->waitForPageToLoad("30000");
+			$this->type("name", "Support Requests");
+			$this->type("description", "Tracker for support requests");
+			$this->click("post_changes");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Tracker created successfully"));
+
+			$this->type("name", "Patches");
+			$this->type("description", "Proposed changes to code");
+			$this->click("post_changes");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Tracker created successfully"));
+
+			$this->type("name", "Feature Requests");
+			$this->type("description", "New features that people want");
+			$this->click("post_changes");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Tracker created successfully"));
+		}
+
+		if (in_array ('tasks', $what)) {
+			$this->click("link=Admin");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Tools");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Tasks Admin");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Add a Subproject");
+			$this->waitForPageToLoad("30000");
+			$this->type("project_name", "To Do");
+			$this->type("description", "Things we have to do");
+			$this->click("submit");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Subproject Inserted"));
+			
+			$this->type("project_name", "Next Release");
+			$this->type("description", "Items for our next release");
+			$this->click("submit");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Subproject Inserted"));
+		}
+
+		if (in_array ('forums', $what)) {
+			$this->click("link=Admin");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Tools");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Forums Admin");
+			$this->waitForPageToLoad("30000");
+			
+			$this->click("link=Add forum");
+			$this->waitForPageToLoad("30000");
+			$this->type("forum_name", "Open-Discussion");
+			$this->type("description", "General Discussion");
+			$this->click("submit");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Forum added successfully"));
+
+			$this->type("forum_name", "Help");
+			$this->type("description", "Get Public Help");
+			$this->click("submit");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Forum added successfully"));
+
+			$this->type("forum_name", "Developers-Discussion");
+			$this->type("description", "Project Developer Discussion");
+			$this->click("//input[@name='is_public' and @value='0']");
+			$this->click("submit");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Forum added successfully"));
+
+			$this->click("link=Forums");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("open-discussion"));
+			$this->assertTrue($this->isTextPresent("Get Public Help"));
+			$this->assertTrue($this->isTextPresent("Project Developer Discussion"));
+		}
+
+		if (in_array ('docs', $what)) {
+			$this->click("link=Docs");
+			$this->waitForPageToLoad("30000");
+			$this->click("link=Add new documentation directory");
+			$this->waitForPageToLoad("30000");
+			$this->type("groupname", "Uncategorized Submissions");
+			$this->click("//input[@id='submitaddsubgroup']");
+			$this->waitForPageToLoad("30000");
+			$this->assertTrue($this->isTextPresent("Uncategorized Submissions"));
+		}
+	}
+
 	protected function login($username)
 	{
 		$this->open( ROOT );

Modified: branches/Branch_5_1/tests/func/Trackers/relationTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Trackers/relationTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Trackers/relationTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -49,6 +49,7 @@
 {
 	function testCreateRelation()
 	{
+		$this->populateStandardTemplate('trackers');
 		$this->init();
 					
 		// Testing extra-fields
@@ -56,7 +57,7 @@
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Bugs");
 		$this->waitForPageToLoad("30000");
-		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/?group_id=6&atid=101')]");
+		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/')]");
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Manage Custom Fields");
 		$this->waitForPageToLoad("30000");

Modified: branches/Branch_5_1/tests/func/Trackers/trackersTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Trackers/trackersTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Trackers/trackersTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -49,6 +49,7 @@
 {
 	function testSimpleCreate()
 	{
+		$this->populateStandardTemplate('trackers');
 		$this->init();
 
 		// Test: Create a simple bug report (Message1/Text1).
@@ -120,6 +121,7 @@
 
 	function testExtraFields()
 	{
+		$this->populateStandardTemplate('trackers');
 		$this->init();
 
 		// Testing extra-fields
@@ -127,7 +129,7 @@
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Bugs");
 		$this->waitForPageToLoad("30000");
-		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/?group_id=6&atid=101')]");
+		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/')]");
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Manage Custom Fields");
 		$this->waitForPageToLoad("30000");
@@ -136,8 +138,7 @@
 		$this->click("field_type");
 		$this->click("post_changes");
 		$this->waitForPageToLoad("30000");
-$this->click("//tr[@id='field-number']/td[4]/a[1]");
-		//$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/index.php?add_opt=1&boxid=22&group_id=6&atid=101')]");
+		$this->click("//tr[@id='field-number']/td[4]/a[1]");
 		$this->waitForPageToLoad("30000");
 		$this->type("name", "1");
 		$this->click("post_changes");
@@ -155,7 +156,8 @@
 		$this->assertTrue($this->isTextPresent("Element inserted"));
 
 		// Testing [#3649]: 0 not accepted when modifying a select list value
-		$this->open(ROOT."/tracker/admin/index.php?group_id=6&atid=101&add_extrafield=1");
+		$this->click("link=Manage Custom Fields");
+		$this->waitForPageToLoad("30000");
 		$this->click("//tr[@id='field-number']/td[3]/a[5]");
 		$this->waitForPageToLoad("30000");
 		$this->type("name", "10");
@@ -171,12 +173,13 @@
 
 	function testCreateAndDeleteNewTracker()
 	{
+		$this->populateStandardTemplate('trackers');
 		$this->init();
 
 		// Create a new tracker and delete it after.
 		$this->click("link=Tracker");
 		$this->waitForPageToLoad("30000");
-		$this->click("//a[@href='".URL."tracker/admin/?group_id=6']");
+		$this->click("//a[contains(@href,'".ROOT."/tracker/admin/')]");
 		$this->waitForPageToLoad("30000");
 		$this->type("name", "newTracker");
 		$this->type("description", "This is a new tracker");

Modified: branches/Branch_5_1/tests/func/Trackers/workflowTest.php
===================================================================
--- branches/Branch_5_1/tests/func/Trackers/workflowTest.php	2010-12-16 23:39:50 UTC (rev 11826)
+++ branches/Branch_5_1/tests/func/Trackers/workflowTest.php	2010-12-17 14:32:04 UTC (rev 11827)
@@ -49,6 +49,7 @@
 {
 	function testWorkflow()
 	{
+		$this->populateStandardTemplate('trackers');
 		$this->init();
 			
 		// Testing extra-fields
@@ -56,7 +57,7 @@
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Bugs");
 		$this->waitForPageToLoad("30000");
-		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/?group_id=6&atid=101')]");
+		$this->click("//a[contains(@href, '".ROOT. "/tracker/admin/')]");
 		$this->waitForPageToLoad("30000");
 		$this->click("link=Manage Custom Fields");
 		$this->waitForPageToLoad("30000");




More information about the Fusionforge-commits mailing list