Skip to content

Commit 4140aea

Browse files
committed
Add request time
1 parent af12141 commit 4140aea

File tree

4 files changed

+326
-0
lines changed

4 files changed

+326
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
3+
*
4+
* @license GNU AGPL version 3 or any later version
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as
8+
* published by the Free Software Foundation, either version 3 of the
9+
* License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*
19+
*/
20+
21+
(function() {
22+
23+
OCA.WorkflowEngine = OCA.WorkflowEngine || {};
24+
OCA.WorkflowEngine.Plugins = OCA.WorkflowEngine.Plugins || {};
25+
26+
OCA.WorkflowEngine.Plugins.RequestTimePlugin = {
27+
getCheck: function() {
28+
return {
29+
'class': 'OCA\\WorkflowEngine\\Check\\RequestTime',
30+
'name': t('workflowengine', 'Request time'),
31+
'operators': [
32+
{'operator': 'in', 'name': t('workflowengine', 'between')},
33+
{'operator': '!in', 'name': t('workflowengine', 'not between')}
34+
]
35+
};
36+
},
37+
render: function(element, check) {
38+
if (check['class'] !== 'OCA\\WorkflowEngine\\Check\\RequestTime') {
39+
return;
40+
}
41+
42+
var placeholder = '["10:00 Europe\\/Berlin","16:00 Europe\\/Berlin"]'; // FIXME need a time picker JS plugin
43+
$(element).css('width', '300px')
44+
.attr('placeholder', placeholder)
45+
.attr('title', t('workflowengine', 'Example: {placeholder}', {placeholder: placeholder}, undefined, {escape: false}))
46+
.addClass('has-tooltip')
47+
.tooltip({
48+
placement: 'bottom'
49+
});
50+
}
51+
};
52+
})();
53+
54+
OC.Plugins.register('OCA.WorkflowEngine.CheckPlugins', OCA.WorkflowEngine.Plugins.RequestTimePlugin);

