5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009, Roland Mas
7 * Copyright 2010, Franck Villaume - Capgemini
9 * This file is part of FusionForge.
11 * FusionForge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published
13 * by the Free Software Foundation; either version 2 of the License,
14 * or (at your option) any later version.
16 * FusionForge is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with FusionForge; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 require_once $gfcommon.'tracker/ArtifactTypes.class.php';
28 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
29 require_once $gfcommon.'forum/Forum.class.php';
30 require_once $gfcommon.'forum/ForumFactory.class.php';
31 require_once $gfcommon.'pm/ProjectGroup.class.php';
32 require_once $gfcommon.'pm/ProjectGroupFactory.class.php';
33 require_once $gfcommon.'include/Role.class.php';
34 require_once $gfcommon.'frs/FRSPackage.class.php';
35 require_once $gfcommon.'docman/DocumentGroup.class.php';
36 require_once $gfcommon.'mail/MailingList.class.php';
37 require_once $gfcommon.'mail/MailingListFactory.class.php';
38 require_once $gfcommon.'survey/SurveyFactory.class.php';
39 require_once $gfcommon.'survey/SurveyQuestionFactory.class.php';
40 require_once $gfcommon.'include/gettext.php';
41 require_once $gfcommon.'include/GroupJoinRequest.class.php';
43 //the license_id of "Other/proprietary" license
44 define('GROUP_LICENSE_OTHER',126);
46 $LICENSE_NAMES=array();
49 * group_get_licences() - get the licenses list
51 * @return array list of licenses
53 function & group_get_licenses() {
54 global $LICENSE_NAMES;
55 if(empty($LICENSE_NAMES)) {
56 $result = db_query_params ('select * from licenses', array());
57 while($data = db_fetch_array($result)) {
58 $LICENSE_NAMES[$data['license_id']] = $data['license_name'];
61 return $LICENSE_NAMES;
67 * group_get_object() - Get the group object.
69 * group_get_object() is useful so you can pool group objects/save database queries
70 * You should always use this instead of instantiating the object directly.
72 * You can now optionally pass in a db result handle. If you do, it re-uses that query
73 * to instantiate the objects.
75 * IMPORTANT! That db result must contain all fields
76 * from groups table or you will have problems
79 * @param int Result set handle ("SELECT * FROM groups WHERE group_id=xx")
80 * @return a group object or false on failure
82 function &group_get_object($group_id,$res=false) {
83 //create a common set of group objects
84 //saves a little wear on the database
86 //automatically checks group_type and
87 //returns appropriate object
90 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
92 //the db result handle was passed in
94 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1', array ($group_id)) ;
96 if (!$res || db_numrows($res) < 1) {
97 $GROUP_OBJ["_".$group_id."_"]=false;
100 check group type and set up object
102 if (db_result($res,0,'type_id')==1) {
104 $GROUP_OBJ["_".$group_id."_"]= new Group($group_id,$res);
107 $GROUP_OBJ["_".$group_id."_"]=false;
111 return $GROUP_OBJ["_".$group_id."_"];
114 function &group_get_objects($id_arr) {
117 // Note: if we don't do this, the result may be corrupted
121 for ($i=0; $i<count($id_arr); $i++) {
123 // See if this ID already has been fetched in the cache
128 if (!isset($GROUP_OBJ["_".$id_arr[$i]."_"])) {
129 $fetch[]=$id_arr[$i];
131 $return[] =& $GROUP_OBJ["_".$id_arr[$i]."_"];
134 if (count($fetch) > 0) {
135 $res=db_query_params ('SELECT * FROM groups WHERE group_id = ANY ($1)',
136 array (db_int_array_to_any_clause ($fetch))) ;
137 while ($arr = db_fetch_array($res)) {
138 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
139 $return[] =& $GROUP_OBJ["_".$arr['group_id']."_"];
145 function &group_get_active_projects() {
146 $res=db_query_params ('SELECT group_id FROM groups WHERE status=$1',
148 return group_get_objects (util_result_column_to_array($res,0)) ;
151 function &group_get_object_by_name($groupname) {
152 $res=db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array ($groupname)) ;
153 return group_get_object(db_result($res,0,'group_id'),$res);
156 function &group_get_objects_by_name($groupname_arr) {
157 $res=db_query_params ('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
158 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.
221 function Group($id=false, $res=false) {
224 //setting up an empty object
225 //probably going to call create()
229 if (!$this->fetchData($id)) {
234 // Assoc array was passed in
236 if (is_array($res)) {
237 $this->data_array =& $res;
239 if (db_numrows($res) < 1) {
240 //function in class we extended
241 $this->setError(_('Group Not Found'));
242 $this->data_array=array();
245 //set up an associative array for use by other functions
246 $this->data_array = db_fetch_array_by_row($res, 0);
255 * fetchData - May need to refresh database fields if an update occurred.
257 * @param int The group_id.
259 function fetchData($group_id) {
260 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
262 if (!$res || db_numrows($res) < 1) {
263 $this->setError(sprintf(_('fetchData():: %s'),db_error()));
266 $this->data_array = db_fetch_array($res);
271 * create - Create new group.
273 * This method should be called on empty Group object.
275 * @param object The User object.
276 * @param string The full name of the user.
277 * @param string The Unix name of the user.
278 * @param string The new group description.
279 * @param string The purpose of the group.
280 * @param bool Whether to send an email or not
282 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true) {
283 // $user is ignored - anyone can create pending group
286 if ($this->getID()!=0) {
287 $this->setError(_('Group::create: Group object already exists'));
289 } else if (!$this->validateGroupName($group_name)) {
291 } else if (!account_groupnamevalid($unix_name)) {
292 $this->setError(_('Invalid Unix name'));
294 } else if (!$SYS->sysUseUnixName($unix_name)) {
295 $this->setError(_('Unix name already taken'));
297 } else if (db_numrows(db_query_params('SELECT group_id FROM groups WHERE unix_group_name=$1',
298 array ($unix_name))) > 0) {
299 $this->setError(_('Unix name already taken'));
301 } else if (strlen($purpose)<10) {
302 $this->setError(_('Please describe your Registration Purpose in a more comprehensive manner'));
304 } else if (strlen($purpose)>1500) {
305 $this->setError(_('The Registration Purpose text is too long. Please make it smaller than 1500 bytes.'));
307 } else if (strlen($description)<10) {
308 $this->setError(_('Describe in a more comprehensive manner your project.'));
310 } else if (strlen($description)>255) {
311 $this->setError(_('Your project description is too long. Please make it smaller than 256 bytes.'));
315 srand((double)microtime()*1000000);
316 $random_num = rand(0,1000000);
320 $res = db_query_params ('
336 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
337 array (htmlspecialchars ($group_name),
340 htmlspecialchars($description),
341 $unix_name.".".forge_get_config('web_host'),
342 $unix_name.".".forge_get_config('web_host'),
346 htmlspecialchars($purpose),
349 md5($random_num) )) ;
350 if (!$res || db_affected_rows($res) < 1) {
351 $this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
356 $id = db_insertid($res, 'groups', 'group_id');
358 $this->setError(sprintf(_('ERROR: Could not get group id: %s'),db_error()));
363 if (!$this->fetchData($id)) {
369 $gjr = new GroupJoinRequest ($this) ;
370 $gjr->create ($user->getID(),
371 'Fake GroupJoinRequest to store the creator of a project',
375 // Now, make the user an admin
377 $res=db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags,
378 cvs_flags, artifact_flags, forum_flags, role_id)
379 VALUES ($1, $2, $3, $4, $5, $6, $7)',
380 array ($user->getID(),
387 if (!$res || db_affected_rows($res) < 1) {
388 $this->setError(sprintf(_('ERROR: Could not add admin to newly created group: %s'),db_error()));
394 $hook_params = array ();
395 $hook_params['group'] = $this;
396 $hook_params['group_id'] = $this->getID();
397 $hook_params['group_name'] = $group_name;
398 $hook_params['unix_group_name'] = $unix_name;
399 plugin_hook ("group_create", $hook_params);
403 $this->sendNewProjectNotificationEmail();
411 * updateAdmin - Update core properties of group object.
413 * This function require site admin privilege.
415 * @param object User requesting operation (for access control).
416 * @param bool Whether group is publicly accessible (0/1).
417 * @param int Group type (1-project, 2-foundry).
418 * @param string Machine on which group's home directory located.
419 * @param string Domain which serves group's WWW.
423 function updateAdmin(&$user, $is_public, $type_id, $unix_box, $http_domain) {
424 $perm =& $this->getPermission ();
426 if (!$perm || !is_object($perm)) {
427 $this->setError(_('Could not get permission.'));
431 if (!$perm->isSuperUser()) {
432 $this->setError(_('Permission denied.'));
438 $res = db_query_params ('
440 SET is_public=$1, type_id=$2,
441 unix_box=$3, http_domain=$4
449 if (!$res || db_affected_rows($res) < 1) {
450 $this->setError(_('ERROR: DB: Could not change group properties: %s'),db_error());
455 // Log the audit trail
456 if ($is_public != $this->isPublic()) {
457 $this->addHistory('is_public', $this->isPublic());
459 if ($type_id != $this->data_array['type_id']) {
460 $this->addHistory('type_id', $this->data_array['type_id']);
462 if ($unix_box != $this->data_array['unix_box']) {
463 $this->addHistory('unix_box', $this->data_array['unix_box']);
465 if ($http_domain != $this->data_array['http_domain']) {
466 $this->addHistory('http_domain', $this->data_array['http_domain']);
469 if (!$this->fetchData($this->getID())) {
478 * update - Update number of common properties.
480 * Unlike updateAdmin(), this function accessible to project admin.
482 * @param object User requesting operation (for access control).
483 * @param bool Whether group is publicly accessible (0/1).
484 * @param string Project's license (string ident).
485 * @param int Group type (1-project, 2-foundry).
486 * @param string Machine on which group's home directory located.
487 * @param string Domain which serves group's WWW.
488 * @return int status.
491 function update(&$user, $group_name,$homepage,$short_description,$use_mail,$use_survey,$use_forum,
492 $use_pm,$use_pm_depend_box,$use_scm,$use_news,$use_docman,
493 $new_doc_address,$send_all_docs,$logo_image_id,
494 $use_ftp,$use_tracker,$use_frs,$use_stats,$tags,$is_public) {
496 $perm =& $this->getPermission ();
498 if (!$perm || !is_object($perm)) {
499 $this->setError(_('Could not get permission.'));
503 if (!$perm->isAdmin()) {
504 $this->setError(_('Permission denied.'));
508 // Validate some values
509 if ($this->getPublicName() != $group_name) {
510 if (!$this->validateGroupName($group_name)) {
515 if ($new_doc_address) {
516 $invalid_mails = validate_emails($new_doc_address);
517 if (count($invalid_mails) > 0) {
518 $this->setError(sprintf (ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
523 // in the database, these all default to '1',
524 // so we have to explicity set 0
537 if (!$use_pm_depend_box) {
538 $use_pm_depend_box=0;
561 if (!$send_all_docs) {
565 $homepage = ltrim($homepage);
567 $homepage=forge_get_config('web_host').'/projects/'.$this->getUnixName().'/';
570 if (strlen(htmlspecialchars($short_description))>255) {
571 $this->setError(_('Error updating project information: Maximum length for Project Description is 255 chars.'));
577 //XXX not yet actived logo_image_id='$logo_image_id',
578 $res = db_query_params ('UPDATE groups
581 short_description=$3,
586 use_pm_depend_box=$8,
598 array (htmlspecialchars($group_name),
600 htmlspecialchars($short_description),
619 $this->setError(sprintf(_('Error updating project information: %s'), db_error()));
624 if ($this->setTags($tags) === false) {
629 $hook_params = array ();
630 $hook_params['group'] = $this;
631 $hook_params['group_id'] = $this->getID();
632 $hook_params['group_homepage'] = $homepage;
633 $hook_params['group_name'] = htmlspecialchars($group_name);
634 $hook_params['group_description'] = htmlspecialchars($short_description);
635 plugin_hook ("group_update", $hook_params);
637 // Log the audit trail
638 $this->addHistory('Changed Public Info', '');
640 if (!$this->fetchData($this->getID())) {
649 * getID - Simply return the group_id for this object.
651 * @return int group_id.
654 return $this->data_array['group_id'];
658 * getType() - Foundry, project, etc.
660 * @return int The type flag from the database.
663 return $this->data_array['type_id'];
668 * getStatus - the status code.
670 * Statuses char include I,H,A,D.
672 function getStatus() {
673 return $this->data_array['status'];
677 * setStatus - set the status code.
679 * Statuses include I,H,A,D.
681 * @param object User requesting operation (for access control).
682 * @param string Status value.
683 * @return boolean success.
686 function setStatus(&$user, $status) {
689 $perm =& $this->getPermission ();
690 if (!$perm || !is_object($perm)) {
691 $this->setPermissionDeniedError();
693 } elseif (!$perm->isSuperUser()) {
694 $this->setPermissionDeniedError();
698 // Projects in 'A' status can only go to 'H' or 'D'
699 // Projects in 'D' status can only go to 'A'
700 // Projects in 'P' status can only go to 'A' OR 'D'
701 // Projects in 'I' status can only go to 'P'
702 // Projects in 'H' status can only go to 'A' OR 'D'
703 $allowed_status_changes = array(
704 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
705 'IP'=>1,'HA'=>1,'HD'=>1
708 // Check that status transition is valid
709 if ($this->getStatus() != $status
710 && !$allowed_status_changes[$this->getStatus().$status]) {
711 $this->setError(_('Invalid Status Change'));
717 $res = db_query_params ('UPDATE groups
719 WHERE group_id=$2', array ($status, $this->getID())) ;
721 if (!$res || db_affected_rows($res) < 1) {
722 $this->setError(sprintf(_('ERROR: DB: Could not change group status: %s'),db_error()));
728 // Activate system group, if not yet
729 if (!$SYS->sysCheckGroup($this->getID())) {
730 if (!$SYS->sysCreateGroup($this->getID())) {
731 $this->setError($SYS->getErrorMessage());
736 if (!$this->activateUsers()) {
741 /* Otherwise, the group is not active, and make sure that
742 System group is not active either */
743 } else if ($SYS->sysCheckGroup($this->getID())) {
744 if (!$SYS->sysRemoveGroup($this->getID())) {
745 $this->setError($SYS->getErrorMessage());
751 $hook_params = array ();
752 $hook_params['group'] = $this;
753 $hook_params['group_id'] = $this->getID();
754 $hook_params['status'] = $status;
755 plugin_hook ("group_setstatus", $hook_params);
759 // Log the audit trail
760 if ($status != $this->getStatus()) {
761 $this->addHistory('Status', $this->getStatus());
764 $this->data_array['status'] = $status;
769 * isProject - Simple boolean test to see if it's a project or not.
771 * @return boolean is_project.
773 function isProject() {
774 if ($this->getType()==1) {
782 * isPublic - Simply returns the is_public flag from the database.
784 * @return boolean is_public.
786 function isPublic() {
787 return $this->data_array['is_public'];
791 * isActive - Database field status of 'A' returns true.
793 * @return boolean is_active.
795 function isActive() {
796 if ($this->getStatus()=='A') {
804 * getUnixName - the unix_name
806 * @return string unix_name.
808 function getUnixName() {
809 return strtolower($this->data_array['unix_group_name']);
813 * getPublicName - the full-length public name.
815 * @return string The group_name.
817 function getPublicName() {
818 return $this->data_array['group_name'];
822 * getRegisterPurpose - the text description of the purpose of this project.
824 * @return string The description.
826 function getRegisterPurpose() {
827 return $this->data_array['register_purpose'];
831 * getDescription - the text description of this project.
833 * @return string The description.
835 function getDescription() {
836 return $this->data_array['short_description'];
840 * getStartDate - the unix time this project was registered.
842 * @return int (unix time) of registration.
844 function getStartDate() {
845 return $this->data_array['register_time'];
849 * getLogoImageID - the id of the logo in the database for this project.
851 * @return int The ID of logo image in db_images table (or 100 if none).
853 function getLogoImageID() {
854 return $this->data_array['logo_image_id'];
858 * getUnixBox - the hostname of the unix box where this project is located.
860 * @return string The name of the unix machine for the group.
862 function getUnixBox() {
863 return $this->data_array['unix_box'];
867 * getSCMBox - the hostname of the scm box where this project is located.
869 * @return string The name of the unix machine for the group.
871 function getSCMBox() {
872 return $this->data_array['scm_box'];
875 * setSCMBox - the hostname of the scm box where this project is located.
877 * @param string The name of the new SCM_BOX
879 function setSCMBox($scm_box) {
881 if ($scm_box == $this->data_array['scm_box']) {
886 $res = db_query_params ('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array ($scm_box, $this->getID ()));
888 $this->addHistory('scm_box', $this->data_array['scm_box']);
889 $this->data_array['scm_box']=$scm_box;
894 $this->setError(_("Couldn't insert SCM_BOX to database"));
898 $this->setError(_("SCM Box can't be empty"));
904 * getDomain - the hostname.domain where their web page is located.
906 * @return string The name of the group [web] domain.
908 function getDomain() {
909 return $this->data_array['http_domain'];
913 * getLicense - the license they chose.
915 * @return int ident of group license.
917 function getLicense() {
918 return $this->data_array['license'];
922 * getLicenseName - the name of the license
924 * @return string license name
926 function getLicenseName() {
927 $licenses =& group_get_licenses();
928 if(isset($licenses[$this->data_array['license']])) {
929 return $licenses[$this->data_array['license']];
936 * getLicenseOther - optional string describing license.
938 * @return string The custom license.
940 function getLicenseOther() {
941 if ($this->getLicense() == GROUP_LICENSE_OTHER) {
942 return $this->data_array['license_other'];
949 * getRegistrationPurpose - the text description of the purpose of this project.
951 * @return string The application for project hosting.
953 function getRegistrationPurpose() {
954 return $this->data_array['register_purpose'];
959 * getAdmins() - Get array of Admin user objects.
961 * @return array Array of User objects.
963 function &getAdmins() {
964 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID()) ;
966 $user_ids = array () ;
968 foreach ($roles as $role) {
969 if (! ($role instanceof RoleExplicit)) {
972 if ($role->getHomeProject() == NULL
973 || $role->getHomeProject()->getID() != $this->getID()) {
977 foreach ($role->getUsers() as $u) {
978 $user_ids[] = $u->getID() ;
982 return user_get_objects(array_unique($user_ids));
987 Common Group preferences for tools
992 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
994 * @return boolean enable_scm.
996 function enableAnonSCM() {
998 $r = RoleAnonymous::getInstance () ;
999 return $r->hasPermission ('scm', $this->getID(), 'read') ;
1001 if ($this->isPublic() && $this->usesSCM()) {
1002 return $this->data_array['enable_anonscm'];
1009 function SetUsesAnonSCM ($booleanparam) {
1011 $booleanparam = $booleanparam ? 1 : 0 ;
1013 $r = RoleAnonymous::getInstance () ;
1014 $r->setSetting ('scm', $this->getID(), $booleanparam) ;
1017 $res = db_query_params ('UPDATE groups SET enable_anonscm=$1 WHERE group_id=$2',
1018 array ($booleanparam, $this->getID()));
1020 $this->data_array['enable_anonscm']=$booleanparam;
1029 function setUsesSCM ($booleanparam) {
1031 $booleanparam = $booleanparam ? 1 : 0 ;
1032 $res = db_query_params ('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
1033 array ($booleanparam, $this->getID()));
1035 $this->data_array['use_scm']=$booleanparam;
1044 * enablePserver - whether or not this group has opted to enable Pserver.
1046 * @return boolean enable_pserver.
1048 function enablePserver() {
1049 if ($this->usesSCM()) {
1050 return $this->data_array['enable_pserver'];
1056 function SetUsesPserver ($booleanparam) {
1058 $booleanparam = $booleanparam ? 1 : 0 ;
1059 $res = db_query_params ('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1060 array ($booleanparam, $this->getID()));
1062 $this->data_array['enable_pserver']=$booleanparam;
1071 * usesSCM - whether or not this group has opted to use SCM.
1073 * @return boolean uses_scm.
1075 function usesSCM() {
1077 if (forge_get_config('use_scm')) {
1078 return $this->data_array['use_scm'];
1085 * usesMail - whether or not this group has opted to use mailing lists.
1087 * @return boolean uses_mail.
1089 function usesMail() {
1091 if (forge_get_config('use_mail')) {
1092 return $this->data_array['use_mail'];
1099 * usesNews - whether or not this group has opted to use news.
1101 * @return boolean uses_news.
1103 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() {
1119 if (forge_get_config('use_forum')) {
1120 return $this->data_array['use_forum'];
1127 * usesStats - whether or not this group has opted to use stats.
1129 * @return boolean uses_stats.
1131 function usesStats() {
1132 return $this->data_array['use_stats'];
1136 * usesFRS - whether or not this group has opted to use file release system.
1138 * @return boolean uses_frs.
1140 function usesFRS() {
1142 if (forge_get_config('use_frs')) {
1143 return $this->data_array['use_frs'];
1150 * usesTracker - whether or not this group has opted to use tracker.
1152 * @return boolean uses_tracker.
1154 function usesTracker() {
1156 if (forge_get_config('use_tracker')) {
1157 return $this->data_array['use_tracker'];
1164 * useCreateOnline - whether or not this group has opted to use create online documents option.
1166 * @return boolean use_docman_create_online.
1168 function useCreateOnline() {
1170 if (forge_get_config('use_docman')) {
1171 return $this->data_array['use_docman_create_online'];
1178 * usesDocman - whether or not this group has opted to use docman.
1180 * @return boolean use_docman.
1182 function usesDocman() {
1184 if (forge_get_config('use_docman')) {
1185 return $this->data_array['use_docman'];
1192 * useDocmanSearch - whether or not this group has opted to use docman search engine.
1194 * @return boolean use_docman_search.
1196 function useDocmanSearch() {
1198 if (forge_get_config('use_docman')) {
1199 return $this->data_array['use_docman_search'];
1206 * useWebdav - whether or not this group has opted to use webdav interface.
1208 * @return boolean use_docman_search.
1210 function useWebdav() {
1212 if (forge_get_config('use_webdav')) {
1213 return $this->data_array['use_webdav'];
1220 * usesFTP - whether or not this group has opted to use FTP.
1222 * @return boolean uses_ftp.
1224 function usesFTP() {
1226 if (forge_get_config('use_ftp')) {
1227 return $this->data_array['use_ftp'];
1234 * usesSurvey - whether or not this group has opted to use surveys.
1236 * @return boolean uses_survey.
1238 function usesSurvey() {
1240 if (forge_get_config('use_survey')) {
1241 return $this->data_array['use_survey'];
1248 * usesPM - whether or not this group has opted to Project Manager.
1250 * @return boolean uses_projman.
1254 if (forge_get_config('use_pm')) {
1255 return $this->data_array['use_pm'];
1262 * getPlugins - get a list of all available group plugins
1264 * @return array array containing plugin_id => plugin_name
1266 function getPlugins() {
1267 if (!isset($this->plugins_data)) {
1268 $this->plugins_data = array () ;
1269 $res = db_query_params ('SELECT group_plugin.plugin_id, plugins.plugin_name
1270 FROM group_plugin, plugins
1271 WHERE group_plugin.group_id=$1
1272 AND group_plugin.plugin_id=plugins.plugin_id', array ($this->getID()));
1273 $rows = db_numrows($res);
1275 for ($i=0; $i<$rows; $i++) {
1276 $plugin_id = db_result($res,$i,'plugin_id');
1277 $this->plugins_data[$plugin_id] = db_result($res,$i,'plugin_name');
1280 return $this->plugins_data ;
1284 * usesPlugin - returns true if the group uses a particular plugin
1286 * @param string name of the plugin
1287 * @return boolean whether plugin is being used or not
1289 function usesPlugin($pluginname) {
1290 $plugins_data = $this->getPlugins() ;
1291 foreach ($plugins_data as $p_id => $p_name) {
1292 if ($p_name == $pluginname) {
1299 * added for Codendi compatibility
1300 * usesServices - returns true if the group uses a particular plugin or feature
1302 * @param string name of the plugin
1303 * @return boolean whether plugin is being used or not
1305 function usesService($feature) {
1306 $plugins_data = $this->getPlugins() ;
1307 $pm = plugin_manager_get_object();
1308 foreach ($plugins_data as $p_id => $p_name) {
1309 if ($p_name == $feature) {
1312 if ($pm->getPluginByName($p_name)->provide($feature) ) {
1320 * setPluginUse - enables/disables plugins for the group
1322 * @param string name of the plugin
1323 * @param boolean the new state
1324 * @return string database result
1326 function setPluginUse($pluginname, $val=true) {
1327 if ($val == $this->usesPlugin($pluginname)) {
1328 // State is already good, returning
1331 $res = db_query_params ('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1332 array ($pluginname));
1333 $rows = db_numrows($res);
1335 // Error: no plugin by that name
1338 $plugin_id = db_result($res,0,'plugin_id');
1340 unset ($this->plugins_data) ;
1342 $res = db_query_params ('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1343 array ($this->getID(),
1347 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1348 array ($this->getID(),
1355 * getDocEmailAddress - get email address(es) to send doc notifications to.
1357 * @return string email address.
1359 function getDocEmailAddress() {
1360 return $this->data_array['new_doc_address'];
1364 * DocEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1366 * @return boolean email_on_all_doc_updates.
1368 function docEmailAll() {
1369 return $this->data_array['send_all_docs'];
1374 * getHomePage - The URL for this project's home page.
1376 * @return string homepage URL.
1378 function getHomePage() {
1379 return $this->data_array['homepage'];
1383 * getTags - Tags of this project.
1385 * @return string List of tags.
1387 function getTags() {
1388 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1389 $res = db_query_params($sql, array($this->getID()));
1390 return join(', ', util_result_column_to_array($res));
1394 * setTags - Set tags of this project.
1396 * @return string database result.
1398 function setTags($tags) {
1400 $sql='DELETE FROM project_tags WHERE group_id=$1';
1401 $res=db_query_params($sql, array($this->getID()));
1403 $this->setError('Deleting old tags: '.db_error());
1407 $inserted = array();
1408 $tags_array = preg_split('/[;,]/', $tags);
1409 foreach ($tags_array as $tag) {
1410 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1411 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1412 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1413 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1418 if ($tag == '' || array_search($tag, $inserted) !== false) continue;
1419 $sql='INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1420 $res=db_query_params($sql, array($this->getID(), $tag));
1422 $this->setError(_('Setting tags: ').db_error());
1433 * getPermission - Return a Permission for this Group
1435 * @return object The Permission.
1437 function &getPermission() {
1438 return permission_get_object($this);
1442 function delete($sure,$really_sure,$really_really_sure) {
1443 if (!$sure || !$really_sure || !$really_really_sure) {
1444 $this->setMissingParamsError();
1447 if ($this->getID() == forge_get_config('news_group') ||
1448 $this->getID() == 1 ||
1449 $this->getID() == forge_get_config('stats_group') ||
1450 $this->getID() == forge_get_config('peer_rating_group')) {
1451 $this->setError(_('Cannot Delete System Group'));
1454 $perm =& $this->getPermission ();
1455 if (!$perm || !is_object($perm)) {
1456 $this->setPermissionDeniedError();
1458 } elseif ($perm->isError()) {
1459 $this->setPermissionDeniedError();
1461 } elseif (!$perm->isSuperUser()) {
1462 $this->setPermissionDeniedError();
1468 // Remove all the members
1470 $members =& $this->getMembers();
1471 for ($i=0; $i<count($members); $i++) {
1472 $this->removeUser($members[$i]->getID());
1474 // Failsafe until user_group table is gone
1475 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1',
1476 array ($this->getID())) ;
1480 $atf = new ArtifactTypeFactory($this);
1481 $at_arr =& $atf->getArtifactTypes();
1482 for ($i=0; $i<count($at_arr); $i++) {
1483 if (!is_object($at_arr[$i])) {
1484 printf (_("Not Object: ArtifactType: %d"),$i);
1487 $at_arr[$i]->delete(1,1);
1492 $ff = new ForumFactory($this);
1493 $f_arr =& $ff->getForums();
1494 for ($i=0; $i<count($f_arr); $i++) {
1495 if (!is_object($f_arr[$i])) {
1496 printf (_("Not Object: Forum: %d"),$i);
1499 $f_arr[$i]->delete(1,1);
1502 // Delete Subprojects
1504 $pgf = new ProjectGroupFactory($this);
1505 $pg_arr =& $pgf->getProjectGroups();
1506 for ($i=0; $i<count($pg_arr); $i++) {
1507 if (!is_object($pg_arr[$i])) {
1508 printf (_("Not Object: ProjectGroup: %d"),$i);
1511 $pg_arr[$i]->delete(1,1);
1514 // Delete FRS Packages
1516 //$frspf = new FRSPackageFactory($this);
1517 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
1518 array ($this->getID())) ;
1519 //echo 'frs_package'.db_error();
1520 //$frsp_arr =& $frspf->getPackages();
1521 while ($arr = db_fetch_array($res)) {
1522 //if (!is_object($pg_arr[$i])) {
1523 // echo "Not Object: ProjectGroup: ".$i;
1526 $frsp=new FRSPackage($this,$arr['package_id'],$arr);
1532 $news_group=&group_get_object(forge_get_config('news_group'));
1533 $res = db_query_params ('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1534 array ($this->getID())) ;
1536 $this->setError(_('Error Deleting News: ').db_error());
1541 for ($i=0; $i<db_numrows($res); $i++) {
1542 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1543 if (!$Forum->delete(1,1)) {
1544 printf (_("Could Not Delete News Forum: %d"),$Forum->getID());
1547 $res = db_query_params ('DELETE FROM news_bytes WHERE group_id=$1',
1548 array ($this->getID())) ;
1550 $this->setError(_('Error Deleting News: ').db_error());
1558 $res = db_query_params ('DELETE FROM doc_data WHERE group_id=$1',
1559 array ($this->getID())) ;
1561 $this->setError(_('Error Deleting Documents: ').db_error());
1566 $res = db_query_params ('DELETE FROM doc_groups WHERE group_id=$1',
1567 array ($this->getID())) ;
1569 $this->setError(_('Error Deleting Documents: ').db_error());
1577 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1579 $this->setError(_('Error Deleting Tags: ').db_error());
1585 // Delete group history
1587 $res = db_query_params ('DELETE FROM group_history WHERE group_id=$1',
1588 array ($this->getID())) ;
1590 $this->setError(_('Error Deleting Project History: ').db_error());
1596 // Delete group plugins
1598 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1',
1599 array ($this->getID())) ;
1601 $this->setError(_('Error Deleting Project Plugins: ').db_error());
1607 // Delete group cvs stats
1609 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1610 array ($this->getID())) ;
1612 $this->setError(_('Error Deleting SCM Statistics: ').db_error());
1620 $sf = new SurveyFactory($this);
1621 $s_arr =& $sf->getSurveys();
1622 for ($i=0; $i<count($s_arr); $i++) {
1623 if (!is_object($s_arr[$i])) {
1624 printf (_("Not Object: Survey: %d"),$i);
1627 $s_arr[$i]->delete();
1630 // Delete SurveyQuestions
1632 $sqf = new SurveyQuestionFactory($this);
1633 $sq_arr =& $sqf->getSurveyQuestions();
1634 for ($i=0; $i<count($sq_arr); $i++) {
1635 if (!is_object($sq_arr[$i])) {
1636 printf (_("Not Object: SurveyQuestion: %d"),$i);
1639 $sq_arr[$i]->delete();
1642 // Delete Mailing List Factory
1644 $mlf = new MailingListFactory($this);
1645 $ml_arr =& $mlf->getMailingLists();
1646 for ($i=0; $i<count($ml_arr); $i++) {
1647 if (!is_object($ml_arr[$i])) {
1648 printf (_("Not Object: MailingList: %d"),$i);
1651 if (!$ml_arr[$i]->delete(1,1)) {
1652 $this->setError(_('Could not properly delete the mailing list'));
1658 $res = db_query_params ('DELETE FROM trove_group_link WHERE group_id=$1',
1659 array ($this->getID())) ;
1661 $this->setError(_('Error Deleting Trove: ').db_error());
1666 $res = db_query_params ('DELETE FROM trove_agg WHERE group_id=$1',
1667 array ($this->getID())) ;
1669 $this->setError(_('Error Deleting Trove: ').db_error());
1677 $res = db_query_params ('DELETE FROM project_sums_agg WHERE group_id=$1',
1678 array ($this->getID())) ;
1680 $this->setError(_('Error Deleting Counters: ').db_error());
1685 $res = db_query_params ('INSERT INTO deleted_groups (unix_group_name,delete_date,isdeleted) VALUES ($1, $2, $3)',
1686 array ($this->getUnixName(),
1690 $this->setError(_('Error Deleting Project: ').db_error());
1695 $res = db_query_params ('DELETE FROM groups WHERE group_id=$1',
1696 array ($this->getID())) ;
1698 $this->setError(_('Error Deleting Project: ').db_error());
1708 $hook_params = array ();
1709 $hook_params['group'] = $this;
1710 $hook_params['group_id'] = $this->getID();
1711 plugin_hook ("group_delete", $hook_params);
1713 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
1714 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
1716 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
1717 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
1722 $res = db_query_params ('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
1723 array ($this->getID())) ;
1724 //echo 'rep_group_act_monthly'.db_error();
1725 $res = db_query_params ('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
1726 array ($this->getID())) ;
1727 //echo 'rep_group_act_weekly'.db_error();
1728 $res = db_query_params ('DELETE FROM rep_group_act_daily WHERE group_id=$1',
1729 array ($this->getID())) ;
1730 //echo 'rep_group_act_daily'.db_error();
1731 unset($this->data_array);
1739 Basic functions to add/remove users to/from a group
1740 and update their permissions
1746 * addUser - controls adding a user to a group.
1748 * @param string Unix name of the user to add OR integer user_id.
1749 * @param int The role_id this user should have.
1750 * @return boolean success.
1753 function addUser($user_identifier,$role_id) {
1756 Admins can add users to groups
1759 if (!forge_check_perm ('project_admin', $this->getID())) {
1760 $this->setPermissionDeniedError();
1766 get user id for this user's unix_name
1768 if (is_int ($user_identifier)) { // user_id or user_name
1769 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array ($user_identifier)) ;
1771 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array ($user_identifier)) ;
1773 if (db_numrows($res_newuser) > 0) {
1775 // make sure user is active
1777 if (db_result($res_newuser,0,'status') != 'A') {
1778 $this->setError(_('User is not active. Only active users can be added.'));
1784 // user was found - set new user_id var
1786 $user_id = db_result($res_newuser,0,'user_id');
1788 $role = new Role($this,$role_id);
1789 if (!$role || !is_object($role)) {
1790 $this->setError(_('Error Getting Role Object'));
1793 } elseif ($role->isError()) {
1794 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1800 $role->addUser (user_get_object ($user_id)) ;
1801 if (!$SYS->sysCheckCreateGroup($this->getID())){
1802 $this->setError($SYS->getErrorMessage());
1806 if (!$SYS->sysCheckCreateUser($user_id)) {
1807 $this->setError($SYS->getErrorMessage());
1814 // if not already a member, add them
1816 $res_member = db_query_params ('SELECT user_id
1818 WHERE user_id=$1 AND group_id=$2',
1819 array ($user_id, $this->getID())) ;
1821 if (db_numrows($res_member) < 1) {
1823 // Create this user's row in the user_group table
1825 $res = db_query_params ('INSERT INTO user_group
1826 (user_id,group_id,admin_flags,forum_flags,project_flags,
1827 doc_flags,cvs_flags,member_role,release_flags,artifact_flags)
1828 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)',
1840 //verify the insert worked
1841 if (!$res || db_affected_rows($res) < 1) {
1842 $this->setError(sprintf(_('ERROR: Could Not Add User To Group: %s'),db_error()));
1847 // check and create if group doesn't exists
1849 //echo "<h2>Group::addUser SYS->sysCheckCreateGroup(".$this->getID().")</h2>";
1850 if (!$SYS->sysCheckCreateGroup($this->getID())){
1851 $this->setError($SYS->getErrorMessage());
1856 // check and create if user doesn't exists
1858 //echo "<h2>Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1859 if (!$SYS->sysCheckCreateUser($user_id)) {
1860 $this->setError($SYS->getErrorMessage());
1867 //echo "<h2>Group::addUser role->setUser($user_id)</h2>";
1868 if (!$role->setUser($user_id)) {
1869 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1875 // user was already a member
1876 // make sure they are set up
1878 $user=&user_get_object($user_id,$res_newuser);
1879 $user->fetchData($user->getID());
1880 $role = new Role($this,$role_id);
1881 if (!$role || !is_object($role)) {
1882 $this->setError(_('Error Getting Role Object'));
1885 } elseif ($role->isError()) {
1886 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1890 //echo "<h2>Already Member Group::addUser role->setUser($user_id)</h2>";
1891 if (!$role->setUser($user_id)) {
1892 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1897 // set up their system info
1899 //echo "<h2>Already Member Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1900 if (!$SYS->sysCheckCreateUser($user_id)) {
1901 $this->setError($SYS->getErrorMessage());
1909 // user doesn't exist
1911 $this->setError(_('ERROR: User does not exist'));
1916 $hook_params['group'] = $this;
1917 $hook_params['group_id'] = $this->getID();
1918 $hook_params['user'] = &user_get_object($user_id);
1919 $hook_params['user_id'] = $user_id;
1920 plugin_hook ("group_adduser", $hook_params);
1925 $this->addHistory('Added User',$user_identifier);
1931 * removeUser - controls removing a user from a group.
1933 * Users can remove themselves.
1935 * @param int The ID of the user to remove.
1936 * @return boolean success.
1938 function removeUser($user_id) {
1941 if ($user_id != user_getid()
1942 || !forge_check_perm ('project_admin', $this->getID())) {
1943 $this->setPermissionDeniedError();
1950 $user = user_get_object ($user_id) ;
1951 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
1952 $found_role = NULL ;
1953 foreach ($roles as $role) {
1954 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
1955 $found_role = $role ;
1959 if ($found_role == NULL) {
1960 $this->setError(sprintf(_('ERROR: User not removed: %s')));
1964 $found_role->removeUser ($user) ;
1965 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
1966 $this->setError($SYS->getErrorMessage());
1972 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1 AND user_id=$2',
1973 array ($this->getID(),
1975 if (!$res || db_affected_rows($res) < 1) {
1976 $this->setError(sprintf(_('ERROR: User not removed: %s'),db_error()));
1983 // reassign open artifacts to id=100
1985 $res = db_query_params ('UPDATE artifact SET assigned_to=100
1986 WHERE group_artifact_id
1987 IN (SELECT group_artifact_id
1988 FROM artifact_group_list
1989 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
1990 array ($this->getID(),
1993 $this->setError(sprintf(_('ERROR: DB: artifact: %s'),db_error()));
1999 // reassign open tasks to id=100
2000 // first have to purge any assignments that would cause
2001 // conflict with existing assignment to 100
2003 $res = db_query_params ('DELETE FROM project_assigned_to
2004 WHERE project_task_id IN (SELECT pt.project_task_id
2005 FROM project_task pt, project_group_list pgl, project_assigned_to pat
2006 WHERE pt.group_project_id = pgl.group_project_id
2007 AND pat.project_task_id=pt.project_task_id
2008 AND pt.status_id=1 AND pgl.group_id=$1
2009 AND pat.assigned_to_id=$2)
2010 AND assigned_to_id=100',
2011 array ($this->getID(),
2014 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),1,db_error()));
2018 $res = db_query_params ('UPDATE project_assigned_to SET assigned_to_id=100
2019 WHERE project_task_id IN (SELECT pt.project_task_id
2020 FROM project_task pt, project_group_list pgl
2021 WHERE pt.group_project_id = pgl.group_project_id
2022 AND pt.status_id=1 AND pgl.group_id=$1)
2023 AND assigned_to_id=$2',
2024 array ($this->getID(),
2027 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),2,db_error()));
2033 // Remove user from system
2035 if (!$SYS->sysGroupRemoveUser($this->getID(),$user_id)) {
2036 $this->setError($SYS->getErrorMessage());
2041 $hook_params['group'] = $this;
2042 $hook_params['group_id'] = $this->getID();
2043 $hook_params['user'] = &user_get_object($user_id);
2044 $hook_params['user_id'] = $user_id;
2045 plugin_hook ("group_removeuser", $hook_params);
2048 $this->addHistory('Removed User',$user_id);
2055 * updateUser - controls updating a user's role in this group.
2057 * @param int The ID of the user.
2058 * @param int The role_id to set this user to.
2059 * @return boolean success.
2061 function updateUser($user_id,$role_id) {
2064 if (!forge_check_perm ('project_admin', $this->getID())) {
2065 $this->setPermissionDeniedError();
2070 $newrole = RBACEngine::getInstance()->getRoleById ($role_id) ;
2071 if (!$newrole || !is_object($newrole)) {
2072 $this->setError(_('Could Not Get Role'));
2074 } elseif ($newrole->isError()) {
2075 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2077 } elseif ($newrole->getHomeProject() == NULL
2078 || $newrole->getHomeProject()->getID() != $this->getID()) {
2079 $this->setError(_('Wrong destination role'));
2082 $user = user_get_object ($user_id) ;
2083 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
2084 $found_role = NULL ;
2085 foreach ($roles as $role) {
2086 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2087 $found_role = $role ;
2091 if ($found_role == NULL) {
2092 $this->setError(sprintf(_('ERROR: User not removed: %s')));
2096 $found_role->removeUser ($user) ;
2097 $newrole->addUser ($user) ;
2099 $role = new Role($this,$role_id);
2100 if (!$role || !is_object($role)) {
2101 $this->setError(_('Could Not Get Role'));
2103 } elseif ($role->isError()) {
2104 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2107 //echo "<h3>Group::updateUser role->setUser($user_id)</h3>";
2108 if (!$role->setUser($user_id)) {
2109 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2114 $this->addHistory('Updated User',$user_id);
2119 * addHistory - Makes an audit trail entry for this project.
2121 * @param string The name of the field.
2122 * @param string The Old Value for this $field_name.
2123 * @return database result handle.
2126 function addHistory($field_name, $old_value) {
2127 return db_query_params ('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2128 VALUES ($1,$2,$3,$4,$5)',
2129 array ($this->getID(),
2137 * activateUsers - Make sure that group members have unix accounts.
2139 * Setup unix accounts for group members. Can be called even
2140 * if members are already active.
2144 function activateUsers() {
2146 Activate member(s) of the project
2150 $members = $this->getUsers (true) ;
2152 foreach ($members as $member) {
2154 foreach (RBACEngine::getInstance()->getAvailableRolesForUser ($member) as $role) {
2155 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2158 if (!$this->addUser($member->getUnixName(),$role->getID())) {
2165 $res_member = db_query_params ('SELECT user_id,role_id FROM user_group WHERE group_id=$1',
2166 array ($this->getID())) ;
2167 while ($row_member = db_fetch_array($res_member)) {
2168 $u = user_get_object($row_member['user_id']) ;
2169 if (!$this->addUser($u->getUnixName(),$row_member['role_id'])) {
2179 * getMembers - returns array of User objects for this project
2181 * @return array of User objects for this group.
2183 function &getMembers() {
2184 return $this->getUsers (true) ;
2188 * approve - Approve pending project.
2190 * @param object The User object who is doing the updating.
2193 function approve(&$user) {
2195 if ($this->getStatus()=='A') {
2196 $this->setError(_("Group already active"));
2202 // Step 1: Activate group and create LDAP entries
2203 if (!$this->setStatus($user, 'A')) {
2208 // Switch to system language for item creation
2209 setup_gettext_from_sys_lang ();
2214 // Tracker Integration
2217 if (forge_get_config ('use_tracker')) {
2218 $ats = new ArtifactTypes($this);
2219 if (!$ats || !is_object($ats)) {
2220 $this->setError(_('Error creating ArtifactTypes object'));
2222 setup_gettext_from_context();
2224 } else if ($ats->isError()) {
2225 $this->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
2227 setup_gettext_from_context();
2230 if (!$ats->createTrackers()) {
2231 $this->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
2233 setup_gettext_from_context();
2240 // Forum Integration
2243 if (forge_get_config ('use_forum')) {
2244 $f = new Forum($this);
2245 if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
2246 $this->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
2248 setup_gettext_from_context();
2251 $f = new Forum($this);
2252 if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
2253 $this->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
2255 setup_gettext_from_context();
2258 $f = new Forum($this);
2259 if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
2260 $this->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
2262 setup_gettext_from_context();
2269 // Doc Mgr Integration
2272 if (forge_get_config('use_docman')) {
2273 $dg = new DocumentGroup($this);
2274 if (!$dg->create(_('Uncategorized Submissions'))) {
2275 $this->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
2277 setup_gettext_from_context();
2287 if (forge_get_config ('use_frs')) {
2288 $frs = new FRSPackage($this);
2289 if (!$frs->create($this->getUnixName())) {
2290 $this->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
2292 setup_gettext_from_context();
2302 if (forge_get_config ('use_pm')) {
2303 $pg = new ProjectGroup($this);
2304 if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
2305 $this->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
2307 setup_gettext_from_context();
2310 $pg = new ProjectGroup($this);
2311 if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
2312 $this->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
2314 setup_gettext_from_context();
2321 // Set Default Roles
2325 $idadmin_group = NULL ;
2326 foreach (get_group_join_requests ($this) as $gjr) {
2327 $idadmin_group = $gjr->getUserID() ;
2330 if ($idadmin_group == NULL) {
2331 $idadmin_group = $user->getID();
2335 $admin_group = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1 AND admin_flags=$2',
2336 array ($this->getID(),
2338 if (db_numrows($admin_group) > 0) {
2339 $idadmin_group = db_result($admin_group,0,'user_id');
2341 $idadmin_group = $user->getID();
2342 db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags) VALUES ($1, $2, $3)',
2343 array ($idadmin_group,
2349 $role = new Role($this);
2350 $todo = array_keys($role->defaults);
2351 for ($c=0; $c<count($todo); $c++) {
2352 $role = new Role($this);
2353 if (! ($role_id = $role->createDefault($todo[$c]))) {
2354 $this->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
2356 setup_gettext_from_context();
2359 $role = new Role($this, $role_id);
2360 if ($role->getVal('projectadmin',0)=='A') {
2361 $role->setUser($idadmin_group);
2366 $roles = $this->getRoles() ;
2367 foreach ($roles as $r) {
2368 if ($r->getSetting ('project_admin', $this->getID())) {
2369 $r->addUser (user_get_object ($idadmin_group)) ;
2372 if ($this->isPublic()) {
2373 $ra = RoleAnonymous::getInstance() ;
2374 $rl = RoleLoggedIn::getInstance() ;
2375 $ra->linkProject ($this) ;
2376 $rl->linkProject ($this) ;
2378 $ra->setSetting ('project_read', $this->getID(), 1) ;
2379 $rl->setSetting ('project_read', $this->getID(), 1) ;
2381 $ra->setSetting ('frs', $this->getID(), 1) ;
2382 $rl->setSetting ('frs', $this->getID(), 1) ;
2384 $ra->setSetting ('docman', $this->getID(), 1) ;
2385 $rl->setSetting ('docman', $this->getID(), 1) ;
2387 $ff = new ForumFactory ($this) ;
2388 foreach ($ff->getAllForumIds() as $fid) {
2389 $f = forum_get_object ($fid) ;
2390 if ($f->isPublic()) {
2391 $l = $f->getModerationLevel() ;
2393 $rl->setSetting ('forum', $fid, 3) ;
2395 $rl->setSetting ('forum', $fid, 2) ;
2397 if ($f->allowAnonymous()) {
2399 $ra->setSetting ('forum', $fid, 3) ;
2401 $ra->setSetting ('forum', $fid, 2) ;
2404 $ra->setSetting ('forum', $fid, 1) ;
2409 $pgf = new ProjectGroupFactory ($this) ;
2410 foreach ($pgf->getAllProjectGroupIds() as $pgid) {
2411 $pg = projectgroup_get_object ($pgid) ;
2412 if ($pg->isPublic()) {
2413 $ra->setSetting ('pm', $pgid, 1) ;
2414 $rl->setSetting ('pm', $pgid, 1) ;
2418 $atf = new ArtifactTypeFactory ($this) ;
2419 foreach ($atf->getAllArtifactTypeIds() as $atid) {
2420 $at = artifactType_get_object ($atid) ;
2421 if ($at->isPublic()) {
2422 $ra->setSetting ('tracker', $atid, 1) ;
2423 $rl->setSetting ('tracker', $atid, 1) ;
2427 foreach (get_group_join_requests ($this) as $gjr) {
2428 $gjr->delete (true) ;
2434 // Create MailingList
2437 if (forge_get_config('use_mail')) {
2438 $mlist = new MailingList($this);
2439 if (!$mlist->create('commits',_('Commits'),1,$idadmin_group)) {
2440 $this->setError(sprintf(_('ML: %s'),$mlist->getErrorMessage()));
2442 setup_gettext_from_context();
2447 // Switch back to user preference
2448 setup_gettext_from_context();
2452 $this->sendApprovalEmail();
2453 $this->addHistory('Approved', 'x');
2456 // Plugin can make approve operation there
2459 $params[0] = $idadmin_group ;
2460 $params[1] = $this->getID();
2461 plugin_hook('group_approved',$params);
2469 * sendApprovalEmail - Send new project email.
2471 * @return boolean success.
2474 function sendApprovalEmail() {
2475 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID()) ;
2477 if (count($admins) < 1) {
2478 $this->setError(_("Group does not have any administrators."));
2482 // send one email per admin
2483 foreach ($admins as $admin) {
2484 setup_gettext_for_user ($admin) ;
2486 $message=sprintf(_('Your project registration for %4$s has been approved.
2488 Project Full Name: %1$s
2489 Project Unix Name: %2$s
2491 Your DNS will take up to a day to become active on our site.
2492 Your web site is accessible through your shell account. Please read
2493 site documentation (see link below) about intended usage, available
2494 services, and directory layout of the account.
2497 own project page in %4$s while logged in, you will find
2498 additional menu functions to your left labeled \'Project Admin\'.
2500 We highly suggest that you now visit %4$s and create a public
2501 description for your project. This can be done by visiting your project
2502 page while logged in, and selecting \'Project Admin\' from the menus
2503 on the left (or by visiting %3$s
2506 Your project will also not appear in the Trove Software Map (primary
2507 list of projects hosted on %4$s which offers great flexibility in
2508 browsing and search) until you categorize it in the project administration
2509 screens. So that people can find your project, you should do this now.
2510 Visit your project while logged in, and select \'Project Admin\' from the
2513 Enjoy the system, and please tell others about %4$s. Let us know
2514 if there is anything we can do to help you.
2517 htmlspecialchars_decode($this->getPublicName()),
2518 $this->getUnixName(),
2519 util_make_url ('/project/admin/?group_id='.$this->getID()),
2520 forge_get_config ('forge_name'));
2522 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Approved'), forge_get_config ('forge_name')), $message);
2524 setup_gettext_from_context();
2532 * sendRejectionEmail - Send project rejection email.
2534 * This function sends out a rejection message to a user who
2535 * registered a project.
2537 * @param int The id of the response to use.
2538 * @param string The rejection message.
2539 * @return completion status.
2542 function sendRejectionEmail($response_id, $message="zxcv") {
2543 $submitters = array () ;
2545 foreach (get_group_join_requests ($this) as $gjr) {
2546 $submitters[] = user_get_object($gjr->getUserID()) ;
2549 $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",
2551 while ($arr = db_fetch_array ($res)) {
2552 $submitter[] =& user_get_object($arr['user_id']);
2556 if (count ($submitters) < 1) {
2557 $this->setError(_("Group does not have any administrators."));
2561 foreach ($submitters as $admin) {
2562 setup_gettext_for_user ($admin) ;
2564 $response=sprintf(_('Your project registration for %3$s has been denied.
2566 Project Full Name: %1$s
2567 Project Unix Name: %2$s
2569 Reasons for negative decision:
2571 '), $this->getPublicName(), $this->getUnixName(), forge_get_config ('forge_name'));
2573 // Check to see if they want to send a custom rejection response
2574 if ($response_id == 0) {
2575 $response .= $message;
2577 $response .= db_result (
2578 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array ($response_id)),
2583 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Denied'), forge_get_config ('forge_name')), $response);
2584 setup_gettext_from_context();
2591 * sendNewProjectNotificationEmail - Send new project notification email.
2593 * This function sends out a notification email to the
2594 * SourceForge admin user when a new project is
2597 * @return boolean success.
2600 function sendNewProjectNotificationEmail() {
2601 // Get the user who wants to register the project
2602 $submitters = array () ;
2604 foreach (get_group_join_requests ($this) as $gjr) {
2605 $submitters[] = user_get_object($gjr->getUserID()) ;
2608 $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",
2610 while ($arr = db_fetch_array ($res)) {
2611 $submitter[] =& user_get_object($arr['user_id']);
2614 if (count ($submitters) < 1) {
2615 $this->setError(_("Could not find user who has submitted the project."));
2619 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_approve', -1) ;
2621 if (count($admins) < 1) {
2622 $this->setError(_("There is no administrator to send the mail to."));
2626 foreach ($admins as $admin) {
2627 $admin_email = $admin->getEmail () ;
2628 setup_gettext_for_user ($admin) ;
2630 foreach ($submitters as $u) {
2631 $submitter_names[] = $u->getRealName() ;
2634 $message = sprintf(_('New %1$s Project Submitted
2636 Project Full Name: %2$s
2637 Submitted Description: %3$s
2639 forge_get_config ('forge_name'),
2640 htmlspecialchars_decode($this->getPublicName()),
2641 htmlspecialchars_decode($this->getRegistrationPurpose()));
2643 foreach ($submitters as $submitter) {
2644 $message .= sprintf(_('Submitter: %1$s (%2$s)
2646 $submitter->getRealName(),
2647 $submitter->getUnixName());
2650 $message .= sprintf (_('
2651 Please visit the following URL to approve or reject this project:
2653 util_make_url ('/admin/approve-pending.php')) ;
2654 util_send_message($admin_email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2655 setup_gettext_from_context();
2659 $email = $submitter->getEmail() ;
2660 setup_gettext_for_user ($submitter) ;
2662 $message=sprintf(_('New %1$s Project Submitted
2664 Project Full Name: %2$s
2665 Submitted Description: %3$s
2667 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'));
2669 util_send_message($email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2670 setup_gettext_from_context();
2679 * validateGroupName - Validate the group name
2681 * @param string Group name.
2683 * @return an error false and set an error is the group name is invalide otherwise return true
2685 function validateGroupName($group_name) {
2686 if (strlen($group_name)<3) {
2687 $this->setError(_('Group name is too short'));
2689 } else if (strlen(htmlspecialchars($group_name))>50) {
2690 $this->setError(_('Group name is too long'));
2692 } else if ($group=group_get_object_by_publicname($group_name)) {
2693 $this->setError(_('Group name already taken'));
2701 * getRoles - Get the roles of the group.
2703 * @return array of Role id of this group.
2705 function getRolesId () {
2706 $role_ids = array () ;
2709 $res = db_query_params ('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2710 array ($this->getID()));
2711 while ($arr = db_fetch_array($res)) {
2712 $role_ids[] = $arr['role_id'] ;
2714 $res = db_query_params ('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2715 array ($this->getID()));
2716 while ($arr = db_fetch_array($res)) {
2717 $role_ids[] = $arr['role_id'] ;
2720 $res = db_query_params ('SELECT role_id FROM role WHERE group_id=$1',
2721 array ($this->getID()));
2722 while ($arr = db_fetch_array($res)) {
2723 $role_ids[] = $arr['role_id'] ;
2727 return array_unique ($role_ids) ;
2730 function getRoles () {
2731 $result = array () ;
2733 $roles = $this->getRolesId () ;
2735 $engine = RBACEngine::getInstance() ;
2736 foreach ($roles as $role_id) {
2737 $result[] = $engine->getRoleById ($role_id) ;
2740 foreach ($roles as $role_id) {
2741 $result[] = new Role ($this, $role_id) ;
2748 function normalizeAllRoles () {
2749 $roles = $this->getRoles () ;
2751 foreach ($roles as $r) {
2752 $r->normalizeData () ;
2757 * getUnixStatus - Status of activation of unix account.
2759 * @return char (N)one, (A)ctive, (S)uspended or (D)eleted
2761 function getUnixStatus() {
2762 return $this->data_array['unix_status'];
2766 * setUnixStatus - Sets status of activation of unix account.
2768 * @param string The unix status.
2774 * @return boolean success.
2776 function setUnixStatus($status) {
2779 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
2784 $this->setError(sprintf(_('ERROR - Could Not Update Group Unix Status: %s'),db_error()));
2788 if ($status == 'A') {
2789 if (!$SYS->sysCheckCreateGroup($this->getID())) {
2790 $this->setError($SYS->getErrorMessage());
2795 if ($SYS->sysCheckGroup($this->getID())) {
2796 if (!$SYS->sysRemoveGroup($this->getID())) {
2797 $this->setError($SYS->getErrorMessage());
2804 $this->data_array['unix_status']=$status;
2811 * getUsers - Get the users of a group
2813 * @return array of user's objects.
2815 function getUsers($onlylocal = true) {
2816 if (!isset($this->membersArr)) {
2817 $this->membersArr = array () ;
2821 foreach ($this->getRoles() as $role) {
2823 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
2826 foreach ($role->getUsers() as $user) {
2827 $ids[] = $user->getID() ;
2830 $ids = array_unique ($ids) ;
2831 foreach ($ids as $id) {
2832 $u = user_get_object ($id) ;
2833 if ($u->isActive()) {
2834 $this->membersArr[] = $u ;
2839 $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',
2840 array ($this->getID(),
2842 if (!$users_group_res) {
2843 $this->setError('Error: Enable to get users from group '. $this->getID() . ' ' .db_error());
2847 for ($i=0; $i<db_numrows($users_group_res); $i++) {
2848 $this->membersArr[$i] = new GFUser(db_result($users_group_res,$i,'user_id'),false);
2853 return $this->membersArr;
2856 function setDocmanCreateOnlineStatus($status) {
2858 /* if we activate search engine, we probably want to reindex */
2859 $res = db_query_params ('UPDATE groups SET use_docman_create_online=$1 WHERE group_id=$2',
2864 $this->setError(sprintf(_('ERROR - Could Not Update Group DocmanCreateOnline Status: %s'),db_error()));
2868 $this->data_array['use_docman_create_online']=$status;
2874 function setDocmanWebdav($status) {
2876 /* if we activate search engine, we probably want to reindex */
2877 $res = db_query_params ('UPDATE groups SET use_webdav=$1 WHERE group_id=$2',
2882 $this->setError(sprintf(_('ERROR - Could Not Update Group UseWebdab Status: %s'),db_error()));
2886 $this->data_array['use_webdav']=$status;
2892 function setDocmanSearchStatus($status) {
2894 /* if we activate search engine, we probably want to reindex */
2895 $res = db_query_params ('UPDATE groups SET use_docman_search=$1, force_docman_reindex=$1 WHERE group_id=$2',
2900 $this->setError(sprintf(_('ERROR - Could Not Update Group UseDocmanSearch Status: %s'),db_error()));
2904 $this->data_array['use_docman_search']=$status;
2910 function setDocmanForceReindexSearch($status) {
2912 /* if we activate search engine, we probably want to reindex */
2913 $res = db_query_params ('UPDATE groups SET force_docman_reindex=$1 WHERE group_id=$2',
2918 $this->setError(sprintf(_('ERROR - Could Not Update Group force_docman_reindex %s'),db_error()));
2922 $this->data_array['force_docman_reindex']=$status;
2928 function setStorageAPI($type) {
2932 function getStorageAPI() {
2938 * group_getname() - get the group name
2940 * @param int The group ID
2944 function group_getname ($group_id = 0) {
2945 $grp = &group_get_object($group_id);
2947 return $grp->getPublicName();
2954 * group_getunixname() - get the unixname for a group
2956 * @param int The group ID
2960 function group_getunixname ($group_id) {
2961 $grp = &group_get_object($group_id);
2963 return $grp->getUnixName();
2970 * group_get_result() - Get the group object result ID.
2972 * @param int The group ID
2976 function &group_get_result($group_id=0) {
2977 $grp = &group_get_object($group_id);
2979 return $grp->getData();
2985 class ProjectComparator {
2986 var $criterion = 'name' ;
2988 function Compare ($a, $b) {
2989 switch ($this->criterion) {
2992 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName()) ;
2993 if ($namecmp != 0) {
2996 /* If several projects share a same public name */
2997 return strcoll ($a->getUnixName(), $b->getUnixName()) ;
3000 return strcmp ($a->getUnixName(), $b->getUnixName()) ;
3003 $aid = $a->getID() ;
3004 $bid = $b->getID() ;
3008 return ($a < $b) ? -1 : 1;
3014 function sortProjectList (&$list, $criterion='name') {
3015 $cmp = new ProjectComparator () ;
3016 $cmp->criterion = $criterion ;
3018 return usort ($list, array ($cmp, 'Compare')) ;
3023 // c-file-style: "bsd"