5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009, Roland Mas
8 * This file is part of FusionForge.
10 * FusionForge is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published
12 * by the Free Software Foundation; either version 2 of the License,
13 * or (at your option) any later version.
15 * FusionForge is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with FusionForge; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 require_once $gfcommon.'tracker/ArtifactTypes.class.php';
27 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
28 require_once $gfcommon.'forum/Forum.class.php';
29 require_once $gfcommon.'forum/ForumFactory.class.php';
30 require_once $gfcommon.'pm/ProjectGroup.class.php';
31 require_once $gfcommon.'pm/ProjectGroupFactory.class.php';
32 require_once $gfcommon.'include/Role.class.php';
33 require_once $gfcommon.'frs/FRSPackage.class.php';
34 require_once $gfcommon.'docman/DocumentGroup.class.php';
35 require_once $gfcommon.'mail/MailingList.class.php';
36 require_once $gfcommon.'mail/MailingListFactory.class.php';
37 require_once $gfcommon.'survey/SurveyFactory.class.php';
38 require_once $gfcommon.'survey/SurveyQuestionFactory.class.php';
39 require_once $gfcommon.'include/gettext.php';
40 require_once $gfcommon.'include/GroupJoinRequest.class.php';
42 //the license_id of "Other/proprietary" license
43 define('GROUP_LICENSE_OTHER',126);
45 $LICENSE_NAMES=array();
48 * group_get_licences() - get the licenses list
50 * @return array list of licenses
52 function & group_get_licenses() {
53 global $LICENSE_NAMES;
54 if(empty($LICENSE_NAMES)) {
55 $result = db_query_params ('select * from licenses', array());
56 while($data = db_fetch_array($result)) {
57 $LICENSE_NAMES[$data['license_id']] = $data['license_name'];
60 return $LICENSE_NAMES;
66 * group_get_object() - Get the group object.
68 * group_get_object() is useful so you can pool group objects/save database queries
69 * You should always use this instead of instantiating the object directly.
71 * You can now optionally pass in a db result handle. If you do, it re-uses that query
72 * to instantiate the objects.
74 * IMPORTANT! That db result must contain all fields
75 * from groups table or you will have problems
78 * @param int Result set handle ("SELECT * FROM groups WHERE group_id=xx")
79 * @return a group object or false on failure
81 function &group_get_object($group_id,$res=false) {
82 //create a common set of group objects
83 //saves a little wear on the database
85 //automatically checks group_type and
86 //returns appropriate object
89 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
91 //the db result handle was passed in
93 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1', array ($group_id)) ;
95 if (!$res || db_numrows($res) < 1) {
96 $GROUP_OBJ["_".$group_id."_"]=false;
99 check group type and set up object
101 if (db_result($res,0,'type_id')==1) {
103 $GROUP_OBJ["_".$group_id."_"]= new Group($group_id,$res);
106 $GROUP_OBJ["_".$group_id."_"]=false;
110 return $GROUP_OBJ["_".$group_id."_"];
113 function &group_get_objects($id_arr) {
116 // Note: if we don't do this, the result may be corrupted
120 for ($i=0; $i<count($id_arr); $i++) {
122 // See if this ID already has been fetched in the cache
127 if (!isset($GROUP_OBJ["_".$id_arr[$i]."_"])) {
128 $fetch[]=$id_arr[$i];
130 $return[] =& $GROUP_OBJ["_".$id_arr[$i]."_"];
133 if (count($fetch) > 0) {
134 $res=db_query_params ('SELECT * FROM groups WHERE group_id = ANY ($1)',
135 array (db_int_array_to_any_clause ($fetch))) ;
136 while ($arr = db_fetch_array($res)) {
137 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
138 $return[] =& $GROUP_OBJ["_".$arr['group_id']."_"];
144 function &group_get_active_projects() {
145 $res=db_query_params ('SELECT group_id FROM groups WHERE status=$1',
147 return group_get_objects (util_result_column_to_array($res,0)) ;
150 function &group_get_object_by_name($groupname) {
151 $res=db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array ($groupname)) ;
152 return group_get_object(db_result($res,0,'group_id'),$res);
155 function &group_get_objects_by_name($groupname_arr) {
156 $res=db_query_params ('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
157 array (db_string_array_to_any_clause ($groupname_arr))
159 $arr =& util_result_column_to_array($res,0);
160 return group_get_objects($arr);
163 function &group_get_object_by_publicname($groupname) {
164 $res=db_query_params ('SELECT * FROM groups WHERE lower(group_name) LIKE $1',
165 array (htmlspecialchars (strtolower ($groupname)))) ;
167 return group_get_object(db_result($res,0,'group_id'),$res);
170 class Group extends Error {
172 * Associative array of data from db.
174 * @var array $data_array.
179 * array of User objects.
181 * @var array $membersArr.
186 * Whether the use is an admin/super user of this project.
188 * @var bool $is_admin.
193 * Artifact types result handle.
195 * @var int $types_res.
200 * Associative array of data for plugins.
202 * @var array $plugins_data.
208 * Associative array of data for the group menu.
210 * @var array $menu_data.
215 * Group - Group object constructor - use group_get_object() to instantiate.
217 * @param int Required - group_id of the group you want to instantiate.
218 * @param int Database result from select query OR associative array of all columns.
220 function Group($id=false, $res=false) {
223 //setting up an empty object
224 //probably going to call create()
228 if (!$this->fetchData($id)) {
233 // Assoc array was passed in
235 if (is_array($res)) {
236 $this->data_array =& $res;
238 if (db_numrows($res) < 1) {
239 //function in class we extended
240 $this->setError(_('Group Not Found'));
241 $this->data_array=array();
244 //set up an associative array for use by other functions
245 $this->data_array = db_fetch_array_by_row($res, 0);
254 * fetchData - May need to refresh database fields if an update occurred.
256 * @param int The group_id.
258 function fetchData($group_id) {
259 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
261 if (!$res || db_numrows($res) < 1) {
262 $this->setError(sprintf(_('fetchData():: %s'),db_error()));
265 $this->data_array = db_fetch_array($res);
270 * create - Create new group.
272 * This method should be called on empty Group object.
274 * @param object The User object.
275 * @param string The full name of the user.
276 * @param string The Unix name of the user.
277 * @param string The new group description.
278 * @param string The purpose of the group.
279 * @param bool Whether to send an email or not
281 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true) {
282 // $user is ignored - anyone can create pending group
285 if ($this->getID()!=0) {
286 $this->setError(_('Group::create: Group object already exists'));
288 } else if (!$this->validateGroupName($group_name)) {
290 } else if (!account_groupnamevalid($unix_name)) {
291 $this->setError(_('Invalid Unix name'));
293 } else if (!$SYS->sysUseUnixName($unix_name)) {
294 $this->setError(_('Unix name already taken'));
296 } else if (db_numrows(db_query_params('SELECT group_id FROM groups WHERE unix_group_name=$1',
297 array ($unix_name))) > 0) {
298 $this->setError(_('Unix name already taken'));
300 } else if (strlen($purpose)<10) {
301 $this->setError(_('Please describe your Registration Purpose in a more comprehensive manner'));
303 } else if (strlen($purpose)>1500) {
304 $this->setError(_('The Registration Purpose text is too long. Please make it smaller than 1500 bytes.'));
306 } else if (strlen($description)<10) {
307 $this->setError(_('Describe in a more comprehensive manner your project.'));
309 } else if (strlen($description)>255) {
310 $this->setError(_('Your project description is too long. Please make it smaller than 256 bytes.'));
314 srand((double)microtime()*1000000);
315 $random_num = rand(0,1000000);
319 $res = db_query_params ('
335 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
336 array (htmlspecialchars ($group_name),
339 htmlspecialchars($description),
340 $unix_name.".".forge_get_config('web_host'),
341 $unix_name.".".forge_get_config('web_host'),
345 htmlspecialchars($purpose),
348 md5($random_num) )) ;
349 if (!$res || db_affected_rows($res) < 1) {
350 $this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
355 $id = db_insertid($res, 'groups', 'group_id');
357 $this->setError(sprintf(_('ERROR: Could not get group id: %s'),db_error()));
363 $gjr = new GroupJoinRequest ($this) ;
364 $gjr->create ($user->getID(),
365 'Fake GroupJoinRequest to store the creator of a project',
369 // Now, make the user an admin
371 $res=db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags,
372 cvs_flags, artifact_flags, forum_flags, role_id)
373 VALUES ($1, $2, $3, $4, $5, $6, $7)',
374 array ($user->getID(),
381 if (!$res || db_affected_rows($res) < 1) {
382 $this->setError(sprintf(_('ERROR: Could not add admin to newly created group: %s'),db_error()));
388 if (!$this->fetchData($id)) {
393 $hook_params = array ();
394 $hook_params['group'] = $this;
395 $hook_params['group_id'] = $this->getID();
396 $hook_params['group_name'] = $group_name;
397 $hook_params['unix_group_name'] = $unix_name;
398 plugin_hook ("group_create", $hook_params);
402 $this->sendNewProjectNotificationEmail();
410 * updateAdmin - Update core properties of group object.
412 * This function require site admin privilege.
414 * @param object User requesting operation (for access control).
415 * @param bool Whether group is publicly accessible (0/1).
416 * @param int Group type (1-project, 2-foundry).
417 * @param string Machine on which group's home directory located.
418 * @param string Domain which serves group's WWW.
422 function updateAdmin(&$user, $is_public, $type_id, $unix_box, $http_domain) {
423 $perm =& $this->getPermission ();
425 if (!$perm || !is_object($perm)) {
426 $this->setError(_('Could not get permission.'));
430 if (!$perm->isSuperUser()) {
431 $this->setError(_('Permission denied.'));
437 $res = db_query_params ('
439 SET is_public=$1, type_id=$2,
440 unix_box=$3, http_domain=$4
448 if (!$res || db_affected_rows($res) < 1) {
449 $this->setError(_('ERROR: DB: Could not change group properties: %s'),db_error());
454 // Log the audit trail
455 if ($is_public != $this->isPublic()) {
456 $this->addHistory('is_public', $this->isPublic());
458 if ($type_id != $this->data_array['type_id']) {
459 $this->addHistory('type_id', $this->data_array['type_id']);
461 if ($unix_box != $this->data_array['unix_box']) {
462 $this->addHistory('unix_box', $this->data_array['unix_box']);
464 if ($http_domain != $this->data_array['http_domain']) {
465 $this->addHistory('http_domain', $this->data_array['http_domain']);
468 if (!$this->fetchData($this->getID())) {
477 * update - Update number of common properties.
479 * Unlike updateAdmin(), this function accessible to project admin.
481 * @param object User requesting operation (for access control).
482 * @param bool Whether group is publicly accessible (0/1).
483 * @param string Project's license (string ident).
484 * @param int Group type (1-project, 2-foundry).
485 * @param string Machine on which group's home directory located.
486 * @param string Domain which serves group's WWW.
487 * @return int status.
490 function update(&$user, $group_name,$homepage,$short_description,$use_mail,$use_survey,$use_forum,
491 $use_pm,$use_pm_depend_box,$use_scm,$use_news,$use_docman,
492 $new_doc_address,$send_all_docs,$logo_image_id,
493 $use_ftp,$use_tracker,$use_frs,$use_stats,$tags,$is_public) {
495 $perm =& $this->getPermission ();
497 if (!$perm || !is_object($perm)) {
498 $this->setError(_('Could not get permission.'));
502 if (!$perm->isAdmin()) {
503 $this->setError(_('Permission denied.'));
507 // Validate some values
508 if ($this->getPublicName() != $group_name) {
509 if (!$this->validateGroupName($group_name)) {
514 if ($new_doc_address) {
515 $invalid_mails = validate_emails($new_doc_address);
516 if (count($invalid_mails) > 0) {
517 $this->setError(sprintf (ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
522 // in the database, these all default to '1',
523 // so we have to explicity set 0
536 if (!$use_pm_depend_box) {
537 $use_pm_depend_box=0;
560 if (!$send_all_docs) {
564 $homepage = ltrim($homepage);
566 $homepage=forge_get_config('web_host').'/projects/'.$this->getUnixName().'/';
569 if (strlen(htmlspecialchars($short_description))>255) {
570 $this->setError(_('Error updating project information: Maximum length for Project Description is 255 chars.'));
576 //XXX not yet actived logo_image_id='$logo_image_id',
577 $res = db_query_params ('UPDATE groups
580 short_description=$3,
585 use_pm_depend_box=$8,
597 array (htmlspecialchars($group_name),
599 htmlspecialchars($short_description),
618 $this->setError(sprintf(_('Error updating project information: %s'), db_error()));
623 if ($this->setTags($tags) === false) {
628 $hook_params = array ();
629 $hook_params['group'] = $this;
630 $hook_params['group_id'] = $this->getID();
631 $hook_params['group_homepage'] = $homepage;
632 $hook_params['group_name'] = htmlspecialchars($group_name);
633 $hook_params['group_description'] = htmlspecialchars($short_description);
634 plugin_hook ("group_update", $hook_params);
636 // Log the audit trail
637 $this->addHistory('Changed Public Info', '');
639 if (!$this->fetchData($this->getID())) {
648 * getID - Simply return the group_id for this object.
650 * @return int group_id.
653 return $this->data_array['group_id'];
657 * getType() - Foundry, project, etc.
659 * @return int The type flag from the database.
662 return $this->data_array['type_id'];
667 * getStatus - the status code.
669 * Statuses char include I,H,A,D.
671 function getStatus() {
672 return $this->data_array['status'];
676 * setStatus - set the status code.
678 * Statuses include I,H,A,D.
680 * @param object User requesting operation (for access control).
681 * @param string Status value.
682 * @return boolean success.
685 function setStatus(&$user, $status) {
688 $perm =& $this->getPermission ();
689 if (!$perm || !is_object($perm)) {
690 $this->setPermissionDeniedError();
692 } elseif (!$perm->isSuperUser()) {
693 $this->setPermissionDeniedError();
697 // Projects in 'A' status can only go to 'H' or 'D'
698 // Projects in 'D' status can only go to 'A'
699 // Projects in 'P' status can only go to 'A' OR 'D'
700 // Projects in 'I' status can only go to 'P'
701 // Projects in 'H' status can only go to 'A' OR 'D'
702 $allowed_status_changes = array(
703 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
704 'IP'=>1,'HA'=>1,'HD'=>1
707 // Check that status transition is valid
708 if ($this->getStatus() != $status
709 && !$allowed_status_changes[$this->getStatus().$status]) {
710 $this->setError(_('Invalid Status Change'));
716 $res = db_query_params ('UPDATE groups
718 WHERE group_id=$2', array ($status, $this->getID())) ;
720 if (!$res || db_affected_rows($res) < 1) {
721 $this->setError(sprintf(_('ERROR: DB: Could not change group status: %s'),db_error()));
727 // Activate system group, if not yet
728 if (!$SYS->sysCheckGroup($this->getID())) {
729 if (!$SYS->sysCreateGroup($this->getID())) {
730 $this->setError($SYS->getErrorMessage());
735 if (!$this->activateUsers()) {
740 /* Otherwise, the group is not active, and make sure that
741 System group is not active either */
742 } else if ($SYS->sysCheckGroup($this->getID())) {
743 if (!$SYS->sysRemoveGroup($this->getID())) {
744 $this->setError($SYS->getErrorMessage());
750 $hook_params = array ();
751 $hook_params['group'] = $this;
752 $hook_params['group_id'] = $this->getID();
753 $hook_params['status'] = $status;
754 plugin_hook ("group_setstatus", $hook_params);
758 // Log the audit trail
759 if ($status != $this->getStatus()) {
760 $this->addHistory('Status', $this->getStatus());
763 $this->data_array['status'] = $status;
768 * isProject - Simple boolean test to see if it's a project or not.
770 * @return boolean is_project.
772 function isProject() {
773 if ($this->getType()==1) {
781 * isPublic - Simply returns the is_public flag from the database.
783 * @return boolean is_public.
785 function isPublic() {
786 return $this->data_array['is_public'];
790 * isActive - Database field status of 'A' returns true.
792 * @return boolean is_active.
794 function isActive() {
795 if ($this->getStatus()=='A') {
803 * getUnixName - the unix_name
805 * @return string unix_name.
807 function getUnixName() {
808 return strtolower($this->data_array['unix_group_name']);
812 * getPublicName - the full-length public name.
814 * @return string The group_name.
816 function getPublicName() {
817 return $this->data_array['group_name'];
821 * getRegisterPurpose - the text description of the purpose of this project.
823 * @return string The description.
825 function getRegisterPurpose() {
826 return $this->data_array['register_purpose'];
830 * getDescription - the text description of this project.
832 * @return string The description.
834 function getDescription() {
835 return $this->data_array['short_description'];
839 * getStartDate - the unix time this project was registered.
841 * @return int (unix time) of registration.
843 function getStartDate() {
844 return $this->data_array['register_time'];
848 * getLogoImageID - the id of the logo in the database for this project.
850 * @return int The ID of logo image in db_images table (or 100 if none).
852 function getLogoImageID() {
853 return $this->data_array['logo_image_id'];
857 * getUnixBox - the hostname of the unix box where this project is located.
859 * @return string The name of the unix machine for the group.
861 function getUnixBox() {
862 return $this->data_array['unix_box'];
866 * getSCMBox - the hostname of the scm box where this project is located.
868 * @return string The name of the unix machine for the group.
870 function getSCMBox() {
871 return $this->data_array['scm_box'];
874 * setSCMBox - the hostname of the scm box where this project is located.
876 * @param string The name of the new SCM_BOX
878 function setSCMBox($scm_box) {
880 if ($scm_box == $this->data_array['scm_box']) {
885 $res = db_query_params ('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array ($scm_box, $this->getID ()));
887 $this->addHistory('scm_box', $this->data_array['scm_box']);
888 $this->data_array['scm_box']=$scm_box;
893 $this->setError(_("Couldn't insert SCM_BOX to database"));
897 $this->setError(_("SCM Box can't be empty"));
903 * getDomain - the hostname.domain where their web page is located.
905 * @return string The name of the group [web] domain.
907 function getDomain() {
908 return $this->data_array['http_domain'];
912 * getLicense - the license they chose.
914 * @return int ident of group license.
916 function getLicense() {
917 return $this->data_array['license'];
921 * getLicenseName - the name of the license
923 * @return string license name
925 function getLicenseName() {
926 $licenses =& group_get_licenses();
927 if(isset($licenses[$this->data_array['license']])) {
928 return $licenses[$this->data_array['license']];
935 * getLicenseOther - optional string describing license.
937 * @return string The custom license.
939 function getLicenseOther() {
940 if ($this->getLicense() == GROUP_LICENSE_OTHER) {
941 return $this->data_array['license_other'];
948 * getRegistrationPurpose - the text description of the purpose of this project.
950 * @return string The application for project hosting.
952 function getRegistrationPurpose() {
953 return $this->data_array['register_purpose'];
958 * getAdmins() - Get array of Admin user objects.
960 * @return array Array of User objects.
962 function &getAdmins() {
963 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID()) ;
965 $user_ids = array () ;
967 foreach ($roles as $role) {
968 if (! ($role instanceof RoleExplicit)) {
971 if ($role->getHomeProject() == NULL
972 || $role->getHomeProject()->getID() != $this->getID()) {
976 foreach ($role->getUsers() as $u) {
977 $user_ids[] = $u->getID() ;
981 return user_get_objects(array_unique($user_ids));
986 Common Group preferences for tools
991 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
993 * @return boolean enable_scm.
995 function enableAnonSCM() {
997 $r = RoleAnonymous::getInstance () ;
998 return $r->hasPermission ('scm', $this->getID(), 'read') ;
1000 if ($this->isPublic() && $this->usesSCM()) {
1001 return $this->data_array['enable_anonscm'];
1008 function SetUsesAnonSCM ($booleanparam) {
1010 $booleanparam = $booleanparam ? 1 : 0 ;
1012 $r = RoleAnonymous::getInstance () ;
1013 $r->setSetting ('scm', $this->getID(), $booleanparam) ;
1016 $res = db_query_params ('UPDATE groups SET enable_anonscm=$1 WHERE group_id=$2',
1017 array ($booleanparam, $this->getID()));
1019 $this->data_array['enable_anonscm']=$booleanparam;
1028 function setUsesSCM ($booleanparam) {
1030 $booleanparam = $booleanparam ? 1 : 0 ;
1031 $res = db_query_params ('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
1032 array ($booleanparam, $this->getID()));
1034 $this->data_array['use_scm']=$booleanparam;
1043 * enablePserver - whether or not this group has opted to enable Pserver.
1045 * @return boolean enable_pserver.
1047 function enablePserver() {
1048 if ($this->usesSCM()) {
1049 return $this->data_array['enable_pserver'];
1055 function SetUsesPserver ($booleanparam) {
1057 $booleanparam = $booleanparam ? 1 : 0 ;
1058 $res = db_query_params ('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1059 array ($booleanparam, $this->getID()));
1061 $this->data_array['enable_pserver']=$booleanparam;
1070 * usesSCM - whether or not this group has opted to use SCM.
1072 * @return boolean uses_scm.
1074 function usesSCM() {
1076 if (forge_get_config('use_scm')) {
1077 return $this->data_array['use_scm'];
1084 * usesMail - whether or not this group has opted to use mailing lists.
1086 * @return boolean uses_mail.
1088 function usesMail() {
1090 if (forge_get_config('use_mail')) {
1091 return $this->data_array['use_mail'];
1098 * usesNews - whether or not this group has opted to use news.
1100 * @return boolean uses_news.
1102 function usesNews() {
1104 if (forge_get_config('use_news')) {
1105 return $this->data_array['use_news'];
1112 * usesForum - whether or not this group has opted to use discussion forums.
1114 * @return boolean uses_forum.
1116 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() {
1141 if (forge_get_config('use_frs')) {
1142 return $this->data_array['use_frs'];
1149 * usesTracker - whether or not this group has opted to use tracker.
1151 * @return boolean uses_tracker.
1153 function usesTracker() {
1155 if (forge_get_config('use_tracker')) {
1156 return $this->data_array['use_tracker'];
1163 * usesDocman - whether or not this group has opted to use docman.
1165 * @return boolean uses_docman.
1167 function usesDocman() {
1169 if (forge_get_config('use_docman')) {
1170 return $this->data_array['use_docman'];
1176 * usesDocmanSearch - whether or not this group has opted to use docman search engine.
1178 * @return boolean use_docman_search.
1180 function useDocmanSearch() {
1182 if (forge_get_config('use_docman')) {
1183 return $this->data_array['use_docman_search'];
1190 * usesFTP - whether or not this group has opted to use FTP.
1192 * @return boolean uses_ftp.
1194 function usesFTP() {
1196 if (forge_get_config('use_ftp')) {
1197 return $this->data_array['use_ftp'];
1204 * usesSurvey - whether or not this group has opted to use surveys.
1206 * @return boolean uses_survey.
1208 function usesSurvey() {
1210 if (forge_get_config('use_survey')) {
1211 return $this->data_array['use_survey'];
1218 * usesPM - whether or not this group has opted to Project Manager.
1220 * @return boolean uses_projman.
1224 if (forge_get_config('use_pm')) {
1225 return $this->data_array['use_pm'];
1232 * getPlugins - get a list of all available group plugins
1234 * @return array array containing plugin_id => plugin_name
1236 function getPlugins() {
1237 if (!isset($this->plugins_data)) {
1238 $this->plugins_data = array () ;
1239 $res = db_query_params ('SELECT group_plugin.plugin_id, plugins.plugin_name
1240 FROM group_plugin, plugins
1241 WHERE group_plugin.group_id=$1
1242 AND group_plugin.plugin_id=plugins.plugin_id', array ($this->getID()));
1243 $rows = db_numrows($res);
1245 for ($i=0; $i<$rows; $i++) {
1246 $plugin_id = db_result($res,$i,'plugin_id');
1247 $this->plugins_data[$plugin_id] = db_result($res,$i,'plugin_name');
1250 return $this->plugins_data ;
1254 * usesPlugin - returns true if the group uses a particular plugin
1256 * @param string name of the plugin
1257 * @return boolean whether plugin is being used or not
1259 function usesPlugin($pluginname) {
1260 $plugins_data = $this->getPlugins() ;
1261 foreach ($plugins_data as $p_id => $p_name) {
1262 if ($p_name == $pluginname) {
1269 * added for Codendi compatibility
1270 * usesServices - returns true if the group uses a particular plugin or feature
1272 * @param string name of the plugin
1273 * @return boolean whether plugin is being used or not
1275 function usesService($feature) {
1276 $plugins_data = $this->getPlugins() ;
1277 $pm = plugin_manager_get_object();
1278 foreach ($plugins_data as $p_id => $p_name) {
1279 if ($p_name == $feature) {
1282 if ($pm->getPluginByName($p_name)->provide($feature) ) {
1290 * setPluginUse - enables/disables plugins for the group
1292 * @param string name of the plugin
1293 * @param boolean the new state
1294 * @return string database result
1296 function setPluginUse($pluginname, $val=true) {
1297 if ($val == $this->usesPlugin($pluginname)) {
1298 // State is already good, returning
1301 $res = db_query_params ('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1302 array ($pluginname));
1303 $rows = db_numrows($res);
1305 // Error: no plugin by that name
1308 $plugin_id = db_result($res,0,'plugin_id');
1310 unset ($this->plugins_data) ;
1312 $res = db_query_params ('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1313 array ($this->getID(),
1317 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1318 array ($this->getID(),
1325 * getDocEmailAddress - get email address(es) to send doc notifications to.
1327 * @return string email address.
1329 function getDocEmailAddress() {
1330 return $this->data_array['new_doc_address'];
1334 * DocEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1336 * @return boolean email_on_all_doc_updates.
1338 function docEmailAll() {
1339 return $this->data_array['send_all_docs'];
1344 * getHomePage - The URL for this project's home page.
1346 * @return string homepage URL.
1348 function getHomePage() {
1349 return $this->data_array['homepage'];
1353 * getTags - Tags of this project.
1355 * @return string List of tags.
1357 function getTags() {
1358 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1359 $res = db_query_params($sql, array($this->getID()));
1360 return join(', ', util_result_column_to_array($res));
1364 * setTags - Set tags of this project.
1366 * @return string database result.
1368 function setTags($tags) {
1370 $sql='DELETE FROM project_tags WHERE group_id=$1';
1371 $res=db_query_params($sql, array($this->getID()));
1373 $this->setError('Deleting old tags: '.db_error());
1377 $inserted = array();
1378 $tags_array = preg_split('/[;,]/', $tags);
1379 foreach ($tags_array as $tag) {
1380 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1381 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1382 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1383 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1388 if ($tag == '' || array_search($tag, $inserted) !== false) continue;
1389 $sql='INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1390 $res=db_query_params($sql, array($this->getID(), $tag));
1392 $this->setError(_('Setting tags: ').db_error());
1403 * getPermission - Return a Permission for this Group
1405 * @return object The Permission.
1407 function &getPermission() {
1408 return permission_get_object($this);
1412 function delete($sure,$really_sure,$really_really_sure) {
1413 if (!$sure || !$really_sure || !$really_really_sure) {
1414 $this->setMissingParamsError();
1417 if ($this->getID() == forge_get_config('news_group') ||
1418 $this->getID() == 1 ||
1419 $this->getID() == forge_get_config('stats_group') ||
1420 $this->getID() == forge_get_config('peer_rating_group')) {
1421 $this->setError(_('Cannot Delete System Group'));
1424 $perm =& $this->getPermission ();
1425 if (!$perm || !is_object($perm)) {
1426 $this->setPermissionDeniedError();
1428 } elseif ($perm->isError()) {
1429 $this->setPermissionDeniedError();
1431 } elseif (!$perm->isSuperUser()) {
1432 $this->setPermissionDeniedError();
1438 // Remove all the members
1440 $members =& $this->getMembers();
1441 for ($i=0; $i<count($members); $i++) {
1442 $this->removeUser($members[$i]->getID());
1444 // Failsafe until user_group table is gone
1445 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1',
1446 array ($this->getID())) ;
1450 $atf = new ArtifactTypeFactory($this);
1451 $at_arr =& $atf->getArtifactTypes();
1452 for ($i=0; $i<count($at_arr); $i++) {
1453 if (!is_object($at_arr[$i])) {
1454 printf (_("Not Object: ArtifactType: %d"),$i);
1457 $at_arr[$i]->delete(1,1);
1462 $ff = new ForumFactory($this);
1463 $f_arr =& $ff->getForums();
1464 for ($i=0; $i<count($f_arr); $i++) {
1465 if (!is_object($f_arr[$i])) {
1466 printf (_("Not Object: Forum: %d"),$i);
1469 $f_arr[$i]->delete(1,1);
1472 // Delete Subprojects
1474 $pgf = new ProjectGroupFactory($this);
1475 $pg_arr =& $pgf->getProjectGroups();
1476 for ($i=0; $i<count($pg_arr); $i++) {
1477 if (!is_object($pg_arr[$i])) {
1478 printf (_("Not Object: ProjectGroup: %d"),$i);
1481 $pg_arr[$i]->delete(1,1);
1484 // Delete FRS Packages
1486 //$frspf = new FRSPackageFactory($this);
1487 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
1488 array ($this->getID())) ;
1489 //echo 'frs_package'.db_error();
1490 //$frsp_arr =& $frspf->getPackages();
1491 while ($arr = db_fetch_array($res)) {
1492 //if (!is_object($pg_arr[$i])) {
1493 // echo "Not Object: ProjectGroup: ".$i;
1496 $frsp=new FRSPackage($this,$arr['package_id'],$arr);
1502 $news_group=&group_get_object(forge_get_config('news_group'));
1503 $res = db_query_params ('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1504 array ($this->getID())) ;
1506 $this->setError(_('Error Deleting News: ').db_error());
1511 for ($i=0; $i<db_numrows($res); $i++) {
1512 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1513 if (!$Forum->delete(1,1)) {
1514 printf (_("Could Not Delete News Forum: %d"),$Forum->getID());
1517 $res = db_query_params ('DELETE FROM news_bytes WHERE group_id=$1',
1518 array ($this->getID())) ;
1520 $this->setError(_('Error Deleting News: ').db_error());
1528 $res = db_query_params ('DELETE FROM doc_data WHERE group_id=$1',
1529 array ($this->getID())) ;
1531 $this->setError(_('Error Deleting Documents: ').db_error());
1536 $res = db_query_params ('DELETE FROM doc_groups WHERE group_id=$1',
1537 array ($this->getID())) ;
1539 $this->setError(_('Error Deleting Documents: ').db_error());
1547 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1549 $this->setError(_('Error Deleting Tags: ').db_error());
1555 // Delete group history
1557 $res = db_query_params ('DELETE FROM group_history WHERE group_id=$1',
1558 array ($this->getID())) ;
1560 $this->setError(_('Error Deleting Project History: ').db_error());
1566 // Delete group plugins
1568 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1',
1569 array ($this->getID())) ;
1571 $this->setError(_('Error Deleting Project Plugins: ').db_error());
1577 // Delete group cvs stats
1579 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1580 array ($this->getID())) ;
1582 $this->setError(_('Error Deleting SCM Statistics: ').db_error());
1590 $sf = new SurveyFactory($this);
1591 $s_arr =& $sf->getSurveys();
1592 for ($i=0; $i<count($s_arr); $i++) {
1593 if (!is_object($s_arr[$i])) {
1594 printf (_("Not Object: Survey: %d"),$i);
1597 $s_arr[$i]->delete();
1600 // Delete SurveyQuestions
1602 $sqf = new SurveyQuestionFactory($this);
1603 $sq_arr =& $sqf->getSurveyQuestions();
1604 for ($i=0; $i<count($sq_arr); $i++) {
1605 if (!is_object($sq_arr[$i])) {
1606 printf (_("Not Object: SurveyQuestion: %d"),$i);
1609 $sq_arr[$i]->delete();
1612 // Delete Mailing List Factory
1614 $mlf = new MailingListFactory($this);
1615 $ml_arr =& $mlf->getMailingLists();
1616 for ($i=0; $i<count($ml_arr); $i++) {
1617 if (!is_object($ml_arr[$i])) {
1618 printf (_("Not Object: MailingList: %d"),$i);
1621 if (!$ml_arr[$i]->delete(1,1)) {
1622 $this->setError(_('Could not properly delete the mailing list'));
1628 $res = db_query_params ('DELETE FROM trove_group_link WHERE group_id=$1',
1629 array ($this->getID())) ;
1631 $this->setError(_('Error Deleting Trove: ').db_error());
1636 $res = db_query_params ('DELETE FROM trove_agg WHERE group_id=$1',
1637 array ($this->getID())) ;
1639 $this->setError(_('Error Deleting Trove: ').db_error());
1647 $res = db_query_params ('DELETE FROM project_sums_agg WHERE group_id=$1',
1648 array ($this->getID())) ;
1650 $this->setError(_('Error Deleting Counters: ').db_error());
1655 $res = db_query_params ('INSERT INTO deleted_groups (unix_group_name,delete_date,isdeleted) VALUES ($1, $2, $3)',
1656 array ($this->getUnixName(),
1660 $this->setError(_('Error Deleting Project: ').db_error());
1665 $res = db_query_params ('DELETE FROM groups WHERE group_id=$1',
1666 array ($this->getID())) ;
1668 $this->setError(_('Error Deleting Project: ').db_error());
1678 $hook_params = array ();
1679 $hook_params['group'] = $this;
1680 $hook_params['group_id'] = $this->getID();
1681 plugin_hook ("group_delete", $hook_params);
1683 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
1684 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
1686 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
1687 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
1692 $res = db_query_params ('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
1693 array ($this->getID())) ;
1694 //echo 'rep_group_act_monthly'.db_error();
1695 $res = db_query_params ('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
1696 array ($this->getID())) ;
1697 //echo 'rep_group_act_weekly'.db_error();
1698 $res = db_query_params ('DELETE FROM rep_group_act_daily WHERE group_id=$1',
1699 array ($this->getID())) ;
1700 //echo 'rep_group_act_daily'.db_error();
1701 unset($this->data_array);
1709 Basic functions to add/remove users to/from a group
1710 and update their permissions
1716 * addUser - controls adding a user to a group.
1718 * @param string Unix name of the user to add OR integer user_id.
1719 * @param int The role_id this user should have.
1720 * @return boolean success.
1723 function addUser($user_identifier,$role_id) {
1726 Admins can add users to groups
1729 if (!forge_check_perm ('project_admin', $this->getID())) {
1730 $this->setPermissionDeniedError();
1736 get user id for this user's unix_name
1738 if (is_int ($user_identifier)) { // user_id or user_name
1739 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array ($user_identifier)) ;
1741 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array ($user_identifier)) ;
1743 if (db_numrows($res_newuser) > 0) {
1745 // make sure user is active
1747 if (db_result($res_newuser,0,'status') != 'A') {
1748 $this->setError(_('User is not active. Only active users can be added.'));
1754 // user was found - set new user_id var
1756 $user_id = db_result($res_newuser,0,'user_id');
1758 $role = new Role($this,$role_id);
1759 if (!$role || !is_object($role)) {
1760 $this->setError(_('Error Getting Role Object'));
1763 } elseif ($role->isError()) {
1764 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1770 $role->addUser (user_get_object ($user_id)) ;
1771 if (!$SYS->sysCheckCreateGroup($this->getID())){
1772 $this->setError($SYS->getErrorMessage());
1776 if (!$SYS->sysCheckCreateUser($user_id)) {
1777 $this->setError($SYS->getErrorMessage());
1784 // if not already a member, add them
1786 $res_member = db_query_params ('SELECT user_id
1788 WHERE user_id=$1 AND group_id=$2',
1789 array ($user_id, $this->getID())) ;
1791 if (db_numrows($res_member) < 1) {
1793 // Create this user's row in the user_group table
1795 $res = db_query_params ('INSERT INTO user_group
1796 (user_id,group_id,admin_flags,forum_flags,project_flags,
1797 doc_flags,cvs_flags,member_role,release_flags,artifact_flags)
1798 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)',
1810 //verify the insert worked
1811 if (!$res || db_affected_rows($res) < 1) {
1812 $this->setError(sprintf(_('ERROR: Could Not Add User To Group: %s'),db_error()));
1817 // check and create if group doesn't exists
1819 //echo "<h2>Group::addUser SYS->sysCheckCreateGroup(".$this->getID().")</h2>";
1820 if (!$SYS->sysCheckCreateGroup($this->getID())){
1821 $this->setError($SYS->getErrorMessage());
1826 // check and create if user doesn't exists
1828 //echo "<h2>Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1829 if (!$SYS->sysCheckCreateUser($user_id)) {
1830 $this->setError($SYS->getErrorMessage());
1837 //echo "<h2>Group::addUser role->setUser($user_id)</h2>";
1838 if (!$role->setUser($user_id)) {
1839 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1845 // user was already a member
1846 // make sure they are set up
1848 $user=&user_get_object($user_id,$res_newuser);
1849 $user->fetchData($user->getID());
1850 $role = new Role($this,$role_id);
1851 if (!$role || !is_object($role)) {
1852 $this->setError(_('Error Getting Role Object'));
1855 } elseif ($role->isError()) {
1856 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1860 //echo "<h2>Already Member Group::addUser role->setUser($user_id)</h2>";
1861 if (!$role->setUser($user_id)) {
1862 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1867 // set up their system info
1869 //echo "<h2>Already Member Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1870 if (!$SYS->sysCheckCreateUser($user_id)) {
1871 $this->setError($SYS->getErrorMessage());
1879 // user doesn't exist
1881 $this->setError(_('ERROR: User does not exist'));
1886 $hook_params['group'] = $this;
1887 $hook_params['group_id'] = $this->getID();
1888 $hook_params['user'] = &user_get_object($user_id);
1889 $hook_params['user_id'] = $user_id;
1890 plugin_hook ("group_adduser", $hook_params);
1895 $this->addHistory('Added User',$user_identifier);
1901 * removeUser - controls removing a user from a group.
1903 * Users can remove themselves.
1905 * @param int The ID of the user to remove.
1906 * @return boolean success.
1908 function removeUser($user_id) {
1911 if ($user_id != user_getid()
1912 || !forge_check_perm ('project_admin', $this->getID())) {
1913 $this->setPermissionDeniedError();
1920 $user = user_get_object ($user_id) ;
1921 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
1922 $found_role = NULL ;
1923 foreach ($roles as $role) {
1924 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
1925 $found_role = $role ;
1929 if ($found_role == NULL) {
1930 $this->setError(sprintf(_('ERROR: User not removed: %s')));
1934 $found_role->removeUser ($user) ;
1935 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
1936 $this->setError($SYS->getErrorMessage());
1942 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1 AND user_id=$2',
1943 array ($this->getID(),
1945 if (!$res || db_affected_rows($res) < 1) {
1946 $this->setError(sprintf(_('ERROR: User not removed: %s'),db_error()));
1953 // reassign open artifacts to id=100
1955 $res = db_query_params ('UPDATE artifact SET assigned_to=100
1956 WHERE group_artifact_id
1957 IN (SELECT group_artifact_id
1958 FROM artifact_group_list
1959 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
1960 array ($this->getID(),
1963 $this->setError(sprintf(_('ERROR: DB: artifact: %s'),db_error()));
1969 // reassign open tasks to id=100
1970 // first have to purge any assignments that would cause
1971 // conflict with existing assignment to 100
1973 $res = db_query_params ('DELETE FROM project_assigned_to
1974 WHERE project_task_id IN (SELECT pt.project_task_id
1975 FROM project_task pt, project_group_list pgl, project_assigned_to pat
1976 WHERE pt.group_project_id = pgl.group_project_id
1977 AND pat.project_task_id=pt.project_task_id
1978 AND pt.status_id=1 AND pgl.group_id=$1
1979 AND pat.assigned_to_id=$2)
1980 AND assigned_to_id=100',
1981 array ($this->getID(),
1984 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),1,db_error()));
1988 $res = db_query_params ('UPDATE project_assigned_to SET assigned_to_id=100
1989 WHERE project_task_id IN (SELECT pt.project_task_id
1990 FROM project_task pt, project_group_list pgl
1991 WHERE pt.group_project_id = pgl.group_project_id
1992 AND pt.status_id=1 AND pgl.group_id=$1)
1993 AND assigned_to_id=$2',
1994 array ($this->getID(),
1997 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),2,db_error()));
2003 // Remove user from system
2005 if (!$SYS->sysGroupRemoveUser($this->getID(),$user_id)) {
2006 $this->setError($SYS->getErrorMessage());
2011 $hook_params['group'] = $this;
2012 $hook_params['group_id'] = $this->getID();
2013 $hook_params['user'] = &user_get_object($user_id);
2014 $hook_params['user_id'] = $user_id;
2015 plugin_hook ("group_removeuser", $hook_params);
2018 $this->addHistory('Removed User',$user_id);
2025 * updateUser - controls updating a user's role in this group.
2027 * @param int The ID of the user.
2028 * @param int The role_id to set this user to.
2029 * @return boolean success.
2031 function updateUser($user_id,$role_id) {
2034 if (!forge_check_perm ('project_admin', $this->getID())) {
2035 $this->setPermissionDeniedError();
2040 $newrole = RBACEngine::getInstance()->getRoleById ($role_id) ;
2041 if (!$newrole || !is_object($newrole)) {
2042 $this->setError(_('Could Not Get Role'));
2044 } elseif ($newrole->isError()) {
2045 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2047 } elseif ($newrole->getHomeProject() == NULL
2048 || $newrole->getHomeProject()->getID() != $this->getID()) {
2049 $this->setError(_('Wrong destination role'));
2052 $user = user_get_object ($user_id) ;
2053 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
2054 $found_role = NULL ;
2055 foreach ($roles as $role) {
2056 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2057 $found_role = $role ;
2061 if ($found_role == NULL) {
2062 $this->setError(sprintf(_('ERROR: User not removed: %s')));
2066 $found_role->removeUser ($user) ;
2067 $newrole->addUser ($user) ;
2069 $role = new Role($this,$role_id);
2070 if (!$role || !is_object($role)) {
2071 $this->setError(_('Could Not Get Role'));
2073 } elseif ($role->isError()) {
2074 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2077 //echo "<h3>Group::updateUser role->setUser($user_id)</h3>";
2078 if (!$role->setUser($user_id)) {
2079 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2084 $this->addHistory('Updated User',$user_id);
2089 * addHistory - Makes an audit trail entry for this project.
2091 * @param string The name of the field.
2092 * @param string The Old Value for this $field_name.
2093 * @return database result handle.
2096 function addHistory($field_name, $old_value) {
2097 return db_query_params ('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2098 VALUES ($1,$2,$3,$4,$5)',
2099 array ($this->getID(),
2107 * activateUsers - Make sure that group members have unix accounts.
2109 * Setup unix accounts for group members. Can be called even
2110 * if members are already active.
2114 function activateUsers() {
2116 Activate member(s) of the project
2120 $members = $this->getUsers (true) ;
2122 foreach ($members as $member) {
2124 foreach (RBACEngine::getInstance()->getAvailableRolesForUser ($member) as $role) {
2125 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2128 if (!$this->addUser($member->getUnixName(),$role->getID())) {
2135 $res_member = db_query_params ('SELECT user_id,role_id FROM user_group WHERE group_id=$1',
2136 array ($this->getID())) ;
2137 while ($row_member = db_fetch_array($res_member)) {
2138 $u = user_get_object($row_member['user_id']) ;
2139 if (!$this->addUser($u->getUnixName(),$row_member['role_id'])) {
2149 * getMembers - returns array of User objects for this project
2151 * @return array of User objects for this group.
2153 function &getMembers() {
2154 return $this->getUsers (true) ;
2158 * approve - Approve pending project.
2160 * @param object The User object who is doing the updating.
2163 function approve(&$user) {
2165 if ($this->getStatus()=='A') {
2166 $this->setError(_("Group already active"));
2172 // Step 1: Activate group and create LDAP entries
2173 if (!$this->setStatus($user, 'A')) {
2178 // Switch to system language for item creation
2179 setup_gettext_from_sys_lang ();
2184 // Tracker Integration
2187 if (forge_get_config ('use_tracker')) {
2188 $ats = new ArtifactTypes($this);
2189 if (!$ats || !is_object($ats)) {
2190 $this->setError(_('Error creating ArtifactTypes object'));
2192 setup_gettext_from_context();
2194 } else if ($ats->isError()) {
2195 $this->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
2197 setup_gettext_from_context();
2200 if (!$ats->createTrackers()) {
2201 $this->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
2203 setup_gettext_from_context();
2210 // Forum Integration
2213 if (forge_get_config ('use_forum')) {
2214 $f = new Forum($this);
2215 if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
2216 $this->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
2218 setup_gettext_from_context();
2221 $f = new Forum($this);
2222 if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
2223 $this->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
2225 setup_gettext_from_context();
2228 $f = new Forum($this);
2229 if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
2230 $this->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
2232 setup_gettext_from_context();
2239 // Doc Mgr Integration
2242 if (forge_get_config('use_docman')) {
2243 $dg = new DocumentGroup($this);
2244 if (!$dg->create(_('Uncategorized Submissions'))) {
2245 $this->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
2247 setup_gettext_from_context();
2257 if (forge_get_config ('use_frs')) {
2258 $frs = new FRSPackage($this);
2259 if (!$frs->create($this->getUnixName())) {
2260 $this->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
2262 setup_gettext_from_context();
2272 if (forge_get_config ('use_pm')) {
2273 $pg = new ProjectGroup($this);
2274 if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
2275 $this->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
2277 setup_gettext_from_context();
2280 $pg = new ProjectGroup($this);
2281 if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
2282 $this->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
2284 setup_gettext_from_context();
2291 // Set Default Roles
2295 $idadmin_group = NULL ;
2296 foreach (get_group_join_requests ($this) as $gjr) {
2297 $idadmin_group = $gjr->getUserID() ;
2300 if ($idadmin_group == NULL) {
2301 $idadmin_group = $user->getID();
2305 $admin_group = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1 AND admin_flags=$2',
2306 array ($this->getID(),
2308 if (db_numrows($admin_group) > 0) {
2309 $idadmin_group = db_result($admin_group,0,'user_id');
2311 $idadmin_group = $user->getID();
2312 db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags) VALUES ($1, $2, $3)',
2313 array ($idadmin_group,
2319 $role = new Role($this);
2320 $todo = array_keys($role->defaults);
2321 for ($c=0; $c<count($todo); $c++) {
2322 $role = new Role($this);
2323 if (! ($role_id = $role->createDefault($todo[$c]))) {
2324 $this->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
2326 setup_gettext_from_context();
2329 $role = new Role($this, $role_id);
2330 if ($role->getVal('projectadmin',0)=='A') {
2331 $role->setUser($idadmin_group);
2336 $roles = $this->getRoles() ;
2337 foreach ($roles as $r) {
2338 if ($r->getSetting ('project_admin', $this->getID())) {
2339 $r->addUser (user_get_object ($idadmin_group)) ;
2342 if ($this->isPublic()) {
2343 RoleAnonymous::getInstance()->linkProject($this) ;
2344 RoleLoggedIn::getInstance()->linkProject($this) ;
2346 foreach (get_group_join_requests ($this) as $gjr) {
2347 $gjr->delete (true) ;
2353 // Create MailingList
2356 if (forge_get_config('use_mail')) {
2357 $mlist = new MailingList($this);
2358 if (!$mlist->create('commits',_('Commits'),1,$idadmin_group)) {
2359 $this->setError(sprintf(_('ML: %s'),$mlist->getErrorMessage()));
2361 setup_gettext_from_context();
2366 // Switch back to user preference
2367 setup_gettext_from_context();
2371 $this->sendApprovalEmail();
2372 $this->addHistory('Approved', 'x');
2375 // Plugin can make approve operation there
2378 $params[0] = $idadmin_group ;
2379 $params[1] = $this->getID();
2380 plugin_hook('group_approve',$params);
2388 * sendApprovalEmail - Send new project email.
2390 * @return boolean success.
2393 function sendApprovalEmail() {
2394 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID()) ;
2396 if (count($admins) < 1) {
2397 $this->setError(_("Group does not have any administrators."));
2401 // send one email per admin
2402 foreach ($admins as $admin) {
2403 setup_gettext_for_user ($admin) ;
2405 $message=sprintf(_('Your project registration for %4$s has been approved.
2407 Project Full Name: %1$s
2408 Project Unix Name: %2$s
2410 Your DNS will take up to a day to become active on our site.
2411 Your web site is accessible through your shell account. Please read
2412 site documentation (see link below) about intended usage, available
2413 services, and directory layout of the account.
2416 own project page in %4$s while logged in, you will find
2417 additional menu functions to your left labeled \'Project Admin\'.
2419 We highly suggest that you now visit %4$s and create a public
2420 description for your project. This can be done by visiting your project
2421 page while logged in, and selecting \'Project Admin\' from the menus
2422 on the left (or by visiting %3$s
2425 Your project will also not appear in the Trove Software Map (primary
2426 list of projects hosted on %4$s which offers great flexibility in
2427 browsing and search) until you categorize it in the project administration
2428 screens. So that people can find your project, you should do this now.
2429 Visit your project while logged in, and select \'Project Admin\' from the
2432 Enjoy the system, and please tell others about %4$s. Let us know
2433 if there is anything we can do to help you.
2436 htmlspecialchars_decode($this->getPublicName()),
2437 $this->getUnixName(),
2438 util_make_url ('/project/admin/?group_id='.$this->getID()),
2439 forge_get_config ('forge_name'));
2441 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Approved'), forge_get_config ('forge_name')), $message);
2443 setup_gettext_from_context();
2451 * sendRejectionEmail - Send project rejection email.
2453 * This function sends out a rejection message to a user who
2454 * registered a project.
2456 * @param int The id of the response to use.
2457 * @param string The rejection message.
2458 * @return completion status.
2461 function sendRejectionEmail($response_id, $message="zxcv") {
2462 $res_admins = db_query_params ('
2463 SELECT u.email, u.language, u.user_id
2464 FROM users u, user_group ug
2465 WHERE ug.group_id=$1
2466 AND u.user_id=ug.user_id',
2467 array ($this->getID())) ;
2468 if (db_numrows($res_admins) < 1) {
2469 $this->setError(_("Group does not have any administrators."));
2473 while ($row_admins = db_fetch_array($res_admins)) {
2474 $admin =& user_get_object($row_admins['user_id']);
2475 setup_gettext_for_user ($admin) ;
2477 $response=sprintf(_('Your project registration for %3$s has been denied.
2479 Project Full Name: %1$s
2480 Project Unix Name: %2$s
2482 Reasons for negative decision:
2484 '), $this->getPublicName(), $this->getUnixName(), forge_get_config ('forge_name'));
2486 // Check to see if they want to send a custom rejection response
2487 if ($response_id == 0) {
2488 $response .= $message;
2490 $response .= db_result (
2491 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array ($response_id)),
2496 util_send_message($row_admins['email'], sprintf(_('%1$s Project Denied'), forge_get_config ('forge_name')), $response);
2497 setup_gettext_from_context();
2504 * sendNewProjectNotificationEmail - Send new project notification email.
2506 * This function sends out a notification email to the
2507 * SourceForge admin user when a new project is
2510 * @return boolean success.
2513 function sendNewProjectNotificationEmail() {
2514 // Get the user who wants to register the project
2515 $res = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1',
2516 array ($this->getID())) ;
2518 if (db_numrows($res) < 1) {
2519 $this->setError(_("Could not find user who has submitted the project."));
2523 $submitter =& user_get_object(db_result($res,0,'user_id'));
2526 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_approve', -1) ;
2528 if (count($admins) < 1) {
2529 $this->setError(_("There is no administrator to send the mail to."));
2533 foreach ($admins as $admin) {
2534 $admin_email = $admin->getEmail () ;
2535 setup_gettext_for_user ($admin) ;
2537 $message=sprintf(_('New %1$s Project Submitted
2539 Project Full Name: %2$s
2540 Submitted Description: %3$s
2541 Submitter: %5$s (%6$s)
2543 Please visit the following URL to approve or reject this project:
2545 forge_get_config ('forge_name'),
2546 htmlspecialchars_decode($this->getPublicName()),
2547 htmlspecialchars_decode($this->getRegistrationPurpose()),
2548 util_make_url ('/admin/approve-pending.php'),
2549 $submitter->getRealName(),
2550 $submitter->getUnixName());
2551 util_send_message($admin_email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2552 setup_gettext_from_context();
2556 $email = $submitter->getEmail() ;
2557 setup_gettext_for_user ($submitter) ;
2559 $message=sprintf(_('New %1$s Project Submitted
2561 Project Full Name: %2$s
2562 Submitted Description: %3$s
2564 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'));
2566 util_send_message($email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2567 setup_gettext_from_context();
2576 * validateGroupName - Validate the group name
2578 * @param string Group name.
2580 * @return an error false and set an error is the group name is invalide otherwise return true
2582 function validateGroupName($group_name) {
2583 if (strlen($group_name)<3) {
2584 $this->setError(_('Group name is too short'));
2586 } else if (strlen(htmlspecialchars($group_name))>50) {
2587 $this->setError(_('Group name is too long'));
2589 } else if ($group=group_get_object_by_publicname($group_name)) {
2590 $this->setError(_('Group name already taken'));
2598 * getRoles - Get the roles of the group.
2600 * @return array of Role id of this group.
2602 function getRolesId () {
2603 $role_ids = array () ;
2606 $res = db_query_params ('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2607 array ($this->getID()));
2608 while ($arr = db_fetch_array($res)) {
2609 $role_ids[] = $arr['role_id'] ;
2611 $res = db_query_params ('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2612 array ($this->getID()));
2613 while ($arr = db_fetch_array($res)) {
2614 $role_ids[] = $arr['role_id'] ;
2617 $res = db_query_params ('SELECT role_id FROM role WHERE group_id=$1',
2618 array ($this->getID()));
2619 while ($arr = db_fetch_array($res)) {
2620 $role_ids[] = $arr['role_id'] ;
2624 return array_unique ($role_ids) ;
2627 function getRoles () {
2628 $result = array () ;
2630 $roles = $this->getRolesId () ;
2632 $engine = RBACEngine::getInstance() ;
2633 foreach ($roles as $role_id) {
2634 $result[] = $engine->getRoleById ($role_id) ;
2637 foreach ($roles as $role_id) {
2638 $result[] = new Role ($this, $role_id) ;
2645 function normalizeAllRoles () {
2646 $roles = $this->getRoles () ;
2648 foreach ($roles as $r) {
2649 $r->normalizeData () ;
2654 * getUnixStatus - Status of activation of unix account.
2656 * @return char (N)one, (A)ctive, (S)uspended or (D)eleted
2658 function getUnixStatus() {
2659 return $this->data_array['unix_status'];
2663 * setUnixStatus - Sets status of activation of unix account.
2665 * @param string The unix status.
2671 * @return boolean success.
2673 function setUnixStatus($status) {
2676 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
2681 $this->setError(sprintf(_('ERROR - Could Not Update Group Unix Status: %s'),db_error()));
2685 if ($status == 'A') {
2686 if (!$SYS->sysCheckCreateGroup($this->getID())) {
2687 $this->setError($SYS->getErrorMessage());
2692 if ($SYS->sysCheckGroup($this->getID())) {
2693 if (!$SYS->sysRemoveGroup($this->getID())) {
2694 $this->setError($SYS->getErrorMessage());
2701 $this->data_array['unix_status']=$status;
2708 * getUsers - Get the users of a group
2710 * @return array of user's objects.
2712 function getUsers($onlylocal = true) {
2713 if (!isset($this->membersArr)) {
2714 $this->membersArr = array () ;
2718 foreach ($this->getRoles() as $role) {
2720 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
2723 foreach ($role->getUsers() as $user) {
2724 $ids[] = $user->getID() ;
2727 $ids = array_unique ($ids) ;
2728 foreach ($ids as $id) {
2729 $u = user_get_object ($id) ;
2730 if ($u->isActive()) {
2731 $this->membersArr[] = $u ;
2736 $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',
2737 array ($this->getID(),
2739 if (!$users_group_res) {
2740 $this->setError('Error: Enable to get users from group '. $this->getID() . ' ' .db_error());
2744 for ($i=0; $i<db_numrows($users_group_res); $i++) {
2745 $this->membersArr[$i] = new GFUser(db_result($users_group_res,$i,'user_id'),false);
2750 return $this->membersArr;
2753 function setDocmanSearchStatus($status) {
2755 /* if we activate search engine, we probably want to reindex */
2756 $res = db_query_params ('UPDATE groups SET use_docman_search=$1, force_docman_reindex=$1 WHERE group_id=$2',
2761 $this->setError(sprintf(_('ERROR - Could Not Update Group UseDocmanSearch Status: %s'),db_error()));
2765 $this->data_array['use_docman_search']=$status;
2771 function setDocmanForceReindexSearch($status) {
2773 /* if we activate search engine, we probably want to reindex */
2774 $res = db_query_params ('UPDATE groups SET force_docman_reindex=$1 WHERE group_id=$2',
2779 $this->setError(sprintf(_('ERROR - Could Not Update Group force_docman_reindex %s'),db_error()));
2783 $this->data_array['force_docman_reindex']=$status;
2791 * group_getname() - get the group name
2793 * @param int The group ID
2797 function group_getname ($group_id = 0) {
2798 $grp = &group_get_object($group_id);
2800 return $grp->getPublicName();
2807 * group_getunixname() - get the unixname for a group
2809 * @param int The group ID
2813 function group_getunixname ($group_id) {
2814 $grp = &group_get_object($group_id);
2816 return $grp->getUnixName();
2823 * group_get_result() - Get the group object result ID.
2825 * @param int The group ID
2829 function &group_get_result($group_id=0) {
2830 $grp = &group_get_object($group_id);
2832 return $grp->getData();
2838 class ProjectComparator {
2839 var $criterion = 'name' ;
2841 function Compare ($a, $b) {
2842 switch ($this->criterion) {
2845 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName()) ;
2846 if ($namecmp != 0) {
2849 /* If several projects share a same public name */
2850 return strcoll ($a->getUnixName(), $b->getUnixName()) ;
2853 return strcmp ($a->getUnixName(), $b->getUnixName()) ;
2856 $aid = $a->getID() ;
2857 $bid = $b->getID() ;
2861 return ($a < $b) ? -1 : 1;
2867 function sortProjectList (&$list, $criterion='name') {
2868 $cmp = new ProjectComparator () ;
2869 $cmp->criterion = $criterion ;
2871 return usort ($list, array ($cmp, 'Compare')) ;
2876 // c-file-style: "bsd"