apps/workflowengine/lib/AppInfo/Application.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ function() {
5959
'filesizeplugin',
6060
'filesystemtagsplugin',
6161
'requestremoteaddressplugin',
62+
'requesttimeplugin',
6263
'requesturlplugin',
6364
'requestuseragentplugin',
6465
'usergroupmembershipplugin',
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
4+
*
5+
* @license GNU AGPL version 3 or any later version
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
*/
21+
22+
namespace OCA\WorkflowEngine\Check;
23+
24+
25+
use OCP\AppFramework\Utility\ITimeFactory;
26+
use OCP\Files\Storage\IStorage;
27+
use OCP\WorkflowEngine\ICheck;
28+
29+
class RequestTime implements ICheck {
30+
31+
const REGEX_TIME = '([0-1][0-9]|2[0-3]):([0-5][0-9])';
32+
const REGEX_TIMEZONE = '([a-zA-Z]+(?:\\\\\\/[a-zA-Z\-\_]+)+)';
33+
34+
/** @var bool[] */
35+
protected $cachedResults;
36+
37+
/** @var ITimeFactory */
38+
protected $timeFactory;
39+
40+
/**
41+
* @param ITimeFactory $timeFactory
42+
*/
43+
public function __construct(ITimeFactory $timeFactory) {
44+
$this->timeFactory = $timeFactory;
45+
}
46+
47+
/**
48+
* @param IStorage $storage
49+
* @param string $path
50+
*/
51+
public function setFileInfo(IStorage $storage, $path) {
52+
// A different path doesn't change time, so nothing to do here.
53+
}
54+
55+
/**
56+
* @param string $operator
57+
* @param string $value
58+
* @return bool
59+
*/
60+
public function executeCheck($operator, $value) {
61+
$valueHash = md5($value);
62+
63+
if (isset($this->cachedResults[$valueHash])) {
64+
return $this->cachedResults[$valueHash];
65+
}
66+
67+
$timestamp = $this->timeFactory->getTime();
68+
69+
$values = json_decode($value, true);
70+
$timestamp1 = $this->getTimestamp($timestamp, $values[0]);
71+
$timestamp2 = $this->getTimestamp($timestamp, $values[1]);
72+
73+
if ($timestamp1 < $timestamp2) {
74+
$in = $timestamp1 <= $timestamp && $timestamp <= $timestamp2;
75+
} else {
76+
$in = $timestamp1 <= $timestamp || $timestamp <= $timestamp2;
77+
}
78+
79+
return ($operator === 'in') ? $in : !$in;
80+
}
81+
82+
/**
83+
* @param int $currentTimestamp
84+
* @param string $value Format: "H:i e"
85+
* @return int
86+
*/
87+
protected function getTimestamp($currentTimestamp, $value) {
88+
list($time1, $timezone1) = explode(' ', $value);
89+
list($hour1, $minute1) = explode(':', $time1);
90+
$date1 = new \DateTime('now', new \DateTimeZone($timezone1));
91+
$date1->setTimestamp($currentTimestamp);
92+
$date1->setTime($hour1, $minute1);
93+
94+
return $date1->getTimestamp();
95+
}
96+
97+
/**
98+
* @param string $operator
99+
* @param string $value
100+
* @throws \UnexpectedValueException
101+
*/
102+
public function validateCheck($operator, $value) {
103+
if (!in_array($operator, ['in', '!in'])) {
104+
throw new \UnexpectedValueException('Invalid operator', 1);
105+
}
106+
107+
$regexValue = '\"' . self::REGEX_TIME . ' ' . self::REGEX_TIMEZONE . '\"';
108+
$result = preg_match('/^\[' . $regexValue . ',' . $regexValue . '\]$/', $value, $matches);
109+
if (!$result) {
110+
throw new \UnexpectedValueException('Invalid time limits', 2);
111+
}
112+
113+
try {
114+
new \DateTimeZone(stripslashes($matches[3]));
115+
} catch(\Exception $e) {
116+
throw new \UnexpectedValueException('Invalid timezone1', 3);
117+
}
118+
119+
try {
120+
new \DateTimeZone(stripslashes($matches[6]));
121+
} catch(\Exception $e) {
122+
throw new \UnexpectedValueException('Invalid timezone2', 3);
123+
}
124+
}
125+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com>
4+
*
5+
* @license GNU AGPL version 3 or any later version
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU Affero General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
*/
21+
22+
namespace OCA\WorkflowEngine\Tests\Check;
23+
24+
25+
class RequestTimeTest extends \Test\TestCase {
26+
27+
/** @var \OCP\AppFramework\Utility\ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */
28+
protected $timeFactory;
29+
30+
protected function setUp() {
31+
parent::setUp();
32+
33+
$this->timeFactory = $this->getMockBuilder('OCP\AppFramework\Utility\ITimeFactory')
34+
->getMock();
35+
}
36+
37+
public function dataExecuteCheck() {
38+
return [
39+
[json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin']), 1467870105, false], // 2016-07-07T07:41:45+02:00
40+
[json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin']), 1467873705, true], // 2016-07-07T08:41:45+02:00
41+
[json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin']), 1467902505, true], // 2016-07-07T16:41:45+02:00
42+
[json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin']), 1467906105, false], // 2016-07-07T17:41:45+02:00
43+
[json_encode(['17:00 Europe/Berlin', '08:00 Europe/Berlin']), 1467870105, true], // 2016-07-07T07:41:45+02:00
44+
[json_encode(['17:00 Europe/Berlin', '08:00 Europe/Berlin']), 1467873705, false], // 2016-07-07T08:41:45+02:00
45+
[json_encode(['17:00 Europe/Berlin', '08:00 Europe/Berlin']), 1467902505, false], // 2016-07-07T16:41:45+02:00
46+
[json_encode(['17:00 Europe/Berlin', '08:00 Europe/Berlin']), 1467906105, true], // 2016-07-07T17:41:45+02:00
47+
48+
[json_encode(['08:00 Australia/Adelaide', '17:00 Australia/Adelaide']), 1467843105, false], // 2016-07-07T07:41:45+09:30
49+
[json_encode(['08:00 Australia/Adelaide', '17:00 Australia/Adelaide']), 1467846705, true], // 2016-07-07T08:41:45+09:30
50+
[json_encode(['08:00 Australia/Adelaide', '17:00 Australia/Adelaide']), 1467875505, true], // 2016-07-07T16:41:45+09:30
51+
[json_encode(['08:00 Australia/Adelaide', '17:00 Australia/Adelaide']), 1467879105, false], // 2016-07-07T17:41:45+09:30
52+
[json_encode(['17:00 Australia/Adelaide', '08:00 Australia/Adelaide']), 1467843105, true], // 2016-07-07T07:41:45+09:30
53+
[json_encode(['17:00 Australia/Adelaide', '08:00 Australia/Adelaide']), 1467846705, false], // 2016-07-07T08:41:45+09:30
54+
[json_encode(['17:00 Australia/Adelaide', '08:00 Australia/Adelaide']), 1467875505, false], // 2016-07-07T16:41:45+09:30
55+
[json_encode(['17:00 Australia/Adelaide', '08:00 Australia/Adelaide']), 1467879105, true], // 2016-07-07T17:41:45+09:30
56+
57+
[json_encode(['08:00 Pacific/Niue', '17:00 Pacific/Niue']), 1467916905, false], // 2016-07-07T07:41:45-11:00
58+
[json_encode(['08:00 Pacific/Niue', '17:00 Pacific/Niue']), 1467920505, true], // 2016-07-07T08:41:45-11:00
59+
[json_encode(['08:00 Pacific/Niue', '17:00 Pacific/Niue']), 1467949305, true], // 2016-07-07T16:41:45-11:00
60+
[json_encode(['08:00 Pacific/Niue', '17:00 Pacific/Niue']), 1467952905, false], // 2016-07-07T17:41:45-11:00
61+
[json_encode(['17:00 Pacific/Niue', '08:00 Pacific/Niue']), 1467916905, true], // 2016-07-07T07:41:45-11:00
62+
[json_encode(['17:00 Pacific/Niue', '08:00 Pacific/Niue']), 1467920505, false], // 2016-07-07T08:41:45-11:00
63+
[json_encode(['17:00 Pacific/Niue', '08:00 Pacific/Niue']), 1467949305, false], // 2016-07-07T16:41:45-11:00
64+
[json_encode(['17:00 Pacific/Niue', '08:00 Pacific/Niue']), 1467952905, true], // 2016-07-07T17:41:45-11:00
65+
];
66+
}
67+
68+
/**
69+
* @dataProvider dataExecuteCheck
70+
* @param string $value
71+
* @param int $timestamp
72+
* @param bool $expected
73+
*/
74+
public function testExecuteCheckIn($value, $timestamp, $expected) {
75+
$check = new \OCA\WorkflowEngine\Check\RequestTime($this->timeFactory);
76+
77+
$this->timeFactory->expects($this->once())
78+
->method('getTime')
79+
->willReturn($timestamp);
80+
81+
$this->assertEquals($expected, $check->executeCheck('in', $value));
82+
}
83+
84+
/**
85+
* @dataProvider dataExecuteCheck
86+
* @param string $value
87+
* @param int $timestamp
88+
* @param bool $expected
89+
*/
90+
public function testExecuteCheckNotIn($value, $timestamp, $expected) {
91+
$check = new \OCA\WorkflowEngine\Check\RequestTime($this->timeFactory);
92+
93+
$this->timeFactory->expects($this->once())
94+
->method('getTime')
95+
->willReturn($timestamp);
96+
97+
$this->assertEquals(!$expected, $check->executeCheck('!in', $value));
98+
}
99+
100+
public function dataValidateCheck() {
101+
return [
102+
['in', json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin'])],
103+
['!in', json_encode(['08:00 Europe/Berlin', '17:00 America/North_Dakota/Beulah'])],
104+
['in', json_encode(['08:00 America/Port-au-Prince', '17:00 America/Argentina/San_Luis'])],
105+
];
106+
}
107+
108+
/**
109+
* @dataProvider dataValidateCheck
110+
* @param string $operator
111+
* @param string $value
112+
*/
113+
public function testValidateCheck($operator, $value) {
114+
$check = new \OCA\WorkflowEngine\Check\RequestTime($this->timeFactory);
115+
$check->validateCheck($operator, $value);
116+
}
117+
118+
public function dataValidateCheckInvalid() {
119+
return [
120+
['!!in', json_encode(['08:00 Europe/Berlin', '17:00 Europe/Berlin']), 1, 'Invalid operator'],
121+
['in', json_encode(['28:00 Europe/Berlin', '17:00 Europe/Berlin']), 2, 'Invalid time limits'],
122+
['in', json_encode(['08:00 Europa/Berlin', '17:00 Europe/Berlin']), 3, 'Invalid timezone1'],
123+
['in', json_encode(['08:00 Europe/Berlin', '17:00 Europa/Berlin']), 3, 'Invalid timezone2'],
124+
['in', json_encode(['08:00 Europe/Bearlin', '17:00 Europe/Berlin']), 3, 'Invalid timezone1'],
125+
['in', json_encode(['08:00 Europe/Berlin', '17:00 Europe/Bearlin']), 3, 'Invalid timezone2'],
126+
];
127+
}
128+
129+
/**
130+
* @dataProvider dataValidateCheckInvalid
131+
* @param string $operator
132+
* @param string $value
133+
* @param int $exceptionCode
134+
* @param string $exceptionMessage
135+
*/
136+
public function testValidateCheckInvalid($operator, $value, $exceptionCode, $exceptionMessage) {
137+
$check = new \OCA\WorkflowEngine\Check\RequestTime($this->timeFactory);
138+
139+
try {
140+
$check->validateCheck($operator, $value);
141+
} catch (\UnexpectedValueException $e) {
142+
$this->assertEquals($exceptionCode, $e->getCode());
143+
$this->assertEquals($exceptionMessage, $e->getMessage());
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)