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';
41 //the license_id of "Other/proprietary" license
42 define('GROUP_LICENSE_OTHER',126);
44 $LICENSE_NAMES=array();
47 * group_get_licences() - get the licenses list
49 * @return array list of licenses
51 function & group_get_licenses() {
52 global $LICENSE_NAMES;
53 if(empty($LICENSE_NAMES)) {
54 $result = db_query_params ('select * from licenses', array());
55 while($data = db_fetch_array($result)) {
56 $LICENSE_NAMES[$data['license_id']] = $data['license_name'];
59 return $LICENSE_NAMES;
65 * group_get_object() - Get the group object.
67 * group_get_object() is useful so you can pool group objects/save database queries
68 * You should always use this instead of instantiating the object directly.
70 * You can now optionally pass in a db result handle. If you do, it re-uses that query
71 * to instantiate the objects.
73 * IMPORTANT! That db result must contain all fields
74 * from groups table or you will have problems
77 * @param int Result set handle ("SELECT * FROM groups WHERE group_id=xx")
78 * @return a group object or false on failure
80 function &group_get_object($group_id,$res=false) {
81 //create a common set of group objects
82 //saves a little wear on the database
84 //automatically checks group_type and
85 //returns appropriate object
88 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
90 //the db result handle was passed in
92 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1', array ($group_id)) ;
94 if (!$res || db_numrows($res) < 1) {
95 $GROUP_OBJ["_".$group_id."_"]=false;
98 check group type and set up object
100 if (db_result($res,0,'type_id')==1) {
102 $GROUP_OBJ["_".$group_id."_"]= new Group($group_id,$res);
105 $GROUP_OBJ["_".$group_id."_"]=false;
109 return $GROUP_OBJ["_".$group_id."_"];
112 function &group_get_objects($id_arr) {
115 // Note: if we don't do this, the result may be corrupted
119 for ($i=0; $i<count($id_arr); $i++) {
121 // See if this ID already has been fetched in the cache
126 if (!isset($GROUP_OBJ["_".$id_arr[$i]."_"])) {
127 $fetch[]=$id_arr[$i];
129 $return[] =& $GROUP_OBJ["_".$id_arr[$i]."_"];
132 if (count($fetch) > 0) {
133 $res=db_query_params ('SELECT * FROM groups WHERE group_id = ANY ($1)',
134 array (db_int_array_to_any_clause ($fetch))) ;
135 while ($arr = db_fetch_array($res)) {
136 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
137 $return[] =& $GROUP_OBJ["_".$arr['group_id']."_"];
143 function &group_get_object_by_name($groupname) {
144 $res=db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array ($groupname)) ;
145 return group_get_object(db_result($res,0,'group_id'),$res);
148 function &group_get_objects_by_name($groupname_arr) {
149 $res=db_query_params ('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
150 array (db_string_array_to_any_clause ($groupname_arr))
152 $arr =& util_result_column_to_array($res,0);
153 return group_get_objects($arr);
156 function &group_get_object_by_publicname($groupname) {
157 $res=db_query_params ('SELECT * FROM groups WHERE lower(group_name) LIKE $1',
158 array (htmlspecialchars (strtolower ($groupname)))) ;
160 return group_get_object(db_result($res,0,'group_id'),$res);
163 class Group extends Error {
165 * Associative array of data from db.
167 * @var array $data_array.
172 * array of User objects.
174 * @var array $membersArr.
179 * Whether the use is an admin/super user of this project.
181 * @var bool $is_admin.
186 * Artifact types result handle.
188 * @var int $types_res.
193 * Associative array of data for plugins.
195 * @var array $plugins_data.
201 * Associative array of data for the group menu.
203 * @var array $menu_data.
208 * Group - Group object constructor - use group_get_object() to instantiate.
210 * @param int Required - group_id of the group you want to instantiate.
211 * @param int Database result from select query OR associative array of all columns.
213 function Group($id=false, $res=false) {
216 //setting up an empty object
217 //probably going to call create()
221 if (!$this->fetchData($id)) {
226 // Assoc array was passed in
228 if (is_array($res)) {
229 $this->data_array =& $res;
231 if (db_numrows($res) < 1) {
232 //function in class we extended
233 $this->setError(_('Group Not Found'));
234 $this->data_array=array();
237 //set up an associative array for use by other functions
238 $this->data_array = db_fetch_array_by_row($res, 0);
247 * fetchData - May need to refresh database fields if an update occurred.
249 * @param int The group_id.
251 function fetchData($group_id) {
252 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
254 if (!$res || db_numrows($res) < 1) {
255 $this->setError(sprintf(_('fetchData():: %s'),db_error()));
258 $this->data_array = db_fetch_array($res);
263 * create - Create new group.
265 * This method should be called on empty Group object.
267 * @param object The User object.
268 * @param string The full name of the user.
269 * @param string The Unix name of the user.
270 * @param string The new group description.
271 * @param string The purpose of the group.
272 * @param bool Whether to send an email or not
274 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box='shell1', $scm_box='cvs1', $is_public=1, $send_mail=true) {
275 // $user is ignored - anyone can create pending group
278 if ($this->getID()!=0) {
279 $this->setError(_('Group::create: Group object already exists'));
281 } else if (!$this->validateGroupName($group_name)) {
283 } else if (!account_groupnamevalid($unix_name)) {
284 $this->setError(_('Invalid Unix name'));
286 } else if (!$SYS->sysUseUnixName($unix_name)) {
287 $this->setError(_('Unix name already taken'));
289 } else if (db_numrows(db_query_params('SELECT group_id FROM groups WHERE unix_group_name=$1',
290 array ($unix_name))) > 0) {
291 $this->setError(_('Unix name already taken'));
293 } else if (strlen($purpose)<10) {
294 $this->setError(_('Please describe your Registration Purpose in a more comprehensive manner'));
296 } else if (strlen($purpose)>1500) {
297 $this->setError(_('The Registration Purpose text is too long. Please make it smaller than 1500 bytes.'));
299 } else if (strlen($description)<10) {
300 $this->setError(_('Describe in a more comprehensive manner your project.'));
302 } else if (strlen($description)>255) {
303 $this->setError(_('Your project description is too long. Please make it smaller than 256 bytes.'));
307 srand((double)microtime()*1000000);
308 $random_num = rand(0,1000000);
312 $res = db_query_params ('
328 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
329 array (htmlspecialchars ($group_name),
332 htmlspecialchars($description),
333 $unix_name.".".forge_get_config('web_host'),
334 $unix_name.".".forge_get_config('web_host'),
338 htmlspecialchars($purpose),
341 md5($random_num) )) ;
342 if (!$res || db_affected_rows($res) < 1) {
343 $this->setError(sprintf(_('ERROR: Could not create group: %s'),db_error()));
348 $id = db_insertid($res, 'groups', 'group_id');
350 $this->setError(sprintf(_('ERROR: Could not get group id: %s'),db_error()));
356 // Now, make the user an admin
358 $res=db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags,
359 cvs_flags, artifact_flags, forum_flags, role_id)
360 VALUES ($1, $2, $3, $4, $5, $6, $7)',
361 array ($user->getID(),
368 if (!$res || db_affected_rows($res) < 1) {
369 $this->setError(sprintf(_('ERROR: Could not add admin to newly created group: %s'),db_error()));
374 if (!$this->fetchData($id)) {
379 $hook_params = array ();
380 $hook_params['group'] = $this;
381 $hook_params['group_id'] = $this->getID();
382 $hook_params['group_name'] = $group_name;
383 $hook_params['unix_group_name'] = $unix_name;
384 plugin_hook ("group_create", $hook_params);
388 $this->sendNewProjectNotificationEmail();
396 * updateAdmin - Update core properties of group object.
398 * This function require site admin privilege.
400 * @param object User requesting operation (for access control).
401 * @param bool Whether group is publicly accessible (0/1).
402 * @param int Group type (1-project, 2-foundry).
403 * @param string Machine on which group's home directory located.
404 * @param string Domain which serves group's WWW.
408 function updateAdmin(&$user, $is_public, $type_id, $unix_box, $http_domain) {
409 $perm =& $this->getPermission ();
411 if (!$perm || !is_object($perm)) {
412 $this->setError(_('Could not get permission.'));
416 if (!$perm->isSuperUser()) {
417 $this->setError(_('Permission denied.'));
423 $res = db_query_params ('
425 SET is_public=$1, type_id=$2,
426 unix_box=$3, http_domain=$4
434 if (!$res || db_affected_rows($res) < 1) {
435 $this->setError(_('ERROR: DB: Could not change group properties: %s'),db_error());
440 // Log the audit trail
441 if ($is_public != $this->isPublic()) {
442 $this->addHistory('is_public', $this->isPublic());
444 if ($type_id != $this->data_array['type_id']) {
445 $this->addHistory('type_id', $this->data_array['type_id']);
447 if ($unix_box != $this->data_array['unix_box']) {
448 $this->addHistory('unix_box', $this->data_array['unix_box']);
450 if ($http_domain != $this->data_array['http_domain']) {
451 $this->addHistory('http_domain', $this->data_array['http_domain']);
454 if (!$this->fetchData($this->getID())) {
463 * update - Update number of common properties.
465 * Unlike updateAdmin(), this function accessible to project admin.
467 * @param object User requesting operation (for access control).
468 * @param bool Whether group is publicly accessible (0/1).
469 * @param string Project's license (string ident).
470 * @param int Group type (1-project, 2-foundry).
471 * @param string Machine on which group's home directory located.
472 * @param string Domain which serves group's WWW.
473 * @return int status.
476 function update(&$user, $group_name,$homepage,$short_description,$use_mail,$use_survey,$use_forum,
477 $use_pm,$use_pm_depend_box,$use_scm,$use_news,$use_docman,
478 $new_doc_address,$send_all_docs,$logo_image_id,
479 $use_ftp,$use_tracker,$use_frs,$use_stats,$tags,$is_public) {
481 $perm =& $this->getPermission ();
483 if (!$perm || !is_object($perm)) {
484 $this->setError(_('Could not get permission.'));
488 if (!$perm->isAdmin()) {
489 $this->setError(_('Permission denied.'));
493 // Validate some values
494 if ($this->getPublicName() != $group_name) {
495 if (!$this->validateGroupName($group_name)) {
500 if ($new_doc_address) {
501 $invalid_mails = validate_emails($new_doc_address);
502 if (count($invalid_mails) > 0) {
503 $this->setError(sprintf (ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
508 // in the database, these all default to '1',
509 // so we have to explicity set 0
522 if (!$use_pm_depend_box) {
523 $use_pm_depend_box=0;
546 if (!$send_all_docs) {
550 $homepage = ltrim($homepage);
552 $homepage=forge_get_config('web_host').'/projects/'.$this->getUnixName().'/';
555 if (strlen(htmlspecialchars($short_description))>255) {
556 $this->setError(_('Error updating project information: Maximum length for Project Description is 255 chars.'));
562 //XXX not yet actived logo_image_id='$logo_image_id',
563 $res = db_query_params ('UPDATE groups
566 short_description=$3,
571 use_pm_depend_box=$8,
583 array (htmlspecialchars($group_name),
585 htmlspecialchars($short_description),
604 $this->setError(sprintf(_('Error updating project information: %s'), db_error()));
609 if ($this->setTags($tags) === false) {
614 $hook_params = array ();
615 $hook_params['group'] = $this;
616 $hook_params['group_id'] = $this->getID();
617 $hook_params['group_homepage'] = $homepage;
618 $hook_params['group_name'] = htmlspecialchars($group_name);
619 $hook_params['group_description'] = htmlspecialchars($short_description);
620 plugin_hook ("group_update", $hook_params);
622 // Log the audit trail
623 $this->addHistory('Changed Public Info', '');
625 if (!$this->fetchData($this->getID())) {
634 * getID - Simply return the group_id for this object.
636 * @return int group_id.
639 return $this->data_array['group_id'];
643 * getType() - Foundry, project, etc.
645 * @return int The type flag from the database.
648 return $this->data_array['type_id'];
653 * getStatus - the status code.
655 * Statuses char include I,H,A,D.
657 function getStatus() {
658 return $this->data_array['status'];
662 * setStatus - set the status code.
664 * Statuses include I,H,A,D.
666 * @param object User requesting operation (for access control).
667 * @param string Status value.
668 * @return boolean success.
671 function setStatus(&$user, $status) {
674 $perm =& $this->getPermission ();
675 if (!$perm || !is_object($perm)) {
676 $this->setPermissionDeniedError();
678 } elseif (!$perm->isSuperUser()) {
679 $this->setPermissionDeniedError();
683 // Projects in 'A' status can only go to 'H' or 'D'
684 // Projects in 'D' status can only go to 'A'
685 // Projects in 'P' status can only go to 'A' OR 'D'
686 // Projects in 'I' status can only go to 'P'
687 // Projects in 'H' status can only go to 'A' OR 'D'
688 $allowed_status_changes = array(
689 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
690 'IP'=>1,'HA'=>1,'HD'=>1
693 // Check that status transition is valid
694 if ($this->getStatus() != $status
695 && !$allowed_status_changes[$this->getStatus().$status]) {
696 $this->setError(_('Invalid Status Change'));
702 $res = db_query_params ('UPDATE groups
704 WHERE group_id=$2', array ($status, $this->getID())) ;
706 if (!$res || db_affected_rows($res) < 1) {
707 $this->setError(sprintf(_('ERROR: DB: Could not change group status: %s'),db_error()));
713 // Activate system group, if not yet
714 if (!$SYS->sysCheckGroup($this->getID())) {
715 if (!$SYS->sysCreateGroup($this->getID())) {
716 $this->setError($SYS->getErrorMessage());
721 if (!$this->activateUsers()) {
726 /* Otherwise, the group is not active, and make sure that
727 System group is not active either */
728 } else if ($SYS->sysCheckGroup($this->getID())) {
729 if (!$SYS->sysRemoveGroup($this->getID())) {
730 $this->setError($SYS->getErrorMessage());
736 $hook_params = array ();
737 $hook_params['group'] = $this;
738 $hook_params['group_id'] = $this->getID();
739 $hook_params['status'] = $status;
740 plugin_hook ("group_setstatus", $hook_params);
744 // Log the audit trail
745 if ($status != $this->getStatus()) {
746 $this->addHistory('Status', $this->getStatus());
749 $this->data_array['status'] = $status;
754 * isProject - Simple boolean test to see if it's a project or not.
756 * @return boolean is_project.
758 function isProject() {
759 if ($this->getType()==1) {
767 * isPublic - Simply returns the is_public flag from the database.
769 * @return boolean is_public.
771 function isPublic() {
772 return $this->data_array['is_public'];
776 * isActive - Database field status of 'A' returns true.
778 * @return boolean is_active.
780 function isActive() {
781 if ($this->getStatus()=='A') {
789 * getUnixName - the unix_name
791 * @return string unix_name.
793 function getUnixName() {
794 return strtolower($this->data_array['unix_group_name']);
798 * getPublicName - the full-length public name.
800 * @return string The group_name.
802 function getPublicName() {
803 return $this->data_array['group_name'];
807 * getRegisterPurpose - the text description of the purpose of this project.
809 * @return string The description.
811 function getRegisterPurpose() {
812 return $this->data_array['register_purpose'];
816 * getDescription - the text description of this project.
818 * @return string The description.
820 function getDescription() {
821 return $this->data_array['short_description'];
825 * getStartDate - the unix time this project was registered.
827 * @return int (unix time) of registration.
829 function getStartDate() {
830 return $this->data_array['register_time'];
834 * getLogoImageID - the id of the logo in the database for this project.
836 * @return int The ID of logo image in db_images table (or 100 if none).
838 function getLogoImageID() {
839 return $this->data_array['logo_image_id'];
843 * getUnixBox - the hostname of the unix box where this project is located.
845 * @return string The name of the unix machine for the group.
847 function getUnixBox() {
848 return $this->data_array['unix_box'];
852 * getSCMBox - the hostname of the scm box where this project is located.
854 * @return string The name of the unix machine for the group.
856 function getSCMBox() {
857 return $this->data_array['scm_box'];
860 * setSCMBox - the hostname of the scm box where this project is located.
862 * @param string The name of the new SCM_BOX
864 function setSCMBox($scm_box) {
866 if ($scm_box == $this->data_array['scm_box']) {
871 $res = db_query_params ('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array ($scm_box, $this->getID ()));
873 $this->addHistory('scm_box', $this->data_array['scm_box']);
874 $this->data_array['scm_box']=$scm_box;
879 $this->setError(_("Couldn't insert SCM_BOX to database"));
883 $this->setError(_("SCM Box can't be empty"));
889 * getDomain - the hostname.domain where their web page is located.
891 * @return string The name of the group [web] domain.
893 function getDomain() {
894 return $this->data_array['http_domain'];
898 * getLicense - the license they chose.
900 * @return int ident of group license.
902 function getLicense() {
903 return $this->data_array['license'];
907 * getLicenseName - the name of the license
909 * @return string license name
911 function getLicenseName() {
912 $licenses =& group_get_licenses();
913 if(isset($licenses[$this->data_array['license']])) {
914 return $licenses[$this->data_array['license']];
921 * getLicenseOther - optional string describing license.
923 * @return string The custom license.
925 function getLicenseOther() {
926 if ($this->getLicense() == GROUP_LICENSE_OTHER) {
927 return $this->data_array['license_other'];
934 * getRegistrationPurpose - the text description of the purpose of this project.
936 * @return string The application for project hosting.
938 function getRegistrationPurpose() {
939 return $this->data_array['register_purpose'];
944 * getAdmins() - Get array of Admin user objects.
946 * @return array Array of User objects.
948 function &getAdmins() {
949 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID()) ;
951 $user_ids = array () ;
953 foreach ($roles as $role) {
954 if (! ($role instanceof RoleExplicit)) {
957 if ($role->getHomeProject() == NULL
958 || $role->getHomeProject()->getID() != $this->getID()) {
962 foreach ($role->getUsers() as $u) {
963 $user_ids[] = $u->getID() ;
967 return user_get_objects(array_unique($user_ids));
972 Common Group preferences for tools
977 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
979 * @return boolean enable_scm.
981 function enableAnonSCM() {
983 $r = RoleAnonymous::getInstance () ;
984 return $r->hasPermission ('scm', $this->getID(), 'read') ;
986 if ($this->isPublic() && $this->usesSCM()) {
987 return $this->data_array['enable_anonscm'];
994 function SetUsesAnonSCM ($booleanparam) {
996 $booleanparam = $booleanparam ? 1 : 0 ;
998 $r = RoleAnonymous::getInstance () ;
999 $r->setSetting ('scm', $this->getID(), $booleanparam) ;
1002 $res = db_query_params ('UPDATE groups SET enable_anonscm=$1 WHERE group_id=$2',
1003 array ($booleanparam, $this->getID()));
1005 $this->data_array['enable_anonscm']=$booleanparam;
1014 function setUsesSCM ($booleanparam) {
1016 $booleanparam = $booleanparam ? 1 : 0 ;
1017 $res = db_query_params ('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
1018 array ($booleanparam, $this->getID()));
1020 $this->data_array['use_scm']=$booleanparam;
1029 * enablePserver - whether or not this group has opted to enable Pserver.
1031 * @return boolean enable_pserver.
1033 function enablePserver() {
1034 if ($this->usesSCM()) {
1035 return $this->data_array['enable_pserver'];
1041 function SetUsesPserver ($booleanparam) {
1043 $booleanparam = $booleanparam ? 1 : 0 ;
1044 $res = db_query_params ('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1045 array ($booleanparam, $this->getID()));
1047 $this->data_array['enable_pserver']=$booleanparam;
1056 * usesSCM - whether or not this group has opted to use SCM.
1058 * @return boolean uses_scm.
1060 function usesSCM() {
1062 if (forge_get_config('use_scm')) {
1063 return $this->data_array['use_scm'];
1070 * usesMail - whether or not this group has opted to use mailing lists.
1072 * @return boolean uses_mail.
1074 function usesMail() {
1076 if (forge_get_config('use_mail')) {
1077 return $this->data_array['use_mail'];
1084 * usesNews - whether or not this group has opted to use news.
1086 * @return boolean uses_news.
1088 function usesNews() {
1090 if (forge_get_config('use_news')) {
1091 return $this->data_array['use_news'];
1098 * usesForum - whether or not this group has opted to use discussion forums.
1100 * @return boolean uses_forum.
1102 function usesForum() {
1104 if (forge_get_config('use_forum')) {
1105 return $this->data_array['use_forum'];
1112 * usesStats - whether or not this group has opted to use stats.
1114 * @return boolean uses_stats.
1116 function usesStats() {
1117 return $this->data_array['use_stats'];
1121 * usesFRS - whether or not this group has opted to use file release system.
1123 * @return boolean uses_frs.
1125 function usesFRS() {
1127 if (forge_get_config('use_frs')) {
1128 return $this->data_array['use_frs'];
1135 * usesTracker - whether or not this group has opted to use tracker.
1137 * @return boolean uses_tracker.
1139 function usesTracker() {
1141 if (forge_get_config('use_tracker')) {
1142 return $this->data_array['use_tracker'];
1149 * usesDocman - whether or not this group has opted to use docman.
1151 * @return boolean uses_docman.
1153 function usesDocman() {
1155 if (forge_get_config('use_docman')) {
1156 return $this->data_array['use_docman'];
1162 * usesDocmanSearch - whether or not this group has opted to use docman search engine.
1164 * @return boolean use_docman_search.
1166 function useDocmanSearch() {
1168 if (forge_get_config('use_docman')) {
1169 return $this->data_array['use_docman_search'];
1176 * usesFTP - whether or not this group has opted to use FTP.
1178 * @return boolean uses_ftp.
1180 function usesFTP() {
1182 if (forge_get_config('use_ftp')) {
1183 return $this->data_array['use_ftp'];
1190 * usesSurvey - whether or not this group has opted to use surveys.
1192 * @return boolean uses_survey.
1194 function usesSurvey() {
1196 if (forge_get_config('use_survey')) {
1197 return $this->data_array['use_survey'];
1204 * usesPM - whether or not this group has opted to Project Manager.
1206 * @return boolean uses_projman.
1210 if (forge_get_config('use_pm')) {
1211 return $this->data_array['use_pm'];
1218 * getPlugins - get a list of all available group plugins
1220 * @return array array containing plugin_id => plugin_name
1222 function getPlugins() {
1223 if (!isset($this->plugins_data)) {
1224 $this->plugins_data = array () ;
1225 $res = db_query_params ('SELECT group_plugin.plugin_id, plugins.plugin_name
1226 FROM group_plugin, plugins
1227 WHERE group_plugin.group_id=$1
1228 AND group_plugin.plugin_id=plugins.plugin_id', array ($this->getID()));
1229 $rows = db_numrows($res);
1231 for ($i=0; $i<$rows; $i++) {
1232 $plugin_id = db_result($res,$i,'plugin_id');
1233 $this->plugins_data[$plugin_id] = db_result($res,$i,'plugin_name');
1236 return $this->plugins_data ;
1240 * usesPlugin - returns true if the group uses a particular plugin
1242 * @param string name of the plugin
1243 * @return boolean whether plugin is being used or not
1245 function usesPlugin($pluginname) {
1246 $plugins_data = $this->getPlugins() ;
1247 foreach ($plugins_data as $p_id => $p_name) {
1248 if ($p_name == $pluginname) {
1255 * added for Codendi compatibility
1256 * usesServices - returns true if the group uses a particular plugin or feature
1258 * @param string name of the plugin
1259 * @return boolean whether plugin is being used or not
1261 function usesService($feature) {
1262 $plugins_data = $this->getPlugins() ;
1263 $pm = plugin_manager_get_object();
1264 foreach ($plugins_data as $p_id => $p_name) {
1265 if ($p_name == $feature) {
1268 if ($pm->getPluginByName($p_name)->provide($feature) ) {
1276 * setPluginUse - enables/disables plugins for the group
1278 * @param string name of the plugin
1279 * @param boolean the new state
1280 * @return string database result
1282 function setPluginUse($pluginname, $val=true) {
1283 if ($val == $this->usesPlugin($pluginname)) {
1284 // State is already good, returning
1287 $res = db_query_params ('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1288 array ($pluginname));
1289 $rows = db_numrows($res);
1291 // Error: no plugin by that name
1294 $plugin_id = db_result($res,0,'plugin_id');
1296 unset ($this->plugins_data) ;
1298 $res = db_query_params ('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1299 array ($this->getID(),
1303 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1304 array ($this->getID(),
1311 * getDocEmailAddress - get email address(es) to send doc notifications to.
1313 * @return string email address.
1315 function getDocEmailAddress() {
1316 return $this->data_array['new_doc_address'];
1320 * DocEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1322 * @return boolean email_on_all_doc_updates.
1324 function docEmailAll() {
1325 return $this->data_array['send_all_docs'];
1330 * getHomePage - The URL for this project's home page.
1332 * @return string homepage URL.
1334 function getHomePage() {
1335 return $this->data_array['homepage'];
1339 * getTags - Tags of this project.
1341 * @return string List of tags.
1343 function getTags() {
1344 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1345 $res = db_query_params($sql, array($this->getID()));
1346 return join(', ', util_result_column_to_array($res));
1350 * setTags - Set tags of this project.
1352 * @return string database result.
1354 function setTags($tags) {
1356 $sql='DELETE FROM project_tags WHERE group_id=$1';
1357 $res=db_query_params($sql, array($this->getID()));
1359 $this->setError('Deleting old tags: '.db_error());
1363 $inserted = array();
1364 $tags_array = preg_split('/[;,]/', $tags);
1365 foreach ($tags_array as $tag) {
1366 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1367 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1368 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1369 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1374 if ($tag == '' || array_search($tag, $inserted) !== false) continue;
1375 $sql='INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1376 $res=db_query_params($sql, array($this->getID(), $tag));
1378 $this->setError(_('Setting tags: ').db_error());
1389 * getPermission - Return a Permission for this Group
1391 * @return object The Permission.
1393 function &getPermission() {
1394 return permission_get_object($this);
1398 function delete($sure,$really_sure,$really_really_sure) {
1399 if (!$sure || !$really_sure || !$really_really_sure) {
1400 $this->setMissingParamsError();
1403 if ($this->getID() == forge_get_config('news_group') ||
1404 $this->getID() == 1 ||
1405 $this->getID() == forge_get_config('stats_group') ||
1406 $this->getID() == forge_get_config('peer_rating_group')) {
1407 $this->setError(_('Cannot Delete System Group'));
1410 $perm =& $this->getPermission ();
1411 if (!$perm || !is_object($perm)) {
1412 $this->setPermissionDeniedError();
1414 } elseif ($perm->isError()) {
1415 $this->setPermissionDeniedError();
1417 } elseif (!$perm->isSuperUser()) {
1418 $this->setPermissionDeniedError();
1424 // Remove all the members
1426 $members =& $this->getMembers();
1427 for ($i=0; $i<count($members); $i++) {
1428 $this->removeUser($members[$i]->getID());
1433 $atf = new ArtifactTypeFactory($this);
1434 $at_arr =& $atf->getArtifactTypes();
1435 for ($i=0; $i<count($at_arr); $i++) {
1436 if (!is_object($at_arr[$i])) {
1437 printf (_("Not Object: ArtifactType: %d"),$i);
1440 $at_arr[$i]->delete(1,1);
1445 $ff = new ForumFactory($this);
1446 $f_arr =& $ff->getForums();
1447 for ($i=0; $i<count($f_arr); $i++) {
1448 if (!is_object($f_arr[$i])) {
1449 printf (_("Not Object: Forum: %d"),$i);
1452 $f_arr[$i]->delete(1,1);
1455 // Delete Subprojects
1457 $pgf = new ProjectGroupFactory($this);
1458 $pg_arr =& $pgf->getProjectGroups();
1459 for ($i=0; $i<count($pg_arr); $i++) {
1460 if (!is_object($pg_arr[$i])) {
1461 printf (_("Not Object: ProjectGroup: %d"),$i);
1464 $pg_arr[$i]->delete(1,1);
1467 // Delete FRS Packages
1469 //$frspf = new FRSPackageFactory($this);
1470 $res = db_query_params ('SELECT * FROM frs_package WHERE group_id=$1',
1471 array ($this->getID())) ;
1472 //echo 'frs_package'.db_error();
1473 //$frsp_arr =& $frspf->getPackages();
1474 while ($arr = db_fetch_array($res)) {
1475 //if (!is_object($pg_arr[$i])) {
1476 // echo "Not Object: ProjectGroup: ".$i;
1479 $frsp=new FRSPackage($this,$arr['package_id'],$arr);
1485 $news_group=&group_get_object(forge_get_config('news_group'));
1486 $res = db_query_params ('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1487 array ($this->getID())) ;
1489 $this->setError(_('Error Deleting News: ').db_error());
1494 for ($i=0; $i<db_numrows($res); $i++) {
1495 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1496 if (!$Forum->delete(1,1)) {
1497 printf (_("Could Not Delete News Forum: %d"),$Forum->getID());
1500 $res = db_query_params ('DELETE FROM news_bytes WHERE group_id=$1',
1501 array ($this->getID())) ;
1503 $this->setError(_('Error Deleting News: ').db_error());
1511 $res = db_query_params ('DELETE FROM doc_data WHERE group_id=$1',
1512 array ($this->getID())) ;
1514 $this->setError(_('Error Deleting Documents: ').db_error());
1519 $res = db_query_params ('DELETE FROM doc_groups WHERE group_id=$1',
1520 array ($this->getID())) ;
1522 $this->setError(_('Error Deleting Documents: ').db_error());
1530 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1532 $this->setError(_('Error Deleting Tags: ').db_error());
1538 // Delete group history
1540 $res = db_query_params ('DELETE FROM group_history WHERE group_id=$1',
1541 array ($this->getID())) ;
1543 $this->setError(_('Error Deleting Project History: ').db_error());
1549 // Delete group plugins
1551 $res = db_query_params ('DELETE FROM group_plugin WHERE group_id=$1',
1552 array ($this->getID())) ;
1554 $this->setError(_('Error Deleting Project Plugins: ').db_error());
1560 // Delete group cvs stats
1562 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1563 array ($this->getID())) ;
1565 $this->setError(_('Error Deleting SCM Statistics: ').db_error());
1573 $sf = new SurveyFactory($this);
1574 $s_arr =& $sf->getSurveys();
1575 for ($i=0; $i<count($s_arr); $i++) {
1576 if (!is_object($s_arr[$i])) {
1577 printf (_("Not Object: Survey: %d"),$i);
1580 $s_arr[$i]->delete();
1583 // Delete SurveyQuestions
1585 $sqf = new SurveyQuestionFactory($this);
1586 $sq_arr =& $sqf->getSurveyQuestions();
1587 for ($i=0; $i<count($sq_arr); $i++) {
1588 if (!is_object($sq_arr[$i])) {
1589 printf (_("Not Object: SurveyQuestion: %d"),$i);
1592 $sq_arr[$i]->delete();
1595 // Delete Mailing List Factory
1597 $mlf = new MailingListFactory($this);
1598 $ml_arr =& $mlf->getMailingLists();
1599 for ($i=0; $i<count($ml_arr); $i++) {
1600 if (!is_object($ml_arr[$i])) {
1601 printf (_("Not Object: MailingList: %d"),$i);
1604 if (!$ml_arr[$i]->delete(1,1)) {
1605 $this->setError(_('Could not properly delete the mailing list'));
1611 $res = db_query_params ('DELETE FROM trove_group_link WHERE group_id=$1',
1612 array ($this->getID())) ;
1614 $this->setError(_('Error Deleting Trove: ').db_error());
1619 $res = db_query_params ('DELETE FROM trove_agg WHERE group_id=$1',
1620 array ($this->getID())) ;
1622 $this->setError(_('Error Deleting Trove: ').db_error());
1630 $res = db_query_params ('DELETE FROM project_sums_agg WHERE group_id=$1',
1631 array ($this->getID())) ;
1633 $this->setError(_('Error Deleting Counters: ').db_error());
1638 $res = db_query_params ('INSERT INTO deleted_groups (unix_group_name,delete_date,isdeleted) VALUES ($1, $2, $3)',
1639 array ($this->getUnixName(),
1643 $this->setError(_('Error Deleting Project: ').db_error());
1648 $res = db_query_params ('DELETE FROM groups WHERE group_id=$1',
1649 array ($this->getID())) ;
1651 $this->setError(_('Error Deleting Project: ').db_error());
1661 $hook_params = array ();
1662 $hook_params['group'] = $this;
1663 $hook_params['group_id'] = $this->getID();
1664 plugin_hook ("group_delete", $hook_params);
1666 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
1667 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
1669 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
1670 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
1675 $res = db_query_params ('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
1676 array ($this->getID())) ;
1677 //echo 'rep_group_act_monthly'.db_error();
1678 $res = db_query_params ('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
1679 array ($this->getID())) ;
1680 //echo 'rep_group_act_weekly'.db_error();
1681 $res = db_query_params ('DELETE FROM rep_group_act_daily WHERE group_id=$1',
1682 array ($this->getID())) ;
1683 //echo 'rep_group_act_daily'.db_error();
1684 unset($this->data_array);
1692 Basic functions to add/remove users to/from a group
1693 and update their permissions
1699 * addUser - controls adding a user to a group.
1701 * @param string Unix name of the user to add OR integer user_id.
1702 * @param int The role_id this user should have.
1703 * @return boolean success.
1706 function addUser($user_identifier,$role_id) {
1709 Admins can add users to groups
1712 if (!forge_check_perm ('project_admin', $this->getID())) {
1713 $this->setPermissionDeniedError();
1719 get user id for this user's unix_name
1721 if (is_int ($user_identifier)) { // user_id or user_name
1722 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array ($user_identifier)) ;
1724 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array ($user_identifier)) ;
1726 if (db_numrows($res_newuser) > 0) {
1728 // make sure user is active
1730 if (db_result($res_newuser,0,'status') != 'A') {
1731 $this->setError(_('User is not active. Only active users can be added.'));
1737 // user was found - set new user_id var
1739 $user_id = db_result($res_newuser,0,'user_id');
1741 $role = new Role($this,$role_id);
1742 if (!$role || !is_object($role)) {
1743 $this->setError(_('Error Getting Role Object'));
1746 } elseif ($role->isError()) {
1747 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1753 $role->addUser (user_get_object ($user_id)) ;
1754 if (!$SYS->sysCheckCreateGroup($this->getID())){
1755 $this->setError($SYS->getErrorMessage());
1759 if (!$SYS->sysCheckCreateUser($user_id)) {
1760 $this->setError($SYS->getErrorMessage());
1767 // if not already a member, add them
1769 $res_member = db_query_params ('SELECT user_id
1771 WHERE user_id=$1 AND group_id=$2',
1772 array ($user_id, $this->getID())) ;
1774 if (db_numrows($res_member) < 1) {
1776 // Create this user's row in the user_group table
1778 $res = db_query_params ('INSERT INTO user_group
1779 (user_id,group_id,admin_flags,forum_flags,project_flags,
1780 doc_flags,cvs_flags,member_role,release_flags,artifact_flags)
1781 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)',
1793 //verify the insert worked
1794 if (!$res || db_affected_rows($res) < 1) {
1795 $this->setError(sprintf(_('ERROR: Could Not Add User To Group: %s'),db_error()));
1800 // check and create if group doesn't exists
1802 //echo "<h2>Group::addUser SYS->sysCheckCreateGroup(".$this->getID().")</h2>";
1803 if (!$SYS->sysCheckCreateGroup($this->getID())){
1804 $this->setError($SYS->getErrorMessage());
1809 // check and create if user doesn't exists
1811 //echo "<h2>Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1812 if (!$SYS->sysCheckCreateUser($user_id)) {
1813 $this->setError($SYS->getErrorMessage());
1820 //echo "<h2>Group::addUser role->setUser($user_id)</h2>";
1821 if (!$role->setUser($user_id)) {
1822 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1828 // user was already a member
1829 // make sure they are set up
1831 $user=&user_get_object($user_id,$res_newuser);
1832 $user->fetchData($user->getID());
1833 $role = new Role($this,$role_id);
1834 if (!$role || !is_object($role)) {
1835 $this->setError(_('Error Getting Role Object'));
1838 } elseif ($role->isError()) {
1839 $this->setError('addUser::roleget::'.$role->getErrorMessage());
1843 //echo "<h2>Already Member Group::addUser role->setUser($user_id)</h2>";
1844 if (!$role->setUser($user_id)) {
1845 $this->setError('addUser::role::setUser'.$role->getErrorMessage());
1850 // set up their system info
1852 //echo "<h2>Already Member Group::addUser SYS->sysCheckCreateUser($user_id)</h2>";
1853 if (!$SYS->sysCheckCreateUser($user_id)) {
1854 $this->setError($SYS->getErrorMessage());
1862 // user doesn't exist
1864 $this->setError(_('ERROR: User does not exist'));
1869 $hook_params['group'] = $this;
1870 $hook_params['group_id'] = $this->getID();
1871 $hook_params['user'] = &user_get_object($user_id);
1872 $hook_params['user_id'] = $user_id;
1873 plugin_hook ("group_adduser", $hook_params);
1878 $this->addHistory('Added User',$user_identifier);
1884 * removeUser - controls removing a user from a group.
1886 * Users can remove themselves.
1888 * @param int The ID of the user to remove.
1889 * @return boolean success.
1891 function removeUser($user_id) {
1894 if ($user_id != user_getid()
1895 || !forge_check_perm ('project_admin', $this->getID())) {
1896 $this->setPermissionDeniedError();
1903 $user = user_get_object ($user_id) ;
1904 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
1905 $found_role = NULL ;
1906 foreach ($roles as $role) {
1907 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
1908 $found_role = $role ;
1912 if ($found_role == NULL) {
1913 $this->setError(sprintf(_('ERROR: User not removed: %s')));
1917 $found_role->removeUser ($user) ;
1918 if (!$SYS->sysGroupRemoveUser($this->getID(),$user_id)) {
1919 $this->setError($SYS->getErrorMessage());
1925 $res = db_query_params ('DELETE FROM user_group WHERE group_id=$1 AND user_id=$2',
1926 array ($this->getID(),
1928 if (!$res || db_affected_rows($res) < 1) {
1929 $this->setError(sprintf(_('ERROR: User not removed: %s'),db_error()));
1936 // reassign open artifacts to id=100
1938 $res = db_query_params ('UPDATE artifact SET assigned_to=100
1939 WHERE group_artifact_id
1940 IN (SELECT group_artifact_id
1941 FROM artifact_group_list
1942 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
1943 array ($this->getID(),
1946 $this->setError(sprintf(_('ERROR: DB: artifact: %s'),db_error()));
1952 // reassign open tasks to id=100
1953 // first have to purge any assignments that would cause
1954 // conflict with existing assignment to 100
1956 $res = db_query_params ('DELETE FROM project_assigned_to
1957 WHERE project_task_id IN (SELECT pt.project_task_id
1958 FROM project_task pt, project_group_list pgl, project_assigned_to pat
1959 WHERE pt.group_project_id = pgl.group_project_id
1960 AND pat.project_task_id=pt.project_task_id
1961 AND pt.status_id=1 AND pgl.group_id=$1
1962 AND pat.assigned_to_id=$2)
1963 AND assigned_to_id=100',
1964 array ($this->getID(),
1967 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),1,db_error()));
1971 $res = db_query_params ('UPDATE project_assigned_to SET assigned_to_id=100
1972 WHERE project_task_id IN (SELECT pt.project_task_id
1973 FROM project_task pt, project_group_list pgl
1974 WHERE pt.group_project_id = pgl.group_project_id
1975 AND pt.status_id=1 AND pgl.group_id=$1)
1976 AND assigned_to_id=$2',
1977 array ($this->getID(),
1980 $this->setError(sprintf(_('ERROR: DB: project_assigned_to %d: %s'),2,db_error()));
1986 // Remove user from system
1988 //echo "<h2>Group::addUser SYS->sysGroupRemoveUser(".$this->getID().",$user_id)</h2>";
1989 if (!$SYS->sysGroupRemoveUser($this->getID(),$user_id)) {
1990 $this->setError($SYS->getErrorMessage());
1995 $hook_params['group'] = $this;
1996 $hook_params['group_id'] = $this->getID();
1997 $hook_params['user'] = &user_get_object($user_id);
1998 $hook_params['user_id'] = $user_id;
1999 plugin_hook ("group_removeuser", $hook_params);
2002 $this->addHistory('Removed User',$user_id);
2009 * updateUser - controls updating a user's role in this group.
2011 * @param int The ID of the user.
2012 * @param int The role_id to set this user to.
2013 * @return boolean success.
2015 function updateUser($user_id,$role_id) {
2018 if (!forge_check_perm ('project_admin', $this->getID())) {
2019 $this->setPermissionDeniedError();
2024 $newrole = RBACEngine::getInstance()->getRoleById ($role_id) ;
2025 if (!$newrole || !is_object($newrole)) {
2026 $this->setError(_('Could Not Get Role'));
2028 } elseif ($newrole->isError()) {
2029 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2031 } elseif ($newrole->getHomeProject() == NULL
2032 || $newrole->getHomeProject()->getID() != $this->getID()) {
2033 $this->setError(_('Wrong destination role'));
2036 $user = user_get_object ($user_id) ;
2037 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user) ;
2038 $found_role = NULL ;
2039 foreach ($roles as $role) {
2040 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2041 $found_role = $role ;
2045 if ($found_role == NULL) {
2046 $this->setError(sprintf(_('ERROR: User not removed: %s')));
2050 $found_role->removeUser ($user) ;
2051 $newrole->addUser ($user) ;
2053 $role = new Role($this,$role_id);
2054 if (!$role || !is_object($role)) {
2055 $this->setError(_('Could Not Get Role'));
2057 } elseif ($role->isError()) {
2058 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2061 //echo "<h3>Group::updateUser role->setUser($user_id)</h3>";
2062 if (!$role->setUser($user_id)) {
2063 $this->setError(sprintf(_('Role: %s'),$role->getErrorMessage()));
2068 $this->addHistory('Updated User',$user_id);
2073 * addHistory - Makes an audit trail entry for this project.
2075 * @param string The name of the field.
2076 * @param string The Old Value for this $field_name.
2077 * @return database result handle.
2080 function addHistory($field_name, $old_value) {
2081 return db_query_params ('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2082 VALUES ($1,$2,$3,$4,$5)',
2083 array ($this->getID(),
2091 * activateUsers - Make sure that group members have unix accounts.
2093 * Setup unix accounts for group members. Can be called even
2094 * if members are already active.
2098 function activateUsers() {
2100 Activate member(s) of the project
2103 $members = $this->getUsers (true) ;
2105 foreach ($members as $member) {
2107 foreach (RBACEngine::getInstance()->getAvailableRolesForUser ($member) as $role) {
2108 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2111 if (!$this->addUser($member->getUnixName(),$role->getID())) {
2122 * getMembers - returns array of User objects for this project
2124 * @return array of User objects for this group.
2126 function &getMembers() {
2127 return $this->getUsers (true) ;
2131 * approve - Approve pending project.
2133 * @param object The User object who is doing the updating.
2136 function approve(&$user) {
2138 if ($this->getStatus()=='A') {
2139 $this->setError(_("Group already active"));
2145 // Step 1: Activate group and create LDAP entries
2146 if (!$this->setStatus($user, 'A')) {
2151 // Switch to system language for item creation
2152 setup_gettext_from_sys_lang ();
2157 // Tracker Integration
2160 if (forge_get_config ('use_tracker')) {
2161 $ats = new ArtifactTypes($this);
2162 if (!$ats || !is_object($ats)) {
2163 $this->setError(_('Error creating ArtifactTypes object'));
2165 setup_gettext_from_context();
2167 } else if ($ats->isError()) {
2168 $this->setError(sprintf (_('ATS%d: %s'), 1, $ats->getErrorMessage()));
2170 setup_gettext_from_context();
2173 if (!$ats->createTrackers()) {
2174 $this->setError(sprintf (_('ATS%d: %s'), 2, $ats->getErrorMessage()));
2176 setup_gettext_from_context();
2183 // Forum Integration
2186 if (forge_get_config ('use_forum')) {
2187 $f = new Forum($this);
2188 if (!$f->create(_('Open-Discussion'),_('General Discussion'),1,'',1,0)) {
2189 $this->setError(sprintf (_('F%d: %s'), 1, $f->getErrorMessage()));
2191 setup_gettext_from_context();
2194 $f = new Forum($this);
2195 if (!$f->create(_('Help'),_('Get Public Help'),1,'',1,0)) {
2196 $this->setError(sprintf (_('F%d: %s'), 2, $f->getErrorMessage()));
2198 setup_gettext_from_context();
2201 $f = new Forum($this);
2202 if (!$f->create(_('Developers-Discussion'),_('Project Developer Discussion'),0,'',1,0)) {
2203 $this->setError(sprintf (_('F%d: %s'), 3, $f->getErrorMessage()));
2205 setup_gettext_from_context();
2212 // Doc Mgr Integration
2215 if (forge_get_config('use_docman')) {
2216 $dg = new DocumentGroup($this);
2217 if (!$dg->create(_('Uncategorized Submissions'))) {
2218 $this->setError(sprintf(_('DG: %s'),$dg->getErrorMessage()));
2220 setup_gettext_from_context();
2230 if (forge_get_config ('use_frs')) {
2231 $frs = new FRSPackage($this);
2232 if (!$frs->create($this->getUnixName())) {
2233 $this->setError(sprintf(_('FRSP: %s'),$frs->getErrorMessage()));
2235 setup_gettext_from_context();
2245 if (forge_get_config ('use_pm')) {
2246 $pg = new ProjectGroup($this);
2247 if (!$pg->create(_('To Do'),_('Things We Have To Do'),1)) {
2248 $this->setError(sprintf(_('PG%d: %s'),1,$pg->getErrorMessage()));
2250 setup_gettext_from_context();
2253 $pg = new ProjectGroup($this);
2254 if (!$pg->create(_('Next Release'),_('Items For Our Next Release'),1)) {
2255 $this->setError(sprintf(_('PG%d: %s'),2,$pg->getErrorMessage()));
2257 setup_gettext_from_context();
2264 // Set Default Roles
2268 $admin_group = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1 AND admin_flags=$2',
2269 array ($this->getID(),
2271 if (db_numrows($admin_group) > 0) {
2272 $idadmin_group = db_result($admin_group,0,'user_id');
2274 $idadmin_group = $user->getID();
2275 db_query_params ('INSERT INTO user_group (user_id, group_id, admin_flags) VALUES ($1, $2, $3)',
2276 array ($idadmin_group,
2281 $role = new Role($this);
2282 $todo = array_keys($role->defaults);
2283 for ($c=0; $c<count($todo); $c++) {
2284 $role = new Role($this);
2285 if (! ($role_id = $role->createDefault($todo[$c]))) {
2286 $this->setError(sprintf(_('R%d: %s'),$c,$role->getErrorMessage()));
2288 setup_gettext_from_context();
2291 $role = new Role($this, $role_id);
2292 if ($role->getVal('projectadmin',0)=='A') {
2293 $role->setUser($idadmin_group);
2298 $roles = $this->getRoles() ;
2299 foreach ($roles as $r) {
2300 if ($r->getSetting ('project_admin', $this->getID())) {
2301 $r->addUser (user_get_object ($idadmin_group)) ;
2305 RoleAnonymous::getInstance()->linkProject($this) ;
2306 RoleLoggedIn::getInstance()->linkProject($this) ;
2311 // Create MailingList
2314 if (forge_get_config('use_mail')) {
2315 $mlist = new MailingList($this);
2316 if (!$mlist->create('commits',_('Commits'),1,$idadmin_group)) {
2317 $this->setError(sprintf(_('ML: %s'),$mlist->getErrorMessage()));
2319 setup_gettext_from_context();
2324 // Switch back to user preference
2325 setup_gettext_from_context();
2329 $this->sendApprovalEmail();
2330 $this->addHistory('Approved', 'x');
2333 // Plugin can make approve operation there
2336 $params[0] = $idadmin_group ;
2337 $params[1] = $this->getID();
2338 plugin_hook('group_approve',$params);
2346 * sendApprovalEmail - Send new project email.
2348 * @return boolean success.
2351 function sendApprovalEmail() {
2352 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID()) ;
2354 if (count($admins) < 1) {
2355 $this->setError(_("Group does not have any administrators."));
2359 // send one email per admin
2360 foreach ($admins as $admin) {
2361 setup_gettext_for_user ($admin) ;
2363 $message=sprintf(_('Your project registration for %4$s has been approved.
2365 Project Full Name: %1$s
2366 Project Unix Name: %2$s
2368 Your DNS will take up to a day to become active on our site.
2369 Your web site is accessible through your shell account. Please read
2370 site documentation (see link below) about intended usage, available
2371 services, and directory layout of the account.
2374 own project page in %4$s while logged in, you will find
2375 additional menu functions to your left labeled \'Project Admin\'.
2377 We highly suggest that you now visit %4$s and create a public
2378 description for your project. This can be done by visiting your project
2379 page while logged in, and selecting \'Project Admin\' from the menus
2380 on the left (or by visiting %3$s
2383 Your project will also not appear in the Trove Software Map (primary
2384 list of projects hosted on %4$s which offers great flexibility in
2385 browsing and search) until you categorize it in the project administration
2386 screens. So that people can find your project, you should do this now.
2387 Visit your project while logged in, and select \'Project Admin\' from the
2390 Enjoy the system, and please tell others about %4$s. Let us know
2391 if there is anything we can do to help you.
2394 htmlspecialchars_decode($this->getPublicName()),
2395 $this->getUnixName(),
2396 util_make_url ('/project/admin/?group_id='.$this->getID()),
2397 forge_get_config ('forge_name'));
2399 util_send_message($admin->getEmail(), sprintf(_('%1$s Project Approved'), forge_get_config ('forge_name')), $message);
2401 setup_gettext_from_context();
2409 * sendRejectionEmail - Send project rejection email.
2411 * This function sends out a rejection message to a user who
2412 * registered a project.
2414 * @param int The id of the response to use.
2415 * @param string The rejection message.
2416 * @return completion status.
2419 function sendRejectionEmail($response_id, $message="zxcv") {
2420 $res_admins = db_query_params ('
2421 SELECT u.email, u.language, u.user_id
2422 FROM users u, user_group ug
2423 WHERE ug.group_id=$1
2424 AND u.user_id=ug.user_id',
2425 array ($this->getID())) ;
2426 if (db_numrows($res_admins) < 1) {
2427 $this->setError(_("Group does not have any administrators."));
2431 while ($row_admins = db_fetch_array($res_admins)) {
2432 $admin =& user_get_object($row_admins['user_id']);
2433 setup_gettext_for_user ($admin) ;
2435 $response=sprintf(_('Your project registration for %3$s has been denied.
2437 Project Full Name: %1$s
2438 Project Unix Name: %2$s
2440 Reasons for negative decision:
2442 '), $this->getPublicName(), $this->getUnixName(), forge_get_config ('forge_name'));
2444 // Check to see if they want to send a custom rejection response
2445 if ($response_id == 0) {
2446 $response .= $message;
2448 $response .= db_result (
2449 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array ($response_id)),
2454 util_send_message($row_admins['email'], sprintf(_('%1$s Project Denied'), forge_get_config ('forge_name')), $response);
2455 setup_gettext_from_context();
2462 * sendNewProjectNotificationEmail - Send new project notification email.
2464 * This function sends out a notification email to the
2465 * SourceForge admin user when a new project is
2468 * @return boolean success.
2471 function sendNewProjectNotificationEmail() {
2472 // Get the user who wants to register the project
2473 $res = db_query_params ('SELECT user_id FROM user_group WHERE group_id=$1',
2474 array ($this->getID())) ;
2476 if (db_numrows($res) < 1) {
2477 $this->setError(_("Could not find user who has submitted the project."));
2481 $submitter =& user_get_object(db_result($res,0,'user_id'));
2484 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_approve', -1) ;
2486 if (count($admins) < 1) {
2487 $this->setError(_("There is no administrator to send the mail to."));
2491 foreach ($admins as $admin) {
2492 $admin_email = $admin->getEmail () ;
2493 setup_gettext_for_user ($admin) ;
2495 $message=sprintf(_('New %1$s Project Submitted
2497 Project Full Name: %2$s
2498 Submitted Description: %3$s
2499 Submitter: %5$s (%6$s)
2501 Please visit the following URL to approve or reject this project:
2503 forge_get_config ('forge_name'),
2504 htmlspecialchars_decode($this->getPublicName()),
2505 htmlspecialchars_decode($this->getRegistrationPurpose()),
2506 util_make_url ('/admin/approve-pending.php'),
2507 $submitter->getRealName(),
2508 $submitter->getUnixName());
2509 util_send_message($admin_email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2510 setup_gettext_from_context();
2514 $email = $submitter->getEmail() ;
2515 setup_gettext_for_user ($submitter) ;
2517 $message=sprintf(_('New %1$s Project Submitted
2519 Project Full Name: %2$s
2520 Submitted Description: %3$s
2522 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'));
2524 util_send_message($email, sprintf(_('New %1$s Project Submitted'), forge_get_config ('forge_name')), $message);
2525 setup_gettext_from_context();
2534 * validateGroupName - Validate the group name
2536 * @param string Group name.
2538 * @return an error false and set an error is the group name is invalide otherwise return true
2540 function validateGroupName($group_name) {
2541 if (strlen($group_name)<3) {
2542 $this->setError(_('Group name is too short'));
2544 } else if (strlen(htmlspecialchars($group_name))>50) {
2545 $this->setError(_('Group name is too long'));
2547 } else if ($group=group_get_object_by_publicname($group_name)) {
2548 $this->setError(_('Group name already taken'));
2556 * getRoles - Get the roles of the group.
2558 * @return array of Role id of this group.
2560 function getRolesId () {
2561 $role_ids = array () ;
2564 $res = db_query_params ('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2565 array ($this->getID()));
2566 while ($arr = db_fetch_array($res)) {
2567 $role_ids[] = $arr['role_id'] ;
2569 $res = db_query_params ('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2570 array ($this->getID()));
2571 while ($arr = db_fetch_array($res)) {
2572 $role_ids[] = $arr['role_id'] ;
2575 $res = db_query_params ('SELECT role_id FROM role WHERE group_id=$1',
2576 array ($this->getID()));
2577 while ($arr = db_fetch_array($res)) {
2578 $role_ids[] = $arr['role_id'] ;
2582 return array_unique ($role_ids) ;
2585 function getRoles () {
2586 $result = array () ;
2588 $roles = $this->getRolesId () ;
2590 $engine = RBACEngine::getInstance() ;
2591 foreach ($roles as $role_id) {
2592 $result[] = $engine->getRoleById ($role_id) ;
2595 foreach ($roles as $role_id) {
2596 $result[] = new Role ($this, $role_id) ;
2603 function normalizeAllRoles () {
2604 $roles = $this->getRoles () ;
2606 foreach ($roles as $r) {
2607 $r->normalizeData () ;
2612 * getUnixStatus - Status of activation of unix account.
2614 * @return char (N)one, (A)ctive, (S)uspended or (D)eleted
2616 function getUnixStatus() {
2617 return $this->data_array['unix_status'];
2621 * setUnixStatus - Sets status of activation of unix account.
2623 * @param string The unix status.
2629 * @return boolean success.
2631 function setUnixStatus($status) {
2634 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
2639 $this->setError(sprintf(_('ERROR - Could Not Update Group Unix Status: %s'),db_error()));
2643 if ($status == 'A') {
2644 if (!$SYS->sysCheckCreateGroup($this->getID())) {
2645 $this->setError($SYS->getErrorMessage());
2650 if ($SYS->sysCheckGroup($this->getID())) {
2651 if (!$SYS->sysRemoveGroup($this->getID())) {
2652 $this->setError($SYS->getErrorMessage());
2659 $this->data_array['unix_status']=$status;
2666 * getUsers - Get the users of a group
2668 * @return array of user's objects.
2670 function getUsers($onlylocal = true) {
2671 if (!isset($this->membersArr)) {
2672 $this->membersArr = array () ;
2676 foreach ($this->getRoles() as $role) {
2678 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
2681 foreach ($role->getUsers() as $user) {
2682 $ids[] = $user->getID() ;
2685 $ids = array_unique ($ids) ;
2686 foreach ($ids as $id) {
2687 $u = user_get_object ($id) ;
2688 if ($u->isActive()) {
2689 $this->membersArr[] = $u ;
2694 $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',
2695 array ($this->getID(),
2697 if (!$users_group_res) {
2698 $this->setError('Error: Enable to get users from group '. $this->getID() . ' ' .db_error());
2702 for ($i=0; $i<db_numrows($users_group_res); $i++) {
2703 $this->membersArr[$i] = new GFUser(db_result($users_group_res,$i,'user_id'),false);
2708 return $this->membersArr;
2711 function setDocmanSearchStatus($status) {
2713 /* if we activate search engine, we probably want to reindex */
2714 $res = db_query_params ('UPDATE groups SET use_docman_search=$1, force_docman_reindex=$1 WHERE group_id=$2',
2719 $this->setError(sprintf(_('ERROR - Could Not Update Group UseDocmanSearch Status: %s'),db_error()));
2723 $this->data_array['use_docman_search']=$status;
2729 function setDocmanForceReindexSearch($status) {
2731 /* if we activate search engine, we probably want to reindex */
2732 $res = db_query_params ('UPDATE groups SET force_docman_reindex=$1 WHERE group_id=$2',
2737 $this->setError(sprintf(_('ERROR - Could Not Update Group force_docman_reindex %s'),db_error()));
2741 $this->data_array['force_docman_reindex']=$status;
2749 * group_getname() - get the group name
2751 * @param int The group ID
2755 function group_getname ($group_id = 0) {
2756 $grp = &group_get_object($group_id);
2758 return $grp->getPublicName();
2765 * group_getunixname() - get the unixname for a group
2767 * @param int The group ID
2771 function group_getunixname ($group_id) {
2772 $grp = &group_get_object($group_id);
2774 return $grp->getUnixName();
2781 * group_get_result() - Get the group object result ID.
2783 * @param int The group ID
2787 function &group_get_result($group_id=0) {
2788 $grp = &group_get_object($group_id);
2790 return $grp->getData();
2796 class ProjectComparator {
2797 var $criterion = 'name' ;
2799 function Compare ($a, $b) {
2800 switch ($this->criterion) {
2803 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName()) ;
2804 if ($namecmp != 0) {
2807 /* If several projects share a same public name */
2808 return strcoll ($a->getUnixName(), $b->getUnixName()) ;
2811 $aid = $a->getID() ;
2812 $bid = $b->getID() ;
2816 return ($a < $b) ? -1 : 1;
2822 function sortProjectList (&$list, $criterion='name') {
2823 $cmp = new ProjectComparator () ;
2824 $cmp->criterion = $criterion ;
2826 return usort ($list, array ($cmp, 'Compare')) ;
2831 // c-file-style: "bsd"