mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-23 23:29:31 +01:00
Improvements for entry widget for robustness, includes automatic server side tests.
This commit is contained in:
parent
88b7c91b42
commit
d0b57cfccd
@ -138,7 +138,12 @@ var et2_entry = (function(){ "use strict"; return et2_valueWidget.extend(
|
||||
// If value was set, find the record explicitly.
|
||||
if(typeof this.options.value == 'string')
|
||||
{
|
||||
widget.options.value = this.getRoot().getArrayMgr('content').getEntry(this.prefix+this.options.value + '['+this.options.field+']');
|
||||
widget.options.value = this.getArrayMgr('content').getEntry(this.id+'['+this.options.field+']') ||
|
||||
this.getRoot().getArrayMgr('content').getEntry(this.prefix+this.options.value + '['+this.options.field+']');
|
||||
}
|
||||
else if (this.options.field && this.options.value && this.options.value[this.options.field])
|
||||
{
|
||||
widget.options.value = this.options.value[this.options.field];
|
||||
}
|
||||
if(this.options.compare)
|
||||
{
|
||||
|
@ -530,6 +530,7 @@ class Etemplate extends Etemplate\Widget\Template
|
||||
public static function reset_request()
|
||||
{
|
||||
self::$request = Etemplate\Request::read();
|
||||
self::$cache = array();
|
||||
}
|
||||
/**
|
||||
* Get template data as array
|
||||
|
@ -70,7 +70,8 @@ abstract class Entry extends Transformer
|
||||
$attrs['id'] = $this->id;
|
||||
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$data_id = $attrs['value'] ? self::form_name($cname, $attrs['value']) : self::form_name($cname, self::ID_PREFIX . $this->id);
|
||||
$prefixed_id = (substr($this->id, 0, 1) == self::ID_PREFIX ? $this->id : self::ID_PREFIX . $this->id);
|
||||
$data_id = $attrs['value'] ? self::form_name($cname, $attrs['value']) : self::form_name($cname, $prefixed_id);
|
||||
|
||||
// No need to proceed
|
||||
if(!$data_id) return;
|
||||
@ -94,8 +95,8 @@ abstract class Entry extends Transformer
|
||||
}
|
||||
|
||||
// Set the new value so transformer can find it. Use prefix to avoid changing the original value
|
||||
$new_value =& self::get_array(self::$request->content, self::ID_PREFIX .$this->id, true, false);
|
||||
if (true) $new_value = $data;
|
||||
$new_value =& self::get_array(self::$request->content, $prefixed_id, true, false);
|
||||
if ($data) $new_value = $data;
|
||||
|
||||
// Check for missing field
|
||||
if(!$attrs['field'] && !$attrs['alternate_fields'])
|
||||
@ -109,10 +110,15 @@ abstract class Entry extends Transformer
|
||||
|
||||
$this->regex($attrs, $new_value);
|
||||
|
||||
// Change this before parent so client gets what it needs
|
||||
// Client is expecting to find data with the prefix
|
||||
if(substr($this->id, 0, 1) !== self::ID_PREFIX)
|
||||
{
|
||||
$this->id = self::ID_PREFIX . $this->id . "[{$attrs['field']}]";
|
||||
}
|
||||
|
||||
parent::beforeSendToClient($cname, $expand);
|
||||
|
||||
// Change this after parent::beforeSendToClient or it adds another layer
|
||||
$this->id = self::ID_PREFIX . $this->id . "[{$attrs['field']}]";
|
||||
|
||||
}
|
||||
|
||||
@ -173,7 +179,8 @@ abstract class Entry extends Transformer
|
||||
protected function customfield($attrs, &$data)
|
||||
{
|
||||
list($app, $type) = explode('-',$attrs['type']);
|
||||
$id = is_array($data) ? static::get_array($data, $this->id) : $data;
|
||||
$data_id = $attrs['value'] ?: $attrs['id'];
|
||||
$id = is_array($data) ? static::get_array($data, $data_id) : $data;
|
||||
if(!$app || !$type || !$GLOBALS['egw_info']['apps'][$app] || !$id ||
|
||||
// Simple CF, already there
|
||||
$data[$attrs['field']]
|
||||
@ -207,9 +214,10 @@ abstract class Entry extends Transformer
|
||||
*/
|
||||
protected function regex($attrs, &$data)
|
||||
{
|
||||
$id = is_array($data) ? static::get_array($data, $this->id) : $data;
|
||||
$data_id = $attrs['value'] ?: $attrs['id'];
|
||||
$id = is_array($data) ? static::get_array($data, $data_id) : $data;
|
||||
$value =& $this->get_data_field($attrs, $data);
|
||||
if(!$attrs['regex'] || !$id || !$value)
|
||||
if(!$attrs['regex'] || !$value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -221,6 +229,6 @@ abstract class Entry extends Transformer
|
||||
$replace = array_pop($regex);
|
||||
$regex = implode(',', $regex);
|
||||
}
|
||||
$value = preg_replace($regex, $replace, $value);
|
||||
$data[$attrs['field']] = preg_replace($regex, $replace, $value);
|
||||
}
|
||||
}
|
25
api/templates/test/entry_test.xet
Normal file
25
api/templates/test/entry_test.xet
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||
<!--
|
||||
This template is used in automated testing
|
||||
|
||||
Most of these need the client side for full functionality, so this is also a
|
||||
list of patterns to test.
|
||||
|
||||
-->
|
||||
<overlay>
|
||||
<template id="api.entry_test" template="" lang="" group="0" version="19.1">
|
||||
<!-- Nice, unique ID with value and field specified -->
|
||||
<entry id="widget" value="entry_id" field="entry_field_1"/>
|
||||
|
||||
<!--No value attribute, will fallback to ID and succeed-->
|
||||
<entry id="entry_id" field="entry_field_2"/>
|
||||
|
||||
<!--No value attribute, ID does not match anything in content, will fallback to ID and fail-->
|
||||
<entry id="no_value" field="entry_field_3"/>
|
||||
|
||||
<!-- Checking compare - should render as X -->
|
||||
<entry id="compare" value="entry_id" field="entry_num_2" compare="2"/>
|
||||
|
||||
</template>
|
||||
</overlay>
|
27
api/templates/test/entry_test_contact.xet
Normal file
27
api/templates/test/entry_test_contact.xet
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE overlay PUBLIC "-//EGroupware GmbH//eTemplate 2//EN" "http://www.egroupware.org/etemplate2.dtd">
|
||||
<!--
|
||||
This template is used in automated testing
|
||||
|
||||
Most of these need the client side for full functionality, so this is also a
|
||||
list of patterns to test.
|
||||
|
||||
-->
|
||||
<overlay>
|
||||
<template id="api.entry_test_contact" template="" lang="" group="0" version="19.1">
|
||||
<!-- Nice, unique ID with value and field specified -->
|
||||
<contact-value id="widget" value="entry_id" field="email"/>
|
||||
|
||||
<!--No value attribute, will fallback to ID and succeed-->
|
||||
<contact-value id="entry_id" field="n_fn"/>
|
||||
|
||||
<!--No value attribute, ID does not match anything in content, will fallback to ID and fail-->
|
||||
<contact-value id="no_value" field="email"/>
|
||||
|
||||
<!-- These are all the same -->
|
||||
<contact-value id="info_contact_email" value="info_contact" options="email"/>
|
||||
<contact-value id="info_contact_email" value="info_contact" field="email"/>
|
||||
<contact-value id="info_contact" options="email"/>
|
||||
|
||||
</template>
|
||||
</overlay>
|
139
api/tests/Etemplate/Widget/ContactEntryTest.php
Normal file
139
api/tests/Etemplate/Widget/ContactEntryTest.php
Normal file
@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Test for contact entry widget, which displays the value of a particular field
|
||||
* (specified by field attribute) from a particular contact (specified
|
||||
* by value attribute).
|
||||
*
|
||||
* This is just the server side, client has it's own issues (but no automatic test)
|
||||
* see infolog/templates/test/entry_test.xet for a test template to use for
|
||||
* manual client side verification.
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @package api
|
||||
* @copyright (c) 2019 Nathan Gray
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Etemplate\Widget;
|
||||
|
||||
require_once realpath(__DIR__.'/../WidgetBaseTest.php');
|
||||
|
||||
use EGroupware\Api\Etemplate;
|
||||
|
||||
class EntryTest extends \EGroupware\Api\Etemplate\WidgetBaseTest {
|
||||
|
||||
const TEST_TEMPLATE = 'api.entry_test_contact';
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
// Delete all elements
|
||||
foreach($this->elements as $id)
|
||||
{
|
||||
list($app, $id) = explode(':',$id);
|
||||
|
||||
$bo_class = "{$app}_bo";
|
||||
$bo = new $bo_class();
|
||||
$bo->delete($id, true, false, true);
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the correct value is extracted, based on the value attribute,
|
||||
* or if it is missing try the ID. This goes to contact, rather than
|
||||
* abstract test class.
|
||||
*/
|
||||
public function testContact()
|
||||
{
|
||||
// Create a test contact
|
||||
$test_contact = $this->make_contact();
|
||||
|
||||
// Instanciate the template
|
||||
$etemplate = new Etemplate();
|
||||
$etemplate->read(static::TEST_TEMPLATE, 'test');
|
||||
|
||||
// Content - IDs are important, they should match valid contacts
|
||||
$content = array(
|
||||
'entry_id' => $GLOBALS['egw_info']['user']['person_id'],
|
||||
'info_contact' => $test_contact
|
||||
);
|
||||
|
||||
$result = $this->mockedExec($etemplate, $content);
|
||||
$data = array();
|
||||
foreach($result as $response)
|
||||
{
|
||||
if($response['type'] == 'et2_load')
|
||||
{
|
||||
$data = $response['data']['data'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the entry was found
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'info_contact_email']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'info_contact']);
|
||||
$this->assertEmpty($data['content'][Entry::ID_PREFIX.'no_value']);
|
||||
|
||||
// Check that the value is present - exact value is pulled client side
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']['email']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']['n_fn']);
|
||||
|
||||
$this->assertEquals($GLOBALS['egw_info']['user']['account_email'], $data['content'][Entry::ID_PREFIX.'entry_id']['email']);
|
||||
$this->assertEquals($GLOBALS['egw_info']['user']['account_fullname'], $data['content'][Entry::ID_PREFIX.'entry_id']['n_fn']);
|
||||
|
||||
// Values are to be done as labels
|
||||
$this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'widget[email]']['type'], 'Unexpected widget type');
|
||||
$this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'entry_id[n_fn]']['type'], 'Unexpected widget type');
|
||||
$this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'info_contact_email[email]']['type'], 'Unexpected widget type');
|
||||
$this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'info_contact[email]']['type'], 'Unexpected widget type');
|
||||
$this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'no_value[email]']['type'], 'Unexpected widget type');
|
||||
|
||||
// No errors
|
||||
$this->assertEmpty($data['validation_errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a contact so we can test
|
||||
*/
|
||||
protected function make_contact()
|
||||
{
|
||||
$bo = new \addressbook_bo();
|
||||
$element = array(
|
||||
'n_fn' => "Mr Test Guy",
|
||||
'n_family' => 'Guy',
|
||||
'n_fileas' => 'Test Organisation: Guy, Test',
|
||||
'n_given' => 'Test',
|
||||
'n_prefix' => 'Mr',
|
||||
'org_name' => 'Test Organisation',
|
||||
'tel_cell' => '555-4321',
|
||||
'tel_home' => '66 12 34 56',
|
||||
'bday' => "1995-07-28T10:52:54Z"
|
||||
);
|
||||
$element_id = $bo->save($element, true, true, true, true);
|
||||
$this->elements[] = 'addressbook:'.$element_id;
|
||||
return $element_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testable entry widget
|
||||
*/
|
||||
class EntryTestWidget extends \EGroupware\Api\Etemplate\Widget\Entry
|
||||
{
|
||||
public function get_entry($value, array $attrs)
|
||||
{
|
||||
$entry = EntryTest::getEntry($value, $attrs);
|
||||
|
||||
return $entry;
|
||||
}
|
||||
}
|
138
api/tests/Etemplate/Widget/EntryTest.php
Normal file
138
api/tests/Etemplate/Widget/EntryTest.php
Normal file
@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Test for special entry widget, which displays the value of a particular field
|
||||
* (specified by field attribute) from a particular egroupware entry (specified
|
||||
* by value attribute).
|
||||
*
|
||||
* Just simple stuff here, the overriding classes have their own tests.
|
||||
*
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @author Nathan Gray
|
||||
* @package api
|
||||
* @copyright (c) 2019 Nathan Gray
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Etemplate\Widget;
|
||||
|
||||
require_once realpath(__DIR__.'/../WidgetBaseTest.php');
|
||||
|
||||
use EGroupware\Api\Etemplate;
|
||||
|
||||
class EntryTest extends \EGroupware\Api\Etemplate\WidgetBaseTest {
|
||||
|
||||
const TEST_TEMPLATE = 'api.entry_test';
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
Etemplate::registerWidget(EntryTestWidget::class, 'entry');
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
Etemplate::reset_request();
|
||||
}
|
||||
public static function getEntry($value, $attrs)
|
||||
{
|
||||
$entry = array();
|
||||
|
||||
$entry['7'] = array(
|
||||
'entry_id' => 7,
|
||||
'entry_field_1' => 'Field 1',
|
||||
'entry_field_2' => 'Field 2',
|
||||
'entry_field_3' => 'Field 3',
|
||||
'entry_num_1' => 1,
|
||||
'entry_num_2' => 2,
|
||||
'entry_num_3' => 3,
|
||||
'entry_date' => '2018-11-12'
|
||||
);
|
||||
return $entry[$value];
|
||||
}
|
||||
/**
|
||||
* Test that the correct value is extracted, based on the value attribute,
|
||||
* or if it is missing try the ID
|
||||
*/
|
||||
public function testValueAttr()
|
||||
{
|
||||
// Instanciate the template
|
||||
$etemplate = new Etemplate();
|
||||
$etemplate->read(static::TEST_TEMPLATE, 'test');
|
||||
|
||||
// Content - entry ID is important, it should match what getEntry() gives
|
||||
$content = array(
|
||||
'entry_id' => '7',
|
||||
'not_entry_id' => '123'
|
||||
);
|
||||
|
||||
$result = $this->mockedExec($etemplate, $content);
|
||||
$data = array();
|
||||
foreach($result as $response)
|
||||
{
|
||||
if($response['type'] == 'et2_load')
|
||||
{
|
||||
$data = $response['data']['data'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the entry was found
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']);
|
||||
|
||||
// Check that the entry was not found
|
||||
$this->assertEmpty($data['content'][Entry::ID_PREFIX.'no_value']);
|
||||
|
||||
// Check that the value is present - exact value is pulled client side
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']['entry_field_1']);
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']['entry_field_2']);
|
||||
|
||||
// No errors
|
||||
$this->assertEmpty($data['validation_errors']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check on compare attribute.
|
||||
* Actual comparison is done client side, but here we check that the value is found.
|
||||
*/
|
||||
public function testCompareAttr()
|
||||
{
|
||||
// Instanciate the template
|
||||
$etemplate = new Etemplate();
|
||||
$etemplate->read(static::TEST_TEMPLATE, 'test');
|
||||
|
||||
// Content - entry ID is important, it should match what getEntry() gives
|
||||
$content = array(
|
||||
'entry_id' => '7',
|
||||
);
|
||||
|
||||
$result = $this->mockedExec($etemplate, $content);
|
||||
$data = array();
|
||||
foreach($result as $response)
|
||||
{
|
||||
if($response['type'] == 'et2_load')
|
||||
{
|
||||
$data = $response['data']['data'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the value is present - exact value is pulled client side
|
||||
$this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'compare']['entry_num_1']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testable entry widget
|
||||
*/
|
||||
class EntryTestWidget extends \EGroupware\Api\Etemplate\Widget\Entry
|
||||
{
|
||||
public function get_entry($value, array $attrs)
|
||||
{
|
||||
$entry = EntryTest::getEntry($value, $attrs);
|
||||
|
||||
return $entry;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user