diff --git a/config.yaml b/config.yaml
index 407cae9..48b276c 100755
--- a/config.yaml
+++ b/config.yaml
@@ -4,4 +4,4 @@ logger:
taskwarrior:
taskdata: /home/aerex/.task
taskrc: /home/aerex/.taskrc
- project_tag_suffix: project_
+ project_category_prefix: project_
diff --git a/lib/Browser.php b/lib/Browser.php
new file mode 100644
index 0000000..40cfd35
--- /dev/null
+++ b/lib/Browser.php
@@ -0,0 +1,10 @@
+end()
->end()
->end()
- ->scalarNode('timezone')
- ->defaultValue('UTC')
- ->validate()
- ->IfNotInArray(CarbonTimeZone::listIdentifiers())
- ->thenInvalid('Invalid timezone identifier %s')
- ->end()
- ->end()
- ->end()
+ ->end()
->end()
->arrayNode('storages')
->children();
@@ -67,4 +59,9 @@ class ConfigBuilder implements ConfigurationInterface {
$parseContents = Yaml::parse($contents);
return $this->processor->processConfiguration($this, [$parseContents]);
}
+
+ public function saveConfigs($configs) {
+ $yaml = Yaml::dump($configs, 3, 2);
+ file_put_contents($this->configFile, $yaml);
+ }
}
diff --git a/lib/Configs/TaskwarriorConfig.php b/lib/Configs/TaskwarriorConfig.php
index f80fb03..e02fcc0 100644
--- a/lib/Configs/TaskwarriorConfig.php
+++ b/lib/Configs/TaskwarriorConfig.php
@@ -11,12 +11,15 @@ class TaskwarriorConfig {
->children()
->scalarNode('taskdata')
->defaultValue('~/.task')
+ ->info('The environment variable overrides the default and the command line, and the "data.location" configuration setting of the task data directory')
->end()
->scalarNode('taskrc')
->defaultValue('~/.taskrc')
+ ->info('The enivronment variable overrides the default and the command line specification of the .taskrc file')
->end()
- ->scalarNode('project_tag_suffix')
+ ->scalarNode('project_category_prefix')
->defaultValue('project_')
+ ->info('The word after the given prefix for a iCal category will be used to identify a task\'s project')
->end()
->end();
diff --git a/lib/Logger.php b/lib/Logger.php
index b01e9b9..3043d3b 100644
--- a/lib/Logger.php
+++ b/lib/Logger.php
@@ -69,4 +69,10 @@ class Logger {
}
}
+ public function setLevel($level) {
+ if ($this->configs['enabled']) {
+ $this->logger->setLevel($level);
+ }
+ }
+
}
diff --git a/lib/Plugin.php b/lib/Plugin.php
index 5e2fcea..b5cca28 100644
--- a/lib/Plugin.php
+++ b/lib/Plugin.php
@@ -3,6 +3,7 @@
namespace Aerex\BaikalStorage;
use Aerex\BaikalStorage\Logger;
+use Monolog\Logger as Monolog;
use Aerex\BaikalStorage\Storages\Taskwarrior;
use Aerex\BaikalStorage\Configs\ConfigBuilder;
use Aerex\BaikalStorage\Configs\TaskwarriorConfig;
@@ -32,6 +33,9 @@ class Plugin extends ServerPlugin {
*/
protected $storageManager;
+ protected $rawConfigs;
+
+
/**
* Creates the Storage plugin
@@ -40,9 +44,9 @@ class Plugin extends ServerPlugin {
*
*/
function __construct($configFile){
- $configs = $this->buildConfigurations($configFile);
- $this->storageManager = new StorageManager($configs);
- $this->initializeStorages($configs);
+ $this->rawConfigs = $this->buildConfigurations($configFile);
+ $this->storageManager = new StorageManager($this->rawConfigs);
+ $this->initializeStorages($this->rawConfigs);
}
public function buildConfigurations($configFile) {
@@ -57,7 +61,7 @@ class Plugin extends ServerPlugin {
*/
public function initializeStorages($configs) {
- $taskwarrior = new Taskwarrior(new Console(['rc.verbose=nothing', 'rc.hooks=off']), $configs, new Logger($configs, 'Taskwarrior'););
+ $taskwarrior = new Taskwarrior(new Console(['rc.verbose=nothing', 'rc.hooks=off']), $configs, new Logger($configs, 'Taskwarrior'));
$this->storageManager->addStorage(Taskwarrior::NAME, $taskwarrior);
}
@@ -82,14 +86,13 @@ class Plugin extends ServerPlugin {
*/
function getPluginName() {
- return 'taskwarrior';
+ return 'baikal-storage';
}
/**
* This method is called before any HTTP method handler.
*
- * This method intercepts any GET, DELETE, PUT and PROPFIND calls to
- * filenames that are known to match the 'temporary file' regex.
+ * This method intercepts any GET, DELETE, PUT and PROPFIND.
*
* @param RequestInterface $request
* @param ResponseInterface $response
@@ -102,8 +105,11 @@ class Plugin extends ServerPlugin {
switch ($request->getMethod()) {
case 'PUT':
$this->httpPut($request, $response);
+ break;
+ case 'POST':
+ $this->httpPost($request, $response);
+ return;
}
- return;
}
@@ -130,6 +136,111 @@ class Plugin extends ServerPlugin {
}
+ /**
+ * This method handles the POST method.
+ *
+ * @param RequestInterface $request
+ *
+ * @return bool
+ */
+ function httpPost(RequestInterface $request, ResponseInterface $response) {
+ $postVars = $request->getPostData();
+ $body = $request->getBodyAsString();
+ if (isset($postVars['baikalStorage'])) {
+ foreach ($this->storageManager->getStorages() as $storage) {
+ if ($storage::NAME == $postVars['baikalStorage']
+ && $postVars['baikalStorageAction'] == 'saveConfigs') {
+ $updateStorageConfigs = $storage->updateConfigs($postVars);
+ $this->rawConfigs['storages'][$postVars['baikalStorage']] = $updateStorageConfigs;
+ }
+ }
+
+ }
+ if (isset($postVars['logLevel'])) {
+ $this->rawConfigs['general']['logger']['level'] = $postVars['logLevel'];
+ }
+ if (isset($postVars['logFilePath'])) {
+ $this->rawConfigs['general']['logger']['file'] = $postVars['logFilePath'];
+ }
+
+ $this->config->saveConfigs($this->rawConfigs);
+
+ $response->setHeader('Location', $request->getUrl());
+ $response->setStatus(302);
+ $request->setBody($body);
+
+
+ }
+
+ /**
+ * Generates the 'general' configuration section
+ * @return string
+ */
+
+ public function generateGeneralConfigSection() {
+ $configuredLogLevel = '';
+ $logFilePath = '';
+ if (isset($this->rawConfigs['general'])
+ && isset($this->rawConfigs['general']['logger'])
+ && $this->rawConfigs['general']['logger']['enabled']) {
+ $configuredLogLevel = $this->rawConfigs['general']['logger']['level'];
+ $logFilePath = $this->rawConfigs['general']['logger']['file'];
+ }
+ $html = '
';
+ }
+
+ return $html;
+ }
+
/**
* Returns a bunch of meta-data about the plugin.
*
@@ -147,6 +258,7 @@ class Plugin extends ServerPlugin {
'name' => $this->getPluginName(),
'description' => 'The plugin provides synchronization between taskwarrior tasks and iCAL events',
'link' => null,
+ 'config' => true
];
}
diff --git a/lib/Storages/IStorage.php b/lib/Storages/IStorage.php
index f35407f..7b4233f 100644
--- a/lib/Storages/IStorage.php
+++ b/lib/Storages/IStorage.php
@@ -7,5 +7,6 @@ use Sabre\VObject\Component\VCalendar as Calendar;
interface IStorage {
public function save(Calendar $c);
public function refresh();
- public function getConfig();
+ public function getConfigBrowser();
+ public function updateConfigs($postData);
}
diff --git a/lib/Storages/Taskwarrior.php b/lib/Storages/Taskwarrior.php
index 996c108..cb57b78 100644
--- a/lib/Storages/Taskwarrior.php
+++ b/lib/Storages/Taskwarrior.php
@@ -3,8 +3,6 @@
namespace Aerex\BaikalStorage\Storages;
use Sabre\VObject\Component\VCalendar as Calendar;
-use Carbon\Carbon;
-use Carbon\CarbonTimeZone;
class Taskwarrior implements IStorage {
@@ -12,17 +10,52 @@ class Taskwarrior implements IStorage {
private $tasks = [];
private $configs;
private $logger;
- private $tz;
public function __construct($console, $configs, $logger) {
$this->console = $console;
$this->configs = $configs['storages']['taskwarrior'];
$this->logger = $logger;
- $this->tz = new CarbonTimeZone($configs['general']['timezone']);
}
- public function getConfig() {
- return $this->config;
+ public function getConfigBrowser() {
+ $html = '';
+ $html .= 'taskrc | ';
+ $html .= 'The enivronment variable overrides the default and the command line specification of the .taskrc file | ';
+ $html .= ' | ';
+ $html .= '
';
+ $html = '';
+ $html .= 'taskrc | ';
+ $html .= 'The enivronment variable overrides the default and the command line specification of the .taskrc file | ';
+ $html .= ' | ';
+ $html .= '
';
+ $html .= '';
+ $html .= 'taskdata | ';
+ $html .= 'The environment variable overrides the default and the command line, and the "data.location" configuration setting of the task data directory | ';
+ $html .= ' | ';
+ $html .= '
';
+ $html .= '';
+ $html .= 'project_category_prefix | ';
+ $html .= "The word after the given prefix for a iCal category will be used to identify a task's project | ";
+ $html .= ' | ';
+ $html .= '
';
+ return $html;
+ }
+
+ public function updateConfigs($postData) {
+ if (isset($postData['tw_taskrc'])) {
+ $this->configs['taskrc'] = $postData['tw_taskrc'];
+ }
+
+ if (isset($postData['tw_taskdata'])){
+ $this->configs['taskdata'] = $postData['tw_taskdata'];
+ }
+
+ if (isset($postData['tw_project_category_prefix'])){
+ $this->configs['project_category_prefix'] = $postData['tw_project_category_prefix'];
+ }
+
+ return $this->configs;
+
}
public function refresh() {
@@ -48,24 +81,41 @@ class Taskwarrior implements IStorage {
if (isset($vtodo->SUMMARY)){
$task['description'] = (string)$vtodo->SUMMARY;
- } else if(isset($vtodo->DESCRIPTION)) {
- $task['description'] = (string)$vtodo->DESCRIPTION;
- }
-
- if (isset($vtodo->DTSTAMP)){
- $task['entry'] = new Carbon($vtodo->DTSTAMP->getDateTime()->format(\DateTime::W3C), $this->tz);
}
+ if (isset($vtodo->DESCRIPTION)) {
+ $annotations = [];
+ if (isset($task['annotations'])) {
+ $annotations = $task['annotations'];
+ }
+ $task['annotations'] = [];
+ $descriptionLines = explode('\n', $vtodo->DESCRIPTION);
+ foreach ($descriptionLines as $key => $descriptionLine) {
+ $annotationEntry = $vtodo->DTSTAMP->getDateTime()->modify("+$key second")->format(\DateTime::ISO8601);
+ foreach ($annotations as $annotation) {
+ if ($annotation['description'] == $descriptionLine) {
+ $annotationEntry = $annotation['entry'];
+ break;
+ }
+ }
+ array_push(['description' => $descriptionLine, 'entry' => $annotationEntry]);
+ }
+ }
+
+ if (!isset($task['entry'])){
+ $task['entry'] = $vtodo->DTSTAMP->getDateTime()->format(\DateTime::ISO8601);
+ }
+
if (isset($vtodo->DTSTART)) {
- $task['start'] = new Carbon($vtodo->DTSTART->getDateTime()->format(\DateTime::W3C), $this->tz);
+ $task['start'] = $vtodo->DTSTART->getDateTime()->format(\DateTime::ISO8601);
}
if (isset($vtodo->DTEND)){
- $task['end'] = new Carbon($vtodo->DTEND->getDateTime()->format(\DateTime::W3C), $this->tz);
+ $task['end'] = $vtodo->DTEND->getDateTime()->format(\DateTime::ISO8601);
}
if (isset($vtodo->{'LAST-MODIFIED'})) {
- $task['modified'] = new Carbon($vtodo->{'LAST-MODIFIED'}->getDateTime()->format(\DateTime::W3C), $this->tz);
+ $task['modified'] = $vtodo->{'LAST-MODIFIED'}->getDateTime()->format(\DateTime::ISO8601);
}
if (isset($vtodo->PRIORITY)) {
@@ -80,7 +130,7 @@ class Taskwarrior implements IStorage {
}
if (isset($vtodo->DUE)){
- $task['due'] = new Carbon($vtodo->DUE->getDateTime());
+ $task['due'] = $vtodo->DUE->getDateTime()->format(\DateTime::ISO8601);
}
if (isset($vtodo->RRULE)) {
@@ -101,13 +151,13 @@ class Taskwarrior implements IStorage {
case 'COMPLETED':
$task['status'] = 'completed';
if (!isset($task['end'])) {
- $task['end'] = new Carbon($vtodo->DTSTAMP->getDateTime()->format(\DateTime::W3C), $this->tz);
+ $task['end'] = $vtodo->DTSTAMP->getDateTime()->format(\DateTime::ISO8601);
}
break;
case 'CANCELED':
$task['status'] = 'deleted';
if (!isset($task['end'])) {
- $task['end'] = new Carbon($vtodo->DTSTAMP->getDateTime()->format(\DateTime::W3C), $this->tz);
+ $task['end'] = $vtodo->DTSTAMP->getDateTime()->format(\DateTime::ISO8601);
}
break;
}
@@ -116,8 +166,8 @@ class Taskwarrior implements IStorage {
if (isset($vtodo->CATEGORIES)) {
$task['tags'] = [];
foreach ($vtodo->CATEGORIES as $category) {
- if (isset($this->configs['project_tag_suffix'])) {
- $projTagSuffixRegExp = sprintf('/^%s/', $this->configs['project_tag_suffix']);
+ if (isset($this->configs['project_category_prefix'])) {
+ $projTagSuffixRegExp = sprintf('/^%s/', $this->configs['project_category_prefix']);
if (preg_match($projTagSuffixRegExp, $category)) {
$task['project'] = preg_replace($projTagSuffixRegExp, '', $category);
continue;
@@ -127,6 +177,15 @@ class Taskwarrior implements IStorage {
}
}
+ if (isset($vtodo->{'RELATED-TO'}) && isset($this->tasks[(string)$vtodo->{'RELATED-TO'}])) {
+ $relatedTask = $this->tasks[(string)$vtodo->{'RELATED-TO'}];
+ $task['depends'] = $relatedTask['uuid'];
+ }
+
+ if (isset($vtodo->GEO)){
+ $task['geo'] = $vtodo->GEO->getRawMimeDirValue();
+ }
+
return $task;
}
diff --git a/tests/Configs/ConfigTest.php b/tests/Configs/ConfigTest.php
index cd094d3..983b482 100644
--- a/tests/Configs/ConfigTest.php
+++ b/tests/Configs/ConfigTest.php
@@ -26,8 +26,6 @@ class ConfigTest extends TestCase {
$this->assertEquals($generalConfigs['logger']['level'], 'ERROR', 'ERROR is not set as default logger level');
$this->assertArrayHasKey('enabled', $generalConfigs['logger'], 'general config logger enabled property is missing');
$this->assertTrue($generalConfigs['logger']['enabled']);
- $this->assertArrayHasKey('timezone', $generalConfigs, 'general config is missing timezone property');
- $this->assertEquals($generalConfigs['timezone'], 'UTC', 'UTC is not set as default timezone');
}
public function testTaskwarriorConfig() {
@@ -42,8 +40,8 @@ class ConfigTest extends TestCase {
$this->assertEquals($taskwarriorConfigs['taskrc'], '/home/aerex/.taskrc');
$this->assertArrayHasKey('taskdata', $taskwarriorConfigs, 'taskwarrior config is missing taskdata property');
$this->assertEquals($taskwarriorConfigs['taskdata'], '/home/aerex/.task');
- $this->assertArrayHasKey('project_tag_suffix', $taskwarriorConfigs, 'taskwarrior config is missing project_tag_suffix property');
- $this->assertEquals($taskwarriorConfigs['project_tag_suffix'], 'project_');
+ $this->assertArrayHasKey('project_category_prefix', $taskwarriorConfigs, 'taskwarrior config is missing project_category_prefix property');
+ $this->assertEquals($taskwarriorConfigs['project_category_prefix'], 'project_');
}
}
diff --git a/tests/Configs/Fixtures/TaskwarriorConfig.yaml b/tests/Configs/Fixtures/TaskwarriorConfig.yaml
index 3fca2dc..65f8f3f 100755
--- a/tests/Configs/Fixtures/TaskwarriorConfig.yaml
+++ b/tests/Configs/Fixtures/TaskwarriorConfig.yaml
@@ -2,9 +2,8 @@ general:
logger:
file: /home/aerex/baikal-storage-plugin.log
level: DEBUG
- timezone: 'America/Denver'
storages:
taskwarrior:
taskdata: /home/aerex/.task
taskrc: /home/aerex/.taskrc
- project_tag_suffix: project_
+ project_category_prefix: project_
diff --git a/tests/StorageManagerTest.php b/tests/StorageManagerTest.php
index f5a727a..06191df 100644
--- a/tests/StorageManagerTest.php
+++ b/tests/StorageManagerTest.php
@@ -30,8 +30,7 @@ class StorageManagerTest extends TestCase {
$this->mockLogger = $this->createMock(Logger::class);
$this->configs = [
'general' => [
- 'logger' => ['file' => '', 'level'=> 'DEBUG', 'enabled' => true],
- 'timezone' => 'UTC'
+ 'logger' => ['file' => '', 'level'=> 'DEBUG', 'enabled' => true]
],
'storages' => [
'taskwarrior' => ['taskrc' => '', 'taskdata' => '']
@@ -44,7 +43,7 @@ public function testAddTaskwarriorStorage() {
$manager = new StorageManager($this->mockConfigBuilder);
$manager->addStorage(Taskwarrior::NAME, $tw);
$storages = $manager->getStorages();
- $configs = $manager->getConfigs();
+ $this->configs = $manager->getConfigs();
$this->assertEquals(sizeof(array_keys($storages)), 1, 'Taskwarrior storage was not added');
$this->assertArrayHasKey('taskwarrior', $storages, 'Storages should have taskwarrior');
}
diff --git a/tests/Storages/TaskwarriorTest.php b/tests/Storages/TaskwarriorTest.php
index 1e165f7..9e922a3 100644
--- a/tests/Storages/TaskwarriorTest.php
+++ b/tests/Storages/TaskwarriorTest.php
@@ -24,7 +24,6 @@ class TaskwarriorTest extends TestCase {
$configs = [
'general' => [
'logger' => ['file' => '', 'level'=> 'DEBUG', 'enabled' => true],
- 'timezone' => 'UTC'
],
'storages' => [
'taskwarrior' => ['taskrc' => '', 'taskdata' => '']
@@ -50,11 +49,47 @@ class TaskwarriorTest extends TestCase {
$this->assertArrayHasKey('description', $task, 'task should have description');
$this->assertEquals((string)$vcalendar->VTODO->SUMMARY, $task['description']);
$this->assertArrayHasKey('due', $task, 'task should have due');
- $this->assertEquals($vcalendar->VTODO->DUE->getDateTime(), $task['due']);
+ $this->assertEquals($vcalendar->VTODO->DUE->getDateTime()->format(\DateTime::ISO8601), $task['due']);
$this->assertArrayHasKey('entry', $task, 'task should have an entry');
- $this->assertEquals($vcalendar->VTODO->DTSTAMP->getDateTime(), $task['entry']);
+ $this->assertEquals($vcalendar->VTODO->DTSTAMP->getDateTime()->format(\DateTime::ISO8601), $task['entry']);
$this->assertArrayHasKey('start', $task, 'task should have start');
- $this->assertEquals($vcalendar->VTODO->DTSTART->getDateTime(), $task['start']);
+ $this->assertEquals($vcalendar->VTODO->DTSTART->getDateTime()->format(\DateTime::ISO8601), $task['start']);
}
+// public function testVObjectToTaskWithDifferentTimezone() {
+// $configs = [
+// 'general' => [
+// 'logger' => ['file' => '', 'level'=> 'DEBUG', 'enabled' => true],
+// ],
+// 'storages' => [
+// 'taskwarrior' => ['taskrc' => '', 'taskdata' => '']
+// ]
+// ];
+// $this->taskwarrior = new Taskwarrior($this->mockConsole, $configs, $this->mockLogger);
+// $vcalendar = new Calendar([
+// 'VTODO' => [
+// 'SUMMARY' => 'Finish project',
+// 'DTSTAMP' => new \DateTime('2020-07-04 10:00:00'),
+// 'DTSTART' => new \DateTime('2020-07-04 12:00:00'),
+// 'DTEND' => new \DateTime('2020-07-05 01:00:00'),
+// 'DUE' => new \DateTime('2020-07-05 03:00:00'),
+// 'LAST_MODIFIED' => new \DateTime('2020-07-04 13:00:00'),
+// 'PRIORITY' => 5,
+// 'RRULE' => 'FREQ=MONTHLY'
+// ]
+// ]);
+//
+// $task = $this->taskwarrior->vObjectToTask($vcalendar->VTODO);
+// $this->assertArrayHasKey('uid', $task, 'task should have a uid');
+// $this->assertEquals((string)$vcalendar->VTODO->UID, $task['uid']);
+// $this->assertArrayHasKey('description', $task, 'task should have description');
+// $this->assertEquals((string)$vcalendar->VTODO->SUMMARY, $task['description']);
+// $this->assertArrayHasKey('due', $task, 'task should have due');
+// $this->assertEquals($vcalendar->VTODO->DUE->getDateTime(), $task['due']);
+// $this->assertArrayHasKey('entry', $task, 'task should have an entry');
+// $this->assertEquals($vcalendar->VTODO->DTSTAMP->getDateTime(), $task['entry']);
+// $this->assertArrayHasKey('start', $task, 'task should have start');
+// $this->assertEquals($vcalendar->VTODO->DTSTART->getDateTime(), $task['start']);
+//
+// }
}