5 * Copyright 1999-2001, VA Linux Systems, Inc.
6 * Copyright 2009-2013, Roland Mas
7 * Copyright 2010-2011, Franck Villaume - Capgemini
8 * Copyright 2010-2012, Alain Peyrat - Alcatel-Lucent
9 * Copyright 2012-2017, Franck Villaume - TrivialDev
10 * Copyright 2013, French Ministry of National Education
11 * Copyright 2017, Stéphane-Eymeric Bredthauer - TrivialDev
12 * http://fusionforge.org
14 * This file is part of FusionForge. FusionForge is free software;
15 * you can redistribute it and/or modify it under the terms of the
16 * GNU General Public License as published by the Free Software
17 * Foundation; either version 2 of the Licence, or (at your option)
20 * FusionForge is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 require_once $gfcommon.'tracker/ArtifactTypes.class.php';
31 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
32 require_once $gfcommon.'tracker/RoadmapFactory.class.php';
33 require_once $gfcommon.'forum/Forum.class.php';
34 require_once $gfcommon.'forum/ForumFactory.class.php';
35 require_once $gfcommon.'pm/ProjectGroup.class.php';
36 require_once $gfcommon.'pm/ProjectGroupFactory.class.php';
37 require_once $gfcommon.'frs/FRSPackage.class.php';
38 require_once $gfcommon.'frs/FRSRelease.class.php';
39 require_once $gfcommon.'docman/DocumentGroup.class.php';
40 require_once $gfcommon.'docman/DocumentGroupFactory.class.php';
41 require_once $gfcommon.'mail/MailingList.class.php';
42 require_once $gfcommon.'mail/MailingListFactory.class.php';
43 require_once $gfcommon.'survey/SurveyFactory.class.php';
44 require_once $gfcommon.'survey/SurveyQuestionFactory.class.php';
45 require_once $gfcommon.'include/gettext.php';
46 require_once $gfcommon.'include/GroupJoinRequest.class.php';
47 require_once $gfcommon.'include/Role.class.php';
48 require_once $gfcommon.'widget/WidgetLayoutManager.class.php';
53 * group_get_object() - Get the group object.
55 * group_get_object() is useful so you can pool group objects/save database queries
56 * You should always use this instead of instantiating the object directly.
58 * You can now optionally pass in a db result handle. If you do, it re-uses that query
59 * to instantiate the objects.
61 * IMPORTANT! That db result must contain all fields
62 * from groups table or you will have problems
64 * @param int $group_id Required
65 * @param int|bool $res Result set handle ("SELECT * FROM groups WHERE group_id=xx")
66 * @return Group|bool A group object or false on failure
68 function &group_get_object($group_id, $res = false) {
69 //create a common set of group objects
70 //saves a little wear on the database
72 //automatically checks group_type and
73 //returns appropriate object
76 if (!isset($GROUP_OBJ["_".$group_id."_"])) {
78 //the db result handle was passed in
80 $res = db_query_params('SELECT * FROM groups WHERE group_id=$1', array($group_id));
82 if (!$res || db_numrows($res) < 1) {
83 $GROUP_OBJ["_".$group_id."_"]=false;
88 $GROUP_OBJ["_".$group_id."_"] = new Group($group_id, $res);
91 return $GROUP_OBJ["_".$group_id."_"];
94 function &group_get_objects($id_arr) {
97 // Note: if we don't do this, the result may be corrupted
101 foreach ($id_arr as $id) {
103 // See if this ID already has been fetched in the cache
105 if (!isset($GROUP_OBJ["_".$id."_"])) {
109 if (count($fetch) > 0) {
110 $res=db_query_params('SELECT * FROM groups WHERE group_id = ANY ($1)',
111 array(db_int_array_to_any_clause($fetch)));
112 while ($arr = db_fetch_array($res)) {
113 $GROUP_OBJ["_".$arr['group_id']."_"] = new Group($arr['group_id'],$arr);
116 foreach ($id_arr as $id) {
117 $return[] =& $GROUP_OBJ["_".$id."_"];
122 function &group_get_active_projects() {
123 $res = db_query_params('SELECT group_id FROM groups WHERE status=$1',
125 return group_get_objects(util_result_column_to_array($res,0));
128 function &group_get_all_projects() {
129 $res = db_query_params ('SELECT group_id FROM groups',
131 return group_get_objects(util_result_column_to_array($res,0));
134 function &group_get_template_projects() {
135 $res = db_query_params('SELECT group_id FROM groups WHERE is_template=1 AND status != $1',
137 return group_get_objects(util_result_column_to_array($res,0));
140 function &group_get_object_by_name($groupname) {
141 $res = db_query_params('SELECT * FROM groups WHERE unix_group_name=$1', array($groupname));
142 return group_get_object(db_result($res, 0, 'group_id'), $res);
145 function &group_get_objects_by_name($groupname_arr) {
146 $res = db_query_params('SELECT group_id FROM groups WHERE unix_group_name = ANY ($1)',
147 array(db_string_array_to_any_clause($groupname_arr)));
148 $arr =& util_result_column_to_array($res,0);
149 return group_get_objects($arr);
152 function group_get_object_by_publicname($groupname) {
153 $res = db_query_params('SELECT * FROM groups WHERE lower(group_name) LIKE $1',
154 array(htmlspecialchars(html_entity_decode(strtolower($groupname)))));
155 return group_get_object(db_result($res, 0, 'group_id'), $res);
158 function filter_groups_by_read_access($grps) {
159 $filteredgrps = array();
160 foreach ($grps as $g) {
161 if (forge_check_perm ('project_read', $g->getID())) {
162 $filteredgrps[] = $g;
165 return $filteredgrps;
169 * get_public_active_projects_asc() - Get a list of rows for public active projects (initially in trove/full_list)
171 * @param int $max_query_limit Optional Maximum number of rows to limit query length
172 * @param int $offset start to retrieve rows from offset value
173 * @return array List of public active projects
175 function group_get_public_active_projects_asc($max_query_limit = -1, $offset = 0) {
177 if (session_loggedin()) {
179 $userRoles = $LUSER->getRoles();
180 if (count($userRoles)) {
181 foreach ($userRoles as $r) {
182 $role_id .= ', '.$r->getID();
187 $res_grp = db_query_params ('
188 SELECT group_id, group_name, unix_group_name, short_description, register_time
190 WHERE status = $1 AND is_template=0 AND register_time > 0
191 AND group_id in (select ref_id FROM pfo_role_setting WHERE section_name = $2 and perm_val = 1 and role_id IN ('.$role_id.'))
192 ORDER BY group_name ASC
194 array('A', 'project_read'),
195 $max_query_limit, $offset);
197 while ($row_grp = db_fetch_array($res_grp)) {
198 $projects[] = $row_grp;
204 * group_get_readable_projects_using_tag_asc() - Get a list of group_id for active projects (initially in trove/tag_cloud)
206 * @param string $selected_tag Tag to search
207 * @param int $max_query_limit Optional Maximum number of rows to limit query length
208 * @param int $offset start to retrieve rows from offset value
209 * @return array List of public active projects
211 function group_get_readable_projects_using_tag_asc($selected_tag, $max_query_limit = -1, $offset = 0) {
213 if (session_loggedin()) {
215 $userRoles = $LUSER->getRoles();
216 if (count($userRoles)) {
217 foreach ($userRoles as $r) {
218 $role_id .= ', '.$r->getID();
223 $res_grp = db_query_params ('SELECT groups.group_id, group_name, unix_group_name, short_description, register_time
224 FROM project_tags, groups
225 WHERE LOWER(name) = $1
226 AND project_tags.group_id = groups.group_id
227 AND groups.status = $2 AND groups.is_template=0 AND groups.register_time > 0
228 AND groups.group_id in (select ref_id FROM pfo_role_setting WHERE section_name = $3 and perm_val = 1 and role_id IN ('.$role_id.'))
229 ORDER BY groups.group_name ASC',
230 array(strtolower($selected_tag), 'A', 'project_read'),
231 $max_query_limit, $offset);
233 while ($row_grp = db_fetch_array($res_grp)) {
234 $projects[] = $row_grp;
239 class Group extends FFError {
241 * Associative array of data from db.
243 * @var array $data_array.
248 * array of User objects.
250 * @var array $membersArr.
255 * Group - Group object constructor - use group_get_object() to instantiate.
257 * @param int|bool $id Required - Id of the group you want to instantiate.
258 * @param int|bool $res Database result from select query OR associative array of all columns.
260 function __construct($id = false, $res = false) {
261 parent::__construct();
263 //setting up an empty object
264 //probably going to call create()
268 if (!$this->fetchData($id)) {
273 // Assoc array was passed in
275 if (is_array($res)) {
276 $this->data_array =& $res;
278 if (db_numrows($res) < 1) {
279 //function in class we extended
280 $this->setError(_('Group Not Found'));
281 $this->data_array=array();
284 //set up an associative array for use by other functions
285 $this->data_array = db_fetch_array_by_row($res, 0);
293 * fetchData - May need to refresh database fields if an update occurred.
295 * @param int $group_id The group_id.
296 * @return bool success or not
298 function fetchData($group_id) {
299 $res = db_query_params ('SELECT * FROM groups WHERE group_id=$1',
301 if (!$res || db_numrows($res) < 1) {
302 $this->setError('fetchData()'._(': ').db_error());
305 $this->data_array = db_fetch_array($res);
310 * create - Create new group.
312 * This method should be called on empty Group object.
313 * It will add an entry for a pending group/project (status 'P')
315 * @param object $user The User object.
316 * @param string $group_name The full name of the user.
317 * @param string $unix_name The Unix name of the user.
318 * @param string $description The new group description.
319 * @param string $purpose The purpose of the group.
320 * @param string $unix_box
321 * @param string $scm_box
322 * @param bool $send_mail Whether to send an email or not
323 * @param int $built_from_template The id of the project this new project is based on
324 * @param int $createtimestamp The Time Stamp of creation to ease import.
325 * @return bool success or not
327 function create(&$user, $group_name, $unix_name, $description, $purpose, $unix_box = 'shell1',
328 $scm_box = 'cvs1', $send_mail = true, $built_from_template = 0, $createtimestamp = null) {
329 // $user is ignored - anyone can create pending group
332 if ($this->getID()!=0) {
333 $this->setError(_('Group object already exists.'));
335 } elseif (!$this->validateGroupName($group_name)) {
336 $this->setError(_('Invalid project name'));
338 } elseif (!account_groupnamevalid($unix_name)) {
339 $this->setError(_('Invalid Unix Name.'));
341 } elseif (!$SYS->sysUseUnixName($unix_name)) {
342 $this->setError(_('Unix name already taken.'));
344 } elseif (strlen($purpose)<10) {
345 $this->setError(_('Please describe your Registration Project Purpose and Summarization in a more comprehensive manner.'));
347 } elseif (strlen($purpose)>1500) {
348 $this->setError(_('The Registration Project Purpose and Summarization text is too long. Please make it smaller than 1500 characters.'));
350 } elseif (strlen($description)<10) {
351 $this->setError(_('Describe in a more comprehensive manner your project.'));
355 // Check if use_project_vhost for homepage
356 if (forge_get_config('use_project_vhost')) {
357 $homepage = $unix_name.'.'.forge_get_config('web_host');
359 $homepage = forge_get_config('web_host')."/www/".$unix_name."/";
363 $createtimestamp = (($createtimestamp) ? $createtimestamp : time());
364 $res = db_query_params('
379 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)',
380 array(htmlspecialchars($group_name),
382 htmlspecialchars($description),
388 htmlspecialchars($purpose),
390 md5(util_randbytes()),
391 $built_from_template));
392 if (!$res || db_affected_rows($res) < 1) {
393 $this->setError(_('Error')._(': ')._('Cannot create group')._(': ').db_error());
398 $id = db_insertid($res, 'groups', 'group_id');
400 $this->setError(_('Error')._(': ')._('Cannot get group id')._(': ').db_error());
405 if (!$this->fetchData($id)) {
410 $gjr = new GroupJoinRequest($this);
411 $gjr->create($user->getID(), 'Fake GroupJoinRequest to store the creator of a project', false);
413 $hook_params = array();
414 $hook_params['group'] = $this;
415 $hook_params['group_id'] = $this->getID();
416 $hook_params['group_name'] = $group_name;
417 $hook_params['unix_group_name'] = $unix_name;
418 $hook_params['createtimestamp'] = $createtimestamp;
419 plugin_hook("group_create", $hook_params);
423 $this->sendNewProjectNotificationEmail();
431 * updateAdmin - Update core properties of group object.
433 * This function require site admin privilege.
435 * @param object $user User requesting operation (for access control).
436 * @param string $unix_box Machine on which group's home directory located.
437 * @param string $http_domain Domain which serves group's WWW.
438 * @return bool status.
441 function updateAdmin(&$user, $unix_box, $http_domain) {
442 $perm =& $this->getPermission();
444 if (!$perm || !is_object($perm)) {
445 $this->setError(_('Could not get permission.'));
449 if (!$perm->isSuperUser()) {
450 $this->setError(_('Permission denied.'));
456 $res = db_query_params('
458 SET unix_box=$1, http_domain=$2
464 if (!$res || db_affected_rows($res) < 1) {
465 $this->setError(_('Error')._(': ')._('Cannot change group properties')._(': ').db_error());
470 // Log the audit trail
471 if ($unix_box != $this->data_array['unix_box']) {
472 $this->addHistory('unix_box', $this->data_array['unix_box']);
474 if ($http_domain != $this->data_array['http_domain']) {
475 $this->addHistory('http_domain', $this->data_array['http_domain']);
478 if (!$this->fetchData($this->getID())) {
487 * update - Update number of common properties.
489 * Unlike updateAdmin(), this function accessible to project admin.
491 * @param object $user User requesting operation (for access control).
492 * @param string $group_name
493 * @param string $homepage
494 * @param string $short_description
495 * @param bool $use_mail
496 * @param bool $use_survey
497 * @param bool $use_forum
498 * @param bool $use_pm
499 * @param bool $use_pm_depend_box
500 * @param bool $use_scm
501 * @param bool $use_news
502 * @param bool $use_docman
503 * @param string $new_doc_address
504 * @param bool $send_all_docs
505 * @param int $logo_image_id XXXX UNUSED XXXX -> see getLogoImageID function
506 * @param bool $use_ftp
507 * @param bool $use_tracker
508 * @param bool $use_frs
509 * @param bool $use_stats
510 * @param string $tags
511 * @param bool $use_activity
512 * @param bool $is_public group is publicly accessible
513 * @return int status.
516 function update(&$user, $group_name, $homepage, $short_description, $use_mail, $use_survey, $use_forum,
517 $use_pm, $use_pm_depend_box, $use_scm, $use_news, $use_docman,
518 $new_doc_address, $send_all_docs, $logo_image_id,
519 $use_ftp, $use_tracker, $use_frs, $use_stats, $tags, $use_activity, $is_public) {
521 $perm =& $this->getPermission();
523 if (!$perm || !is_object($perm)) {
524 $this->setError(_('Could not get permission.'));
528 if (!$perm->isAdmin()) {
529 $this->setError(_('Permission denied.'));
533 // Validate some values
534 if ($this->getPublicName() != htmlspecialchars($group_name)) {
535 if (!$this->validateGroupName($group_name)) {
540 if ($new_doc_address) {
541 $invalid_mails = validate_emails($new_doc_address);
542 if (count($invalid_mails) > 0) {
543 $this->setError(sprintf(ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
548 // in the database, these all default to '1',
549 // so we have to explicitly set 0
562 if (!$use_pm_depend_box) {
563 $use_pm_depend_box = 0;
586 if (!$use_activity) {
589 if (!$send_all_docs) {
593 $homepage = ltrim($homepage);
595 $homepage = util_make_url('/projects/'.$this->getUnixName().'/');
600 $res = db_query_params('UPDATE groups
603 short_description=$3,
608 use_pm_depend_box=$8,
619 array(htmlspecialchars($group_name),
621 htmlspecialchars($short_description),
638 if (!$res || db_affected_rows($res) < 1) {
639 $this->setError(_('Error updating project information')._(': ').db_error());
644 if (!$this->setUseDocman($use_docman)) {
645 $this->setError(_('Error updating project information use_docman')._(': ').db_error());
650 if ($this->setTags($tags) === false) {
655 // Log the audit trail
656 $this->addHistory('Changed Public Info', '');
658 if (!$this->fetchData($this->getID())) {
663 $hook_params = array();
664 $hook_params['group'] = $this;
665 $hook_params['group_id'] = $this->getID();
666 $hook_params['group_homepage'] = $homepage;
667 $hook_params['group_name'] = htmlspecialchars($group_name);
668 $hook_params['group_description'] = htmlspecialchars($short_description);
669 $hook_params['group_ispublic'] = $is_public;
670 if (!plugin_hook("group_update", $hook_params)) {
671 if (!$this->isError()) {
672 $this->setError(_('Error updating project information in plugin_hook group_update'));
683 * getID - Simply return the group_id for this object.
685 * @return int group_id.
688 return $this->data_array['group_id'];
692 * getStatus - the status code.
694 * Statuses char include I,H,A,D,P.
701 function getStatus() {
702 return $this->data_array['status'];
706 * setStatus - set the status code.
708 * Statuses include I,H,A,D,P.
715 * @param object $user User requesting operation (for access control).
716 * @param string $status Status value.
717 * @return bool success.
720 function setStatus(&$user, $status) {
723 if (!forge_check_global_perm_for_user($user, 'approve_projects')) {
724 $this->setPermissionDeniedError();
728 // Projects in 'A' status can only go to 'H' or 'D'
729 // Projects in 'D' status can only go to 'A'
730 // Projects in 'P' status can only go to 'A' OR 'D'
731 // Projects in 'I' status can only go to 'P'
732 // Projects in 'H' status can only go to 'A' OR 'D'
733 $allowed_status_changes = array(
734 'AH'=>1,'AD'=>1,'DA'=>1,'PA'=>1,'PD'=>1,
735 'IP'=>1,'HA'=>1,'HD'=>1
738 // Check that status transition is valid
739 if ($this->getStatus() != $status
740 && !array_key_exists($this->getStatus(). $status, $allowed_status_changes)) {
741 $this->setError(_('Invalid Status Change From')._(': ').$this->getStatus()._(' To ')._(': ').$status);
747 $res = db_query_params('UPDATE groups
749 WHERE group_id=$2', array($status, $this->getID()));
751 if (!$res || db_affected_rows($res) < 1) {
752 $this->setError(_('Error')._(': ')._('Cannot change group status')._(': ').db_error());
758 // Activate system group, if not yet
759 if (!$SYS->sysCheckGroup($this->getID())) {
760 if (!$SYS->sysCreateGroup($this->getID())) {
761 $this->setError($SYS->getErrorMessage());
766 if (!$this->activateUsers()) {
771 /* Otherwise, the group is not active, and make sure that
772 System group is not active either */
773 } elseif ($SYS->sysCheckGroup($this->getID())) {
774 if (!$SYS->sysRemoveGroup($this->getID())) {
775 $this->setError($SYS->getErrorMessage());
781 $hook_params = array();
782 $hook_params['group'] = $this;
783 $hook_params['group_id'] = $this->getID();
784 $hook_params['status'] = $status;
785 plugin_hook("group_setstatus", $hook_params);
789 // Log the audit trail
790 if ($status != $this->getStatus()) {
791 $this->addHistory(_('Status'), $this->getStatus());
794 $this->data_array['status'] = $status;
799 * isPublic - Wrapper around RBAC to check if a project is anonymously readable
801 * @return boo is_public.
803 function isPublic() {
804 $ra = RoleAnonymous::getInstance();
805 return $ra->hasPermission('project_read', $this->getID());
809 * isActive - Database field status of 'A' returns true.
811 * @return bool is_active.
813 function isActive() {
814 if ($this->getStatus() == 'A') {
822 * isTemplate - Simply returns the is_template flag from the database.
824 * @return bool is_template.
826 function isTemplate() {
827 return $this->data_array['is_template'];
831 * setAsTemplate - Set the template status of a project
833 * @param bool $booleanparam is_template.
836 function setAsTemplate($booleanparam) {
838 $booleanparam = $booleanparam ? 1 : 0;
839 $res = db_query_params('UPDATE groups SET is_template=$1 WHERE group_id=$2',
840 array($booleanparam, $this->getID()));
842 $this->data_array['is_template'] = $booleanparam;
852 * getTemplateProject - Return the project template this project is built from
854 * @return object The template project
856 function getTemplateProject() {
857 return group_get_object($this->data_array['built_from_template']);
861 * getUnixName - the unix_name
863 * @return string unix_name.
865 function getUnixName() {
866 return strtolower($this->data_array['unix_group_name']);
870 * getPublicName - the full-length public name.
872 * @return string The group_name.
874 function getPublicName() {
875 return $this->data_array['group_name'];
879 * getRegisterPurpose - the text description of the purpose of this project.
881 * @return string The description.
883 function getRegisterPurpose() {
884 return $this->data_array['register_purpose'];
888 * getDescription - the text description of this project.
890 * @return string The description.
892 function getDescription() {
893 return $this->data_array['short_description'];
897 * getStartDate - the unix time this project was registered.
899 * @return int (unix time) of registration.
901 function getStartDate() {
902 return $this->data_array['register_time'];
906 * getLogoImageID - the id of the logo in the database for this project.
908 * @return int The ID of logo image in db_images table (or 100 if none).
910 function getLogoImageID() {
911 if (!isset($this->data_array['logo_image_id'])) {
912 $res = db_query_params('select id from db_images where group_id = $1 and is_logo = $2',
913 array($this->getID(), 1));
914 if ($res && db_numrows($res)) {
915 $this->data_array['logo_image_id'] = db_result($res, 0, 'id');
917 $this->data_array['logo_image_id'] = null;
920 return $this->data_array['logo_image_id'];
924 * getUnixBox - the hostname of the unix box where this project is located.
926 * @return string The name of the unix machine for the group.
928 function getUnixBox() {
929 return $this->data_array['unix_box'];
933 * getSCMBox - the hostname of the scm box where this project is located.
935 * @return string The name of the unix machine for the group.
937 function getSCMBox() {
938 return $this->data_array['scm_box'];
941 * setSCMBox - the hostname of the scm box where this project is located.
943 * @param string $scm_box The name of the new SCM_BOX
946 function setSCMBox($scm_box) {
948 if ($scm_box == $this->data_array['scm_box']) {
953 $res = db_query_params('UPDATE groups SET scm_box=$1 WHERE group_id=$2', array($scm_box, $this->getID()));
955 $this->addHistory('scm_box', $this->data_array['scm_box']);
956 $this->data_array['scm_box'] = $scm_box;
961 $this->setError(_("Could not insert SCM_BOX to database"));
965 $this->setError(_("SCM Box cannot be empty"));
971 * getDomain - the hostname.domain where their web page is located.
973 * @return string The name of the group [web] domain.
975 function getDomain() {
976 return $this->data_array['http_domain'];
980 * getRegistrationPurpose - the text description of the purpose of this project.
982 * @return string The application for project hosting.
984 function getRegistrationPurpose() {
985 return $this->data_array['register_purpose'];
989 * getAdmins - Get array of Admin user objects.
991 * @return array Array of User objects.
993 function &getAdmins() {
994 $roles = RBACEngine::getInstance()->getRolesByAllowedAction ('project_admin', $this->getID());
998 foreach ($roles as $role) {
999 if (! ($role instanceof RoleExplicit)) {
1002 if ($role->getHomeProject() == NULL
1003 || $role->getHomeProject()->getID() != $this->getID()) {
1007 foreach ($role->getUsers() as $u) {
1008 $user_ids[] = $u->getID();
1011 $active_ids = array();
1012 $ids = array_unique ($user_ids);
1013 foreach ($ids as $id) {
1014 $u = user_get_object ($id);
1015 if ($u->isActive()) {
1023 Common Group preferences for tools
1027 * enableAnonSCM - whether or not this group has opted to enable Anonymous SCM.
1029 * @return boolean enable_scm.
1031 function enableAnonSCM() {
1032 $r = RoleAnonymous::getInstance();
1033 return $r->hasPermission('scm', $this->getID(), 'read');
1036 function SetUsesAnonSCM($booleanparam) {
1038 $booleanparam = $booleanparam ? 1 : 0;
1039 $r = RoleAnonymous::getInstance();
1040 $r->setSetting('scm', $this->getID(), $booleanparam);
1045 * enablePserver - whether or not this group has opted to enable Pserver.
1047 * @return bool enable_pserver.
1049 function enablePserver() {
1050 if ($this->usesSCM()) {
1051 return $this->data_array['enable_pserver'];
1057 function SetUsesPserver($booleanparam) {
1059 $booleanparam = $booleanparam ? 1 : 0;
1060 $res = db_query_params('UPDATE groups SET enable_pserver=$1 WHERE group_id=$2',
1061 array($booleanparam, $this->getID()));
1063 $this->data_array['enable_pserver'] = $booleanparam;
1073 * usesSCM - whether or not this group has opted to use SCM.
1075 * @return bool uses_scm.
1077 function usesSCM() {
1078 if (forge_get_config('use_scm')) {
1079 return $this->data_array['use_scm'];
1086 * setUseSCM - Set the SCM usage
1088 * @param bool $booleanparam enabled/disabled
1091 function setUseSCM($booleanparam) {
1093 $booleanparam = $booleanparam ? 1 : 0;
1094 $res = db_query_params('UPDATE groups SET use_scm=$1 WHERE group_id=$2',
1095 array($booleanparam, $this->getID()));
1097 $this->data_array['use_scm'] = $booleanparam;
1107 * usesMail - whether or not this group has opted to use mailing lists.
1109 * @return bool uses_mail.
1111 function usesMail() {
1112 if (forge_get_config('use_mail')) {
1113 return $this->data_array['use_mail'];
1118 $hook_params = array();
1119 $hook_params['group'] = $this;
1120 $hook_params['group_id'] = $this->getID();
1121 $hook_params['group_homepage'] = $this->getHomePage();
1122 $hook_params['group_name'] = $this->getPublicName();
1123 $hook_params['group_description'] = $this->getDescription();
1124 plugin_hook ("group_update", $hook_params);
1128 * setUseMail - Set the mailing-list usage
1130 * @param bool $booleanparam enabled/disabled
1133 function setUseMail($booleanparam) {
1135 $booleanparam = $booleanparam ? 1 : 0;
1136 $res = db_query_params('UPDATE groups SET use_mail=$1 WHERE group_id=$2',
1137 array($booleanparam, $this->getID()));
1139 $this->data_array['use_mail'] = $booleanparam;
1149 * usesNews - whether or not this group has opted to use news.
1151 * @return bool uses_news.
1153 function usesNews() {
1154 if (forge_get_config('use_news')) {
1155 return $this->data_array['use_news'];
1161 function setUseNews($booleanparam) {
1163 $booleanparam = $booleanparam ? 1 : 0;
1164 $res = db_query_params('UPDATE groups SET use_news=$1 WHERE group_id=$2',
1165 array($booleanparam, $this->getID()));
1167 $this->data_array['use_news'] = $booleanparam;
1177 * usesActivity - whether or not this group has opted to display Project Activities.
1179 * @return bool uses_activities.
1181 function usesActivity() {
1182 if (forge_get_config('use_activity')) {
1183 return $this->data_array['use_activity'];
1189 function setUseActivity($booleanparam) {
1191 $booleanparam = $booleanparam ? 1 : 0;
1192 $res = db_query_params('UPDATE groups SET use_activity=$1 WHERE group_id=$2',
1193 array($booleanparam, $this->getID()));
1195 $this->data_array['use_activity'] = $booleanparam;
1205 * usesForum - whether or not this group has opted to use discussion forums.
1207 * @return bool uses_forum.
1209 function usesForum() {
1210 if (forge_get_config('use_forum')) {
1211 return $this->data_array['use_forum'];
1218 * setUseForum - Set the forum usage
1220 * @param bool $booleanparam enabled/disabled
1223 function setUseForum($booleanparam) {
1225 $booleanparam = $booleanparam ? 1 : 0;
1226 $res = db_query_params('UPDATE groups SET use_forum=$1 WHERE group_id=$2',
1227 array($booleanparam, $this->getID()));
1229 $this->data_array['use_forum'] = $booleanparam;
1239 * usesStats - whether or not this group has opted to use stats.
1241 * @return bool uses_stats.
1243 function usesStats() {
1244 return $this->data_array['use_stats'];
1248 * usesFRS - whether or not this group has opted to use file release system.
1250 * @return bool uses_frs.
1252 function usesFRS() {
1253 if (forge_get_config('use_frs')) {
1254 return $this->data_array['use_frs'];
1261 * setUseFRS - Set the FRS usage
1263 * @param bool $booleanparam enabled/disabled
1266 function setUseFRS($booleanparam) {
1268 $booleanparam = $booleanparam ? 1 : 0;
1269 $res = db_query_params('UPDATE groups SET use_frs=$1 WHERE group_id=$2',
1270 array($booleanparam, $this->getID()));
1272 $this->data_array['use_frs']=$booleanparam;
1282 * usesTracker - whether or not this group has opted to use tracker.
1284 * @return bool uses_tracker.
1286 function usesTracker() {
1287 if (forge_get_config('use_tracker')) {
1288 return $this->data_array['use_tracker'];
1295 * setUseTracker - Set the tracker usage
1297 * @param bool $booleanparam enabled/disabled
1300 function setUseTracker($booleanparam) {
1302 $booleanparam = $booleanparam ? 1 : 0;
1303 $res = db_query_params ('UPDATE groups SET use_tracker=$1 WHERE group_id=$2',
1304 array($booleanparam, $this->getID()));
1306 $this->data_array['use_tracker']=$booleanparam;
1316 * useCreateOnline - whether or not this group has opted to use create online documents option.
1318 * @return bool use_docman_create_online.
1320 function useCreateOnline() {
1321 if (forge_get_config('use_docman')) {
1322 return $this->data_array['use_docman_create_online'];
1329 * usesDocman - whether or not this group has opted to use docman.
1331 * @return bool use_docman.
1333 function usesDocman() {
1334 if (forge_get_config('use_docman')) {
1335 return $this->data_array['use_docman'];
1342 * setUseDocman - Set the docman usage
1344 * @param bool $booleanparam enabled/disabled
1347 function setUseDocman($booleanparam) {
1349 $booleanparam = $booleanparam ? 1 : 0;
1350 $res = db_query_params('UPDATE groups SET use_docman = $1 WHERE group_id = $2',
1351 array($booleanparam, $this->getID()));
1353 // check if / doc_group exists, if not create it
1354 $trashdir = db_query_params('select groupname from doc_groups where groupname = $1 and group_id = $2',
1355 array('.trash', $this->getID()));
1356 if ($trashdir && db_numrows($trashdir) == 0) {
1357 $resinsert = db_query_params('insert into doc_groups (groupname, group_id, stateid) values ($1, $2, $3)',
1358 array('.trash', $this->getID(), '2'));
1364 $this->data_array['use_docman'] = $booleanparam;
1374 * useDocmanSearch - whether or not this group has opted to use docman search engine.
1376 * @return bool use_docman_search.
1378 function useDocmanSearch() {
1379 if (forge_get_config('use_docman')) {
1380 return $this->data_array['use_docman_search'];
1387 * useWebdav - whether or not this group has opted to use webdav interface.
1389 * @return bool use_docman_search.
1391 function useWebdav() {
1392 if (forge_get_config('use_webdav')) {
1393 return $this->data_array['use_webdav'];
1400 * usesFTP - whether or not this group has opted to use FTP.
1402 * @return bool uses_ftp.
1404 function usesFTP() {
1405 if (forge_get_config('use_ftp')) {
1406 return $this->data_array['use_ftp'];
1413 * usesSurvey - whether or not this group has opted to use surveys.
1415 * @return bool uses_survey.
1417 function usesSurvey() {
1418 if (forge_get_config('use_survey')) {
1419 return $this->data_array['use_survey'];
1426 * usesPM - whether or not this group has opted to Project Manager.
1428 * @return bool uses_projman.
1431 if (forge_get_config('use_pm')) {
1432 return $this->data_array['use_pm'];
1439 * setUsePM - Set the PM usage
1441 * @param bool $booleanparam enabled/disabled
1444 function setUsePM($booleanparam) {
1446 $booleanparam = $booleanparam ? 1 : 0;
1447 $res = db_query_params('UPDATE groups SET use_pm=$1 WHERE group_id=$2',
1448 array($booleanparam, $this->getID()));
1450 $this->data_array['use_pm']=$booleanparam;
1460 * getPlugins - get a list of all available group plugins
1462 * @return array array containing plugin_id => plugin_name
1464 function getPlugins() {
1465 if (!isset($this->plugins_data)) {
1466 $this->plugins_data = array();
1467 $res = db_query_params('SELECT group_plugin.plugin_id, plugins.plugin_name
1468 FROM group_plugin, plugins
1469 WHERE group_plugin.group_id=$1
1470 AND group_plugin.plugin_id=plugins.plugin_id', array($this->getID()));
1471 $rows = db_numrows($res);
1473 for ($i=0; $i<$rows; $i++) {
1474 $plugin_id = db_result($res, $i, 'plugin_id');
1475 $this->plugins_data[$plugin_id] = db_result($res, $i, 'plugin_name');
1478 return $this->plugins_data;
1482 * usesPlugin - returns true if the group uses a particular plugin
1484 * @param string $pluginname name of the plugin
1485 * @return bool whether plugin is being used or not
1487 function usesPlugin($pluginname) {
1488 $plugins_data = $this->getPlugins();
1489 foreach ($plugins_data as $p_id => $p_name) {
1490 if ($p_name == $pluginname) {
1498 * added for Codendi compatibility
1499 * usesServices - returns true if the group uses a particular plugin or feature
1501 * @param string $feature name of the plugin
1502 * @return bool whether plugin is being used or not
1504 function usesService($feature) {
1505 $plugins_data = $this->getPlugins();
1506 $pm = plugin_manager_get_object();
1507 foreach ($plugins_data as $p_id => $p_name) {
1508 if ($p_name == $feature) {
1511 if ($pm->getPluginByName($p_name)->provide($feature)) {
1519 * setPluginUse - enables/disables plugins for the group
1521 * @param string $pluginname name of the plugin
1522 * @param bool $val the new state
1523 * @return string database result
1525 function setPluginUse($pluginname, $val=true) {
1526 if ($val == $this->usesPlugin($pluginname)) {
1527 // State is already good, returning
1530 $res = db_query_params('SELECT plugin_id FROM plugins WHERE plugin_name=$1',
1531 array($pluginname));
1532 $rows = db_numrows($res);
1534 // Error: no plugin by that name
1537 $plugin_id = db_result($res,0,'plugin_id');
1539 unset($this->plugins_data);
1541 $res = db_query_params('INSERT INTO group_plugin (group_id, plugin_id) VALUES ($1, $2)',
1542 array($this->getID(),
1545 $res = db_query_params('DELETE FROM group_plugin WHERE group_id=$1 AND plugin_id=$2',
1546 array($this->getID(),
1549 $this->normalizeAllRoles();
1550 $hook_params = array();
1551 $hook_params['group_id'] = $this->getID();
1552 $hook_params['val'] = $val;
1553 plugin_hook("group_plugin_use", $hook_params);
1558 * getDocEmailAddress - get email address(es) to send doc notifications to.
1560 * @return string email address.
1562 function getDocEmailAddress() {
1563 return $this->data_array['new_doc_address'];
1566 function setDocEmailAddress($email) {
1567 $invalid_mails = validate_emails($email);
1568 if (count($invalid_mails) > 0) {
1569 $this->setError(sprintf(ngettext('New Doc Address Appeared Invalid: %s', 'New Doc Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
1573 $res = db_query_params('UPDATE groups SET new_doc_address = $1 WHERE group_id = $2',
1574 array($email, $this->getID()));
1577 $this->setError(_('Error')._(': ')._('Cannot Update Group new_doc_address')._(': ').db_error());
1581 $this->data_array['new_doc_address'] = $email;
1588 * docEmailAll - whether or not this group has opted to use receive notices on all doc updates.
1590 * @return bool email_on_all_doc_updates.
1592 function docEmailAll() {
1593 return $this->data_array['send_all_docs'];
1596 function setDocEmailAll($status) {
1598 $res = db_query_params('UPDATE groups SET send_all_docs = $1 WHERE group_id = $2',
1599 array($status, $this->getID()));
1602 $this->setError(_('Error')._(': ')._('Cannot Update Group send_all_docs')._(': ').db_error());
1606 $this->data_array['send_all_docs'] = $status;
1613 * getFRSEmailAddress - get email address(es) to send FRS notifications to.
1615 * @return string email address.
1617 function getFRSEmailAddress() {
1618 return $this->data_array['new_frs_address'];
1621 function setFRSEmailAddress($email) {
1622 $invalid_mails = validate_emails($email);
1623 if (count($invalid_mails) > 0) {
1624 $this->setError(sprintf(ngettext('New FRS Address Appeared Invalid: %s', 'New FRS Addresses Appeared Invalid: %s', count($invalid_mails)),implode(',',$invalid_mails)));
1628 $res = db_query_params('UPDATE groups SET new_frs_address = $1 WHERE group_id = $2',
1629 array($email, $this->getID()));
1632 $this->setError(_('Error')._(': ')._('Cannot Update Group new_frs_address')._(': ').db_error());
1636 $this->data_array['new_frs_address'] = $email;
1643 * frsEmailAll - whether or not this group has opted to use receive notices on all frs updates.
1645 * @return bool email_on_all_frs_updates.
1647 function frsEmailAll() {
1648 return $this->data_array['send_all_frs'];
1651 function setFRSEmailAll($status) {
1653 $res = db_query_params('UPDATE groups SET send_all_frs = $1 WHERE group_id = $2',
1654 array($status, $this->getID()));
1657 $this->setError(_('Error')._(': ')._('Cannot Update Group send_frs_docs')._(': ').db_error());
1661 $this->data_array['send_frs_docs'] = $status;
1668 * getHomePage - The URL for this project's home page.
1670 * @return string homepage URL.
1672 function getHomePage() {
1673 if (!preg_match("/^[a-zA-Z][a-zA-Z0-9+.-]*:/",
1674 $this->data_array['homepage'])) {
1675 $this->data_array['homepage'] = 'http://' .
1676 $this->data_array['homepage'];
1678 return $this->data_array['homepage'];
1682 * setHomepage - the hostname of the website url where this project is located.
1684 * @param string $homepage The name of the new HOMEPAGE
1687 function setHomepage($homepage) {
1689 if ($homepage == $this->data_array['homepage']) {
1694 $res = db_query_params('UPDATE groups SET homepage=$1 WHERE group_id=$2', array($homepage, $this->getID()));
1696 $this->addHistory('homepage', $this->data_array['homepage']);
1697 $this->data_array['homepage'] = $homepage;
1702 $this->setError(_('Could not insert homepage to database'));
1706 $this->setError(_('Homepage cannot be empty'));
1712 * getTags - Tags of this project.
1714 * @return string List of tags. Comma separated
1716 function getTags() {
1717 $sql = 'SELECT name FROM project_tags WHERE group_id = $1';
1718 $res = db_query_params($sql, array($this->getID()));
1719 return join(', ', util_result_column_to_array($res));
1723 * setTags - Set tags of this project.
1725 * @param string $tags
1726 * @return string database result.
1728 function setTags($tags) {
1730 $sql = 'DELETE FROM project_tags WHERE group_id=$1';
1731 $res = db_query_params($sql, array($this->getID()));
1733 $this->setError(_('Deleting old tags')._(': ').db_error());
1737 $inserted = array();
1738 $tags_array = preg_split('/[;,]/', $tags);
1739 foreach ($tags_array as $tag) {
1740 $tag = preg_replace('/[\t\r\n]/', ' ', $tag);
1741 // Allowed caracteres: [A-Z][a-z][0-9] -_&'#+.
1742 if (preg_match('/[^[:alnum:]| |\-|_|\&|\'|#|\+|\.]/', $tag)) {
1743 $this->setError(_('Bad tag name, you only can use the following characters: [A-Z][a-z][0-9]-_&\'#+. and space'));
1748 if ($tag == '' || array_search($tag, $inserted) !== false) {
1751 $sql = 'INSERT INTO project_tags (group_id,name) VALUES ($1, $2)';
1752 $res = db_query_params($sql, array($this->getID(), $tag));
1754 $this->setError(_('Setting tags')._(': ').db_error());
1765 * getPermission - Return a Permission for this Group
1767 * @return object The Permission.
1769 function &getPermission() {
1770 return permission_get_object($this);
1773 function delete($sure, $really_sure, $really_really_sure) {
1774 if (!$sure || !$really_sure || !$really_really_sure) {
1775 $this->setMissingParamsError(_('Please tick all checkboxes.'));
1778 if ($this->getID() == forge_get_config('news_group') ||
1779 $this->getID() == 1 ||
1780 $this->getID() == forge_get_config('stats_group') ||
1781 $this->getID() == forge_get_config('peer_rating_group')) {
1782 $this->setError(_('Cannot Delete System Group'));
1785 $perm = $this->getPermission();
1786 if (!$perm || !is_object($perm)) {
1787 $this->setPermissionDeniedError();
1789 } elseif ($perm->isError() || !$perm->isSuperUser()) {
1790 $this->setPermissionDeniedError();
1796 // Remove all the members
1798 $members = $this->getMembers(false);
1799 foreach ($members as $i) {
1800 if(!$this->removeUser($i->getID())) {
1801 $this->setError(_('Could not properly remove member')._(': ').$i->getID());
1806 // unlink roles from this project
1807 foreach ($this->getRoles() as $r) {
1808 if ($r->getHomeProject() == NULL
1809 || $r->getHomeProject()->getID() != $this->getID()) {
1810 $r->unlinkProject($this);
1817 $atf = new ArtifactTypeFactory($this, true);
1818 $at_arr = $atf->getArtifactTypes();
1819 foreach ($at_arr as $i) {
1820 if (!is_object($i)) {
1823 if (!$i->delete(1,1)) {
1824 $this->setError(_('Could not properly delete the tracker')._(': ').$i->getErrorMessage());
1831 $rmf = new RoadmapFactory($this);
1832 $rm_arr = $rmf->getRoadmaps();
1833 foreach ($rm_arr as $i) {
1834 if (!is_object($i)) {
1837 if (!$i->delete()) {
1838 $this->setError(_('Could not properly delete the roadmap')._(': ').$i->getErrorMessage());
1846 $ff = new ForumFactory($this, true);
1847 $f_arr = $ff->getForums();
1848 foreach ($f_arr as $i) {
1849 if (!is_object($i)) {
1852 if(!$i->delete(1,1)) {
1853 $this->setError(_('Could not properly delete the forum')._(': ').$i->getErrorMessage());
1859 // Delete Subprojects
1861 $pgf = new ProjectGroupFactory($this, true);
1862 $pg_arr = $pgf->getProjectGroups();
1863 foreach ($pg_arr as $i) {
1864 if (!is_object($i)) {
1867 if (!$i->delete(1,1)) {
1868 $this->setError(_('Could not properly delete the ProjectGroup')._(': ').$i->getErrorMessage());
1874 // Delete FRS Packages
1876 $res = db_query_params('SELECT * FROM frs_package WHERE group_id=$1',
1877 array($this->getID()));
1879 $this->setError(_('Error FRS Packages')._(': ').db_error());
1884 while ($arr = db_fetch_array($res)) {
1885 $frsp=new FRSPackage($this, $arr['package_id'], $arr);
1886 if (!$frsp->delete(1, 1)) {
1887 $this->setError(_('Could not properly delete the FRSPackage')._(': ').$frsp->getErrorMessage());
1894 $news_group=group_get_object(forge_get_config('news_group'));
1895 $res = db_query_params('SELECT forum_id FROM news_bytes WHERE group_id=$1',
1896 array($this->getID()));
1898 $this->setError(_('Error Deleting News')._(': ').db_error());
1903 for ($i=0; $i<db_numrows($res); $i++) {
1904 $Forum = new Forum($news_group,db_result($res,$i,'forum_id'));
1905 if (!$Forum->delete(1,1)) {
1906 $this->setError(_('Could not delete News Forum')._(': ').$Forum->getID());
1911 // Delete news forums in group itself
1912 for ($i = 0; $i < db_numrows($res); $i++) {
1913 $Forum = new Forum($this, db_result($res, $i, 'forum_id'));
1914 if (!$Forum->delete(1, 1)) {
1915 $this->setError(_('Could not delete News Forum')._(': ').$Forum->getID());
1920 $res = db_query_params('DELETE FROM news_bytes WHERE group_id=$1',
1921 array($this->getID()));
1923 $this->setError(_('Error Deleting News')._(': ').db_error());
1931 $res = db_query_params('DELETE FROM doc_data WHERE group_id=$1',
1932 array($this->getID()));
1934 $this->setError(_('Error Deleting Documents')._(': ').db_error());
1939 $res = db_query_params('DELETE FROM doc_groups WHERE group_id=$1',
1940 array($this->getID()));
1942 $this->setError(_('Error Deleting Document Groups')._(': ').db_error());
1950 $res=db_query_params('DELETE FROM project_tags WHERE group_id=$1', array($this->getID()));
1952 $this->setError(_('Error Deleting Tags')._(': ').db_error());
1958 // Delete group history
1960 $res = db_query_params('DELETE FROM group_history WHERE group_id=$1',
1961 array($this->getID()));
1963 $this->setError(_('Error Deleting Project History')._(': ').db_error());
1969 // Delete group plugins
1971 $res = db_query_params('DELETE FROM group_plugin WHERE group_id=$1',
1972 array($this->getID()));
1974 $this->setError(_('Error Deleting Project Plugins')._(': ').db_error());
1980 // Delete group cvs stats
1982 $res = db_query_params ('DELETE FROM stats_cvs_group WHERE group_id=$1',
1983 array($this->getID()));
1985 $this->setError(_('Error Deleting SCM Statistics')._(': ').db_error());
1993 $sf = new SurveyFactory($this, true);
1994 $s_arr =& $sf->getSurveys();
1995 foreach ($s_arr as $i) {
1996 if (!is_object($i)) {
1999 if (!$i->delete()) {
2000 $this->setError(_('Could not properly delete the survey'));
2005 // Delete SurveyQuestions
2007 $sqf = new SurveyQuestionFactory($this);
2008 $sq_arr = $sqf->getSurveyQuestions();
2009 if (is_array($sq_arr)) {
2010 foreach ($sq_arr as $i) {
2011 if (!is_object($i)) {
2014 if (!$i->delete()) {
2015 $this->setError(_('Could not properly delete the survey questions'));
2023 // Delete Mailing List Factory
2025 $mlf = new MailingListFactory($this, true);
2026 $ml_arr = $mlf->getMailingLists();
2027 foreach ($ml_arr as $i) {
2028 if (!is_object($i)) {
2031 if (!$i->delete(1,1)) {
2032 $this->setError(_('Could not properly delete the mailing list'));
2040 $res = db_query_params('DELETE FROM trove_group_link WHERE group_id=$1',
2041 array($this->getID()));
2043 $this->setError(_('Error Deleting Trove')._(': ').db_error());
2048 $res = db_query_params('DELETE FROM trove_agg WHERE group_id=$1',
2049 array($this->getID()));
2051 $this->setError(_('Error Deleting Trove')._(': ').db_error());
2059 $res = db_query_params('DELETE FROM project_sums_agg WHERE group_id=$1',
2060 array($this->getID()));
2062 $this->setError(_('Error Deleting Counters')._(': ').db_error());
2067 $res = db_query_params('INSERT INTO deleted_groups (unix_group_name, delete_date, isdeleted) VALUES ($1, $2, $3)',
2068 array($this->getUnixName(),
2072 $this->setError(_('Error Deleting Project')._(': ').db_error());
2077 // Remove users & delete roles from this project
2078 $members = $this->getMembers();
2079 foreach ($members as $userObject) {
2080 $this->removeUser($userObject->getID());
2082 $localRolesId = $this->getRolesId(false);
2083 foreach ($localRolesId as $localRoleId) {
2084 $roleObject = new Role($this, $localRoleId);
2085 $roleObject->delete();
2087 // Delete entry in groups.
2088 $res = db_query_params('DELETE FROM groups WHERE group_id=$1',
2089 array($this->getID()));
2091 $this->setError(_('Error Deleting Project')._(': ').db_error());
2098 $hook_params = array();
2099 $hook_params['group'] = $this;
2100 $hook_params['group_id'] = $this->getID();
2101 plugin_hook("group_delete", $hook_params);
2103 if (forge_get_config('upload_dir') != '' && $this->getUnixName()) {
2104 exec('/bin/rm -rf '.forge_get_config('upload_dir').'/'.$this->getUnixName().'/');
2106 if (forge_get_config('ftp_upload_dir') != '' && $this->getUnixName()) {
2107 exec('/bin/rm -rf '.forge_get_config('ftp_upload_dir').'/'.$this->getUnixName().'/');
2112 db_query_params('DELETE FROM rep_group_act_monthly WHERE group_id=$1',
2113 array($this->getID()));
2114 //echo 'rep_group_act_monthly'.db_error();
2115 db_query_params('DELETE FROM rep_group_act_weekly WHERE group_id=$1',
2116 array($this->getID()));
2117 //echo 'rep_group_act_weekly'.db_error();
2118 db_query_params('DELETE FROM rep_group_act_daily WHERE group_id=$1',
2119 array($this->getID()));
2120 //echo 'rep_group_act_daily'.db_error();
2121 unset($this->data_array);
2126 Basic functions to add/remove users to/from a group
2127 and update their permissions
2131 * addUser - controls adding a user to a group.
2133 * @param string $user_identifier Unix name of the user to add OR integer user_id.
2134 * @param int $role_id The role_id this user should have.
2135 * @return bool success.
2138 function addUser($user_identifier, $role_id) {
2141 Admins can add users to groups
2144 if (!forge_check_perm ('project_admin', $this->getID())) {
2145 $this->setPermissionDeniedError();
2151 get user id for this user's unix_name
2153 if (is_int ($user_identifier)) { // user_id or user_name
2154 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_id=$1', array($user_identifier));
2156 $res_newuser = db_query_params ('SELECT * FROM users WHERE user_name=$1', array($user_identifier));
2158 if (db_numrows($res_newuser) > 0) {
2160 // make sure user is active
2162 if (db_result($res_newuser,0,'status') != 'A') {
2163 $this->setError(_('User is not active. Only active users can be added.'));
2169 // user was found - set new user_id var
2171 $user_id = db_result($res_newuser,0,'user_id');
2173 $role = new Role($this, $role_id);
2174 if (!$role || !is_object($role)) {
2175 $this->setError(_('Error Getting Role Object'));
2178 } elseif ($role->isError()) {
2179 $this->setError('addUser::roleget::'.$role->getErrorMessage());
2184 $role->addUser(user_get_object($user_id));
2185 if (!$SYS->sysCheckCreateGroup($this->getID())){
2186 $this->setError($SYS->getErrorMessage());
2190 if (!$SYS->sysCheckCreateUser($user_id)) {
2191 $this->setError($SYS->getErrorMessage());
2195 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
2196 $this->setError($SYS->getErrorMessage());
2202 // user doesn't exist
2204 $this->setError(_('That user does not exist.'));
2209 $hook_params['group'] = $this;
2210 $hook_params['group_id'] = $this->getID();
2211 $hook_params['user'] = user_get_object($user_id);
2212 $hook_params['user_id'] = $user_id;
2213 plugin_hook ("group_adduser", $hook_params);
2218 $this->addHistory(_('Added User'), $user_identifier);
2224 $add_u = user_get_object($user_id);
2226 if (is_array($this->membersArr)) {
2227 foreach ($this->membersArr as $u) {
2228 if ($u->getID() == $add_u->getID()) {
2234 $this->membersArr[] = $add_u;
2242 * removeUser - controls removing a user from a group.
2244 * Users can remove themselves.
2246 * @param int $user_id The ID of the user to remove.
2247 * @return bool success.
2249 function removeUser($user_id) {
2252 if ($user_id != user_getid()
2253 && !forge_check_perm('project_admin', $this->getID())) {
2254 $this->setPermissionDeniedError();
2260 $user = user_get_object($user_id);
2261 $roles = RBACEngine::getInstance()->getAvailableRolesForUser($user);
2262 $found_roles = array();
2263 foreach ($roles as $role) {
2264 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2265 $found_roles[] = $role;
2268 if (count($found_roles) == 0) {
2269 $this->setError(_('Error')._(': ')._('User not removed')._(': ').$user_id);
2273 foreach ($found_roles as $found_role) {
2274 $found_role->removeUser($user);
2275 if (!$SYS->sysGroupCheckUser($this->getID(), $user_id)) {
2276 $this->setError($SYS->getErrorMessage());
2283 // reassign open artifacts to id=100
2285 $res = db_query_params('UPDATE artifact SET assigned_to=100
2286 WHERE group_artifact_id
2287 IN (SELECT group_artifact_id
2288 FROM artifact_group_list
2289 WHERE group_id=$1 AND status_id=1 AND assigned_to=$2)',
2290 array($this->getID(),
2293 $this->setError(_('Error')._(': ')._('artifact')._(': ').db_error());
2299 // reassign open tasks to id=100
2300 // first have to purge any assignments that would cause
2301 // conflict with existing assignment to 100
2303 $res = db_query_params('DELETE FROM project_assigned_to
2304 WHERE project_task_id IN (SELECT pt.project_task_id
2305 FROM project_task pt, project_group_list pgl, project_assigned_to pat
2306 WHERE pt.group_project_id = pgl.group_project_id
2307 AND pat.project_task_id=pt.project_task_id
2308 AND pt.status_id=1 AND pgl.group_id=$1
2309 AND pat.assigned_to_id=$2)
2310 AND assigned_to_id=100',
2311 array($this->getID(),
2314 $this->setError(_('Error')._(': ').sprintf(_('project_assigned_to %d: %s'), 1, db_error()));
2318 $res = db_query_params('UPDATE project_assigned_to SET assigned_to_id=100
2319 WHERE project_task_id IN (SELECT pt.project_task_id
2320 FROM project_task pt, project_group_list pgl
2321 WHERE pt.group_project_id = pgl.group_project_id
2322 AND pt.status_id=1 AND pgl.group_id=$1)
2323 AND assigned_to_id=$2',
2324 array($this->getID(),
2327 $this->setError(_('Error')._(': ').sprintf(_('project_assigned_to %d: %s'), 2, db_error()));
2333 // Remove user from system
2335 if (!$SYS->sysGroupRemoveUser($this->getID(), $user_id)) {
2336 $this->setError($SYS->getErrorMessage());
2341 $hook_params['group'] = $this;
2342 $hook_params['group_id'] = $this->getID();
2343 $hook_params['user'] = user_get_object($user_id);
2344 $hook_params['user_id'] = $user_id;
2345 plugin_hook("group_removeuser", $hook_params);
2348 $this->addHistory(_('Removed User'), $user_id);
2355 $del_u = user_get_object($user_id);
2356 foreach ($this->membersArr as $k => $u) {
2357 if ($u->getID() == $del_u->getID()) {
2358 unset($this->membersArr[$k]);
2367 * updateUser - controls updating a user's role in this group.
2369 * @param int $user_id The ID of the user.
2370 * @param int $role_id The role_id to set this user to.
2371 * @return bool success.
2373 function updateUser($user_id, $role_id) {
2375 if (!forge_check_perm ('project_admin', $this->getID())) {
2376 $this->setPermissionDeniedError();
2380 $newrole = RBACEngine::getInstance()->getRoleById ($role_id);
2381 if (!$newrole || !is_object($newrole)) {
2382 $this->setError(_('Could Not Get Role'));
2384 } elseif ($newrole->isError()) {
2385 $this->setError(_('Role')._(': ').$role->getErrorMessage());
2387 } elseif ($newrole->getHomeProject() == NULL
2388 || $newrole->getHomeProject()->getID() != $this->getID()) {
2389 $this->setError(_('Wrong destination role'));
2392 $user = user_get_object ($user_id);
2393 $roles = RBACEngine::getInstance()->getAvailableRolesForUser ($user);
2395 foreach ($roles as $role) {
2396 if ($role->getHomeProject() && $role->getHomeProject()->getID() == $this->getID()) {
2397 $found_role = $role;
2401 if ($found_role == NULL) {
2402 $this->setError(_('Error')._(': ')._('User not removed')._(': ').$user_id);
2406 $found_role->removeUser ($user);
2407 $newrole->addUser ($user);
2409 $this->addHistory(_('Updated User'), $user_id);
2414 * addHistory - Makes an audit trail entry for this project.
2416 * @param string $field_name The name of the field.
2417 * @param string $old_value The Old Value for this $field_name.
2418 * @return resource database result handle.
2421 function addHistory($field_name, $old_value) {
2422 if ($old_value == NULL) {
2426 return db_query_params('INSERT INTO group_history(group_id,field_name,old_value,mod_by,adddate)
2427 VALUES ($1,$2,$3,$4,$5)',
2428 array($this->getID(),
2436 * activateUsers - Make sure that group members have unix accounts.
2438 * Setup unix accounts for group members. Can be called even
2439 * if members are already active.
2443 function activateUsers() {
2445 Activate member(s) of the project
2450 $members = $this->getUsers(true);
2452 foreach ($members as $member) {
2453 $user_id = $member->getID();
2455 if (!$SYS->sysCheckCreateGroup($this->getID())){
2456 $this->setError($SYS->getErrorMessage());
2460 if (!$SYS->sysCheckCreateUser($user_id)) {
2461 $this->setError($SYS->getErrorMessage());
2465 if (!$SYS->sysGroupCheckUser($this->getID(),$user_id)) {
2466 $this->setError($SYS->getErrorMessage());
2476 * getMembers - returns array of User objects for this project
2478 * @param boolean $onlyactive Only users with state active, or all users of group
2479 * @return array of User objects for this group.
2481 function getMembers($onlyactive = true) {
2482 return $this->getUsers(true, $onlyactive);
2486 * replaceTemplateStrings - fill-in some blanks with project name
2488 * @param string $string Template string
2489 * @return string String after replacements
2491 function replaceTemplateStrings($string) {
2492 $string = str_replace('UNIXNAME', $this->getUnixName(), $string);
2493 $string = str_replace('PUBLICNAME', $this->getPublicName(), $string);
2494 $string = str_replace('DESCRIPTION', $this->getDescription(), $string);
2499 * approve - Approve pending project.
2501 * @param object $user The User object who is doing the updating.
2505 function approve(&$user) {
2506 global $gfcommon,$gfwww;
2507 require_once $gfcommon.'widget/WidgetLayoutManager.class.php';
2509 if ($this->getStatus()=='A') {
2510 $this->setError(_('Group already active'));
2516 // Step 1: Activate group and create LDAP entries
2517 if (!$this->setStatus($user, 'A')) {
2524 // Switch to system language for item creation
2525 setup_gettext_from_sys_lang();
2527 // Create default roles
2528 $idadmin_group = NULL;
2529 foreach (get_group_join_requests ($this) as $gjr) {
2530 $idadmin_group = $gjr->getUserID();
2533 if ($idadmin_group == NULL) {
2534 $idadmin_group = $user->getID();
2537 $template = $this->getTemplateProject();
2538 $id_mappings = array();
2539 $seen_admin_role = false;
2541 // Copy roles from template project
2542 foreach($template->getRoles() as $oldrole) {
2543 if ($oldrole->getHomeProject() != NULL) {
2544 $role = new Role($this);
2546 // Need to use a different role name so that the permissions aren't set from the hardcoded defaults
2547 $role->create('TEMPORARY ROLE NAME', $data, true);
2548 $role->setName($oldrole->getName());
2549 if ($oldrole->getSetting ('project_admin', $template->getID())) {
2550 $seen_admin_role = true;
2554 $role->linkProject($this);
2556 $id_mappings['role'][$oldrole->getID()] = $role->getID();
2557 // Reuse the project_admin permission
2558 $role->setSetting ('project_admin', $this->getID(), $oldrole->getSetting ('project_admin', $template->getID()));
2562 if (!$seen_admin_role) {
2563 $role = new Role($this);
2564 $adminperms = array('project_admin' => array ($this->getID() => 1));
2565 $role_id = $role->create ('Admin', $adminperms, true);
2568 $roles = $this->getRoles();
2569 foreach ($roles as $r) {
2570 if ($r->getHomeProject() == NULL) {
2573 if ($r->getSetting ('project_admin', $this->getID())) {
2574 $r->addUser(user_get_object ($idadmin_group));
2578 // Temporarily switch to the submitter's identity
2579 $saved_session = session_get_user();
2580 session_set_internal($idadmin_group);
2583 if (forge_get_config('use_tracker')) {
2584 $this->setUseTracker ($template->usesTracker());
2585 if ($template->usesTracker()) {
2586 $oldatf = new ArtifactTypeFactory($template);
2587 foreach ($oldatf->getArtifactTypes() as $o) {
2588 $t = new ArtifactType ($this);
2589 $t->create ($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->emailAll(),$o->getEmailAddress(),$o->getDuePeriod()/86400,0,$o->getSubmitInstructions(),$o->getBrowseInstructions());
2590 $id_mappings['tracker'][$o->getID()] = $t->getID();
2595 if (forge_get_config('use_pm')) {
2596 $this->setUsePM ($template->usesPM());
2597 if ($template->usesPM()) {
2598 $oldpgf = new ProjectGroupFactory($template);
2599 foreach ($oldpgf->getProjectGroups() as $o) {
2600 $pg = new ProjectGroup($this);
2601 $pg->create($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->getSendAllPostsTo());
2602 $id_mappings['pm'][$o->getID()] = $pg->getID();
2607 if (forge_get_config('use_forum')) {
2608 $this->setUseForum($template->usesForum());
2609 if ($template->usesForum()) {
2610 $oldff = new ForumFactory($template);
2611 foreach ($oldff->getForums() as $o) {
2612 $f = new Forum($this);
2613 $f->create($this->replaceTemplateStrings($o->getName()),$this->replaceTemplateStrings($o->getDescription()),$o->getSendAllPostsTo(),1);
2614 $id_mappings['forum'][$o->getID()] = $f->getID();
2619 if (forge_get_config('use_docman')) {
2620 $this->setUseDocman($template->usesDocman());
2621 if ($template->usesDocman()) {
2622 $olddgf = new DocumentGroupFactory($template);
2623 // First pass: create all docgroups
2624 $id_mappings['docman_docgroup'][0] = 0;
2625 foreach ($olddgf->getDocumentGroups(array(1, 5)) as $o) {
2626 $ndg = new DocumentGroup($this);
2627 // .trash is a reserved directory
2628 if ($o->getName() != '.trash') {
2629 $ndg->create($this->replaceTemplateStrings($o->getName()), 0, 1, null, true);
2630 $id_mappings['docman_docgroup'][$o->getID()] = $ndg->getID();
2633 // Second pass: restore hierarchy links & stateid
2634 foreach ($olddgf->getDocumentGroups(array(1, 5)) as $o) {
2635 $ndgf = new DocumentGroup($this);
2636 if ($o->getName() != '.trash') {
2637 $ndgf->fetchData($id_mappings['docman_docgroup'][$o->getID()]);
2638 $ndgf->update($ndgf->getName(), $id_mappings['docman_docgroup'][$o->getParentID()], 0, $o->getState());
2644 if (forge_get_config('use_frs')) {
2645 $this->setUseFRS ($template->usesFRS());
2646 if ($template->usesFRS()) {
2647 foreach (get_frs_packages($template) as $o) {
2648 $newp = new FRSPackage($this);
2649 $nname = $this->replaceTemplateStrings($o->getName());
2650 $newp->create($nname, $o->isPublic());
2651 $id_mappings['frs'][$o->getID()] = $newp->getID();
2652 foreach(get_frs_releases($o) as $or) {
2653 $newr = new FRSRelease($newp);
2654 $newr->create($this->replaceTemplateStrings($or->getName()), $this->replaceTemplateStrings($or->getNotes()), $this->replaceTemplateStrings($or->getChanges()), $or->getPreformatted());
2655 $id_mappings['frs_release'][$or->getID()] = $newr->getID();
2661 if (forge_get_config('use_mail')) {
2662 $this->setUseMail($template->usesMail());
2663 if ($template->usesMail()) {
2664 $oldmlf = new MailingListFactory($template);
2665 foreach ($oldmlf->getMailingLists() as $o) {
2666 $ml = new MailingList($this);
2667 $nname = preg_replace ('/^'.$template->getUnixName().'-/','',$o->getName());
2669 $ndescription = $this->replaceTemplateStrings($o->getDescription());
2670 $ml->create($nname, $ndescription, $o->isPublic());
2676 /* use SCM plugin from template group */
2677 $this->setUseSCM($template->usesSCM());
2679 foreach ($template->getPlugins() as
2680 $plugin_id => $plugin_name) {
2681 $this->setPluginUse($plugin_name);
2684 /* use SCM choice from registration page */
2685 foreach ($template->getPlugins() as $plugin_id => $plugin_name) {
2686 if (substr($plugin_name, 3) == 'scm' &&
2687 $plugin_name != 'scmhook') {
2688 /* skip copying scm plugins */
2691 /* enable other plugins though */
2692 $this->setPluginUse($plugin_name);
2696 foreach ($template->getRoles() as $oldrole) {
2697 $newrole = RBACEngine::getInstance()->getRoleById($id_mappings['role'][$oldrole->getID()]);
2698 if ($oldrole->getHomeProject() != NULL
2699 && $oldrole->getHomeProject()->getID() == $template->getID()) {
2700 $newrole->setPublic ($oldrole->isPublic());
2702 $oldsettings = $oldrole->getSettingsForProject ($template);
2704 $sections = array('project_read', 'project_admin', 'scm', 'docman', 'tracker_admin', 'new_tracker', 'forum_admin', 'new_forum', 'pm_admin', 'new_pm', 'frs_admin', 'new_frs');
2705 foreach ($sections as $section) {
2706 $newrole->setSetting ($section, $this->getID(), $oldsettings[$section][$template->getID()]);
2709 $sections = array('tracker', 'pm', 'forum', 'frs');
2710 foreach ($sections as $section) {
2711 if (isset ($oldsettings[$section])) {
2712 foreach ($oldsettings[$section] as $k => $v) {
2713 // Only copy perms for tools that have been copied
2714 if (isset ($id_mappings[$section][$k])) {
2715 $newrole->setSetting ($section,
2716 $id_mappings[$section][$k],
2724 $lm = new WidgetLayoutManager();
2725 $lm->createDefaultLayoutForProject($this->getID(), $template->getID());
2727 // second computation to clone fields and workflow
2728 if (forge_get_config('use_tracker')) {
2729 if ($template->usesTracker()) {
2730 $oldatf = new ArtifactTypeFactory($template);
2731 foreach ($oldatf->getArtifactTypes() as $o) {
2732 $t = artifactType_get_object($id_mappings['tracker'][$o->getID()]);
2733 $id_mappings['tracker'][$o->getID()] = $t->getID();
2734 $newEFIds = $t->cloneFieldsFrom($o->getID(), $id_mappings);
2735 if (forge_get_config('use_tracker_widget_display')) {
2736 $lm->createDefaultLayoutForTracker($t->getID(), $o->getID(), $newEFIds);
2743 $params['template'] = $template;
2744 $params['project'] = $this;
2745 $params['id_mappings'] = $id_mappings;
2746 plugin_hook_by_reference ('clone_project_from_template', $params);
2748 // Disable everything - except use_scm (manually set in the registration page)
2749 db_query_params ('UPDATE groups SET use_mail = 0, use_survey = 0, use_forum = 0, use_pm = 0, use_pm_depend_box = 0, use_news = 0,
2750 use_docman = 0, use_ftp = 0, use_tracker = 0, use_frs = 0, use_stats = 0 WHERE group_id = $1',
2751 array($this->getID()));
2754 $this->normalizeAllRoles();
2755 // empty members cache because the group creator is not yet in cache.
2756 unset($this->membersArr);
2757 $this->activateUsers();
2759 // Delete fake join request
2760 foreach (get_group_join_requests ($this) as $gjr) {
2764 // Switch back to user preference
2765 session_set_internal($saved_session->getID());
2766 setup_gettext_from_context();
2768 $this->sendApprovalEmail();
2769 $this->addHistory(_('Approved'), 'x');
2772 // Plugin can make approve operation there
2775 $params['group'] = $this;
2776 $params['group_id'] = $this->getID();
2777 plugin_hook('group_approved', $params);
2783 * sendApprovalEmail - Send new project email.
2785 * @return bool success.
2788 function sendApprovalEmail() {
2789 $admins = RBACEngine::getInstance()->getUsersByAllowedAction ('project_admin', $this->getID());
2791 if (count($admins) < 1) {
2792 $this->setError(_('Group does not have any administrators.'));
2796 // send one email per admin
2797 foreach ($admins as $admin) {
2798 setup_gettext_for_user ($admin);
2800 $message = sprintf(_('Your project registration for %4$s has been approved.
2802 Project Full Name: %1$s
2803 Project Unix Name: %2$s
2805 Your DNS will take up to a day to become active on our site.
2806 Your web site is accessible through your shell account. Please read
2807 site documentation (see link below) about intended usage, available
2808 services, and directory layout of the account.
2811 own project page in %4$s while logged in, you will find
2812 additional menu functions to your left labeled \'Project Admin\'.
2814 We highly suggest that you now visit %4$s and create a public
2815 description for your project. This can be done by visiting your project
2816 page while logged in, and selecting \'Project Admin\' from the menus
2817 on the left (or by visiting %3$s
2820 Your project will also not appear in the Trove Software Map (primary
2821 list of projects hosted on %4$s which offers great flexibility in
2822 browsing and search) until you categorize it in the project administration
2823 screens. So that people can find your project, you should do this now.
2824 Visit your project while logged in, and select \'Project Admin\' from the
2827 Enjoy the system, and please tell others about %4$s. Let us know
2828 if there is anything we can do to help you.
2831 htmlspecialchars_decode($this->getPublicName()),
2832 $this->getUnixName(),
2833 util_make_url ('/project/admin/?group_id='.$this->getID()),
2834 forge_get_config ('forge_name'));
2836 util_send_message($admin->getEmail(), sprintf(_('%s Project Approved'), forge_get_config ('forge_name')), $message);
2838 setup_gettext_from_context();
2845 * sendRejectionEmail - Send project rejection email.
2847 * This function sends out a rejection message to a user who
2848 * registered a project.
2850 * @param int $response_id The id of the response to use.
2851 * @param string $message The rejection message.
2852 * @return bool completion status.
2855 function sendRejectionEmail($response_id, $message = 'zxcv') {
2856 $submitters = array();
2857 foreach (get_group_join_requests ($this) as $gjr) {
2858 $submitters[] = user_get_object($gjr->getUserID());
2861 if (count ($submitters) < 1) {
2862 $this->setError(_('Group does not have any administrators.'));
2866 foreach ($submitters as $admin) {
2867 setup_gettext_for_user($admin);
2869 $response = sprintf(_('Your project registration for %s has been denied.'), forge_get_config('forge_name')) . "\n\n"
2870 . _('Project Full Name')._(': '). $this->getPublicName() . "\n"
2871 . _('Project Unix Name')._(': '). $this->getUnixName() . "\n\n"
2872 . _('Reasons for negative decision')._(': ') . "\n\n";
2874 // Check to see if they want to send a custom rejection response
2875 if ($response_id == 0) {
2876 $response .= $message;
2878 $response .= db_result(
2879 db_query_params('SELECT response_text FROM canned_responses WHERE response_id=$1', array($response_id)),
2884 util_send_message($admin->getEmail(), sprintf(_('%s Project Denied'), forge_get_config('forge_name')), $response);
2885 setup_gettext_from_context();
2892 * sendNewProjectNotificationEmail - Send new project notification email.
2894 * This function sends out a notification email to the
2895 * SourceForge admin user when a new project is
2898 * @return bool success.
2901 function sendNewProjectNotificationEmail() {
2902 // Get the user who wants to register the project
2903 $submitters = array();
2904 foreach (get_group_join_requests ($this) as $gjr) {
2905 $submitters[] = user_get_object($gjr->getUserID());
2907 if (count ($submitters) < 1) {
2908 $this->setError(_('Could not find user who has submitted the project.'));
2912 $admins = RBACEngine::getInstance()->getUsersByAllowedAction('approve_projects', -1);
2914 if (count($admins) < 1) {
2915 $this->setError(_('There is no administrator to send the mail to.'));
2919 foreach ($admins as $admin) {
2920 $admin_email = $admin->getEmail();
2921 setup_gettext_for_user ($admin);
2923 $message = sprintf(_('New %s Project Submitted'), forge_get_config('forge_name')) . "\n\n"
2924 . _('Project Full Name')._(': ').htmlspecialchars_decode($this->getPublicName()) . "\n"
2925 . _('Submitted Description')._(': ').htmlspecialchars_decode($this->getRegistrationPurpose()) . "\n";
2927 foreach ($submitters as $submitter) {
2928 $message .= _('Submitter')._(': ').$submitter->getRealName().' ('.$submitter->getUnixName().')' . "\n\n";
2932 . _('Please visit the following URL to approve or reject this project')._(': '). "\n"
2933 . util_make_url('/admin/approve-pending.php');
2934 util_send_message($admin_email, sprintf(_('New %s Project Submitted'), forge_get_config('forge_name')), $message);
2935 setup_gettext_from_context();
2938 $email = $submitter->getEmail();
2939 setup_gettext_for_user ($submitter);
2941 $message = sprintf(_('New %s Project Submitted'), forge_get_config ('forge_name')) . "\n\n"
2942 . _('Project Full Name')._(': ') . $this->getPublicName() . "\n"
2943 . _('Submitted Description')._(': ') . util_unconvert_htmlspecialchars($this->getRegistrationPurpose()) . "\n\n"
2944 . sprintf(_('The %s admin team will now examine your project submission. You will be notified of their decision.'),
2945 forge_get_config ('web_host'));
2947 util_send_message($email, sprintf(_('New %s Project Submitted'), forge_get_config ('forge_name')), $message);
2948 setup_gettext_from_context();
2954 * validateGroupName - Validate the group name
2956 * @param string $group_name Project name.
2958 * @return bool an error false and set an error is the group name is invalid otherwise return true
2960 function validateGroupName($group_name) {
2961 if (strlen($group_name)<3) {
2962 $this->setError(_('Project name is too short'));
2964 } elseif (strlen(htmlspecialchars($group_name))>40) {
2965 $this->setError(_('Project name is too long'));
2967 } elseif (group_get_object_by_publicname($group_name)) {
2968 $this->setError(_('Project name already taken'));
2975 * getRolesId - Get Ids of the roles of the group.
2977 * @param bool all role ids or local role ids only. Default is all role ids
2978 * @return array Role ids of this group.
2980 function getRolesId($global = true) {
2981 $role_ids = array();
2983 $res = db_query_params('SELECT role_id FROM pfo_role WHERE home_group_id=$1',
2984 array($this->getID()));
2985 while ($arr = db_fetch_array($res)) {
2986 $role_ids[] = $arr['role_id'];
2989 $res = db_query_params('SELECT role_id FROM role_project_refs WHERE group_id=$1',
2990 array($this->getID()));
2991 while ($arr = db_fetch_array($res)) {
2992 $role_ids[] = $arr['role_id'];
2996 return array_unique($role_ids);
3000 * getRoles - Get the roles of the group.
3002 * @param bool all roles or local roles only. Default is all roles
3003 * @return array Roles of this group.
3005 function getRoles($global = true) {
3008 $roles = $this->getRolesId($global);
3009 $engine = RBACEngine::getInstance();
3010 foreach ($roles as $role_id) {
3011 $result[] = $engine->getRoleById($role_id);
3017 function normalizeAllRoles() {
3018 $roles = $this->getRoles();
3020 foreach ($roles as $r) {
3021 $r->normalizeData();
3026 * getUnixStatus - Status of activation of unix account.
3028 * @return string Values: (N)one, (A)ctive, (S)uspended or (D)eleted
3030 function getUnixStatus() {
3031 return $this->data_array['unix_status'];
3035 * setUnixStatus - Sets status of activation of unix account.
3037 * @param string $status The unix status.
3043 * @return bool success.
3045 function setUnixStatus($status) {
3048 $res = db_query_params ('UPDATE groups SET unix_status=$1 WHERE group_id=$2',
3053 $this->setError(_('Error')._(': ')._('Cannot Update Group Unix Status')._(': ').db_error());
3057 if ($status == 'A') {
3058 if (!$SYS->sysCheckCreateGroup($this->getID())) {
3059 $this->setError($SYS->getErrorMessage());
3064 if ($SYS->sysCheckGroup($this->getID())) {
3065 if (!$SYS->sysRemoveGroup($this->getID())) {
3066 $this->setError($SYS->getErrorMessage());
3073 $this->data_array['unix_status'] = $status;
3080 * getUsers - Get the users of a group
3082 * @param bool $onlylocal
3083 * @param boolean $onlyactive Only users with state active, or all users of group
3084 * @return array user's objects.
3086 function getUsers($onlylocal = true, $onlyactive = true) {
3087 if (!isset($this->membersArr)) {
3088 $this->membersArr = array();
3091 foreach ($this->getRoles() as $role) {
3093 && ($role->getHomeProject() == NULL || $role->getHomeProject()->getID() != $this->getID())) {
3096 foreach ($role->getUsers() as $user) {
3097 $ids[] = $user->getID();
3100 $ids = array_unique ($ids);
3101 foreach ($ids as $id) {
3102 $u = user_get_object ($id);
3103 if (!$onlyactive || $u->isActive()) {
3104 $this->membersArr[] = $u;
3108 return $this->membersArr;
3111 function setDocmanCreateOnlineStatus($status) {
3113 $res = db_query_params('UPDATE groups SET use_docman_create_online = $1 WHERE group_id = $2',
3114 array($status, $this->getID()));
3117 $this->setError(_('Error')._(': ')._('Cannot Update Group DocmanCreateOnline Status')._(': ').db_error());
3121 $this->data_array['use_docman_create_online'] = $status;
3127 function setDocmanWebdav($status) {
3129 $res = db_query_params('UPDATE groups SET use_webdav = $1 WHERE group_id = $2',
3134 $this->setError(_('Error')._(': ')._('Cannot Update Group UseWebdav Status')._(': ').db_error());
3138 $this->data_array['use_webdav'] = $status;
3144 function setDocmanSearchStatus($status) {
3146 /* if we activate search engine, we probably want to reindex */
3147 $res = db_query_params('UPDATE groups SET use_docman_search = $1, force_docman_reindex = $1 WHERE group_id = $2',
3148 array($status, $this->getID()));
3151 $this->setError(_('Error')._(': ')._('Cannot Update Group UseDocmanSearch Status')._(': ').db_error());
3155 $this->data_array['use_docman_search'] = $status;
3161 function setDocmanForceReindexSearch($status) {
3163 $res = db_query_params('UPDATE groups SET force_docman_reindex = $1 WHERE group_id = $2',
3164 array($status, $this->getID()));
3167 $this->setError(_('Error')._(': ')._('Cannot Update Group force_docman_reindex')._(': ').db_error());
3171 $this->data_array['force_docman_reindex'] = $status;
3179 * @param integer $unit_set_id the effort unit set id
3182 function setEffortUnitSet($unit_set_id) {
3184 $res = db_query_params ('UPDATE groups SET unit_set_id=$1 WHERE group_id=$2',
3185 array($unit_set_id, $this->getID()));
3187 $this->data_array['unit_set_id'] = $unit_set_id;
3197 * getEffortUnitSet - Get the effort unit set id.
3199 * @return integer The id of the effort unit set.
3201 function getEffortUnitSet() {
3202 return $this->data_array['unit_set_id'];
3205 function getWidgetLayoutConfig() {
3206 $lm = new WidgetLayoutManager();
3207 return $lm->getLayout($this->getID(), WidgetLayoutManager::OWNER_TYPE_GROUP);
3212 * group_getname() - get the group name
3214 * @param int $group_id The group ID
3219 function group_getname ($group_id = 0) {
3220 $grp = group_get_object($group_id);
3222 return $grp->getPublicName();
3229 * group_getunixname() - get the unixname for a group
3231 * @param int $group_id The group ID
3236 function group_getunixname ($group_id) {
3237 $grp = group_get_object($group_id);
3239 return $grp->getUnixName();
3246 * group_get_result() - Get the group object result ID.
3248 * @param int $group_id The group ID
3253 function &group_get_result($group_id=0) {
3254 $grp = group_get_object($group_id);
3256 return $grp->getData();
3262 function getAllProjectTags($onlyvisible = true) {
3263 $res = db_query_params('SELECT project_tags.name, groups.group_id FROM groups, project_tags WHERE groups.group_id = project_tags.group_id AND groups.status = $1 ORDER BY project_tags.name, groups.group_id',
3266 if (!$res || db_numrows($res) == 0) {
3272 while ($arr = db_fetch_array($res)) {
3274 $group_id = $arr[1];
3275 if (!isset($result[$tag])) {
3276 $result[$tag] = array();
3279 if (!$onlyvisible || forge_check_perm('project_read', $group_id)) {
3280 $p = group_get_object($group_id);
3281 $result[$tag][] = array('unix_group_name' => $p->getUnixName(),
3282 'group_id' => $group_id);
3290 * Utility class to compare project based in various criteria (names, unixnames, id, ...)
3293 class ProjectComparator {
3294 var $criterion = 'name';
3296 function Compare ($a, $b) {
3297 switch ($this->criterion) {
3300 $namecmp = strcoll ($a->getPublicName(), $b->getPublicName());
3301 if ($namecmp != 0) {
3304 /* If several projects share a same public name */
3305 return strcoll ($a->getUnixName(), $b->getUnixName());
3307 return strcmp ($a->getUnixName(), $b->getUnixName());
3314 return ($aid < $bid) ? -1 : 1;
3319 function sortProjectList (&$list, $criterion='name') {
3320 $cmp = new ProjectComparator();
3321 $cmp->criterion = $criterion;
3323 return usort ($list, array($cmp, 'Compare'));
3328 // c-file-style: "bsd"