5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009-2010, Roland Mas
7 * Copyright 2010-2011, Franck Villaume - Capgemini
8 * Copyright 2010-2011, Alain Peyrat - Alcatel-Lucent
9 * http://fusionforge.org
11 * This file is part of FusionForge. FusionForge is free software;
12 * you can redistribute it and/or modify it under the terms of the
13 * GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the Licence, or (at your option)
17 * FusionForge is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 require_once $gfcommon.'tracker/ArtifactTypes.class.php';
28 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
29 require_once $gfcommon.'forum/Forum.class.php';
30 require_once $gfcommon.'forum/ForumFactory.class.php';
31 require_once $gfcommon.'pm/ProjectGroup.class.php';
32 require_once $gfcommon.'pm/ProjectGroupFactory.class.php';
33 require_once $gfcommon.'include/Role.class.php';
34 require_once $gfcommon.'frs/FRSPackage.class.php';
35 require_once $gfcommon.'docman/DocumentGroup.class.php';
36 require_once $gfcommon.'docman/DocumentGroupFactory.class.php';
37 require_once $gfcommon.'mail/MailingList.class.php';
38 require_once $gfcommon.'mail/MailingListFactory.class.php';
39 require_once $gfcommon.'survey/SurveyFactory.class.php';
40 require_once $gfcommon.'survey/SurveyQuestionFactory.class.php';
41 require_once $gfcommon.'include/gettext.php';
42 require_once $gfcommon.'include/GroupJoinRequest.class.php';
47 * group_get_object() - Get the group object.
49 * group_get_object() is useful so you can pool group objects/save database queries
50 * You should always use this instead of instantiating the object directly.
52 * You can now optionally pass in a db result handle. If you do, it re-uses that query
53 * to instantiate the objects.
55 * IMPORTANT! That db result must contain all fields
56 * from groups table or you will have problems
59 * @param int Result set handle ("SELECT * FROM groups WHERE group_id=xx")
60 * @return object a group object or false on failure
62 function &group_get_object($group_id, $res = false) {
63 //create a common set of group objects
64 //saves a little wear on the database
66 //automatically checks group_type and
67 //returns appropriate object
70 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
72 //the db result handle was passed in
74 $res = db_query_params('SELECT * FROM groups WHERE group_id=$1', array($group_id)) ;
76 if (!$res || db_numrows($res) < 1) {
77 $GROUP_OBJ["_".$group_id."_"]=false;
80 check group type and set up object
82 if (db_result($res,0,'type_id') == 1) {
84 $GROUP_OBJ["_".$group_id."_"] = new Group($group_id, $res);
87 $GROUP_OBJ["_".$group_id."_"] = false;
91 return $GROUP_OBJ["_".$group_id."_"];
94 function &group_get_objects($id_arr) {
97 // Note: if we don't do this, the result may be corrupted
101 foreach ($id_arr as $id) {
103 // See if this ID already has been fetched in the cache
105 if (!isset($GROUP_OBJ["_".$id."_"])) {
109 if (count($fetch) > 0) {
110 $res=db_query_params('SELECT * FROM groups WHERE group_id = ANY ($1)',
111 array(db_int_array_to_any_clause($fetch)));
112 while ($arr = db_fetch_array($res)) {
113 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
116 foreach ($id_arr as $id) {
117 $return[] =& $GROUP_OBJ["_".$id."_"];
122 function &group_get_active_projects() {
123 $res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
125 return group_get_objects(util_result_column_to_array($res,0));
128 function &group_get_template_projects() {
129 $res=db_query_params ('SELECT group_id FROM groups WHERE is_template=1 AND status != $1',
131 return group_get_objects (util_result_column_to_array($res,0)) ;
134 function &group_get_object_by_name($groupname) {
135 $res = db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array($groupname));
136 return group_get_object(db_result($res, 0, 'group_id'), $res);
139 function &group_get_objects_by_name($groupname_arr) {
140 $res = db_query_params('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
141 array(db_string_array_to_any_clause($groupname_arr)));
142 $arr =& util_result_column_to_array($res,0);
143 return group_get_objects($arr);
146 function &group_get_object_by_publicname($groupname) {
147 $res = db_query_params('SELECT * FROM groups WHERE lower(group_name) LIKE $1',
148 array(htmlspecialchars(strtolower($groupname))));
149 return group_get_object(db_result($res, 0, 'group_id'), $res);
152 class Group extends Error {
154 * Associative array of data from db.
156 * @var array $data_array.
161 * array of User objects.
163 * @var array $membersArr.
168 * Whether the use is an admin/super user of this project.
170 * @var bool $is_admin.
175 * Artifact types result handle.
177 * @var int $types_res.
182 * Associative array of data for plugins.
184 * @var array $plugins_data.
190 * Associative array of data for the group menu.
192 * @var array $menu_data.
197 * Group - Group object constructor - use group_get_object() to instantiate.
199 * @param int Required - group_id of the group you want to instantiate.
200 * @param int Database result from select query OR associative array of all columns.
201 * @return boolean success or not
203 function Group($id = false, $res = false) {
206 //setting up an empty object
207 //probably going to call create()
211 if (!$this->fetchData($id)) {
216 // Assoc array was passed in
218 if (is_array($res)) {
219 $this->data_array =& $res;
221 if (db_numrows($res) < 1) {
222 //function in class we extended
223 $this->setError(_('Group Not Found'));
224 $this->data_array=array();
227 //set up an associative array for use by other functions
228 $this->data_array = db_fetch_array_by_row($res, 0);
236 * fetchData - May need to refresh database fields if an update occurred.
238 * @param int The group_id.
239 * @return boolean success or not
241 function fetchData($group_id) {
242 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
244 if (!$res || db_numrows($res) < 1) {
245 $this->setError(sprintf(_('fetchData():: %s'),db_error()));
248 $this->data_array = db_fetch_array($res);
253 * create - Create new group.
255 * This method should be called on empty Group object.
256 * It will add an entry for a pending group/project (status 'P')
258 * @param object The User object.
259 * @param string The full name of the user.
260 * @param string The Unix name of the user.
261 * @param string The new group description.
262 * @param string The purpose of the group.
263 * @param boolean Whether to send an email or not
264 * @param int The id of the project this new project is based on
265 * @return boolean success or not
267 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box = 'shell1',
268 $scm_box = 'cvs1', $is_public = 1, $send_mail = true, $built_from_template = 0) {
269 // $user is ignored - anyone can create pending group
272 if ($this->getID()!=0) {
273 $this->setError(_('Group::create: Group object already exists'));
275 } else if (!$this->validateGroupName($group_name)) {
277 } else if (!account_groupnamevalid($unix_name)) {
278 $this->setError(_('Invalid Unix name'));
280 } else if (!$SYS->sysUseUnixName($unix_name)) {
281 $this->setError(_('Unix name already taken'));
283 } else if (db_numrows(db_query_params('SELECT group_id FROM groups WHERE unix_group_name=$1',
284 array($unix_name))) > 0) {
285 $this->setError(_('Unix name already taken'));
287 } else if (strlen($purpose)<10) {
288 $this->setError(_('Please describe your Registration Purpose in a more comprehensive manner'));
290 } else if (strlen($purpose)>1500) {
291 $this->setError(_('The Registration Purpose text is too long. Please make it smaller than 1500 bytes.'));
293 } else if (strlen($description)<10) {
294 $this->setError(_('Describe in a more comprehensive manner your project.'));
298 // Check if sys_use_project_vhost for homepage
299 if (forge_get_config('use_project_vhost')) {
300 $homepage = $unix_name.".".forge_get_config('web_host');
302 $homepage = forge_get_config('web_host')."/www/".$unix_name."/";
307 $res = db_query_params('
323 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
324 array (htmlspecialchars ($group_name),
326 htmlspecialchars($description),
327 $unix_name.".".forge_get_config('web_host'),
332 htmlspecialchars($purpose),
335 md5(util_randbytes()),
336 $built_from_template));
337 if (!$res || db_affected_rows($res) < 1) {
338 $this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
343 $id = db_insertid($res, 'groups', 'group_id');
345 $this->setError(sprintf(_('ERROR: Could not get group id: %s'),db_error()));
350 if (!$this->fetchData($id)) {
355 $gjr = new GroupJoinRequest($this);
356 $gjr->create($user->getID(),
357 'Fake GroupJoinRequest to store the creator of a project',
360 $hook_params = array();
361 $hook_params['group'] = $this;
362 $hook_params['group_id'] = $this->getID();
363 $hook_params['group_name'] = $group_name;
364 $hook_params['unix_group_name'] = $unix_name;
365 plugin_hook("group_create", $hook_params);
369 $this->sendNewProjectNotificationEmail();
377 * updateAdmin - Update core properties of group object.
379 * This function require site admin privilege.
381 * @param object User requesting operation (for access control).
382 * @param boolean Whether group is publicly accessible (0/1).
383 * @param int Group type (1-project, 2-foundry).
384 * @param string Machine on which group's home directory located.
385 * @param string Domain which serves group's WWW.
389 function updateAdmin(&$user, $is_public, $type_id, $unix_box, $http_domain) {
390 $perm =& $this->getPermission();
392 if (!$perm || !is_object($perm)) {
393 $this->setError(_('Could not get permission.'));
397 if (!$perm->isSuperUser()) {
398 $this->setError(_('Permission denied.'));
404 $res = db_query_params('
406 SET type_id=$1, unix_box=$2, http_domain=$3
413 if (!$res || db_affected_rows($res) < 1) {
414 $this->setError(_('ERROR: DB: Could not change group properties: %s'),db_error());
419 // Log the audit trail
420 if ($type_id != $this->data_array['type_id']) {
421 $this->addHistory('type_id', $this->data_array['type_id']);
423 if ($unix_box != $this->data_array['unix_box']) {
424 $this->addHistory('unix_box', $this->data_array['unix_box']);
426 if ($http_domain != $this->data_array['http_domain']) {
427 $this->addHistory('http_domain', $this->data_array['http_domain']);
430 if (!$this->fetchData($this->getID())) {
439 * update - Update number of common properties.
441 * Unlike updateAdmin(), this function accessible to project admin.
443 * @param object User requesting operation (for access control).
444 * @param boolean Whether group is publicly accessible (0/1).
445 * @param string Project's license (string ident).
446 * @param int Group type (1-project, 2-foundry).
447 * @param string Machine on which group's home directory located.
448 * @param string Domain which serves group's WWW.
449 * @return int status.
452 function update(&$user, $group_name, $homepage, $short_description, $use_mail, $use_survey, $use_forum,
453 $use_pm, $use_pm_depend_box, $use_scm, $use_news, $use_docman,
454 $new_doc_address, $send_all_docs, $logo_image_id,
455 $use_ftp, $use_tracker, $use_frs, $use_stats, $tags, $is_public) {
457 $perm =& $this->getPermission();
459 if (!$perm || !is_object($perm)) {
460 $this->setError(_('Could not get permission.'));
464 if (!$perm->isAdmin()) {
465 $this->setError(_('Permission denied.'));
469 // Validate some values
470 if ($this->getPublicName() != $group_name) {
471 if (!$this->validateGroupName($group_name)) {
476 if ($new_doc_address) {
477 $invalid_mails = validate_emails($new_doc_address);
478 if (count($invalid_mails) > 0) {
479 $this->setError(sprintf(ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
484 // in the database, these all default to '1',
485 // so we have to explicity set 0
498 if (!$use_pm_depend_box) {
499 $use_pm_depend_box = 0;
522 if (!$send_all_docs) {
526 $homepage = ltrim($homepage);
528 $homepage = util_make_url('/projects/' . $this->getUnixName() . '/');
531 if (strlen(htmlspecialchars($short_description))>255) {
532 $this->setError(_('Error updating project information: Maximum length for Project Description is 255 chars.'));
538 //XXX not yet actived logo_image_id='$logo_image_id',
539 $res = db_query_params('UPDATE groups
542 short_description=$3,
547 use_pm_depend_box=$8,
557 array(htmlspecialchars($group_name),
559 htmlspecialchars($short_description),
576 $this->setError(sprintf(_('Error updating project information: %s'), db_error()));
581 if (!$this->setUseDocman($use_docman)) {
582 $this->setError(sprintf(_('Error updating project information: use_docman %s'), db_error()));
587 if ($this->setTags($tags) === false) {
592 $hook_params = array();
593 $hook_params['group'] = $this;
594 $hook_params['group_id'] = $this->getID();
595 $hook_params['group_homepage'] = $homepage;
596 $hook_params['group_name'] = htmlspecialchars($group_name);
597 $hook_params['group_description'] = htmlspecialchars($short_description);
598 $hook_params['group_ispublic'] = $is_public;
599 if (!plugin_hook("group_update", $hook_params)) {
600 if (!$this->isError()) {
601 $this->setError(_('Error updating project information in plugin_hook group_update'));
607 // Log the audit trail
608 $this->addHistory('Changed Public Info', '');
610 if (!$this->fetchData($this->getID())) {
619 * getID - Simply return the group_id for this object.
621 * @return int group_id.
624 return $this->data_array['group_id'];
628 * getType() - Foundry, project, etc.
630 * @return int The type flag from the database.
633 return $this->data_array['type_id'];
638 * getStatus - the status code.
640 * Statuses char include I,H,A,D,P.
641 * TODO : document what these mean :
648 function getStatus() {
649 return $this->data_array['status'];
653 * setStatus - set the status code.
655 * Statuses include I,H,A,D,P.
656 * TODO : document what these mean :
663 * @param object User requesting operation (for access control).
664 * @param string Status value.
665 * @return boolean success.
668 function setStatus(&$user, $status) {
671 if (!forge_check_global_perm('approve_projects')) {
672 $this->setPermissionDeniedError();
676 // Projects in 'A' status can only go to 'H' or 'D'
677 // Projects in 'D' status can only go to 'A'
678 // Projects in 'P' status can only go to 'A' OR 'D'
679 // Projects in 'I' status can only go to 'P'
680 // Projects in 'H' status can only go to 'A' OR 'D'
681 $allowed_status_changes = array(
682 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
683 'IP'=>1,'HA'=>1,'HD'=>1
686 // Check that status transition is valid
687 if ($this->getStatus() != $status
688 && !$allowed_status_changes[$this->getStatus().$status]) {
689 $this->setError(_('Invalid Status Change'));
695 $res = db_query_params('UPDATE groups
697 WHERE group_id=$2', array($status, $this->getID()));
699 if (!$res || db_affected_rows($res) < 1) {
700 $this->setError(sprintf(_('ERROR: DB: Could not change group status: %s'),db_error()));
706 // Activate system group, if not yet
707 if (!$SYS->sysCheckGroup($this->getID())) {
708 if (!$SYS->sysCreateGroup($this->getID())) {
709 $this->setError($SYS->getErrorMessage());
714 if (!$this->activateUsers()) {
719 /* Otherwise, the group is not active, and make sure that
720 System group is not active either */
721 } else if ($SYS->sysCheckGroup($this->getID())) {
722 if (!$SYS->sysRemoveGroup($this->getID())) {
723 $this->setError($SYS->getErrorMessage());
729 $hook_params = array();
730 $hook_params['group'] = $this;
731 $hook_params['group_id'] = $this->getID();
732 $hook_params['status'] = $status;
733 plugin_hook("group_setstatus", $hook_params);
737 // Log the audit trail
738 if ($status != $this->getStatus()) {
739 $this->addHistory('Status', $this->getStatus());
742 $this->data_array['status'] = $status;
747 * isProject - Simple boolean test to see if it's a project or not.
749 * @return boolean is_project.
751 function isProject() {
752 if ($this->getType()==1) {
760 * isPublic - Wrapper around RBAC to check if a project is anonymously readable
762 * @return boolean is_public.
764 function isPublic() {
765 $ra = RoleAnonymous::getInstance() ;
766 return $ra->hasPermission('project_read', $this->getID());
770 * isActive - Database field status of 'A' returns true.
772 * @return boolean is_active.
774 function isActive() {
775 if ($this->getStatus()=='A') {
783 * isTemplate - Simply returns the is_template flag from the database.
785 * @return boolean is_template.
787 function isTemplate() {
788 return $this->data_array['is_template'];
792 * setAsTemplate - Set the template status of a project
794 * @param boolean is_template.
796 function setAsTemplate($booleanparam) {
798 $booleanparam = $booleanparam ? 1 : 0;
799 $res = db_query_params('UPDATE groups SET is_template=$1 WHERE group_id=$2',
800 array($booleanparam, $this->getID()));
802 $this->data_array['is_template']=$booleanparam;
812 * getTemplateProject - Return the project template this project is built from
814 * @return object The template project
816 function getTemplateProject() {
817 return group_get_object($this->data_array['built_from_template']);
821 * getUnixName - the unix_name
823 * @return string unix_name.
825 function getUnixName() {
826 return strtolower($this->data_array['unix_group_name']);
830 * getPublicName - the full-length public name.
832 * @return string The group_name.
834 function getPublicName() {
835 return $this->data_array['group_name'];
839 * getRegisterPurpose - the text description of the purpose of this project.
841 * @return string The description.
843 function getRegisterPurpose() {
844 return $this->data_array['register_purpose'];
848 * getDescription - the text description of this project.
850 * @return string The description.
852 function getDescription() {
853 return $this->data_array['short_description'];
857 * getStartDate - the unix time this project was registered.
859 * @return int (unix time) of registration.
861 function getStartDate() {
862 return $this->data_array['register_time'];
866 * getLogoImageID - the id of the logo in the database for this project.
868 * @return int The ID of logo image in db_images table (or 100 if none).
870 function getLogoImageID() {
871 return $this->data_array['logo_image_id'];
875 * getUnixBox - the hostname of the unix box where this project is located.
877 * @return string The name of the unix machine for the group.
879 function getUnixBox() {
880 return $this->data_array['unix_box'];
884 * getSCMBox - the hostname of the scm box where this project is located.
886 * @return string The name of the unix machine for the group.
888 function getSCMBox() {
889 return $this->data_array['scm_box'];
892 * setSCMBox - the hostname of the scm box where this project is located.
894 * @param string The name of the new SCM_BOX
896 function setSCMBox($scm_box) {
898 if ($scm_box == $this->data_array['scm_box']) {
903 $res = db_query_params('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array($scm_box, $this->getID ()));
905 $this->addHistory('scm_box', $this->data_array['scm_box']);
906 $this->data_array['scm_box'] = $scm_box;
911 $this->setError(_("Couldn't insert SCM_BOX to database"));
915 $this->setError(_("SCM Box can't be empty"));
921 * getDomain - the hostname.domain where their web page is located.
923 * @return string The name of the group [web] domain.
925 function getDomain() {
926 return $this->data_array['http_domain'];
930 * getRegistrationPurpose - the text description of the purpose of this project.
932 * @return string The application for project hosting.
934 function getRegistrationPurpose() {
935 return $this->data_array['register_purpose'];
940 * getAdmins() - Get array of Admin user objects.
942 * @return array Array of User objects.
944 function &getAdmins() {
945 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID());
949 foreach ($roles as $role) {
950 if (! ($role instanceof RoleExplicit)) {
953 if ($role->getHomeProject() == NULL
954 || $role->getHomeProject()->getID() != $this->getID()) {
958 foreach ($role->getUsers() as $u) {
959 $user_ids[] = $u->getID();
962 return user_get_objects(array_unique($user_ids));
966 Common Group preferences for tools
970 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
972 * @return boolean enable_scm.
974 function enableAnonSCM() {
975 $r = RoleAnonymous::getInstance();
976 return $r->hasPermission('scm', $this->getID(), 'read');
979 function SetUsesAnonSCM($booleanparam) {
981 $booleanparam = $booleanparam ? 1 : 0;
982 $r = RoleAnonymous::getInstance();
983 $r->setSetting('scm', $this->getID(), $booleanparam);
988 * enablePserver - whether or not this group has opted to enable Pserver.
990 * @return boolean enable_pserver.
992 function enablePserver() {
993 if ($this->usesSCM()) {
994 return $this->data_array['enable_pserver'];
1000 function SetUsesPserver($booleanparam) {
1002 $booleanparam = $booleanparam ? 1 : 0;
1003 $res = db_query_params('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1004 array($booleanparam, $this->getID()));
1006 $this->data_array['enable_pserver'] = $booleanparam;
1015 * usesSCM - whether or not this group has opted to use SCM.
1017 * @return boolean uses_scm.
1019 function usesSCM() {
1020 if (forge_get_config('use_scm')) {
1021 return $this->data_array['use_scm'];
1028 * setUseSCM - Set the SCM usage
1030 * @param boolean enabled/disabled
1032 function setUseSCM($booleanparam) {
1034 $booleanparam = $booleanparam ? 1 : 0 ;
1035 $res = db_query_params('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
1036 array($booleanparam, $this->getID()));
1038 $this->data_array['use_scm']=$booleanparam;
1048 * usesMail - whether or not this group has opted to use mailing lists.
1050 * @return boolean uses_mail.
1052 function usesMail() {
1053 if (forge_get_config('use_mail')) {
1054 return $this->data_array['use_mail'];
1061 * setUseMail - Set the mailing-list usage
1063 * @param boolean enabled/disabled
1065 function setUseMail($booleanparam) {
1067 $booleanparam = $booleanparam ? 1 : 0 ;
1068 $res = db_query_params('UPDATE groups SET use_mail=$1 WHERE group_id=$2',
1069 array($booleanparam, $this->getID()));
1071 $this->data_array['use_mail']=$booleanparam;
1081 * usesNews - whether or not this group has opted to use news.
1083 * @return boolean uses_news.
1085 function usesNews() {
1086 if (forge_get_config('use_news')) {
1087 return $this->data_array['use_news'];
1094 * usesForum - whether or not this group has opted to use discussion forums.
1096 * @return boolean uses_forum.
1098 function usesForum() {
1099 if (forge_get_config('use_forum')) {
1100 return $this->data_array['use_forum'];
1107 * setUseForum - Set the forum usage
1109 * @param boolean enabled/disabled
1111 function setUseForum($booleanparam) {
1113 $booleanparam = $booleanparam ? 1 : 0;
1114 $res = db_query_params('UPDATE groups SET use_forum=$1 WHERE group_id=$2',
1115 array($booleanparam, $this->getID()));
1117 $this->data_array['use_forum']=$booleanparam;
1127 * usesStats - whether or not this group has opted to use stats.
1129 * @return boolean uses_stats.
1131 function usesStats() {
1132 return $this->data_array['use_stats'];
1136 * usesFRS - whether or not this group has opted to use file release system.
1138 * @return boolean uses_frs.
1140 function usesFRS() {
1141 if (forge_get_config('use_frs')) {
1142 return $this->data_array['use_frs'];
1149 * setUseFRS - Set the FRS usage
1151 * @param boolean enabled/disabled
1153 function setUseFRS($booleanparam) {
1155 $booleanparam = $booleanparam ? 1 : 0;
1156 $res = db_query_params('UPDATE groups SET use_frs=$1 WHERE group_id=$2',
1157 array ($booleanparam, $this->getID()));
1159 $this->data_array['use_frs']=$booleanparam;
1169 * usesTracker - whether or not this group has opted to use tracker.
1171 * @return boolean uses_tracker.
1173 function usesTracker() {
1174 if (forge_get_config('use_tracker')) {
1175 return $this->data_array['use_tracker'];
1182 * setUseTracker - Set the tracker usage
1184 * @param boolean enabled/disabled
1186 function setUseTracker ($booleanparam) {
1188 $booleanparam = $booleanparam ? 1 : 0 ;
1189 $res = db_query_params ('UPDATE groups SET use_tracker=$1 WHERE group_id=$2',
1190 array ($booleanparam, $this->getID()));
1192 $this->data_array['use_tracker']=$booleanparam;
1202 * useCreateOnline - whether or not this group has opted to use create online documents option.
1204 * @return boolean use_docman_create_online.
1206 function useCreateOnline() {
1207 if (forge_get_config('use_docman')) {
1208 return $this->data_array['use_docman_create_online'];
1215 * usesDocman - whether or not this group has opted to use docman.
1217 * @return boolean use_docman.
1219 function usesDocman() {
1220 if (forge_get_config('use_docman')) {
1221 return $this->data_array['use_docman'];
1228 * setUseDocman - Set the docman usage
1230 * @param boolean enabled/disabled
1232 function setUseDocman($booleanparam) {
1234 $booleanparam = $booleanparam ? 1 : 0;
1235 $res = db_query_params('UPDATE groups SET use_docman = $1 WHERE group_id = $2',
1236 array($booleanparam, $this->getID()));
1238 // check if / doc_group exists, if not create it
1239 $trashdir = db_query_params('select groupname from doc_groups where groupname = $1 and group_id = $2',
1240 array('.trash', $this->getID()));
1241 if ($trashdir && db_numrows($trashdir) == 0) {
1242 $resinsert = db_query_params('insert into doc_groups (groupname, group_id, stateid) values ($1, $2, $3)',
1243 array('.trash', $this->getID(), '2'));
1249 $this->data_array['use_docman'] = $booleanparam;
1259 * useDocmanSearch - whether or not this group has opted to use docman search engine.
1261 * @return boolean use_docman_search.
1263 function useDocmanSearch() {
1264 if (forge_get_config('use_docman')) {
1265 return $this->data_array['use_docman_search'];
1272 * useWebdav - whether or not this group has opted to use webdav interface.
1274 * @return boolean use_docman_search.
1276 function useWebdav() {
1277 if (forge_get_config('use_webdav')) {
1278 return $this->data_array['use_webdav'];
1285 * usesFTP - whether or not this group has opted to use FTP.
1287 * @return boolean uses_ftp.
1289 function usesFTP() {
1290 if (forge_get_config('use_ftp')) {
1291 return $this->data_array['use_ftp'];
1298 * usesSurvey - whether or not this group has opted to use surveys.
1300 * @return boolean uses_survey.
1302 function usesSurvey() {
1303 if (forge_get_config('use_survey')) {
1304 return $this->data_array['use_survey'];
1311 * usesPM - whether or not this group has opted to Project Manager.
1313 * @return boolean uses_projman.
1316 if (forge_get_config('use_pm')) {
1317 return $this->data_array['use_pm'];
1324 * setUsePM - Set the PM usage
1326 * @param boolean enabled/disabled
1328 function setUsePM($booleanparam) {
1330 $booleanparam = $booleanparam ? 1 : 0;
1331 $res = db_query_params('UPDATE groups SET use_pm=$1 WHERE group_id=$2',
1332 array($booleanparam, $this->getID()));
1334 $this->data_array['use_pm']=$booleanparam;
1344 * getPlugins - get a list of all available group plugins
1346 * @return array array containing plugin_id => plugin_name
1348 function getPlugins() {
1349 if (!isset($this->plugins_data)) {
1350 $this->plugins_data = array();
1351 $res = db_query_params('SELECT group_plugin.plugin_id, plugins.plugin_name
1352 FROM group_plugin, plugins
1353 WHERE group_plugin.group_id=$1
1354 AND group_plugin.plugin_id=plugins.plugin_id', array($this->getID()));
1355 $rows = db_numrows($res);
1357 for ($i=0; $i<$rows; $i++) {
1358 $plugin_id = db_result($res, $i, 'plugin_id');
1359 $this->plugins_data[$plugin_id] = db_result($res, $i, 'plugin_name');
1362 return $this->plugins_data;
1366 * usesPlugin - returns true if the group uses a particular plugin
1368 * @param string name of the plugin
1369 * @return boolean whether plugin is being used or not
1371 function usesPlugin($pluginname) {
1372 $plugins_data = $this->getPlugins();
1373 foreach ($plugins_data as $p_id => $p_name) {
1374 if ($p_name == $pluginname) {
1382 * added for Codendi compatibility
1383 * usesServices - returns true if the group uses a particular plugin or feature
1385 * @param string name of the plugin
1386 * @return boolean whether plugin is being used or not
1388 function usesService($feature) {
1389 $plugins_data = $this->getPlugins();
1390 $pm = plugin_manager_get_object();
1391 foreach ($plugins_data as $p_id => $p_name) {
1392 if ($p_name == $feature) {
1395 if ($pm->getPluginByName($p_name)->provide($feature)) {
1403 * setPluginUse - enables/disables plugins for the group
1405 * @param string name of the plugin
1406 * @param boolean the new state
1407 * @return string database result
1409 function setPluginUse($pluginname, $val=true) {
1410 if ($val == $this->usesPlugin($pluginname)) {
1411 // State is already good, returning
1414 $res = db_query_params('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1415 array($pluginname));
1416 $rows = db_numrows($res);
1418 // Error: no plugin by that name
1421 $plugin_id = db_result($res,0,'plugin_id');
1423 unset($this->plugins_data);
1425 $res = db_query_params('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1426 array($this->getID(),
1430 $res = db_query_params('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1431 array($this->getID(),
1438 * getDocEmailAddress - get email address(es) to send doc notifications to.
1440 * @return string email address.
1442 function getDocEmailAddress() {
1443 return $this->data_array['new_doc_address'];
1447 * DocEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1449 * @return boolean email_on_all_doc_updates.
1451 function docEmailAll() {
1452 return $this->data_array['send_all_docs'];
1457 * getHomePage - The URL for this project's home page.
1459 * @return string homepage URL.
1461 function getHomePage() {
1462 return $this->data_array['homepage'];
1466 * getTags - Tags of this project.
1468 * @return string List of tags. Comma separated
1470 function getTags() {
1471 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1472 $res = db_query_params($sql, array($this->getID()));
1473 return join(', ', util_result_column_to_array($res));
1477 * setTags - Set tags of this project.
1479 * @return string database result.
1481 function setTags($tags) {
1483 $sql = 'DELETE FROM project_tags WHERE group_id=$1';
1484 $res = db_query_params($sql, array($this->getID()));
1486 $this->setError('Deleting old tags: '.db_error());
1490 $inserted = array();
1491 $tags_array = preg_split('/[;,]/', $tags);
1492 foreach ($tags_array as $tag) {
1493 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1494 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1495 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1496 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1501 if ($tag == '' || array_search($tag, $inserted) !== false) continue;
1502 $sql = 'INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1503 $res = db_query_params($sql, array($this->getID(), $tag));
1505 $this->setError(_('Setting tags:') . ' ' .
1517 * getPermission - Return a Permission for this Group
1519 * @return object The Permission.
1521 function &getPermission() {
1522 return permission_get_object($this);
1526 function delete($sure, $really_sure, $really_really_sure) {
1527 if (!$sure || !$really_sure || !$really_really_sure) {
1528 $this->setMissingParamsError(_('Please tick all checkboxes.'));
1531 if ($this->getID() == forge_get_config('news_group') ||
1532 $this->getID() == 1 ||
1533 $this->getID() == forge_get_config('stats_group') ||
1534 $this->getID() == forge_get_config('peer_rating_group')) {
1535 $this->setError(_('Cannot Delete System Group'));
1538 $perm = $this->getPermission();
1539 if (!$perm || !is_object($perm)) {
1540 $this->setPermissionDeniedError();
1542 } elseif ($perm->isError()) {
1543 $this->setPermissionDeniedError();
1545 } elseif (!$perm->isSuperUser()) {
1546 $this->setPermissionDeniedError();
1552 // Remove all the members
1554 $members = $this->getMembers();
1555 foreach ($members as $i) {
1556 if(!$this->removeUser($i->getID())) {
1557 $this->setError(_('Could not properly remove member:').' '.$i->getID());
1561 // Failsafe until user_group table is gone
1562 $res = db_query_params('DELETE FROM user_group WHERE group_id=$1',
1563 array($this->getID()));
1565 // unlink roles from this project
1566 $ra = RoleAnonymous::getInstance();
1567 $rl = RoleLoggedIn::getInstance();
1568 $ra->unlinkProject($this);
1569 $rl->unlinkProject($this);
1570 // @todo : unlink all the other roles created in the project...
1575 $atf = new ArtifactTypeFactory($this);
1576 $at_arr = $atf->getArtifactTypes();
1577 foreach ($at_arr as $i) {
1578 if (!is_object($i)) {
1581 if (!$i->delete(1,1)) {
1582 $this->setError(_('Could not properly delete the tracker:').' '.$i->getErrorMessage());
1589 $ff = new ForumFactory($this);
1590 $f_arr = $ff->getForums();
1591 foreach ($f_arr as $i) {
1592 if (!is_object($i)) {
1595 if(!$i->delete(1,1)) {
1596 $this->setError(_('Could not properly delete the forum:').' '.$i->getErrorMessage());
1601 // Delete Subprojects
1603 $pgf = new ProjectGroupFactory($this);
1604 $pg_arr = $pgf->getProjectGroups();
1605 foreach ($pg_arr as $i) {
1606 if (!is_object($i)) {
1609 if (!$i->delete(1,1)) {
1610 $this->setError(_('Could not properly delete the ProjectGroup:').' '.$i->getErrorMessage());
1615 // Delete FRS Packages
1617 $res = db_query_params('SELECT * FROM frs_package WHERE group_id=$1',
1618 array($this->getID()));
1620 $this->setError(_('Error FRS Packages: ').db_error());
1625 while ($arr = db_fetch_array($res)) {
1626 $frsp=new FRSPackage($this, $arr['package_id'], $arr);
1627 if (!$frsp->delete(1, 1)) {
1628 $this->setError(_('Could not properly delete the FRSPackage:').' '.$frsp->getErrorMessage());
1635 $news_group=group_get_object(forge_get_config('news_group'));
1636 $res = db_query_params('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1637 array($this->getID()));
1639 $this->setError(_('Error Deleting News: ').db_error());
1644 for ($i=0; $i<db_numrows($res); $i++) {
1645 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1646 if (!$Forum->delete(1,1)) {
1647 $this->setError(_("Could Not Delete News Forum: %d"),$Forum->getID());
1651 $res = db_query_params('DELETE FROM news_bytes WHERE group_id=$1',
1652 array($this->getID()));
1654 $this->setError(_('Error Deleting News: ').db_error());
1662 $res = db_query_params('DELETE FROM doc_data WHERE group_id=$1',
1663 array($this->getID()));
1665 $this->setError(_('Error Deleting Documents: ').db_error());
1670 $res = db_query_params('DELETE FROM doc_groups WHERE group_id=$1',
1671 array($this->getID()));
1673 $this->setError(_('Error Deleting Documents: ').db_error());
1681 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1683 $this->setError(_('Error Deleting Tags: ').db_error());
1689 // Delete group history
1691 $res = db_query_params('DELETE FROM group_history WHERE group_id=$1',
1692 array($this->getID()));
1694 $this->setError(_('Error Deleting Project History: ').db_error());
1700 // Delete group plugins
1702 $res = db_query_params('DELETE FROM group_plugin WHERE group_id=$1',
1703 array($this->getID()));
1705 $this->setError(_('Error Deleting Project Plugins: ').db_error());
1711 // Delete group cvs stats
1713 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1714 array ($this->getID())) ;
1716 $this->setError(_('Error Deleting SCM Statistics: ').db_error());
1724 $sf = new SurveyFactory($this);
1725 $s_arr =& $sf->getSurveys();
1726 foreach ($s_arr as $i) {
1727 if (!is_object($i)) {
1730 if (!$i->delete()) {
1731 $this->setError(_('Could not properly delete the survey'));
1737 // Delete SurveyQuestions
1739 $sqf = new SurveyQuestionFactory($this);
1740 $sq_arr =& $sqf->getSurveyQuestions();
1741 foreach ($sq_arr as $i) {
1742 if (!is_object($i)) {
1745 if (!$i->delete()) {
1746 $this->setError(_('Could not properly delete the survey questions'));
1752 // Delete Mailing List Factory
1754 $mlf = new MailingListFactory($this);
1755 $ml_arr = $mlf->getMailingLists();
1756 foreach ($ml_arr as $i) {
1757 if (!is_object($i)) {
1760 if (!$i->delete(1,1)) {
1761 $this->setError(_('Could not properly delete the mailing list'));
1769 $res = db_query_params('DELETE FROM trove_group_link WHERE group_id=$1',
1770 array($this->getID()));
1772 $this->setError(_('Error Deleting Trove: ').db_error());
1777 $res = db_query_params('DELETE FROM trove_agg WHERE group_id=$1',
1778 array($this->getID()));
1780 $this->setError(_('Error Deleting Trove: ').db_error());
1788 $res = db_query_params('DELETE FROM project_sums_agg WHERE group_id=$1',
1789 array($this->getID()));
1791 $this->setError(_('Error Deleting Counters: ').db_error());
1796 $res = db_query_params('INSERT INTO deleted_groups (unix_group_name, delete_date, isdeleted) VALUES ($1, $2, $3)',
1797 array($this->getUnixName(),
1801 $this->setError(_('Error Deleting Project:').' '.db_error());
1806 // Delete entry in groups.
1807 $res = db_query_params('DELETE FROM groups WHERE group_id=$1',
1808 array($this->getID()));
1810 $this->setError(_('Error Deleting Project:').' '.db_error());
1817 $hook_params = array();
1818 $hook_params['group'] = $this;
1819 $hook_params['group_id'] = $this->getID();
1820 plugin_hook("group_delete", $hook_params);
1822 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
1823 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
1825 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
1826 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
1831 $res = db_query_params('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
1832 array ($this->getID()));
1833 //echo 'rep_group_act_monthly'.db_error();
1834 $res = db_query_params('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
1835 array ($this->getID()));
1836 //echo 'rep_group_act_weekly'.db_error();
1837 $res = db_query_params('DELETE FROM rep_group_act_daily WHERE group_id=$1',
1838 array ($this->getID()));
1839 //echo 'rep_group_act_daily'.db_error();
1840 unset($this->data_array);
1845 Basic functions to add/remove users to/from a group
1846 and update their permissions
1850 * addUser - controls adding a user to a group.
1852 * @param string Unix name of the user to add OR integer user_id.
1853 * @param int The role_id this user should have.
1854 * @return boolean success.
1857 function addUser($user_identifier,$role_id) {
1860 Admins can add users to groups
1863 if (!forge_check_perm ('project_admin', $this->getID())) {
1864 $this->setPermissionDeniedError();
1870 get user id for this user's unix_name
1872 if (is_int ($user_identifier)) { // user_id or user_name
1873 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array ($user_identifier)) ;
1875 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array ($user_identifier)) ;
1877 if (db_numrows($res_newuser) > 0) {
1879 // make sure user is active
1881 if (db_result($res_newuser,0,'status') != 'A') {
1882 $this->setError(_('User is not active. Only active users can be added.'));
1888 // user was found - set new user_id var
1890 $user_id = db_result($res_newuser,0,'user_id');
1892 $role = new Role($this, $role_id);
1893 if (!$role || !is_object($role)) {
1894 $this->setError(_('Error Getting Role Object'));
1897 } elseif ($role->isError()) {
1898 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1903 $role->addUser(user_get_object($user_id)) ;
1904 if (!$SYS->sysCheckCreateGroup($this->getID())){
1905 $this->setError($SYS->getErrorMessage());
1909 if (!$SYS->sysCheckCreateUser($user_id)) {
1910 $this->setError($SYS->getErrorMessage());
1914 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
1915 $this->setError($SYS->getErrorMessage());
1921 // user doesn't exist
1923 $this->setError(_('ERROR: User does not exist'));
1928 $hook_params['group'] = $this;
1929 $hook_params['group_id'] = $this->getID();
1930 $hook_params['user'] = user_get_object($user_id);
1931 $hook_params['user_id'] = $user_id;
1932 plugin_hook ("group_adduser", $hook_params);
1937 $this->addHistory('Added User',$user_identifier);
1943 * removeUser - controls removing a user from a group.
1945 * Users can remove themselves.
1947 * @param int The ID of the user to remove.
1948 * @return boolean success.
1950 function removeUser($user_id) {
1953 if ($user_id != user_getid()
1954 && !forge_check_perm('project_admin', $this->getID())) {
1955 $this->setPermissionDeniedError();
1961 $user = user_get_object($user_id);
1962 $roles = RBACEngine::getInstance()->getAvailableRolesForUser($user);
1964 foreach ($roles as $role) {
1965 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
1966 $found_role = $role;
1970 if ($found_role == NULL) {
1971 $this->setError(sprintf(_('ERROR: User not removed: %s')));
1975 $found_role->removeUser($user);
1976 if (!$SYS->sysGroupCheckUser($this->getID(), $user_id)) {
1977 $this->setError($SYS->getErrorMessage());
1983 // reassign open artifacts to id=100
1985 $res = db_query_params('UPDATE artifact SET assigned_to=100
1986 WHERE group_artifact_id
1987 IN (SELECT group_artifact_id
1988 FROM artifact_group_list
1989 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
1990 array($this->getID(),
1993 $this->setError(_('ERROR: DB: artifact:').' '.db_error());
1999 // reassign open tasks to id=100
2000 // first have to purge any assignments that would cause
2001 // conflict with existing assignment to 100
2003 $res = db_query_params('DELETE FROM project_assigned_to
2004 WHERE project_task_id IN (SELECT pt.project_task_id
2005 FROM project_task pt, project_group_list pgl, project_assigned_to pat
2006 WHERE pt.group_project_id = pgl.group_project_id
2007 AND pat.project_task_id=pt.project_task_id
2008 AND pt.status_id=1 AND pgl.group_id=$1
2009 AND pat.assigned_to_id=$2)
2010 AND assigned_to_id=100',
2011 array($this->getID(),
2014 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'), 1, db_error()));
2018 $res = db_query_params('UPDATE project_assigned_to SET assigned_to_id=100
2019 WHERE project_task_id IN (SELECT pt.project_task_id
2020 FROM project_task pt, project_group_list pgl
2021 WHERE pt.group_project_id = pgl.group_project_id
2022 AND pt.status_id=1 AND pgl.group_id=$1)
2023 AND assigned_to_id=$2',
2024 array($this->getID(),
2027 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'), 2, db_error()));
2033 // Remove user from system
2035 if (!$SYS->sysGroupRemoveUser($this->getID(), $user_id)) {
2036 $this->setError($SYS->getErrorMessage());
2041 $hook_params['group'] = $this;
2042 $hook_params['group_id'] = $this->getID();
2043 $hook_params['user'] = user_get_object($user_id);
2044 $hook_params['user_id'] = $user_id;
2045 plugin_hook ("group_removeuser", $hook_params);
2048 $this->addHistory('Removed User',$user_id);
2055 * updateUser - controls updating a user's role in this group.
2057 * @param int The ID of the user.
2058 * @param int The role_id to set this user to.
2059 * @return boolean success.
2061 function updateUser($user_id,$role_id) {
2064 if (!forge_check_perm ('project_admin', $this->getID())) {
2065 $this->setPermissionDeniedError();
2069 $newrole = RBACEngine::getInstance()->getRoleById ($role_id) ;
2070 if (!$newrole || !is_object($newrole)) {
2071 $this->setError(_('Could Not Get Role'));
2073 } elseif ($newrole->isError()) {
2074 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2076 } elseif ($newrole->getHomeProject() == NULL
2077 || $newrole->getHomeProject()->getID() != $this->getID()) {
2078 $this->setError(_('Wrong destination role'));
2081 $user = user_get_object ($user_id) ;
2082 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
2083 $found_role = NULL ;
2084 foreach ($roles as $role) {
2085 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2086 $found_role = $role ;
2090 if ($found_role == NULL) {
2091 $this->setError(sprintf(_('ERROR: User not removed: %s')));
2095 $found_role->removeUser ($user) ;
2096 $newrole->addUser ($user) ;
2098 $this->addHistory('Updated User',$user_id);
2103 * addHistory - Makes an audit trail entry for this project.
2105 * @param string The name of the field.
2106 * @param string The Old Value for this $field_name.
2107 * @return database result handle.
2110 function addHistory($field_name, $old_value) {
2111 return db_query_params ('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2112 VALUES ($1,$2,$3,$4,$5)',
2113 array ($this->getID(),
2121 * activateUsers - Make sure that group members have unix accounts.
2123 * Setup unix accounts for group members. Can be called even
2124 * if members are already active.
2128 function activateUsers() {
2130 Activate member(s) of the project
2133 $members = $this->getUsers (true) ;
2135 foreach ($members as $member) {
2137 foreach (RBACEngine::getInstance()->getAvailableRolesForUser ($member) as $role) {
2138 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2141 if (!$this->addUser($member->getUnixName(),$role->getID())) {
2152 * getMembers - returns array of User objects for this project
2154 * @return array of User objects for this group.
2156 function getMembers() {
2157 return $this->getUsers (true) ;
2161 * replaceTemplateStrings - fill-in some blanks with project name
2163 * @param string Template string
2164 * @return string String after replacements
2166 function replaceTemplateStrings($string) {
2167 $string = str_replace ('UNIXNAME', $this->getUnixName(), $string) ;
2168 $string = str_replace ('PUBLICNAME', $this->getPublicName(), $string) ;
2169 $string = str_replace ('DESCRIPTION', $this->getDescription(), $string) ;
2174 * approve - Approve pending project.
2176 * @param object The User object who is doing the updating.
2179 function approve(&$user) {
2180 global $gfcommon,$gfwww;
2181 require_once $gfcommon.'widget/WidgetLayoutManager.class.php';
2183 if ($this->getStatus()=='A') {
2184 $this->setError(_("Group already active"));
2190 // Step 1: Activate group and create LDAP entries
2191 if (!$this->setStatus($user, 'A')) {
2196 // Switch to system language for item creation
2197 setup_gettext_from_sys_lang();
2199 // Create default roles
2200 $idadmin_group = NULL;
2201 foreach (get_group_join_requests ($this) as $gjr) {
2202 $idadmin_group = $gjr->getUserID();
2205 if ($idadmin_group == NULL) {
2206 $idadmin_group = $user->getID();
2209 $template = $this->getTemplateProject();
2210 $id_mappings = array();
2211 $seen_admin_role = false;
2213 // Copy roles from template project
2214 foreach($template->getRoles() as $oldrole) {
2215 if ($oldrole->getHomeProject() != NULL) {
2216 $role = new Role($this);
2218 // Need to use a different role name so that the permissions aren't set from the hardcoded defaults
2219 $role->create('TEMPORARY ROLE NAME', $data, true);
2220 $role->setName($oldrole->getName());
2221 if ($oldrole->getSetting ('project_admin', $template->getID())) {
2222 $seen_admin_role = true;
2226 $role->linkProject($this);
2228 $id_mappings['role'][$oldrole->getID()] = $role->getID();
2229 // Reuse the project_admin permission
2230 $role->setSetting ('project_admin', $this->getID(), $oldrole->getSetting ('project_admin', $template->getID())) ;
2234 if (!$seen_admin_role) {
2235 $role = new Role($this);
2236 $adminperms = array ('project_admin' => array ($this->getID() => 1)) ;
2237 $role_id = $role->create ('Admin', $adminperms, true) ;
2240 $roles = $this->getRoles() ;
2241 foreach ($roles as $r) {
2242 if ($r->getHomeProject() == NULL) {
2245 if ($r->getSetting ('project_admin', $this->getID())) {
2246 $r->addUser(user_get_object ($idadmin_group));
2250 // Temporarily switch to the submitter's identity
2251 $saved_session = session_get_user();
2252 session_set_internal($idadmin_group);
2255 if (forge_get_config('use_tracker')) {
2256 $this->setUseTracker ($template->usesTracker());
2257 if ($template->usesTracker()) {
2258 $oldatf = new ArtifactTypeFactory($template);
2259 foreach ($oldatf->getArtifactTypes() as $o) {
2260 $t = new ArtifactType ($this) ;
2261 $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()) ;
2262 $id_mappings['tracker'][$o->getID()] = $t->getID();
2263 $t->cloneFieldsFrom ($o->getID());
2268 if (forge_get_config('use_pm')) {
2269 $this->setUsePM ($template->usesPM());
2270 if ($template->usesPM()) {
2271 $oldpgf = new ProjectGroupFactory($template);
2272 foreach ($oldpgf->getProjectGroups() as $o) {
2273 $pg = new ProjectGroup($this);
2274 $pg->create($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->isPublic(),$o->getSendAllPostsTo());
2275 $id_mappings['pm'][$o->getID()] = $pg->getID();
2280 if (forge_get_config('use_forum')) {
2281 $this->setUseForum($template->usesForum()) ;
2282 if ($template->usesForum()) {
2283 $oldff = new ForumFactory($template) ;
2284 foreach ($oldff->getForums() as $o) {
2285 $f = new Forum($this);
2286 $f->create($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),0,$o->getSendAllPostsTo(),1,0,0);
2287 $id_mappings['forum'][$o->getID()] = $f->getID();
2292 if (forge_get_config('use_docman')) {
2293 $this->setUseDocman($template->usesDocman());
2294 if ($template->usesDocman()) {
2295 $olddgf = new DocumentGroupFactory($template);
2296 // First pass: create all docgroups
2297 $id_mappings['docman_docgroup'][0] = 0;
2298 foreach ($olddgf->getDocumentGroups() as $o) {
2299 $ndgf = new DocumentGroup($this);
2300 // .trash is a reserved directory
2301 if ($o->getName() != '.trash' && $o->getParentID() == 0) {
2302 $ndgf->create($this->replaceTemplateStrings($o->getName()));
2303 $id_mappings['docman_docgroup'][$o->getID()] = $ndgf->getID();
2306 // Second pass: restore hierarchy links
2307 foreach ($olddgf->getDocumentGroups() as $o) {
2308 $ndgf = new DocumentGroup($this);
2309 if ($o->getName() != '.trash' && $o->getParentID() == 0) {
2310 $ndgf->fetchData($id_mappings['docman_docgroup'][$o->getID()]);
2311 $ndgf->update($ndgf->getName(), $id_mappings['docman_docgroup'][$o->getParentID()]);
2317 if (forge_get_config('use_frs')) {
2318 $this->setUseFRS ($template->usesFRS());
2319 if ($template->usesFRS()) {
2320 foreach (get_frs_packages($template) as $o) {
2321 $newp = new FRSPackage($this);
2322 $nname = $this->replaceTemplateStrings($o->getName());
2323 $newp->create ($nname, $o->isPublic());
2328 if (forge_get_config('use_mail')) {
2329 $this->setUseMail($template->usesMail()) ;
2330 if ($template->usesMail()) {
2331 $oldmlf = new MailingListFactory($template);
2332 foreach ($oldmlf->getMailingLists() as $o) {
2333 $ml = new MailingList($this);
2334 $nname = preg_replace ('/^'.$template->getUnixName().'-/','',$o->getName()) ;
2336 $ndescription = $this->replaceTemplateStrings($o->getDescription()) ;
2337 $ml->create($nname, $ndescription, $o->isPublic());
2342 $this->setUseSCM ($template->usesSCM()) ;
2344 foreach ($template->getPlugins() as $plugin_id => $plugin_name) {
2345 $this->setPluginUse ($plugin_name) ;
2348 foreach ($template->getRoles() as $oldrole) {
2349 $newrole = RBACEngine::getInstance()->getRoleById ($id_mappings['role'][$oldrole->getID()]) ;
2350 if ($oldrole->getHomeProject() != NULL
2351 && $oldrole->getHomeProject()->getID() == $template->getID()) {
2352 $newrole->setPublic ($oldrole->isPublic()) ;
2354 $oldsettings = $oldrole->getSettingsForProject ($template) ;
2356 $sections = array ('project_read', 'project_admin', 'frs', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm') ;
2357 foreach ($sections as $section) {
2358 $newrole->setSetting ($section, $this->getID(), $oldsettings[$section][$template->getID()]) ;
2361 $sections = array ('tracker', 'pm', 'forum') ;
2362 foreach ($sections as $section) {
2363 if (isset ($oldsettings[$section])) {
2364 foreach ($oldsettings[$section] as $k => $v) {
2365 // Only copy perms for tools that have been copied
2366 if (isset ($id_mappings[$section][$k])) {
2367 $newrole->setSetting ($section,
2368 $id_mappings[$section][$k],
2376 $lm = new WidgetLayoutManager();
2377 $lm->createDefaultLayoutForProject ($this->getID(), $template->getID()) ;
2379 $params = array () ;
2380 $params['template'] = $template ;
2381 $params['project'] = $this ;
2382 $params['id_mappings'] = $id_mappings ;
2383 plugin_hook_by_reference ('clone_project_from_template', $params) ;
2385 // Disable everything
2386 $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, use_ftp=0, use_tracker=0, use_frs=0, use_stats=0 WHERE group_id=$1',
2388 array ($this->getID())) ;
2391 $this->normalizeAllRoles();
2392 $this->activateUsers();
2394 // Switch back to user preference
2395 session_set_internal($saved_session->getID());
2396 setup_gettext_from_context();
2400 $this->sendApprovalEmail();
2401 $this->addHistory('Approved', 'x');
2404 // Plugin can make approve operation there
2406 $params[0] = $idadmin_group;
2407 $params[1] = $this->getID();
2408 plugin_hook('group_approved', $params);
2416 * sendApprovalEmail - Send new project email.
2418 * @return boolean success.
2421 function sendApprovalEmail() {
2422 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID()) ;
2424 if (count($admins) < 1) {
2425 $this->setError(_("Group does not have any administrators."));
2429 // send one email per admin
2430 foreach ($admins as $admin) {
2431 setup_gettext_for_user ($admin) ;
2433 $message=sprintf(_('Your project registration for %4$s has been approved.
2435 Project Full Name: %1$s
2436 Project Unix Name: %2$s
2438 Your DNS will take up to a day to become active on our site.
2439 Your web site is accessible through your shell account. Please read
2440 site documentation (see link below) about intended usage, available
2441 services, and directory layout of the account.
2444 own project page in %4$s while logged in, you will find
2445 additional menu functions to your left labeled \'Project Admin\'.
2447 We highly suggest that you now visit %4$s and create a public
2448 description for your project. This can be done by visiting your project
2449 page while logged in, and selecting \'Project Admin\' from the menus
2450 on the left (or by visiting %3$s
2453 Your project will also not appear in the Trove Software Map (primary
2454 list of projects hosted on %4$s which offers great flexibility in
2455 browsing and search) until you categorize it in the project administration
2456 screens. So that people can find your project, you should do this now.
2457 Visit your project while logged in, and select \'Project Admin\' from the
2460 Enjoy the system, and please tell others about %4$s. Let us know
2461 if there is anything we can do to help you.
2464 htmlspecialchars_decode($this->getPublicName()),
2465 $this->getUnixName(),
2466 util_make_url ('/project/admin/?group_id='.$this->getID()),
2467 forge_get_config ('forge_name'));
2469 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Approved'), forge_get_config ('forge_name')), $message);
2471 setup_gettext_from_context();
2479 * sendRejectionEmail - Send project rejection email.
2481 * This function sends out a rejection message to a user who
2482 * registered a project.
2484 * @param int The id of the response to use.
2485 * @param string The rejection message.
2486 * @return boolean completion status.
2489 function sendRejectionEmail($response_id, $message="zxcv") {
2490 $submitters = array () ;
2491 foreach (get_group_join_requests ($this) as $gjr) {
2492 $submitters[] = user_get_object($gjr->getUserID());
2495 if (count ($submitters) < 1) {
2496 $this->setError(_("Group does not have any administrators."));
2500 foreach ($submitters as $admin) {
2501 setup_gettext_for_user($admin);
2503 $response=sprintf(_('Your project registration for %3$s has been denied.
2505 Project Full Name: %1$s
2506 Project Unix Name: %2$s
2508 Reasons for negative decision:
2510 '), $this->getPublicName(), $this->getUnixName(), forge_get_config('forge_name'));
2512 // Check to see if they want to send a custom rejection response
2513 if ($response_id == 0) {
2514 $response .= $message;
2516 $response .= db_result(
2517 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array ($response_id)),
2522 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Denied'), forge_get_config ('forge_name')), $response);
2523 setup_gettext_from_context();
2530 * sendNewProjectNotificationEmail - Send new project notification email.
2532 * This function sends out a notification email to the
2533 * SourceForge admin user when a new project is
2536 * @return boolean success.
2539 function sendNewProjectNotificationEmail() {
2540 // Get the user who wants to register the project
2541 $submitters = array();
2542 foreach (get_group_join_requests ($this) as $gjr) {
2543 $submitters[] = user_get_object($gjr->getUserID());
2545 if (count ($submitters) < 1) {
2546 $this->setError(_("Could not find user who has submitted the project."));
2550 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('approve_projects', -1) ;
2552 if (count($admins) < 1) {
2553 $this->setError(_("There is no administrator to send the mail to."));
2557 foreach ($admins as $admin) {
2558 $admin_email = $admin->getEmail () ;
2559 setup_gettext_for_user ($admin) ;
2561 foreach ($submitters as $u) {
2562 $submitter_names[] = $u->getRealName() ;
2565 $message = sprintf(_('New %1$s Project Submitted
2567 Project Full Name: %2$s
2568 Submitted Description: %3$s
2570 forge_get_config ('forge_name'),
2571 htmlspecialchars_decode($this->getPublicName()),
2572 htmlspecialchars_decode($this->getRegistrationPurpose()));
2574 foreach ($submitters as $submitter) {
2575 $message .= sprintf(_('Submitter: %1$s (%2$s)
2577 $submitter->getRealName(),
2578 $submitter->getUnixName());
2581 $message .= sprintf (_('
2582 Please visit the following URL to approve or reject this project:
2584 util_make_url ('/admin/approve-pending.php')) ;
2585 util_send_message($admin_email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2586 setup_gettext_from_context();
2590 $email = $submitter->getEmail() ;
2591 setup_gettext_for_user ($submitter) ;
2593 $message=sprintf(_('New %1$s Project Submitted
2595 Project Full Name: %2$s
2596 Submitted Description: %3$s
2598 The %1$s admin team will now examine your project submission. You will be notified of their decision.'), forge_get_config ('forge_name'), $this->getPublicName(), util_unconvert_htmlspecialchars($this->getRegistrationPurpose()), forge_get_config('web_host'));
2600 util_send_message($email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2601 setup_gettext_from_context();
2610 * validateGroupName - Validate the group name
2612 * @param string Group name.
2614 * @return boolean an error false and set an error is the group name is invalide otherwise return true
2616 function validateGroupName($group_name) {
2617 if (strlen($group_name)<3) {
2618 $this->setError(_('Group name is too short'));
2620 } else if (strlen(htmlspecialchars($group_name))>50) {
2621 $this->setError(_('Group name is too long'));
2623 } else if ($group=group_get_object_by_publicname($group_name)) {
2624 $this->setError(_('Group name already taken'));
2632 * getRolesId - Get Ids of the roles of the group.
2634 * @return array Role ids of this group.
2636 function getRolesId() {
2637 $role_ids = array();
2639 $res = db_query_params('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2640 array($this->getID()));
2641 while ($arr = db_fetch_array($res)) {
2642 $role_ids[] = $arr['role_id'];
2644 $res = db_query_params('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2645 array($this->getID()));
2646 while ($arr = db_fetch_array($res)) {
2647 $role_ids[] = $arr['role_id'];
2650 return array_unique($role_ids);
2654 * getRoles - Get the roles of the group.
2656 * @return array Roles of this group.
2658 function getRoles() {
2661 $roles = $this->getRolesId();
2662 $engine = RBACEngine::getInstance();
2663 foreach ($roles as $role_id) {
2664 $result[] = $engine->getRoleById ($role_id);
2670 function normalizeAllRoles() {
2671 $roles = $this->getRoles();
2673 foreach ($roles as $r) {
2674 $r->normalizeData();
2679 * getUnixStatus - Status of activation of unix account.
2681 * @return char (N)one, (A)ctive, (S)uspended or (D)eleted
2683 function getUnixStatus() {
2684 return $this->data_array['unix_status'];
2688 * setUnixStatus - Sets status of activation of unix account.
2690 * @param string The unix status.
2696 * @return boolean success.
2698 function setUnixStatus($status) {
2701 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
2706 $this->setError(sprintf(_('ERROR - Could Not Update Group Unix Status: %s'),db_error()));
2710 if ($status == 'A') {
2711 if (!$SYS->sysCheckCreateGroup($this->getID())) {
2712 $this->setError($SYS->getErrorMessage());
2717 if ($SYS->sysCheckGroup($this->getID())) {
2718 if (!$SYS->sysRemoveGroup($this->getID())) {
2719 $this->setError($SYS->getErrorMessage());
2726 $this->data_array['unix_status']=$status;
2733 * getUsers - Get the users of a group
2735 * @return array of user's objects.
2737 function getUsers($onlylocal = true) {
2738 if (!isset($this->membersArr)) {
2739 $this->membersArr = array () ;
2742 foreach ($this->getRoles() as $role) {
2744 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
2747 foreach ($role->getUsers() as $user) {
2748 $ids[] = $user->getID() ;
2751 $ids = array_unique ($ids) ;
2752 foreach ($ids as $id) {
2753 $u = user_get_object ($id) ;
2754 if ($u->isActive()) {
2755 $this->membersArr[] = $u ;
2759 return $this->membersArr;
2762 function setDocmanCreateOnlineStatus($status) {
2764 /* if we activate search engine, we probably want to reindex */
2765 $res = db_query_params('UPDATE groups SET use_docman_create_online=$1 WHERE group_id=$2',
2766 array($status, $this->getID()));
2769 $this->setError(sprintf(_('ERROR - Could Not Update Group DocmanCreateOnline Status: %s'),db_error()));
2773 $this->data_array['use_docman_create_online']=$status;
2779 function setDocmanWebdav($status) {
2781 /* if we activate search engine, we probably want to reindex */
2782 $res = db_query_params('UPDATE groups SET use_webdav=$1 WHERE group_id=$2',
2787 $this->setError(sprintf(_('ERROR - Could Not Update Group UseWebdab Status: %s'),db_error()));
2791 $this->data_array['use_webdav']=$status;
2797 function setDocmanSearchStatus($status) {
2799 /* if we activate search engine, we probably want to reindex */
2800 $res = db_query_params('UPDATE groups SET use_docman_search=$1, force_docman_reindex=$1 WHERE group_id=$2',
2805 $this->setError(sprintf(_('ERROR - Could Not Update Group UseDocmanSearch Status: %s'),db_error()));
2809 $this->data_array['use_docman_search']=$status;
2815 function setDocmanForceReindexSearch($status) {
2817 /* if we activate search engine, we probably want to reindex */
2818 $res = db_query_params('UPDATE groups SET force_docman_reindex=$1 WHERE group_id=$2',
2823 $this->setError(sprintf(_('ERROR - Could Not Update Group force_docman_reindex %s'),db_error()));
2827 $this->data_array['force_docman_reindex']=$status;
2833 function setStorageAPI($type) {
2837 function getStorageAPI() {
2843 * group_getname() - get the group name
2845 * @param int The group ID
2849 function group_getname ($group_id = 0) {
2850 $grp = group_get_object($group_id);
2852 return $grp->getPublicName();
2859 * group_getunixname() - get the unixname for a group
2861 * @param int The group ID
2865 function group_getunixname ($group_id) {
2866 $grp = group_get_object($group_id);
2868 return $grp->getUnixName();
2875 * group_get_result() - Get the group object result ID.
2877 * @param int The group ID
2881 function &group_get_result($group_id=0) {
2882 $grp = group_get_object($group_id);
2884 return $grp->getData();
2890 function getAllProjectTags($onlyvisible = true) {
2891 $res = db_query_params('SELECT project_tags.name, groups.group_id FROM groups, project_tags WHERE groups.group_id = project_tags.group_id AND groups.status = $1 ORDER BY project_tags.name, groups.group_id',
2894 if (!$res || db_numrows($res) == 0) {
2900 while ($arr = db_fetch_array($res)) {
2902 $group_id = $arr[1];
2903 if (!isset($result[$tag])) {
2904 $result[$tag] = array();
2907 if (!$onlyvisible || forge_check_perm('project_read', $group_id)) {
2908 $p = group_get_object($group_id);
2909 $result[$tag][] = array('unix_group_name' => $p->getUnixName(),
2910 'group_id' => $group_id);
2918 * Utility class to compare project based in various criteria (names, unixnames, id, ...)
2921 class ProjectComparator {
2922 var $criterion = 'name' ;
2924 function Compare ($a, $b) {
2925 switch ($this->criterion) {
2928 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName()) ;
2929 if ($namecmp != 0) {
2932 /* If several projects share a same public name */
2933 return strcoll ($a->getUnixName(), $b->getUnixName()) ;
2936 return strcmp ($a->getUnixName(), $b->getUnixName()) ;
2939 $aid = $a->getID() ;
2940 $bid = $b->getID() ;
2944 return ($a < $b) ? -1 : 1;
2950 function sortProjectList (&$list, $criterion='name') {
2951 $cmp = new ProjectComparator () ;
2952 $cmp->criterion = $criterion ;
2954 return usort ($list, array ($cmp, 'Compare')) ;
2959 // c-file-style: "bsd"