diff --git a/infolog/inc/class.infolog_datasource.inc.php b/infolog/inc/class.infolog_datasource.inc.php index 897e6ec5c2..637dfe9a36 100644 --- a/infolog/inc/class.infolog_datasource.inc.php +++ b/infolog/inc/class.infolog_datasource.inc.php @@ -113,6 +113,9 @@ class infolog_datasource extends datasource if (!is_array($info)) return false; + $info_contact = $info['info_contact']; + $info_from = $info['info_from']; + // unsetting info_link_id and evtl. info_from if ($info['info_link_id']) { @@ -120,7 +123,8 @@ class infolog_datasource extends datasource unset($info['info_link_id']); unset($info['info_contact']); } - // we need to unset a view fields, to get a new entry + + // we need to unset a few fields to get a new entry foreach(array('info_id','info_owner','info_modified','info_modifierer') as $key) { unset($info[$key]); @@ -159,13 +163,6 @@ class infolog_datasource extends datasource unset($info['info_datecompleted']); } - if(!($info['info_id'] = $this->infolog_bo->write($info))) return false; - - // link the new infolog against the project and setting info_link_id and evtl. info_from - $old_link = $info['info_link_id'] ? Link::get_link($info['info_link_id']) : $info['info_link']; - $info['info_link_id'] = Link::link('projectmanager',$target,'infolog',$info['info_id'],$element['pe_remark'],0,0,1); - unset($info['info_contact']); - // If info_from missing or matches project title, update it if (!$info['info_from'] || $info['info_from'] == Link::title('projectmanager', $info['pm_id'])) { @@ -181,8 +178,6 @@ class infolog_datasource extends datasource if(!($info['info_id'] = $this->infolog_bo->write($info))) return false; $this->infolog_bo->link_id2from($info); - $this->infolog_bo->write($info); - // creating again all links, beside the one to the source-project foreach(Link::get_links('infolog',$element['pe_app_id']) as $link) { @@ -193,13 +188,16 @@ class infolog_datasource extends datasource } Link::link('infolog',$info['info_id'],$link['app'],$link['id'],$link['remark']); } + $this->infolog_bo->write($info); $ret = array($info['info_id'],$info['info_link_id']); - // if we have a parent set, return our callback to modify the parent id, after all entries are copied - if ($info['info_id_parent']) + // if we have a parent set, return our callback to modify the parent id, + // or we have a contact or custom info_from and need to re-set it after + // all entries are copied + if ($info['info_id_parent'] || $info_contact) { $ret[] = array($this,'copy_callback'); // callback - $ret[] = array($info['info_id'],$info['info_id_parent']); // $param + $ret[] = array($info['info_id'],$info['info_id_parent'], $info_contact, $info_from); // $param } return $ret; } @@ -207,6 +205,8 @@ class infolog_datasource extends datasource /** * Callback called after copying of all datasource, used to: * - fix parent id's + * - reset contact if it was a link to another entry (not the project) + * - fix info_from * * @param array $param array($info_id,$info_id_parent) * @param array $apps_copied array('infolog' => array($old_info_id => $new_info_id)) @@ -214,12 +214,22 @@ class infolog_datasource extends datasource public function copy_callback(array $param, array $apps_copied) { //error_log(__METHOD__."(".array2string($param).', '.array2string($apps_copied).')'); - list($info_id,$parent_id) = $param; - if (isset($apps_copied['infolog'][$parent_id]) && ($info = $this->infolog_bo->read($info_id))) + list($info_id,$parent_id, $contact, $from) = $param; + if ($parent_id && isset($apps_copied['infolog'][$parent_id]) && ($info = $this->infolog_bo->read($info_id))) { $info['info_id_parent'] = $apps_copied['infolog'][$parent_id]; $this->infolog_bo->write($info,false,true,true,true); // no default and no notification } + if($contact && $contact['app'] != 'projectmanager' && ($info = $this->infolog_bo->read($info_id))) + { + $info['info_contact'] = $contact; + $this->infolog_bo->write($info,false,true,true,true); // no default and no notification + } + if($from && ($info = $this->infolog_bo->read($info_id))) + { + $info['info_from'] = $from; + $this->infolog_bo->write($info,false,true,true,true); // no default and no notification + } } /** diff --git a/infolog/tests/ProjectTemplateTest.php b/infolog/tests/ProjectTemplateTest.php new file mode 100644 index 0000000000..bc155faf4b --- /dev/null +++ b/infolog/tests/ProjectTemplateTest.php @@ -0,0 +1,170 @@ + 'TEST Template', + 'pm_title' => 'Auto-test for ' . $this->getName(), + 'pm_status' => $status, + 'pm_description' => 'Test project for ' . $this->getName() + ); + + // Save & set modifier, no notifications + try + { + $result = true; + $result = $this->bo->save($project, true, false); + } + catch (\Exception $e) + { + // Something went wrong, we'll just fail + $this->fail($e); + } + + $this->assertFalse((boolean)$result, 'Error making test project'); + $this->assertArrayHasKey('pm_id', $this->bo->data, 'Could not make test project'); + $this->assertThat($this->bo->data['pm_id'], + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + $this->pm_id = $this->bo->data['pm_id']; + + // Add some elements + $this->assertGreaterThan(0, count($GLOBALS['egw_info']['apps']), + 'No apps found to use as projectmanager elements' + ); + + // Make an infolog with a contact + $contact_id = $GLOBALS['egw_info']['user']['person_id']; + $title = Link::title('addressbook', $contact_id); + $this->make_infolog(array( + 'info_contact' => array('app' => 'addressbook', 'id' => $contact_id, 'title' => $title ) + )); + + // Make one with a custom from + $this->make_infolog(array( + 'info_from' => 'Custom from' + )); + + // Need to do this from parent to keep IDs where expected + $this->make_projectmanager(); + + // Force links to run notification now, or we won't get elements since it + // usually waits until Egw::on_shutdown(); + Link::run_notifies(); + + $elements = new \projectmanager_elements_bo($this->bo); + $elements->sync_all($this->pm_id); + + // Make sure all elements are created + $this->checkOriginalElements(false, count($this->elements), "Unable to create all project elements"); + } + + /** + * Make an infolog entry and add it to the project + */ + protected function make_infolog($custom = false) + { + $bo = new \infolog_bo(); + $element = array( + 'info_subject' => "Test infolog for #{$this->pm_id}", + 'info_des' => 'Test element as part of the project for test ' . $this->getName(), + 'info_status' => 'open', + 'pm_id' => $this->pm_id + ); + + if($custom) + { + $element['info_subject'] .= "\tCustomized:\t".\array2string($custom); + $element['info_des'] .= "\nCustomized:\n".\array2string($custom); + $element += $custom; + } + + $element_id = $bo->write($element, true, true, true, true); + $this->elements[] = 'infolog:'.$element_id; + + if($custom) + { + $this->customizations['infolog:'.$element_id] = $custom; + } + } + + /** + * Check that the project elements are present, and have the provided status. + * + * @param String $status + */ + protected function checkClonedElements($clone_id) + { + $element_bo = new \projectmanager_elements_bo(); + $element_bo->pm_id = $clone_id; + $indexed_elements = array(); + $unmatched_elements = $this->elements; + + foreach($element_bo->search(array('pm_id' => $clone_id), false, 'pe_id ASC') as $element) + { + //echo "\tPM:".$element['pm_id'] . ' '. $element['pe_id']."\t".$element['pe_app'] . ':'.$element['pe_app_id'] . "\t".$element['pe_title']."\n".Link::title($element['pe_app'],$element['pe_app_id'])."\n"; + $indexed_elements[$element['pe_app']][] = $element; + } + foreach($this->elements as $key => $_id) + { + list($app, $id) = explode(':', $_id); + + // Don't care about other apps here + if($app !== 'infolog') + { + unset($unmatched_elements[$key]); + continue; + } + + $copied = array_shift($indexed_elements[$app]); + + //echo "$_id:\tCopied element - PM:".$copied['pm_id'] . ' '.$copied['pe_app'] . ':'.$copied['pe_app_id'] . "\t".$copied['pe_title']."\n"; + + $this->assertNotNull($copied, "$app entry $_id did not get copied"); + + // Also check pm_id & info_from + $info_bo = new \infolog_bo(); + $entry = $info_bo->read($copied['pe_app_id']); + $this->assertEquals($clone_id, $entry['pm_id']); + + // Make sure ID is actually different - copied, not linked + $this->assertNotEquals($id, $copied['pe_app_id']); + + unset($unmatched_elements[$key]); + + if($this->customizations[$_id]) + { + $this->assertNotNull($entry); + $this->assertArraySubSet($this->customizations[$_id], $entry); + } + } + + // Check that we found them all + $this->assertEmpty($unmatched_elements, 'Missing copied elements ' . \array2string($unmatched_elements)); + } +} \ No newline at end of file