5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009, Roland Mas
7 * Copyright 2010, Franck Villaume - Capgemini
8 * http://fusionforge.org
10 * This file is part of FusionForge.
12 * FusionForge is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published
14 * by the Free Software Foundation; either version 2 of the License,
15 * or (at your option) any later version.
17 * FusionForge is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with FusionForge; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 require_once $gfcommon.'tracker/ArtifactTypes.class.php';
29 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
30 require_once $gfcommon.'forum/Forum.class.php';
31 require_once $gfcommon.'forum/ForumFactory.class.php';
32 require_once $gfcommon.'pm/ProjectGroup.class.php';
33 require_once $gfcommon.'pm/ProjectGroupFactory.class.php';
34 require_once $gfcommon.'include/Role.class.php';
35 require_once $gfcommon.'frs/FRSPackage.class.php';
36 require_once $gfcommon.'docman/DocumentGroup.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';
44 //the license_id of "Other/proprietary" license
45 define('GROUP_LICENSE_OTHER',126);
47 $LICENSE_NAMES=array();
50 * group_get_licences() - get the licenses list
52 * @return array list of licenses
54 function & group_get_licenses() {
55 global $LICENSE_NAMES;
56 if(empty($LICENSE_NAMES)) {
57 $result = db_query_params ('select * from licenses', array());
58 while($data = db_fetch_array($result)) {
59 $LICENSE_NAMES[$data['license_id']] = $data['license_name'];
62 return $LICENSE_NAMES;
68 * group_get_object() - Get the group object.
70 * group_get_object() is useful so you can pool group objects/save database queries
71 * You should always use this instead of instantiating the object directly.
73 * You can now optionally pass in a db result handle. If you do, it re-uses that query
74 * to instantiate the objects.
76 * IMPORTANT! That db result must contain all fields
77 * from groups table or you will have problems
80 * @param int Result set handle ("SELECT * FROM groups WHERE group_id=xx")
81 * @return object a group object or false on failure
83 function &group_get_object($group_id, $res = false) {
84 //create a common set of group objects
85 //saves a little wear on the database
87 //automatically checks group_type and
88 //returns appropriate object
91 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
93 //the db result handle was passed in
95 $res = db_query_params('SELECT * FROM groups WHERE group_id=$1', array($group_id)) ;
97 if (!$res || db_numrows($res) < 1) {
98 $GROUP_OBJ["_".$group_id."_"]=false;
101 check group type and set up object
103 if (db_result($res,0,'type_id') == 1) {
105 $GROUP_OBJ["_".$group_id."_"] = new Group($group_id, $res);
108 $GROUP_OBJ["_".$group_id."_"] = false;
112 return $GROUP_OBJ["_".$group_id."_"];
115 function &group_get_objects($id_arr) {
118 // Note: if we don't do this, the result may be corrupted
122 for ($i=0; $i < count($id_arr); $i++) {
124 // See if this ID already has been fetched in the cache
129 if (!isset($GROUP_OBJ["_".$id_arr[$i]."_"])) {
130 $fetch[] = $id_arr[$i];
132 $return[] =& $GROUP_OBJ["_".$id_arr[$i]."_"];
135 if (count($fetch) > 0) {
136 $res=db_query_params('SELECT * FROM groups WHERE group_id = ANY ($1)',
137 array(db_int_array_to_any_clause($fetch)));
138 while ($arr = db_fetch_array($res)) {
139 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
140 $return[] =& $GROUP_OBJ["_".$arr['group_id']."_"];
146 function &group_get_active_projects() {
147 $res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
149 return group_get_objects(util_result_column_to_array($res,0)) ;
152 function &group_get_object_by_name($groupname) {
153 $res = db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array($groupname));
154 return group_get_object(db_result($res, 0, 'group_id'), $res);
157 function &group_get_objects_by_name($groupname_arr) {
158 $res = db_query_params('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
159 array (db_string_array_to_any_clause($groupname_arr)));
160 $arr =& util_result_column_to_array($res,0);
161 return group_get_objects($arr);
164 function &group_get_object_by_publicname($groupname) {
165 $res = db_query_params('SELECT * FROM groups WHERE lower(group_name) LIKE $1',
166 array(htmlspecialchars(strtolower($groupname))));
168 return group_get_object(db_result($res, 0, 'group_id'), $res);
171 class Group extends Error {
173 * Associative array of data from db.
175 * @var array $data_array.
180 * array of User objects.
182 * @var array $membersArr.
187 * Whether the use is an admin/super user of this project.
189 * @var bool $is_admin.
194 * Artifact types result handle.
196 * @var int $types_res.
201 * Associative array of data for plugins.
203 * @var array $plugins_data.
209 * Associative array of data for the group menu.
211 * @var array $menu_data.
216 * Group - Group object constructor - use group_get_object() to instantiate.
218 * @param int Required - group_id of the group you want to instantiate.
219 * @param int Database result from select query OR associative array of all columns.
220 * @return boolean success or not
222 function Group($id = false, $res = false) {
225 //setting up an empty object
226 //probably going to call create()
230 if (!$this->fetchData($id)) {
235 // Assoc array was passed in
237 if (is_array($res)) {
238 $this->data_array =& $res;
240 if (db_numrows($res) < 1) {
241 //function in class we extended
242 $this->setError(_('Group Not Found'));
243 $this->data_array=array();
246 //set up an associative array for use by other functions
247 $this->data_array = db_fetch_array_by_row($res, 0);
256 * fetchData - May need to refresh database fields if an update occurred.
258 * @param int The group_id.
259 * @return boolean success or not
261 function fetchData($group_id) {
262 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
264 if (!$res || db_numrows($res) < 1) {
265 $this->setError(sprintf(_('fetchData():: %s'),db_error()));
268 $this->data_array = db_fetch_array($res);
273 * create - Create new group.
275 * This method should be called on empty Group object.
277 * @param object The User object.
278 * @param string The full name of the user.
279 * @param string The Unix name of the user.
280 * @param string The new group description.
281 * @param string The purpose of the group.
282 * @param boolean Whether to send an email or not
283 * @return boolean success or not
285 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true) {
286 // $user is ignored - anyone can create pending group
289 if ($this->getID()!=0) {
290 $this->setError(_('Group::create: Group object already exists'));
292 } else if (!$this->validateGroupName($group_name)) {
294 } else if (!account_groupnamevalid($unix_name)) {
295 $this->setError(_('Invalid Unix name'));
297 } else if (!$SYS->sysUseUnixName($unix_name)) {
298 $this->setError(_('Unix name already taken'));
300 } else if (db_numrows(db_query_params('SELECT group_id FROM groups WHERE unix_group_name=$1',
301 array ($unix_name))) > 0) {
302 $this->setError(_('Unix name already taken'));
304 } else if (strlen($purpose)<10) {
305 $this->setError(_('Please describe your Registration Purpose in a more comprehensive manner'));
307 } else if (strlen($purpose)>1500) {
308 $this->setError(_('The Registration Purpose text is too long. Please make it smaller than 1500 bytes.'));
310 } else if (strlen($description)<10) {
311 $this->setError(_('Describe in a more comprehensive manner your project.'));
313 } else if (strlen($description)>255) {
314 $this->setError(_('Your project description is too long. Please make it smaller than 256 bytes.'));
318 srand((double)microtime()*1000000);
319 $random_num = rand(0,1000000);
323 $res = db_query_params ('
339 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
340 array (htmlspecialchars ($group_name),
343 htmlspecialchars($description),
344 $unix_name.".".forge_get_config('web_host'),
345 $unix_name.".".forge_get_config('web_host'),
349 htmlspecialchars($purpose),
352 md5($random_num) )) ;
353 if (!$res || db_affected_rows($res) < 1) {
354 $this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
359 $id = db_insertid($res, 'groups', 'group_id');
361 $this->setError(sprintf(_('ERROR: Could not get group id: %s'),db_error()));
366 if (!$this->fetchData($id)) {
372 $gjr = new GroupJoinRequest ($this) ;
373 $gjr->create ($user->getID(),
374 'Fake GroupJoinRequest to store the creator of a project',
378 // Now, make the user an admin
380 $res=db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags,
381 cvs_flags, artifact_flags, forum_flags, role_id)
382 VALUES ($1, $2, $3, $4, $5, $6, $7)',
383 array ($user->getID(),
390 if (!$res || db_affected_rows($res) < 1) {
391 $this->setError(sprintf(_('ERROR: Could not add admin to newly created group: %s'),db_error()));
397 $hook_params = array ();
398 $hook_params['group'] = $this;
399 $hook_params['group_id'] = $this->getID();
400 $hook_params['group_name'] = $group_name;
401 $hook_params['unix_group_name'] = $unix_name;
402 plugin_hook ("group_create", $hook_params);
406 $this->sendNewProjectNotificationEmail();
414 * updateAdmin - Update core properties of group object.
416 * This function require site admin privilege.
418 * @param object User requesting operation (for access control).
419 * @param boolean Whether group is publicly accessible (0/1).
420 * @param int Group type (1-project, 2-foundry).
421 * @param string Machine on which group's home directory located.
422 * @param string Domain which serves group's WWW.
426 function updateAdmin(&$user, $is_public, $type_id, $unix_box, $http_domain) {
427 $perm =& $this->getPermission();
429 if (!$perm || !is_object($perm)) {
430 $this->setError(_('Could not get permission.'));
434 if (!$perm->isSuperUser()) {
435 $this->setError(_('Permission denied.'));
441 $res = db_query_params('
443 SET is_public=$1, type_id=$2,
444 unix_box=$3, http_domain=$4
452 if (!$res || db_affected_rows($res) < 1) {
453 $this->setError(_('ERROR: DB: Could not change group properties: %s'),db_error());
458 // Log the audit trail
459 if ($is_public != $this->isPublic()) {
460 $this->addHistory('is_public', $this->isPublic());
462 if ($type_id != $this->data_array['type_id']) {
463 $this->addHistory('type_id', $this->data_array['type_id']);
465 if ($unix_box != $this->data_array['unix_box']) {
466 $this->addHistory('unix_box', $this->data_array['unix_box']);
468 if ($http_domain != $this->data_array['http_domain']) {
469 $this->addHistory('http_domain', $this->data_array['http_domain']);
472 if (!$this->fetchData($this->getID())) {
481 * update - Update number of common properties.
483 * Unlike updateAdmin(), this function accessible to project admin.
485 * @param object User requesting operation (for access control).
486 * @param boolean Whether group is publicly accessible (0/1).
487 * @param string Project's license (string ident).
488 * @param int Group type (1-project, 2-foundry).
489 * @param string Machine on which group's home directory located.
490 * @param string Domain which serves group's WWW.
491 * @return int status.
494 function update(&$user, $group_name,$homepage,$short_description,$use_mail,$use_survey,$use_forum,
495 $use_pm,$use_pm_depend_box,$use_scm,$use_news,$use_docman,
496 $new_doc_address,$send_all_docs,$logo_image_id,
497 $use_ftp,$use_tracker,$use_frs,$use_stats,$tags,$is_public) {
499 $perm =& $this->getPermission ();
501 if (!$perm || !is_object($perm)) {
502 $this->setError(_('Could not get permission.'));
506 if (!$perm->isAdmin()) {
507 $this->setError(_('Permission denied.'));
511 // Validate some values
512 if ($this->getPublicName() != $group_name) {
513 if (!$this->validateGroupName($group_name)) {
518 if ($new_doc_address) {
519 $invalid_mails = validate_emails($new_doc_address);
520 if (count($invalid_mails) > 0) {
521 $this->setError(sprintf (ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
526 // in the database, these all default to '1',
527 // so we have to explicity set 0
540 if (!$use_pm_depend_box) {
541 $use_pm_depend_box=0;
564 if (!$send_all_docs) {
568 $homepage = ltrim($homepage);
570 $homepage=forge_get_config('web_host').'/projects/'.$this->getUnixName().'/';
573 if (strlen(htmlspecialchars($short_description))>255) {
574 $this->setError(_('Error updating project information: Maximum length for Project Description is 255 chars.'));
580 //XXX not yet actived logo_image_id='$logo_image_id',
581 $res = db_query_params ('UPDATE groups
584 short_description=$3,
589 use_pm_depend_box=$8,
601 array(htmlspecialchars($group_name),
603 htmlspecialchars($short_description),
622 $this->setError(sprintf(_('Error updating project information: %s'), db_error()));
627 if ($this->setTags($tags) === false) {
632 $hook_params = array();
633 $hook_params['group'] = $this;
634 $hook_params['group_id'] = $this->getID();
635 $hook_params['group_homepage'] = $homepage;
636 $hook_params['group_name'] = htmlspecialchars($group_name);
637 $hook_params['group_description'] = htmlspecialchars($short_description);
638 $hook_params['group_ispublic'] = $is_public;
639 if (!plugin_hook("group_update", $hook_params)) {
640 if (!$this->isError()) {
641 $this->setError(_('Error updating project information in plugin_hook group_update'));
647 // Log the audit trail
648 $this->addHistory('Changed Public Info', '');
650 if (!$this->fetchData($this->getID())) {
659 * getID - Simply return the group_id for this object.
661 * @return int group_id.
664 return $this->data_array['group_id'];
668 * getType() - Foundry, project, etc.
670 * @return int The type flag from the database.
673 return $this->data_array['type_id'];
678 * getStatus - the status code.
680 * Statuses char include I,H,A,D.
682 function getStatus() {
683 return $this->data_array['status'];
687 * setStatus - set the status code.
689 * Statuses include I,H,A,D.
691 * @param object User requesting operation (for access control).
692 * @param string Status value.
693 * @return boolean success.
696 function setStatus(&$user, $status) {
699 if (!forge_check_global_perm ('approve_projects')) {
700 $this->setPermissionDeniedError();
704 // Projects in 'A' status can only go to 'H' or 'D'
705 // Projects in 'D' status can only go to 'A'
706 // Projects in 'P' status can only go to 'A' OR 'D'
707 // Projects in 'I' status can only go to 'P'
708 // Projects in 'H' status can only go to 'A' OR 'D'
709 $allowed_status_changes = array(
710 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
711 'IP'=>1,'HA'=>1,'HD'=>1
714 // Check that status transition is valid
715 if ($this->getStatus() != $status
716 && !$allowed_status_changes[$this->getStatus().$status]) {
717 $this->setError(_('Invalid Status Change'));
723 $res = db_query_params('UPDATE groups
725 WHERE group_id=$2', array($status, $this->getID()));
727 if (!$res || db_affected_rows($res) < 1) {
728 $this->setError(sprintf(_('ERROR: DB: Could not change group status: %s'),db_error()));
734 // Activate system group, if not yet
735 if (!$SYS->sysCheckGroup($this->getID())) {
736 if (!$SYS->sysCreateGroup($this->getID())) {
737 $this->setError($SYS->getErrorMessage());
742 if (!$this->activateUsers()) {
747 /* Otherwise, the group is not active, and make sure that
748 System group is not active either */
749 } else if ($SYS->sysCheckGroup($this->getID())) {
750 if (!$SYS->sysRemoveGroup($this->getID())) {
751 $this->setError($SYS->getErrorMessage());
757 $hook_params = array ();
758 $hook_params['group'] = $this;
759 $hook_params['group_id'] = $this->getID();
760 $hook_params['status'] = $status;
761 plugin_hook("group_setstatus", $hook_params);
765 // Log the audit trail
766 if ($status != $this->getStatus()) {
767 $this->addHistory('Status', $this->getStatus());
770 $this->data_array['status'] = $status;
775 * isProject - Simple boolean test to see if it's a project or not.
777 * @return boolean is_project.
779 function isProject() {
780 if ($this->getType()==1) {
788 * isPublic - Simply returns the is_public flag from the database.
790 * @return boolean is_public.
792 function isPublic() {
793 return $this->data_array['is_public'];
797 * isActive - Database field status of 'A' returns true.
799 * @return boolean is_active.
801 function isActive() {
802 if ($this->getStatus()=='A') {
810 * getUnixName - the unix_name
812 * @return string unix_name.
814 function getUnixName() {
815 return strtolower($this->data_array['unix_group_name']);
819 * getPublicName - the full-length public name.
821 * @return string The group_name.
823 function getPublicName() {
824 return $this->data_array['group_name'];
828 * getRegisterPurpose - the text description of the purpose of this project.
830 * @return string The description.
832 function getRegisterPurpose() {
833 return $this->data_array['register_purpose'];
837 * getDescription - the text description of this project.
839 * @return string The description.
841 function getDescription() {
842 return $this->data_array['short_description'];
846 * getStartDate - the unix time this project was registered.
848 * @return int (unix time) of registration.
850 function getStartDate() {
851 return $this->data_array['register_time'];
855 * getLogoImageID - the id of the logo in the database for this project.
857 * @return int The ID of logo image in db_images table (or 100 if none).
859 function getLogoImageID() {
860 return $this->data_array['logo_image_id'];
864 * getUnixBox - the hostname of the unix box where this project is located.
866 * @return string The name of the unix machine for the group.
868 function getUnixBox() {
869 return $this->data_array['unix_box'];
873 * getSCMBox - the hostname of the scm box where this project is located.
875 * @return string The name of the unix machine for the group.
877 function getSCMBox() {
878 return $this->data_array['scm_box'];
881 * setSCMBox - the hostname of the scm box where this project is located.
883 * @param string The name of the new SCM_BOX
885 function setSCMBox($scm_box) {
887 if ($scm_box == $this->data_array['scm_box']) {
892 $res = db_query_params ('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array ($scm_box, $this->getID ()));
894 $this->addHistory('scm_box', $this->data_array['scm_box']);
895 $this->data_array['scm_box']=$scm_box;
900 $this->setError(_("Couldn't insert SCM_BOX to database"));
904 $this->setError(_("SCM Box can't be empty"));
910 * getDomain - the hostname.domain where their web page is located.
912 * @return string The name of the group [web] domain.
914 function getDomain() {
915 return $this->data_array['http_domain'];
919 * getLicense - the license they chose.
921 * @return int ident of group license.
923 function getLicense() {
924 return $this->data_array['license'];
928 * getLicenseName - the name of the license
930 * @return string license name
932 function getLicenseName() {
933 $licenses =& group_get_licenses();
934 if(isset($licenses[$this->data_array['license']])) {
935 return $licenses[$this->data_array['license']];
942 * getLicenseOther - optional string describing license.
944 * @return string The custom license.
946 function getLicenseOther() {
947 if ($this->getLicense() == GROUP_LICENSE_OTHER) {
948 return $this->data_array['license_other'];
955 * getRegistrationPurpose - the text description of the purpose of this project.
957 * @return string The application for project hosting.
959 function getRegistrationPurpose() {
960 return $this->data_array['register_purpose'];
965 * getAdmins() - Get array of Admin user objects.
967 * @return array Array of User objects.
969 function &getAdmins() {
970 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID());
972 $user_ids = array() ;
974 foreach ($roles as $role) {
975 if (! ($role instanceof RoleExplicit)) {
978 if ($role->getHomeProject() == NULL
979 || $role->getHomeProject()->getID() != $this->getID()) {
983 foreach ($role->getUsers() as $u) {
984 $user_ids[] = $u->getID();
987 return user_get_objects(array_unique($user_ids));
991 Common Group preferences for tools
995 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
997 * @return boolean enable_scm.
999 function enableAnonSCM() {
1001 $r = RoleAnonymous::getInstance();
1002 return $r->hasPermission('scm', $this->getID(), 'read');
1004 if ($this->isPublic() && $this->usesSCM()) {
1005 return $this->data_array['enable_anonscm'];
1012 function SetUsesAnonSCM($booleanparam) {
1014 $booleanparam = $booleanparam ? 1 : 0;
1016 $r = RoleAnonymous::getInstance();
1017 $r->setSetting('scm', $this->getID(), $booleanparam);
1020 $res = db_query_params('UPDATE groups SET enable_anonscm=$1 WHERE group_id=$2',
1021 array($booleanparam, $this->getID()));
1023 $this->data_array['enable_anonscm'] = $booleanparam;
1032 function setUsesSCM($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;
1047 * enablePserver - whether or not this group has opted to enable Pserver.
1049 * @return boolean enable_pserver.
1051 function enablePserver() {
1052 if ($this->usesSCM()) {
1053 return $this->data_array['enable_pserver'];
1059 function SetUsesPserver($booleanparam) {
1061 $booleanparam = $booleanparam ? 1 : 0 ;
1062 $res = db_query_params('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1063 array($booleanparam, $this->getID()));
1065 $this->data_array['enable_pserver'] = $booleanparam;
1074 * usesSCM - whether or not this group has opted to use SCM.
1076 * @return boolean uses_scm.
1078 function usesSCM() {
1079 if (forge_get_config('use_scm')) {
1080 return $this->data_array['use_scm'];
1087 * usesMail - whether or not this group has opted to use mailing lists.
1089 * @return boolean uses_mail.
1091 function usesMail() {
1092 if (forge_get_config('use_mail')) {
1093 return $this->data_array['use_mail'];
1100 * usesNews - whether or not this group has opted to use news.
1102 * @return boolean uses_news.
1104 function usesNews() {
1105 if (forge_get_config('use_news')) {
1106 return $this->data_array['use_news'];
1113 * usesForum - whether or not this group has opted to use discussion forums.
1115 * @return boolean uses_forum.
1117 function usesForum() {
1118 if (forge_get_config('use_forum')) {
1119 return $this->data_array['use_forum'];
1126 * usesStats - whether or not this group has opted to use stats.
1128 * @return boolean uses_stats.
1130 function usesStats() {
1131 return $this->data_array['use_stats'];
1135 * usesFRS - whether or not this group has opted to use file release system.
1137 * @return boolean uses_frs.
1139 function usesFRS() {
1140 if (forge_get_config('use_frs')) {
1141 return $this->data_array['use_frs'];
1148 * usesTracker - whether or not this group has opted to use tracker.
1150 * @return boolean uses_tracker.
1152 function usesTracker() {
1153 if (forge_get_config('use_tracker')) {
1154 return $this->data_array['use_tracker'];
1161 * useCreateOnline - whether or not this group has opted to use create online documents option.
1163 * @return boolean use_docman_create_online.
1165 function useCreateOnline() {
1166 if (forge_get_config('use_docman')) {
1167 return $this->data_array['use_docman_create_online'];
1174 * usesDocman - whether or not this group has opted to use docman.
1176 * @return boolean use_docman.
1178 function usesDocman() {
1179 if (forge_get_config('use_docman')) {
1180 return $this->data_array['use_docman'];
1187 * useDocmanSearch - whether or not this group has opted to use docman search engine.
1189 * @return boolean use_docman_search.
1191 function useDocmanSearch() {
1192 if (forge_get_config('use_docman')) {
1193 return $this->data_array['use_docman_search'];
1200 * useWebdav - whether or not this group has opted to use webdav interface.
1202 * @return boolean use_docman_search.
1204 function useWebdav() {
1205 if (forge_get_config('use_webdav')) {
1206 return $this->data_array['use_webdav'];
1213 * usesFTP - whether or not this group has opted to use FTP.
1215 * @return boolean uses_ftp.
1217 function usesFTP() {
1218 if (forge_get_config('use_ftp')) {
1219 return $this->data_array['use_ftp'];
1226 * usesSurvey - whether or not this group has opted to use surveys.
1228 * @return boolean uses_survey.
1230 function usesSurvey() {
1231 if (forge_get_config('use_survey')) {
1232 return $this->data_array['use_survey'];
1239 * usesPM - whether or not this group has opted to Project Manager.
1241 * @return boolean uses_projman.
1244 if (forge_get_config('use_pm')) {
1245 return $this->data_array['use_pm'];
1252 * getPlugins - get a list of all available group plugins
1254 * @return array array containing plugin_id => plugin_name
1256 function getPlugins() {
1257 if (!isset($this->plugins_data)) {
1258 $this->plugins_data = array();
1259 $res = db_query_params('SELECT group_plugin.plugin_id, plugins.plugin_name
1260 FROM group_plugin, plugins
1261 WHERE group_plugin.group_id=$1
1262 AND group_plugin.plugin_id=plugins.plugin_id', array($this->getID()));
1263 $rows = db_numrows($res);
1265 for ($i=0; $i<$rows; $i++) {
1266 $plugin_id = db_result($res, $i, 'plugin_id');
1267 $this->plugins_data[$plugin_id] = db_result($res, $i, 'plugin_name');
1270 return $this->plugins_data ;
1274 * usesPlugin - returns true if the group uses a particular plugin
1276 * @param string name of the plugin
1277 * @return boolean whether plugin is being used or not
1279 function usesPlugin($pluginname) {
1280 $plugins_data = $this->getPlugins();
1281 foreach ($plugins_data as $p_id => $p_name) {
1282 if ($p_name == $pluginname) {
1290 * added for Codendi compatibility
1291 * usesServices - returns true if the group uses a particular plugin or feature
1293 * @param string name of the plugin
1294 * @return boolean whether plugin is being used or not
1296 function usesService($feature) {
1297 $plugins_data = $this->getPlugins();
1298 $pm = plugin_manager_get_object();
1299 foreach ($plugins_data as $p_id => $p_name) {
1300 if ($p_name == $feature) {
1303 if ($pm->getPluginByName($p_name)->provide($feature)) {
1311 * setPluginUse - enables/disables plugins for the group
1313 * @param string name of the plugin
1314 * @param boolean the new state
1315 * @return string database result
1317 function setPluginUse($pluginname, $val=true) {
1318 if ($val == $this->usesPlugin($pluginname)) {
1319 // State is already good, returning
1322 $res = db_query_params('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1323 array($pluginname));
1324 $rows = db_numrows($res);
1326 // Error: no plugin by that name
1329 $plugin_id = db_result($res,0,'plugin_id');
1331 unset ($this->plugins_data);
1333 $res = db_query_params('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1334 array($this->getID(),
1338 $res = db_query_params('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1339 array($this->getID(),
1346 * getDocEmailAddress - get email address(es) to send doc notifications to.
1348 * @return string email address.
1350 function getDocEmailAddress() {
1351 return $this->data_array['new_doc_address'];
1355 * DocEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1357 * @return boolean email_on_all_doc_updates.
1359 function docEmailAll() {
1360 return $this->data_array['send_all_docs'];
1365 * getHomePage - The URL for this project's home page.
1367 * @return string homepage URL.
1369 function getHomePage() {
1370 return $this->data_array['homepage'];
1374 * getTags - Tags of this project.
1376 * @return string List of tags.
1378 function getTags() {
1379 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1380 $res = db_query_params($sql, array($this->getID()));
1381 return join(', ', util_result_column_to_array($res));
1385 * setTags - Set tags of this project.
1387 * @return string database result.
1389 function setTags($tags) {
1391 $sql='DELETE FROM project_tags WHERE group_id=$1';
1392 $res=db_query_params($sql, array($this->getID()));
1394 $this->setError('Deleting old tags: '.db_error());
1398 $inserted = array();
1399 $tags_array = preg_split('/[;,]/', $tags);
1400 foreach ($tags_array as $tag) {
1401 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1402 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1403 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1404 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1409 if ($tag == '' || array_search($tag, $inserted) !== false) continue;
1410 $sql='INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1411 $res=db_query_params($sql, array($this->getID(), $tag));
1413 $this->setError(_('Setting tags: ').db_error());
1424 * getPermission - Return a Permission for this Group
1426 * @return object The Permission.
1428 function &getPermission() {
1429 return permission_get_object($this);
1433 function delete($sure, $really_sure, $really_really_sure) {
1434 if (!$sure || !$really_sure || !$really_really_sure) {
1435 $this->setMissingParamsError();
1438 if ($this->getID() == forge_get_config('news_group') ||
1439 $this->getID() == 1 ||
1440 $this->getID() == forge_get_config('stats_group') ||
1441 $this->getID() == forge_get_config('peer_rating_group')) {
1442 $this->setError(_('Cannot Delete System Group'));
1445 $perm =& $this->getPermission();
1446 if (!$perm || !is_object($perm)) {
1447 $this->setPermissionDeniedError();
1449 } elseif ($perm->isError()) {
1450 $this->setPermissionDeniedError();
1452 } elseif (!$perm->isSuperUser()) {
1453 $this->setPermissionDeniedError();
1459 // Remove all the members
1461 $members = $this->getMembers();
1462 for ($i=0; $i<count($members); $i++) {
1463 $this->removeUser($members[$i]->getID());
1465 // Failsafe until user_group table is gone
1466 $res = db_query_params('DELETE FROM user_group WHERE group_id=$1',
1467 array($this->getID()));
1471 $atf = new ArtifactTypeFactory($this);
1472 $at_arr =& $atf->getArtifactTypes();
1473 for ($i=0; $i<count($at_arr); $i++) {
1474 if (!is_object($at_arr[$i])) {
1475 printf(_("Not Object: ArtifactType: %d"), $i);
1478 $at_arr[$i]->delete(1,1);
1483 $ff = new ForumFactory($this);
1484 $f_arr =& $ff->getForums();
1485 for ($i=0; $i<count($f_arr); $i++) {
1486 if (!is_object($f_arr[$i])) {
1487 printf(_("Not Object: Forum: %d"), $i);
1490 if(!$f_arr[$i]->delete(1,1)) {
1491 $this->setError(_('Could not properly delete the forum'));
1495 // Delete Subprojects
1497 $pgf = new ProjectGroupFactory($this);
1498 $pg_arr = $pgf->getProjectGroups();
1499 for ($i=0; $i<count($pg_arr); $i++) {
1500 if (!is_object($pg_arr[$i])) {
1501 printf(_("Not Object: ProjectGroup: %d"), $i);
1504 $pg_arr[$i]->delete(1,1);
1507 // Delete FRS Packages
1509 //$frspf = new FRSPackageFactory($this);
1510 $res = db_query_params('SELECT * FROM frs_package WHERE group_id=$1',
1511 array($this->getID()));
1512 //echo 'frs_package'.db_error();
1513 //$frsp_arr =& $frspf->getPackages();
1514 while ($arr = db_fetch_array($res)) {
1515 //if (!is_object($pg_arr[$i])) {
1516 // echo "Not Object: ProjectGroup: ".$i;
1519 $frsp=new FRSPackage($this, $arr['package_id'], $arr);
1520 $frsp->delete(1, 1);
1525 $news_group=group_get_object(forge_get_config('news_group'));
1526 $res = db_query_params ('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1527 array ($this->getID())) ;
1529 $this->setError(_('Error Deleting News: ').db_error());
1534 for ($i=0; $i<db_numrows($res); $i++) {
1535 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1536 if (!$Forum->delete(1,1)) {
1537 printf (_("Could Not Delete News Forum: %d"),$Forum->getID());
1540 $res = db_query_params ('DELETE FROM news_bytes WHERE group_id=$1',
1541 array ($this->getID())) ;
1543 $this->setError(_('Error Deleting News: ').db_error());
1551 $res = db_query_params ('DELETE FROM doc_data WHERE group_id=$1',
1552 array ($this->getID())) ;
1554 $this->setError(_('Error Deleting Documents: ').db_error());
1559 $res = db_query_params ('DELETE FROM doc_groups WHERE group_id=$1',
1560 array ($this->getID())) ;
1562 $this->setError(_('Error Deleting Documents: ').db_error());
1570 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1572 $this->setError(_('Error Deleting Tags: ').db_error());
1578 // Delete group history
1580 $res = db_query_params ('DELETE FROM group_history WHERE group_id=$1',
1581 array ($this->getID())) ;
1583 $this->setError(_('Error Deleting Project History: ').db_error());
1589 // Delete group plugins
1591 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1',
1592 array ($this->getID())) ;
1594 $this->setError(_('Error Deleting Project Plugins: ').db_error());
1600 // Delete group cvs stats
1602 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1603 array ($this->getID())) ;
1605 $this->setError(_('Error Deleting SCM Statistics: ').db_error());
1613 $sf = new SurveyFactory($this);
1614 $s_arr =& $sf->getSurveys();
1615 for ($i=0; $i<count($s_arr); $i++) {
1616 if (!is_object($s_arr[$i])) {
1617 printf (_("Not Object: Survey: %d"),$i);
1620 $s_arr[$i]->delete();
1623 // Delete SurveyQuestions
1625 $sqf = new SurveyQuestionFactory($this);
1626 $sq_arr =& $sqf->getSurveyQuestions();
1627 for ($i=0; $i<count($sq_arr); $i++) {
1628 if (!is_object($sq_arr[$i])) {
1629 printf (_("Not Object: SurveyQuestion: %d"),$i);
1632 $sq_arr[$i]->delete();
1635 // Delete Mailing List Factory
1637 $mlf = new MailingListFactory($this);
1638 $ml_arr =& $mlf->getMailingLists();
1639 for ($i=0; $i<count($ml_arr); $i++) {
1640 if (!is_object($ml_arr[$i])) {
1641 printf (_("Not Object: MailingList: %d"),$i);
1644 if (!$ml_arr[$i]->delete(1,1)) {
1645 $this->setError(_('Could not properly delete the mailing list'));
1651 $res = db_query_params ('DELETE FROM trove_group_link WHERE group_id=$1',
1652 array ($this->getID())) ;
1654 $this->setError(_('Error Deleting Trove: ').db_error());
1659 $res = db_query_params ('DELETE FROM trove_agg WHERE group_id=$1',
1660 array ($this->getID())) ;
1662 $this->setError(_('Error Deleting Trove: ').db_error());
1670 $res = db_query_params('DELETE FROM project_sums_agg WHERE group_id=$1',
1671 array($this->getID()));
1673 $this->setError(_('Error Deleting Counters: ').db_error());
1678 $res = db_query_params('INSERT INTO deleted_groups (unix_group_name, delete_date, isdeleted) VALUES ($1, $2, $3)',
1679 array($this->getUnixName(),
1683 $this->setError(_('Error Deleting Project: ').db_error());
1688 $res = db_query_params('DELETE FROM groups WHERE group_id=$1',
1689 array($this->getID()));
1691 $this->setError(_('Error Deleting Project: ').db_error());
1701 $hook_params = array ();
1702 $hook_params['group'] = $this;
1703 $hook_params['group_id'] = $this->getID();
1704 plugin_hook("group_delete", $hook_params);
1706 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
1707 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
1709 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
1710 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
1715 $res = db_query_params('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
1716 array ($this->getID()));
1717 //echo 'rep_group_act_monthly'.db_error();
1718 $res = db_query_params('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
1719 array ($this->getID()));
1720 //echo 'rep_group_act_weekly'.db_error();
1721 $res = db_query_params('DELETE FROM rep_group_act_daily WHERE group_id=$1',
1722 array ($this->getID()));
1723 //echo 'rep_group_act_daily'.db_error();
1724 unset($this->data_array);
1730 Basic functions to add/remove users to/from a group
1731 and update their permissions
1735 * addUser - controls adding a user to a group.
1737 * @param string Unix name of the user to add OR integer user_id.
1738 * @param int The role_id this user should have.
1739 * @return boolean success.
1742 function addUser($user_identifier,$role_id) {
1745 Admins can add users to groups
1748 if (!forge_check_perm ('project_admin', $this->getID())) {
1749 $this->setPermissionDeniedError();
1755 get user id for this user's unix_name
1757 if (is_int ($user_identifier)) { // user_id or user_name
1758 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array ($user_identifier)) ;
1760 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array ($user_identifier)) ;
1762 if (db_numrows($res_newuser) > 0) {
1764 // make sure user is active
1766 if (db_result($res_newuser,0,'status') != 'A') {
1767 $this->setError(_('User is not active. Only active users can be added.'));
1773 // user was found - set new user_id var
1775 $user_id = db_result($res_newuser,0,'user_id');
1777 $role = new Role($this,$role_id);
1778 if (!$role || !is_object($role)) {
1779 $this->setError(_('Error Getting Role Object'));
1782 } elseif ($role->isError()) {
1783 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1789 $role->addUser (user_get_object ($user_id)) ;
1790 if (!$SYS->sysCheckCreateGroup($this->getID())){
1791 $this->setError($SYS->getErrorMessage());
1795 if (!$SYS->sysCheckCreateUser($user_id)) {
1796 $this->setError($SYS->getErrorMessage());
1803 // if not already a member, add them
1805 $res_member = db_query_params ('SELECT user_id
1807 WHERE user_id=$1 AND group_id=$2',
1808 array ($user_id, $this->getID())) ;
1810 if (db_numrows($res_member) < 1) {
1812 // Create this user's row in the user_group table
1814 $res = db_query_params ('INSERT INTO user_group
1815 (user_id,group_id,admin_flags,forum_flags,project_flags,
1816 doc_flags,cvs_flags,member_role,release_flags,artifact_flags)
1817 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)',
1829 //verify the insert worked
1830 if (!$res || db_affected_rows($res) < 1) {
1831 $this->setError(sprintf(_('ERROR: Could Not Add User To Group: %s'),db_error()));
1836 // check and create if group doesn't exists
1838 //echo "<h2>Group::addUser SYS->sysCheckCreateGroup(".$this->getID().")</h2>";
1839 if (!$SYS->sysCheckCreateGroup($this->getID())){
1840 $this->setError($SYS->getErrorMessage());
1845 // check and create if user doesn't exists
1847 //echo "<h2>Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1848 if (!$SYS->sysCheckCreateUser($user_id)) {
1849 $this->setError($SYS->getErrorMessage());
1856 //echo "<h2>Group::addUser role->setUser($user_id)</h2>";
1857 if (!$role->setUser($user_id)) {
1858 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1864 // user was already a member
1865 // make sure they are set up
1867 $user=&user_get_object($user_id,$res_newuser);
1868 $user->fetchData($user->getID());
1869 $role = new Role($this,$role_id);
1870 if (!$role || !is_object($role)) {
1871 $this->setError(_('Error Getting Role Object'));
1874 } elseif ($role->isError()) {
1875 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1879 //echo "<h2>Already Member Group::addUser role->setUser($user_id)</h2>";
1880 if (!$role->setUser($user_id)) {
1881 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1886 // set up their system info
1888 //echo "<h2>Already Member Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1889 if (!$SYS->sysCheckCreateUser($user_id)) {
1890 $this->setError($SYS->getErrorMessage());
1898 // user doesn't exist
1900 $this->setError(_('ERROR: User does not exist'));
1905 $hook_params['group'] = $this;
1906 $hook_params['group_id'] = $this->getID();
1907 $hook_params['user'] = &user_get_object($user_id);
1908 $hook_params['user_id'] = $user_id;
1909 plugin_hook ("group_adduser", $hook_params);
1914 $this->addHistory('Added User',$user_identifier);
1920 * removeUser - controls removing a user from a group.
1922 * Users can remove themselves.
1924 * @param int The ID of the user to remove.
1925 *@return boolean success.
1927 function removeUser($user_id) {
1930 if ($user_id != user_getid()
1931 || !forge_check_perm ('project_admin', $this->getID())) {
1932 $this->setPermissionDeniedError();
1939 $user = user_get_object ($user_id) ;
1940 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
1941 $found_role = NULL ;
1942 foreach ($roles as $role) {
1943 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
1944 $found_role = $role ;
1948 if ($found_role == NULL) {
1949 $this->setError(sprintf(_('ERROR: User not removed: %s')));
1953 $found_role->removeUser ($user) ;
1954 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
1955 $this->setError($SYS->getErrorMessage());
1961 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1 AND user_id=$2',
1962 array ($this->getID(),
1964 if (!$res || db_affected_rows($res) < 1) {
1965 $this->setError(sprintf(_('ERROR: User not removed: %s'),db_error()));
1972 // reassign open artifacts to id=100
1974 $res = db_query_params ('UPDATE artifact SET assigned_to=100
1975 WHERE group_artifact_id
1976 IN (SELECT group_artifact_id
1977 FROM artifact_group_list
1978 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
1979 array ($this->getID(),
1982 $this->setError(sprintf(_('ERROR: DB: artifact: %s'),db_error()));
1988 // reassign open tasks to id=100
1989 // first have to purge any assignments that would cause
1990 // conflict with existing assignment to 100
1992 $res = db_query_params ('DELETE FROM project_assigned_to
1993 WHERE project_task_id IN (SELECT pt.project_task_id
1994 FROM project_task pt, project_group_list pgl, project_assigned_to pat
1995 WHERE pt.group_project_id = pgl.group_project_id
1996 AND pat.project_task_id=pt.project_task_id
1997 AND pt.status_id=1 AND pgl.group_id=$1
1998 AND pat.assigned_to_id=$2)
1999 AND assigned_to_id=100',
2000 array ($this->getID(),
2003 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),1,db_error()));
2007 $res = db_query_params ('UPDATE project_assigned_to SET assigned_to_id=100
2008 WHERE project_task_id IN (SELECT pt.project_task_id
2009 FROM project_task pt, project_group_list pgl
2010 WHERE pt.group_project_id = pgl.group_project_id
2011 AND pt.status_id=1 AND pgl.group_id=$1)
2012 AND assigned_to_id=$2',
2013 array ($this->getID(),
2016 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),2,db_error()));
2022 // Remove user from system
2024 if (!$SYS->sysGroupRemoveUser($this->getID(),$user_id)) {
2025 $this->setError($SYS->getErrorMessage());
2030 $hook_params['group'] = $this;
2031 $hook_params['group_id'] = $this->getID();
2032 $hook_params['user'] = &user_get_object($user_id);
2033 $hook_params['user_id'] = $user_id;
2034 plugin_hook ("group_removeuser", $hook_params);
2037 $this->addHistory('Removed User',$user_id);
2044 * updateUser - controls updating a user's role in this group.
2046 * @param int The ID of the user.
2047 * @param int The role_id to set this user to.
2048 * @return boolean success.
2050 function updateUser($user_id,$role_id) {
2053 if (!forge_check_perm ('project_admin', $this->getID())) {
2054 $this->setPermissionDeniedError();
2059 $newrole = RBACEngine::getInstance()->getRoleById ($role_id) ;
2060 if (!$newrole || !is_object($newrole)) {
2061 $this->setError(_('Could Not Get Role'));
2063 } elseif ($newrole->isError()) {
2064 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2066 } elseif ($newrole->getHomeProject() == NULL
2067 || $newrole->getHomeProject()->getID() != $this->getID()) {
2068 $this->setError(_('Wrong destination role'));
2071 $user = user_get_object ($user_id) ;
2072 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
2073 $found_role = NULL ;
2074 foreach ($roles as $role) {
2075 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2076 $found_role = $role ;
2080 if ($found_role == NULL) {
2081 $this->setError(sprintf(_('ERROR: User not removed: %s')));
2085 $found_role->removeUser ($user) ;
2086 $newrole->addUser ($user) ;
2088 $role = new Role($this,$role_id);
2089 if (!$role || !is_object($role)) {
2090 $this->setError(_('Could Not Get Role'));
2092 } elseif ($role->isError()) {
2093 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2096 //echo "<h3>Group::updateUser role->setUser($user_id)</h3>";
2097 if (!$role->setUser($user_id)) {
2098 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2103 $this->addHistory('Updated User',$user_id);
2108 * addHistory - Makes an audit trail entry for this project.
2110 * @param string The name of the field.
2111 * @param string The Old Value for this $field_name.
2112 * @return database result handle.
2115 function addHistory($field_name, $old_value) {
2116 return db_query_params ('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2117 VALUES ($1,$2,$3,$4,$5)',
2118 array ($this->getID(),
2126 * activateUsers - Make sure that group members have unix accounts.
2128 * Setup unix accounts for group members. Can be called even
2129 * if members are already active.
2133 function activateUsers() {
2135 Activate member(s) of the project
2139 $members = $this->getUsers (true) ;
2141 foreach ($members as $member) {
2143 foreach (RBACEngine::getInstance()->getAvailableRolesForUser ($member) as $role) {
2144 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2147 if (!$this->addUser($member->getUnixName(),$role->getID())) {
2154 $res_member = db_query_params('SELECT user_id,role_id FROM user_group WHERE group_id=$1',
2155 array ($this->getID()));
2156 while ($row_member = db_fetch_array($res_member)) {
2157 $u = user_get_object($row_member['user_id']);
2158 if (!$this->addUser($u->getUnixName(),$row_member['role_id'])) {
2168 * getMembers - returns array of User objects for this project
2170 * @return array of User objects for this group.
2172 function getMembers() {
2173 return $this->getUsers (true) ;
2177 * approve - Approve pending project.
2179 * @param object The User object who is doing the updating.
2182 function approve(&$user) {
2184 if ($this->getStatus()=='A') {
2185 $this->setError(_("Group already active"));
2191 // Step 1: Activate group and create LDAP entries
2192 if (!$this->setStatus($user, 'A')) {
2197 // Switch to system language for item creation
2198 setup_gettext_from_sys_lang ();
2200 // Create default roles
2202 $idadmin_group = NULL ;
2203 foreach (get_group_join_requests ($this) as $gjr) {
2204 $idadmin_group = $gjr->getUserID() ;
2207 if ($idadmin_group == NULL) {
2208 $idadmin_group = $user->getID();
2211 $admin_group = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1 AND admin_flags=$2',
2212 array ($this->getID(),
2214 if (db_numrows($admin_group) > 0) {
2215 $idadmin_group = db_result($admin_group,0,'user_id');
2217 $idadmin_group = $user->getID();
2218 db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags) VALUES ($1, $2, $3)',
2219 array ($idadmin_group,
2225 $role = new Role($this);
2226 $todo = array_keys($role->defaults);
2227 for ($c=0; $c<count($todo); $c++) {
2228 $role = new Role($this);
2229 if (! ($role_id = $role->createDefault($todo[$c]))) {
2230 $this->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
2232 setup_gettext_from_context();
2235 $role = new Role($this, $role_id);
2236 if ($role->getVal('projectadmin',0)=='A') {
2237 $role->setUser($idadmin_group);
2242 $roles = $this->getRoles() ;
2243 foreach ($roles as $r) {
2244 if ($r->getSetting ('project_admin', $this->getID())) {
2245 $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) ;
2256 // Tracker Integration
2259 if (forge_get_config ('use_tracker')) {
2260 $ats = new ArtifactTypes($this);
2261 if (!$ats || !is_object($ats)) {
2262 $this->setError(_('Error creating ArtifactTypes object'));
2264 setup_gettext_from_context();
2266 } else if ($ats->isError()) {
2267 $this->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
2269 setup_gettext_from_context();
2272 if (!$ats->createTrackers()) {
2273 $this->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
2275 setup_gettext_from_context();
2282 // Forum Integration
2285 if (forge_get_config ('use_forum')) {
2286 $f = new Forum($this);
2287 if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
2288 $this->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
2290 setup_gettext_from_context();
2293 $f = new Forum($this);
2294 if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
2295 $this->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
2297 setup_gettext_from_context();
2300 $f = new Forum($this);
2301 if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
2302 $this->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
2304 setup_gettext_from_context();
2311 // Doc Mgr Integration
2314 if (forge_get_config('use_docman')) {
2315 $dg = new DocumentGroup($this);
2316 if (!$dg->create(_('Uncategorized Submissions'))) {
2317 $this->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
2319 setup_gettext_from_context();
2329 if (forge_get_config ('use_frs')) {
2330 $frs = new FRSPackage($this);
2331 if (!$frs->create($this->getUnixName())) {
2332 $this->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
2334 setup_gettext_from_context();
2344 if (forge_get_config ('use_pm')) {
2345 $pg = new ProjectGroup($this);
2346 if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
2347 $this->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
2349 setup_gettext_from_context();
2352 $pg = new ProjectGroup($this);
2353 if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
2354 $this->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
2356 setup_gettext_from_context();
2361 // Set permissions for roles
2363 if ($this->isPublic()) {
2364 $ra = RoleAnonymous::getInstance() ;
2365 $rl = RoleLoggedIn::getInstance() ;
2366 $ra->linkProject ($this) ;
2367 $rl->linkProject ($this) ;
2369 $ra->setSetting ('project_read', $this->getID(), 1) ;
2370 $rl->setSetting ('project_read', $this->getID(), 1) ;
2372 $ra->setSetting ('frs', $this->getID(), 1) ;
2373 $rl->setSetting ('frs', $this->getID(), 1) ;
2375 $ra->setSetting ('docman', $this->getID(), 1) ;
2376 $rl->setSetting ('docman', $this->getID(), 1) ;
2378 $ff = new ForumFactory ($this) ;
2379 foreach ($ff->getAllForumIds() as $fid) {
2380 $f = forum_get_object ($fid) ;
2381 if ($f->isPublic()) {
2382 $l = $f->getModerationLevel() ;
2384 $rl->setSetting('forum', $fid, 3);
2386 $rl->setSetting('forum', $fid, 2);
2388 if ($f->allowAnonymous()) {
2390 $ra->setSetting('forum', $fid, 3);
2392 $ra->setSetting('forum', $fid, 2);
2395 $ra->setSetting('forum', $fid, 1);
2400 $pgf = new ProjectGroupFactory($this);
2401 foreach ($pgf->getAllProjectGroupIds() as $pgid) {
2402 $pg = projectgroup_get_object($pgid);
2403 if ($pg->isPublic()) {
2404 $ra->setSetting('pm', $pgid, 1);
2405 $rl->setSetting('pm', $pgid, 1);
2409 $atf = new ArtifactTypeFactory($this);
2410 foreach ($atf->getAllArtifactTypeIds() as $atid) {
2411 $at = artifactType_get_object($atid);
2412 if ($at->isPublic()) {
2413 $ra->setSetting('tracker', $atid, 1);
2414 $rl->setSetting('tracker', $atid, 1);
2418 foreach (get_group_join_requests($this) as $gjr) {
2425 // Create MailingList
2428 if (forge_get_config('use_mail')) {
2429 $mlist = new MailingList($this);
2430 if (!$mlist->create('commits', _('Commits'), 1, $idadmin_group)) {
2431 $this->setError(sprintf(_('ML: %s'), $mlist->getErrorMessage()));
2433 setup_gettext_from_context();
2438 $this->normalizeAllRoles();
2440 // Switch back to user preference
2441 session_set_internal($saved_session->getID());
2442 setup_gettext_from_context();
2446 $this->sendApprovalEmail();
2447 $this->addHistory('Approved', 'x');
2450 // Plugin can make approve operation there
2452 $params[0] = $idadmin_group;
2453 $params[1] = $this->getID();
2454 plugin_hook('group_approved', $params);
2462 * sendApprovalEmail - Send new project email.
2464 * @return boolean success.
2467 function sendApprovalEmail() {
2468 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID()) ;
2470 if (count($admins) < 1) {
2471 $this->setError(_("Group does not have any administrators."));
2475 // send one email per admin
2476 foreach ($admins as $admin) {
2477 setup_gettext_for_user ($admin) ;
2479 $message=sprintf(_('Your project registration for %4$s has been approved.
2481 Project Full Name: %1$s
2482 Project Unix Name: %2$s
2484 Your DNS will take up to a day to become active on our site.
2485 Your web site is accessible through your shell account. Please read
2486 site documentation (see link below) about intended usage, available
2487 services, and directory layout of the account.
2490 own project page in %4$s while logged in, you will find
2491 additional menu functions to your left labeled \'Project Admin\'.
2493 We highly suggest that you now visit %4$s and create a public
2494 description for your project. This can be done by visiting your project
2495 page while logged in, and selecting \'Project Admin\' from the menus
2496 on the left (or by visiting %3$s
2499 Your project will also not appear in the Trove Software Map (primary
2500 list of projects hosted on %4$s which offers great flexibility in
2501 browsing and search) until you categorize it in the project administration
2502 screens. So that people can find your project, you should do this now.
2503 Visit your project while logged in, and select \'Project Admin\' from the
2506 Enjoy the system, and please tell others about %4$s. Let us know
2507 if there is anything we can do to help you.
2510 htmlspecialchars_decode($this->getPublicName()),
2511 $this->getUnixName(),
2512 util_make_url ('/project/admin/?group_id='.$this->getID()),
2513 forge_get_config ('forge_name'));
2515 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Approved'), forge_get_config ('forge_name')), $message);
2517 setup_gettext_from_context();
2525 * sendRejectionEmail - Send project rejection email.
2527 * This function sends out a rejection message to a user who
2528 * registered a project.
2530 * @param int The id of the response to use.
2531 * @param string The rejection message.
2532 * @return completion status.
2535 function sendRejectionEmail($response_id, $message="zxcv") {
2536 $submitters = array () ;
2538 foreach (get_group_join_requests ($this) as $gjr) {
2539 $submitters[] = user_get_object($gjr->getUserID()) ;
2542 $res = db_query_params("SELECT u.user_id FROM users u, user_group ug WHERE ug.group_id=$1 AND u.user_id=ug.user_id",
2544 while ($arr = db_fetch_array ($res)) {
2545 $submitter[] =& user_get_object($arr['user_id']);
2549 if (count ($submitters) < 1) {
2550 $this->setError(_("Group does not have any administrators."));
2554 foreach ($submitters as $admin) {
2555 setup_gettext_for_user ($admin) ;
2557 $response=sprintf(_('Your project registration for %3$s has been denied.
2559 Project Full Name: %1$s
2560 Project Unix Name: %2$s
2562 Reasons for negative decision:
2564 '), $this->getPublicName(), $this->getUnixName(), forge_get_config('forge_name'));
2566 // Check to see if they want to send a custom rejection response
2567 if ($response_id == 0) {
2568 $response .= $message;
2570 $response .= db_result(
2571 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array ($response_id)),
2576 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Denied'), forge_get_config ('forge_name')), $response);
2577 setup_gettext_from_context();
2584 * sendNewProjectNotificationEmail - Send new project notification email.
2586 * This function sends out a notification email to the
2587 * SourceForge admin user when a new project is
2590 * @return boolean success.
2593 function sendNewProjectNotificationEmail() {
2594 // Get the user who wants to register the project
2595 $submitters = array () ;
2597 foreach (get_group_join_requests ($this) as $gjr) {
2598 $submitters[] = user_get_object($gjr->getUserID()) ;
2601 $res = db_query_params("SELECT u.user_id FROM users u, user_group ug WHERE ug.group_id=$1 AND u.user_id=ug.user_id",
2603 while ($arr = db_fetch_array ($res)) {
2604 $submitter[] =& user_get_object($arr['user_id']);
2607 if (count ($submitters) < 1) {
2608 $this->setError(_("Could not find user who has submitted the project."));
2612 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('approve_projects', -1) ;
2614 if (count($admins) < 1) {
2615 $this->setError(_("There is no administrator to send the mail to."));
2619 foreach ($admins as $admin) {
2620 $admin_email = $admin->getEmail () ;
2621 setup_gettext_for_user ($admin) ;
2623 foreach ($submitters as $u) {
2624 $submitter_names[] = $u->getRealName() ;
2627 $message = sprintf(_('New %1$s Project Submitted
2629 Project Full Name: %2$s
2630 Submitted Description: %3$s
2632 forge_get_config ('forge_name'),
2633 htmlspecialchars_decode($this->getPublicName()),
2634 htmlspecialchars_decode($this->getRegistrationPurpose()));
2636 foreach ($submitters as $submitter) {
2637 $message .= sprintf(_('Submitter: %1$s (%2$s)
2639 $submitter->getRealName(),
2640 $submitter->getUnixName());
2643 $message .= sprintf (_('
2644 Please visit the following URL to approve or reject this project:
2646 util_make_url ('/admin/approve-pending.php')) ;
2647 util_send_message($admin_email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2648 setup_gettext_from_context();
2652 $email = $submitter->getEmail() ;
2653 setup_gettext_for_user ($submitter) ;
2655 $message=sprintf(_('New %1$s Project Submitted
2657 Project Full Name: %2$s
2658 Submitted Description: %3$s
2660 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'));
2662 util_send_message($email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2663 setup_gettext_from_context();
2672 * validateGroupName - Validate the group name
2674 * @param string Group name.
2676 * @return an error false and set an error is the group name is invalide otherwise return true
2678 function validateGroupName($group_name) {
2679 if (strlen($group_name)<3) {
2680 $this->setError(_('Group name is too short'));
2682 } else if (strlen(htmlspecialchars($group_name))>50) {
2683 $this->setError(_('Group name is too long'));
2685 } else if ($group=group_get_object_by_publicname($group_name)) {
2686 $this->setError(_('Group name already taken'));
2694 * getRoles - Get the roles of the group.
2696 * @return array Role ids of this group.
2698 function getRolesId() {
2699 $role_ids = array();
2702 $res = db_query_params('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2703 array($this->getID()));
2704 while ($arr = db_fetch_array($res)) {
2705 $role_ids[] = $arr['role_id'];
2707 $res = db_query_params('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2708 array($this->getID()));
2709 while ($arr = db_fetch_array($res)) {
2710 $role_ids[] = $arr['role_id'];
2713 $res = db_query_params('SELECT role_id FROM role WHERE group_id=$1',
2714 array($this->getID()));
2715 while ($arr = db_fetch_array($res)) {
2716 $role_ids[] = $arr['role_id'];
2720 return array_unique($role_ids);
2724 * getRoles - Get the roles of the group.
2726 * @return array Roles of this group.
2728 function getRoles() {
2731 $roles = $this->getRolesId();
2733 $engine = RBACEngine::getInstance();
2734 foreach ($roles as $role_id) {
2735 $result[] = $engine->getRoleById ($role_id);
2738 foreach ($roles as $role_id) {
2739 $result[] = new Role ($this, $role_id);
2746 function normalizeAllRoles() {
2747 $roles = $this->getRoles();
2749 foreach ($roles as $r) {
2750 $r->normalizeData();
2755 * getUnixStatus - Status of activation of unix account.
2757 * @return char (N)one, (A)ctive, (S)uspended or (D)eleted
2759 function getUnixStatus() {
2760 return $this->data_array['unix_status'];
2764 * setUnixStatus - Sets status of activation of unix account.
2766 * @param string The unix status.
2772 * @return boolean success.
2774 function setUnixStatus($status) {
2777 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
2782 $this->setError(sprintf(_('ERROR - Could Not Update Group Unix Status: %s'),db_error()));
2786 if ($status == 'A') {
2787 if (!$SYS->sysCheckCreateGroup($this->getID())) {
2788 $this->setError($SYS->getErrorMessage());
2793 if ($SYS->sysCheckGroup($this->getID())) {
2794 if (!$SYS->sysRemoveGroup($this->getID())) {
2795 $this->setError($SYS->getErrorMessage());
2802 $this->data_array['unix_status']=$status;
2809 * getUsers - Get the users of a group
2811 * @return array of user's objects.
2813 function getUsers($onlylocal = true) {
2814 if (!isset($this->membersArr)) {
2815 $this->membersArr = array () ;
2819 foreach ($this->getRoles() as $role) {
2821 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
2824 foreach ($role->getUsers() as $user) {
2825 $ids[] = $user->getID() ;
2828 $ids = array_unique ($ids) ;
2829 foreach ($ids as $id) {
2830 $u = user_get_object ($id) ;
2831 if ($u->isActive()) {
2832 $this->membersArr[] = $u ;
2837 $users_group_res = db_query_params ('SELECT u.user_id FROM users u, user_group ug WHERE ug.group_id=$1 AND ug.user_id=u.user_id AND u.status=$2',
2838 array ($this->getID(),
2840 if (!$users_group_res) {
2841 $this->setError(_('Error: Enable to get users from group'). ' ' . $this->getID() . ' ' .db_error());
2845 for ($i=0; $i<db_numrows($users_group_res); $i++) {
2846 $this->membersArr[$i] = new GFUser(db_result($users_group_res,$i,'user_id'),false);
2851 return $this->membersArr;
2854 function setDocmanCreateOnlineStatus($status) {
2856 /* if we activate search engine, we probably want to reindex */
2857 $res = db_query_params('UPDATE groups SET use_docman_create_online=$1 WHERE group_id=$2',
2858 array($status, $this->getID()));
2861 $this->setError(sprintf(_('ERROR - Could Not Update Group DocmanCreateOnline Status: %s'),db_error()));
2865 $this->data_array['use_docman_create_online']=$status;
2871 function setDocmanWebdav($status) {
2873 /* if we activate search engine, we probably want to reindex */
2874 $res = db_query_params('UPDATE groups SET use_webdav=$1 WHERE group_id=$2',
2879 $this->setError(sprintf(_('ERROR - Could Not Update Group UseWebdab Status: %s'),db_error()));
2883 $this->data_array['use_webdav']=$status;
2889 function setDocmanSearchStatus($status) {
2891 /* if we activate search engine, we probably want to reindex */
2892 $res = db_query_params('UPDATE groups SET use_docman_search=$1, force_docman_reindex=$1 WHERE group_id=$2',
2897 $this->setError(sprintf(_('ERROR - Could Not Update Group UseDocmanSearch Status: %s'),db_error()));
2901 $this->data_array['use_docman_search']=$status;
2907 function setDocmanForceReindexSearch($status) {
2909 /* if we activate search engine, we probably want to reindex */
2910 $res = db_query_params('UPDATE groups SET force_docman_reindex=$1 WHERE group_id=$2',
2915 $this->setError(sprintf(_('ERROR - Could Not Update Group force_docman_reindex %s'),db_error()));
2919 $this->data_array['force_docman_reindex']=$status;
2925 function setStorageAPI($type) {
2929 function getStorageAPI() {
2935 * group_getname() - get the group name
2937 * @param int The group ID
2941 function group_getname ($group_id = 0) {
2942 $grp = group_get_object($group_id);
2944 return $grp->getPublicName();
2951 * group_getunixname() - get the unixname for a group
2953 * @param int The group ID
2957 function group_getunixname ($group_id) {
2958 $grp = group_get_object($group_id);
2960 return $grp->getUnixName();
2967 * group_get_result() - Get the group object result ID.
2969 * @param int The group ID
2973 function &group_get_result($group_id=0) {
2974 $grp = group_get_object($group_id);
2976 return $grp->getData();
2982 class ProjectComparator {
2983 var $criterion = 'name' ;
2985 function Compare ($a, $b) {
2986 switch ($this->criterion) {
2989 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName()) ;
2990 if ($namecmp != 0) {
2993 /* If several projects share a same public name */
2994 return strcoll ($a->getUnixName(), $b->getUnixName()) ;
2997 return strcmp ($a->getUnixName(), $b->getUnixName()) ;
3000 $aid = $a->getID() ;
3001 $bid = $b->getID() ;
3005 return ($a < $b) ? -1 : 1;
3011 function sortProjectList (&$list, $criterion='name') {
3012 $cmp = new ProjectComparator () ;
3013 $cmp->criterion = $criterion ;
3015 return usort ($list, array ($cmp, 'Compare')) ;
3020 // c-file-style: "bsd"