3 * FusionForge project manager
5 * Copyright 1999-2000, Tim Perdue/Sourceforge
6 * Copyright 2002, Tim Perdue/GForge, LLC
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.'include/Error.class.php';
27 require_once $gfcommon.'include/Validator.class.php';
29 function &projecttask_get_object($project_task_id,$data=false) {
30 global $PROJECTTASK_OBJ;
31 if (!isset($PROJECTTASK_OBJ["_".$project_task_id."_"])) {
33 //the db result handle was passed in
35 $res=db_query("SELECT * FROM project_task_vw
36 WHERE project_task_id='$project_task_id'");
38 if (db_numrows($res) <1 ) {
39 $PROJECTTASK_OBJ["_".$project_task_id."_"]=false;
42 $data =& db_fetch_array($res);
45 $ProjectGroup =& projectgroup_get_object($data["group_project_id"]);
46 $PROJECTTASK_OBJ["_".$project_task_id."_"]= new ProjectTask($ProjectGroup,$project_task_id,$data);
50 return $PROJECTTASK_OBJ["_".$project_task_id."_"];
54 Types of task dependencies
56 define('PM_LINK_DEFAULT','FS');
57 define('PM_LINK_START_START','SS');
58 define('PM_LINK_START_FINISH','SF');
59 define('PM_LINK_FINISH_START','FS');
60 define('PM_LINK_FINISH_FINISH','FF');
62 class ProjectTask extends Error {
65 * Associative array of data from db.
67 * @var array $data_array.
72 * The ProjectGroup object.
74 * @var object $ProjectGroup.
79 var $relatedartifacts;
84 * @param object The ProjectGroup object to which this ProjectTask is associated.
85 * @param int The project_task_id.
86 * @param array The associative array of data.
87 * @return boolean success.
89 function ProjectTask(&$ProjectGroup, $project_task_id=false, $arr=false) {
91 if (!$ProjectGroup || !is_object($ProjectGroup)) {
92 $this->setError('ProjectTask:: No Valid ProjectGroup Object');
95 if ($ProjectGroup->isError()) {
96 $this->setError('ProjectTask:: '.$ProjectGroup->getErrorMessage());
99 $this->ProjectGroup =& $ProjectGroup;
101 if ($project_task_id) {
102 if (!$arr || !is_array($arr)) {
103 if (!$this->fetchData($project_task_id)) {
107 $this->data_array =& $arr;
109 // Verify this message truly belongs to this ProjectGroup
111 if ($this->data_array['group_project_id'] != $this->ProjectGroup->getID()) {
112 $this->setError('Group_project_id in db result does not match ProjectGroup Object');
121 * create - create a new ProjectTask in the database.
123 * @param string The summary of this task.
124 * @param string The detailed description of this task.
125 * @param int The Priority of this task.
126 * @param int The Hours estimated to complete this task.
127 * @param int The (unix) start date of this task.
128 * @param int The (unix) end date of this task.
129 * @param int The category_id of this task.
130 * @param int The percentage of completion in integer format of this task.
131 * @param array An array of user_id's that are assigned this task.
132 * @param array An array of project_task_id's that this task depends on.
133 * @param int The duration of the task in days.
134 * @param int The id of the parent task, if any.
135 * @return boolean success.
137 function create($summary,$details,$priority,$hours,$start_date,$end_date,
138 $category_id,$percent_complete,&$assigned_arr,&$depend_arr,$duration=0,$parent_id=0) {
139 global $sys_database_type;
141 $v = new Validator();
142 $v->check($summary, "summary");
143 $v->check($details, "details");
144 $v->check($priority, "priority");
145 $v->check($hours, "hours");
146 $v->check($start_date, "start date");
147 $v->check($end_date, "end date");
148 $v->check($category_id, "category");
149 if (!$v->isClean()) {
150 $this->setError($v->formErrorMsg("Must include "));
159 if (!$this->ProjectGroup->userIsAdmin()) {
160 $this->setPermissionDeniedError();
165 if ($sys_database_type == "mysql") {
167 $sql = "INSERT INTO project_task (group_project_id,created_by,summary,
168 details,start_date,end_date,status_id,category_id,priority,percent_complete,hours,duration,parent_id)
169 VALUES ('".$this->ProjectGroup->getID()."','".user_getid()."','".htmlspecialchars( $summary )."',
170 '". htmlspecialchars($details) ."', '$start_date','$end_date','1','$category_id','$priority','$percent_complete','$hours','$duration','$parent_id')";
172 $result = db_query( $sql );
173 if (!$result || db_affected_rows($result) < 1) {
174 $this->setError( 'ProjectTask::create() Posting Failed '.db_error().$sql );
179 $result = db_query( "SELECT last_insert_id() AS id" );
181 $this->setError( 'ProjectTask::create() Get Created ID Failed '.db_error().$sql );
186 $project_task_id=db_result($result, 0, 'id');
187 if (!$project_task_id) {
188 $this->setError( 'ProjectTask::create() Created ID is NULL Failed' );
193 $this->data_array['project_task_id']=$project_task_id;
196 $res=db_query("SELECT nextval('project_task_pk_seq') AS id");
197 if (!$project_task_id=db_result($res,0,'id')) {
198 $this->setError( 'Could Not Get Next Project Task ID' );
203 $this->data_array['project_task_id']=$project_task_id;
205 $sql="INSERT INTO project_task (project_task_id,group_project_id,created_by,summary,
206 details,start_date,end_date,status_id,category_id,priority,percent_complete,hours,duration,parent_id)
207 VALUES ('$project_task_id','". $this->ProjectGroup->getID() ."', '".user_getid()."', '". htmlspecialchars($summary) ."',
208 '". htmlspecialchars($details) ."','$start_date','$end_date','1','$category_id','$priority','$percent_complete','$hours','$duration','$parent_id')";
210 $result=db_query($sql);
211 if (!$result || db_affected_rows($result) < 1) {
212 $this->setError('ProjectTask::create() Posting Failed '.db_error().$sql);
218 if (!$this->setDependentOn($depend_arr)) {
222 if (!$this->setAssignedTo($assigned_arr)) {
226 if (!$this->fetchData($project_task_id)) {
230 $this->sendNotice(1);
236 * fetchData - re-fetch the data for this ProjectTask from the database.
238 * @param int The project_task_id.
239 * @return boolean success.
241 function fetchData($project_task_id) {
242 $res=db_query("SELECT * FROM project_task_vw
243 WHERE project_task_id='$project_task_id'
244 AND group_project_id='". $this->ProjectGroup->getID() ."'");
245 if (!$res || db_numrows($res) < 1) {
246 $this->setError('ProjectTask::fetchData() Invalid Task ID'.db_error());
249 $this->data_array =& db_fetch_array($res);
250 db_free_result($res);
255 * getProjectGroup - get the ProjectGroup object this ProjectTask is associated with.
257 * @return Object The ProjectGroup object.
259 function &getProjectGroup() {
260 return $this->ProjectGroup;
264 * getID - get this project_task_id.
266 * @return int The project_task_id.
269 return $this->data_array['project_task_id'];
273 * getSubmittedRealName - get the real name of the person who created this task.
275 * @return string The real name person who created this task.
277 function getSubmittedRealName() {
278 return $this->data_array['realname'];
282 * getDuration - the duration of the task.
284 * @return int The number of days of duration.
286 function getDuration() {
287 return $this->data_array['duration'];
291 * getParentID - the task_id of the parent task, if any.
293 * @return string The real name person who created this task.
295 function getParentID() {
296 return $this->data_array['parent_id'];
300 * getSubmittedUnixName - get the unix name of the person who created this task.
302 * @return string The unix name of the person who created this task.
304 function getSubmittedUnixName() {
305 return $this->data_array['user_name'];
309 * getSummary - get the subject/summary of this task.
311 * @return string The summary.
313 function getSummary() {
314 return $this->data_array['summary'];
318 * getDetails - get the body/details of this task.
320 * @return string The body/details.
322 function getDetails() {
323 return $this->data_array['details'];
327 * getPercentComplete - an integer between 0 and 100.
329 * @return int The percentage of completion of this task.
331 function getPercentComplete() {
332 return $this->data_array['percent_complete'];
336 * getPriority - the priority, between 1 and 9 of this task.
338 * @return int The priority.
340 function getPriority() {
341 return $this->data_array['priority'];
345 * getHours - the hours this task is expected to take.
347 * @return int The hours.
349 function getHours() {
350 return $this->data_array['hours'];
354 * getStartDate - the unix time that this task will start.
356 * @return int The unix start time of this task.
358 function getStartDate() {
359 return $this->data_array['start_date'];
363 * getEndDate - the unix time that this task will end.
365 * @return int The unix end time of this task.
367 function getEndDate() {
368 return $this->data_array['end_date'];
372 * getStatusID - the integer of the status of this task.
374 * @return int the status_id.
376 function getStatusID() {
377 return $this->data_array['status_id'];
381 * getStatusName - the string of the status of this task.
383 * @return string the status_name.
385 function getStatusName() {
386 return $this->data_array['status_name'];
390 * getCategoryID - the category_id of this task.
392 * @return int the category_id.
394 function getCategoryID() {
395 return $this->data_array['category_id'];
399 * getCategoryName - the category_name of this task.
401 * @return int the category_name.
403 function getCategoryName() {
404 return $this->data_array['category_name'];
408 * getLastModifiedDate - the last_modified_date of this task.
410 * @return int the last_modified_date.
412 function getLastModifiedDate() {
413 return $this->data_array['last_modified_date'];
417 * setExternalID - set a row in project_task_external_order which stores
418 * an id, for example an ID generated by MS Project, which needs to be restored later
420 function setExternalID($id) {
421 $res=db_query("UPDATE project_task_external_order SET external_id='$id'
422 WHERE project_task_id='".$this->getID()."'");
423 if (db_affected_rows($res) < 1) {
424 $res=db_query("INSERT INTO project_task_external_order (project_task_id,external_id)
425 VALUES ('".$this->getID()."','$id')");
430 * getExternalID - get the ID that MS Project uses to sort tasks
432 * @return int the id.
434 function getExternalID() {
435 return $this->data_array['external_id'];
439 * getRelatedArtifacts - Return a result set of artifacts which are related to this task.
441 * @returns Database result set.
443 function getRelatedArtifacts() {
444 if (!$this->relatedartifacts) {
445 $this->relatedartifacts=
446 db_query("SELECT agl.group_id,agl.name,agl.group_artifact_id,a.artifact_id,a.open_date,a.summary
447 FROM artifact_group_list agl, artifact a
448 WHERE a.group_artifact_id=agl.group_artifact_id
449 AND EXISTS (SELECT artifact_id FROM project_task_artifact
450 WHERE artifact_id=a.artifact_id
451 AND project_task_id='". $this->getID() ."')");
453 return $this->relatedartifacts;
457 * addRelatedArtifacts - take an array of artifact_id's and build relationships.
459 * @param array An array of artifact_id's to be attached to this task.
460 * @return boolean success.
462 function addRelatedArtifacts($art_array) {
463 if (!$this->ProjectGroup->userIsAdmin()) {
464 $this->setPermissionDeniedError();
468 // SHOULD REALLY INSTANTIATE THIS ARTIFACT OBJECT TO ENSURE PROPER SECURITY - FUTURE
470 // new ArtifactFromID($id)
472 for ($i=0; $i<count($art_array); $i++) {
473 if ($art_array[$i] < 1) {
476 $res=db_query("INSERT INTO project_task_artifact (project_task_id,artifact_id)
477 VALUES ('".$this->getID()."','".$art_array[$i]."')");
479 $this->setError('Error inserting artifact relationship: '.db_error());
487 * removeRelatedArtifacts - take an array of artifact_id's and delete relationships.
489 * @param array An array of artifact_id's to be removed from this task.
490 * @return boolean success.
492 function removeRelatedArtifacts($art_array) {
493 if (!$this->ProjectGroup->userIsAdmin()) {
494 $this->setPermissionDeniedError();
498 for ($i=0; $i<count($art_array); $i++) {
499 $res=db_query("DELETE FROM project_task_artifact
500 WHERE project_task_id='".$this->getID()."'
501 AND artifact_id='".$art_array[$i]."'");
503 $this->setError('Error deleting artifact relationship: '.db_error());
511 * delete - delete this tracker and all its related data.
513 * @param bool I'm Sure.
514 * @return bool true/false;
516 function delete($sure) {
518 $this->setMissingParamsError();
521 if (!$this->ProjectGroup->userIsAdmin()) {
522 $this->setPermissionDeniedError();
527 $res = db_query("DELETE FROM project_assigned_to WHERE project_task_id='".$this->getID()."'");
529 $this->setError('Error deleting assigned users relationship: '.db_error());
533 $res = db_query("DELETE FROM project_dependencies WHERE project_task_id='".$this->getID()."'");
535 $this->setError('Error deleting dependencies: '.db_error());
539 $res = db_query("DELETE FROM project_history WHERE project_task_id='".$this->getID()."'");
541 $this->setError('Error deleting history: '.db_error());
545 $res = db_query("DELETE FROM project_messages WHERE project_task_id='".$this->getID()."'");
547 $this->setError('Error deleting messages: '.db_error());
551 $res = db_query("DELETE FROM project_task_artifact WHERE project_task_id='".$this->getID()."'");
553 $this->setError('Error deleting artifacts: '.db_error());
557 $res = db_query("DELETE FROM rep_time_tracking WHERE project_task_id='".$this->getID()."'");
559 $this->setError('Error deleting time tracking report: '.db_error());
563 $res = db_query("DELETE FROM project_task WHERE project_task_id='".$this->getID()."'");
565 $this->setError('Error deleting task: '.db_error());
575 * getOtherTasks - Return a result set of tasks in this subproject that do not equal
576 * the current task_id.
578 * @returns Database result set.
580 function getOtherTasks () {
582 // May not yet have an ID, if we are creating a NEW task
584 if ($this->getID()) {
585 $addstr=" AND project_task_id <> '". $this->getID() ."' ";
589 $sql="SELECT project_task_id,summary
591 WHERE group_project_id='". $this->ProjectGroup->getID() ."'
592 $addstr ORDER BY project_task_id DESC";
593 return db_query($sql);
597 * getHistory - returns a result set of audit trail for this ProjectTask.
599 * @return database result set.
601 function getHistory() {
603 FROM project_history_user_vw
604 WHERE project_task_id='". $this->getID() ."'
605 ORDER BY mod_date DESC";
606 return db_query($sql);
610 * getMessages - get the list of messages attached to this ProjectTask.
612 * @return database result set.
614 function getMessages() {
616 FROM project_message_user_vw
617 WHERE project_task_id='". $this->getID() ."' ORDER BY postdate DESC";
618 return db_query($sql);
622 * addMessage - Handle the addition of a followup message to this task.
624 * @param string The message.
625 * @returns boolean success.
627 function addMessage($message) {
628 //prevent posting the same message
629 if ($this->getDetails() == htmlspecialchars($message)) {
632 $res=db_query("SELECT * FROM project_messages
633 WHERE project_task_id='".$this->getID()."'
634 AND body='". htmlspecialchars($message) ."'");
635 if (!$res || db_numrows($res) < 1) {
636 $sql="INSERT INTO project_messages (project_task_id,body,posted_by,postdate)
637 VALUES ('". $this->getID() ."','". htmlspecialchars($message) ."','".user_getid()."','". time() ."')";
639 if (!$res || db_affected_rows($res) < 1) {
640 $this->setError('AddMessage():: '.db_error());
651 * addHistory - Handle the insertion of history for these parameters.
653 * @param string The field name.
654 * @param string The old value.
655 * @returns boolean success.
657 function addHistory ($field_name,$old_value) {
658 $sql="insert into project_history(project_task_id,field_name,old_value,mod_by,mod_date)
659 VALUES ('". $this->getID() ."','$field_name','$old_value','".user_getid()."','".time()."')";
660 $result=db_query($sql);
662 $this->setError('ERROR IN AUDIT TRAIL - '.db_error());
670 * checkCircular - recursive function calls itself to look at all tasks you are dependent on.
672 * @param int The project_task_id you are dependent on.
673 * @param int The project_task_id you are checking circular dependencies for.
674 * @returns boolean success.
676 function checkCircular($depend_on_id, $original_id) {
677 //for msproject users - ms project has more complex logic than gforge
680 if ($depend_on_id == $original_id) {
681 $this->setError(_('Circular Dependency Detected\''));
685 $res=db_query("SELECT is_dependent_on_task_id AS id
686 FROM project_dependencies
687 WHERE project_task_id='$depend_on_id'");
688 $rows=db_numrows($res);
690 for ($i=0; $i<$rows; $i++) {
691 if (!$this->checkCircular(db_result($res,$i,'id'), $original_id)) {
699 * setDependentOn - takes an array of project_task_id's and builds dependencies.
701 * @param array The array of project_task_id's.
702 * @returns boolean success.
704 function setDependentOn(&$arr_) {
705 //printr($arr_,'setDependentOn entry');
707 // IMPORTANT - MUST VERIFY NO CIRCULAR DEPENDENCY!!
709 if (!$arr_ || empty($arr_)) {
710 $arr_=array('100'=>PM_LINK_DEFAULT);
712 $arr =& array_keys($arr_);
713 //get existing dependencies to diff against
714 $arr2 =& array_keys($this->getDependentOn());
716 if (count($arr) || count($arr2)) {
717 $add_arr = array_values (array_diff ($arr, $arr2));
718 //echo "add arr: ".print_r($add_arr);
719 $del_arr = array_values (array_diff ($arr2, $arr));
720 //echo "del arr: ".print_r($del_arr);
721 for ($i=0; $i<count($del_arr); $i++) {
722 db_query("DELETE FROM project_dependencies
723 WHERE project_task_id='".$this->getID()."'
724 AND is_dependent_on_task_id='". $del_arr[$i] ."'");
726 $this->setError('setDependentOn()-1:: '.db_error());
730 for ($i=0; $i<count($add_arr); $i++) {
732 // Check task for circular dependencies
734 if (!$this->checkCircular($add_arr[$i],$this->getID())) {
737 $lnk = $arr_[$add_arr[$i]];
739 $lnk=PM_LINK_DEFAULT;
741 $sql="INSERT INTO project_dependencies (project_task_id,is_dependent_on_task_id,link_type)
742 VALUES ('".$this->getID()."','". $add_arr[$i] ."','$lnk')";
745 $this->setError('setDependentOn()-2:: '.db_error().$sql);
756 * convertDependentOn - converts a regular array of dependencies, such
757 * as from a multiple-select-box to an associative array with default
758 * link types. Should be called from web code as part of the create/update calls.
759 * Here we are converting an array like array(1,5,9,77) to array(1=>SS,5=>SF,9=>FS,77=>SS)
761 function &convertDependentOn($arr) {
762 //echo "<p>Convert Dep0: ".print_r($arr);
763 $deps =& $this->getDependentOn();
764 for ($i=0; $i<count($arr); $i++) {
765 if ($deps[$arr[$i]]) {
766 //use existing link_type if it exists
767 $new[$arr[$i]]=$deps[$arr[$i]];
769 //else create with default link type
770 $new[$arr[$i]]=PM_LINK_DEFAULT;
773 //echo "<p>Convert Dep1: ".print_r($new);
778 * getDependentOn - get an array of project_task_id's that you are dependent on.
780 * @return array The array of project_task_id's in this format:
781 * array($id=>$link_type,id2=>link_type2).
783 function &getDependentOn() {
784 if (!$this->getID()) {
785 $this->dependon = array();
786 return $this->dependon;
788 if (!$this->dependon) {
789 $res=db_query("SELECT is_dependent_on_task_id,link_type
790 FROM project_dependencies
791 WHERE project_task_id='".$this->getID()."'");
792 for ($i=0; $i<db_numrows($res); $i++) {
793 $this->dependon[db_result($res,$i,'is_dependent_on_task_id')] = db_result($res,$i,'link_type');
796 /* fix bug 319: if dependentlist is emtpy, set it to 100 (none) */
797 if (!$this->dependon) {
798 $this->dependon[100]=PM_LINK_DEFAULT;
800 return $this->dependon;
804 * setAssignedTo - takes an array of user_id's and builds assignments.
806 * @param array The array of user_id's.
807 * @returns boolean success.
809 function setAssignedTo(&$arr) {
810 $arr2 =& $this->getAssignedTo();
811 $this->assignedto =& $arr;
813 //If no one is assigned, then assign it to "100" - NOBODY
814 if (count($arr) < 1 || ((count($arr)==1) && ($arr[0]==''))) {
817 if (count($arr) || count($arr2)) {
818 $add_arr = array_values(array_diff ($arr, $arr2));
819 $del_arr = array_values(array_diff ($arr2, $arr));
820 for ($i=0; $i<count($del_arr); $i++) {
821 db_query("DELETE FROM project_assigned_to
822 WHERE project_task_id='".$this->getID()."'
823 AND assigned_to_id='". $del_arr[$i] ."'");
825 $this->setError('setAssignedTo()-1:: '.db_error());
829 for ($i=0; $i<count($add_arr); $i++) {
830 db_query("INSERT INTO project_assigned_to (project_task_id,assigned_to_id)
831 VALUES ('".$this->getID()."','". $add_arr[$i] ."')");
833 $this->setError('setAssignedTo()-2:: '.db_error());
844 * getAssignedTo - get an array of user_id's that you are assigned to.
846 * @return array The array of user_id's.
848 function &getAssignedTo() {
849 if (!$this->getID()) {
850 $this->assignedto = array();
851 return $this->assignedto;
853 if (!$this->assignedto) {
854 $this->assignedto =& util_result_column_to_array(db_query("SELECT assigned_to_id
855 FROM project_assigned_to
856 WHERE project_task_id='".$this->getID()."'"));
858 return $this->assignedto;
862 * update - update this ProjectTask in the database.
864 * @param string The summary of this task.
865 * @param string The detailed description of this task.
866 * @param int The Priority of this task.
867 * @param int The Hours estimated to complete this task.
868 * @param int The (unix) start date of this task.
869 * @param int The (unix) end date of this task.
870 * @param int The status_id of this task.
871 * @param int The category_id of this task.
872 * @param int The percentage of completion in integer format of this task.
873 * @param array An array of user_id's that are assigned this task.
874 * @param array An array of project_task_id's that this task depends on.
875 * @param int The GroupProjectID of a new subproject that you want to move this Task to.
876 * @param int The duration of the task in days.
877 * @param int The id of the parent task, if any.
878 * @return boolean success.
880 function update($summary,$details,$priority,$hours,$start_date,$end_date,
881 $status_id,$category_id,$percent_complete,&$assigned_arr,&$depend_arr,
882 $new_group_project_id,$duration=0,$parent_id=0) {
883 $has_changes = false; // if any of the values passed is different from
884 $v = new Validator();
885 $v->check($summary, "summary");
886 $v->check($priority, "priority");
887 $v->check($hours, "hours");
888 $v->check($start_date, "start date");
889 $v->check($end_date, "end date");
890 $v->check($status_id, "status");
891 $v->check($category_id, "category");
892 if (!$v->isClean()) {
893 $this->setError($v->formErrorMsg("Must include "));
899 if ( ($this->getParentID()) != $parent_id ) {
905 if ( ($this->getDuration()) != $duration ) {
909 if (!$this->ProjectGroup->userIsAdmin()) {
910 $this->setPermissionDeniedError();
914 /*if ( ($this->getSummary() != $summary) || ($this->getDetails() != $details) ||
915 ($this->getPriority() != $priority) || ($this->getHours() != $hours) ||
916 ($this->getStartDate() != $start_date) || ($this->getEndDate() != $end_date) ||
917 ($this->getStatusID() != $status_id) || ($this->getCategoryID() != $category_id) ||
918 ($this->getPercentComplete() != $percent_complete) ) {
927 // Attempt to move this Task to a new Subproject
928 // need to instantiate new ProjectGroup obj and test if it works
930 $group_project_id = $this->ProjectGroup->getID();
931 if ($new_group_project_id != $group_project_id) {
932 $newProjectGroup= new ProjectGroup($this->ProjectGroup->getGroup(), $new_group_project_id);
933 if (!is_object($newProjectGroup) || $newProjectGroup->isError()) {
934 $this->setError('ProjectTask: Could not move to new ProjectGroup'. $newProjectGroup->getErrorMessage());
938 /* do they have perms for new ArtifactType?
939 if (!$newArtifactType->userIsAdmin()) {
940 $this->setPermissionDeniedError();
945 // Now set ProjectGroup, Category, and Assigned to 100 in the new ProjectGroup
950 $assigned_to=array('100');
951 $this->ProjectGroup =& $newProjectGroup;
952 $this->addHistory ('group_project_id',$group_project_id);
959 if (!$this->addMessage($details)) {
964 if ($this->getStatusID() != $status_id) {
965 $this->addHistory ('status_id',$this->getStatusID());
969 if ($this->getCategoryID() != $category_id) {
970 $this->addHistory ('category_id',$this->getCategoryID());
974 if ($this->getPriority() != $priority) {
975 $this->addHistory ('priority',$this->getPriority());
979 if ($this->getSummary() != htmlspecialchars(stripslashes($summary))) {
980 $this->addHistory ('summary',addslashes($this->getSummary()));
984 if ($this->getPercentComplete() != $percent_complete) {
985 $this->addHistory ('percent_complete',$this->getPercentComplete());
989 if ($this->getHours() != $hours) {
990 $this->addHistory ('hours',$this->getHours());
994 if ($this->getStartDate() != $start_date) {
995 $this->addHistory ('start_date',$this->getStartDate());
999 if ($this->getEndDate() != $end_date) {
1000 $this->addHistory ('end_date',$this->getEndDate());
1001 $has_changes = true;
1004 $old_assigned = &$this->getAssignedTo();
1005 $diff_assigned_array=array_diff($old_assigned, $assigned_arr);
1006 if (count($diff_assigned_array)>0) {
1007 for ($tmp=0;$tmp<count($old_assigned);$tmp++) {
1008 $this->addHistory('assigned_to_id',$old_assigned[$tmp]);
1010 $has_changes = true;
1012 $old_array =& array_keys($this->getDependentOn());
1013 $diff_array=array_diff($old_array,array_keys($depend_arr));
1014 if (count($diff_array)>0) {
1015 for ($tmp=0;$tmp<count($old_array);$tmp++) {
1016 $this->addHistory('dependent_on_id', $old_array[$tmp]);
1018 $has_changes = true;
1021 if (!$this->setDependentOn($depend_arr)) {
1024 } elseif (!$this->setAssignedTo($assigned_arr)) {
1028 $sql="UPDATE project_task SET
1029 summary='".htmlspecialchars($summary)."',
1030 priority='$priority',
1032 start_date='$start_date',
1033 end_date='$end_date',
1034 status_id='$status_id',
1035 percent_complete='$percent_complete',
1036 category_id='$category_id',
1037 group_project_id='$new_group_project_id',
1038 duration='$duration',
1039 parent_id='$parent_id'
1040 WHERE group_project_id='$group_project_id'
1041 AND project_task_id='".$this->getID()."'";
1043 $res=db_query($sql);
1045 $this->setError('Error On ProjectTask::update-5: '.db_error().$sql);
1049 if (!$this->fetchData($this->getID())) {
1050 $this->setError('Error On ProjectTask::update-6: '.db_error());
1054 if ($has_changes) { //only send email if there was any change
1055 $this->sendNotice();
1066 * sendNotice - contains the logic for sending email/jabber updates.
1068 * @return boolean success.
1070 function sendNotice($first=false) {
1071 global $send_task_email;
1072 if ($send_task_email===false) {
1075 $ids =& $this->getAssignedTo();
1078 // See if there is anyone to send messages to
1080 if (count($ids) < 1 && !$this->ProjectGroup->getSendAllPostsTo()) {
1084 $body = "Task #". $this->getID() ." has been updated. ".
1085 "\n\nProject: ". $this->ProjectGroup->Group->getPublicName() .
1086 "\nSubproject: ". $this->ProjectGroup->getName() .
1087 "\nSummary: ".util_unconvert_htmlspecialchars( $this->getSummary() ).
1088 "\nComplete: ". $this->getPercentComplete() ."%".
1089 "\nStatus: ". $this->getStatusName() .
1090 "\n\nDescription: ". util_unconvert_htmlspecialchars( $this->getDetails() );
1093 Now get the followups to this task
1095 $result2=$this->getMessages();
1097 $rows=db_numrows($result2);
1099 if ($result2 && $rows > 0) {
1100 $body .= "\n\nFollow-Ups:";
1101 for ($i=0; $i<$rows;$i++) {
1102 $body .= "\n\n-------------------------------------------------------";
1103 $body .= "\nDate: ". date(_('Y-m-d H:i'),db_result($result2,$i,'postdate'));
1104 $body .= "\nBy: ".db_result($result2,$i,'user_name');
1105 $body .= "\n\nComment:\n".util_unconvert_htmlspecialchars(db_result($result2,$i,'body'));
1108 $body .= "\n\n-------------------------------------------------------".
1109 "\nFor more info, visit:".
1110 "\n\n".util_make_url ('/pm/task.php?func=detailtask&project_task_id='.$this->getID().
1111 "&group_id=".$this->ProjectGroup->Group->getID().
1112 "&group_project_id=".$this->ProjectGroup->getID());
1114 $subject=sprintf (_('[%1$s - %2$s] [Task #%3$d] '),
1115 $this->ProjectGroup->Group->getUnixName(),
1116 $this->ProjectGroup->getName(),
1118 util_unconvert_htmlspecialchars( $this->getSummary() );
1120 util_handle_message(array_unique($ids),$subject,$body,$this->ProjectGroup->getSendAllPostsTo());
1128 // c-file-style: "bsd"