diff --git a/src/Config.php b/src/Config.php index c1dfa70..7d1bd36 100644 --- a/src/Config.php +++ b/src/Config.php @@ -27,15 +27,35 @@ class Config { */ private $rcOptions; + + public function __construct($taskrc='~/.taskrc', $taskData='~/.task',$rcOptions = [], $bin='task'){ $this->taskrc = $taskrc; $this->bin = $bin; - $this->taskDat = $taskData; - $this->rcOptions = $rcOptions; + $this->taskData = $taskData; + $this->rcOptions = array_merge( + array( + 'rc:' . $this->taskrc, + 'rc.data.location=' . $this->taskData, + 'rc.json.array=true', + 'rc.json.depends.array=true', + 'rc.confirmation=no', + ), + $rcOptions + ); } + public function getTaskBin(){ + return $this->bin; + } + + public function getOptions(){ + return $this->rcOptions; + } + + public function getTaskwarriorInstance(){ $this->taskwarrior = new Taskwarrior($this->taskrc,$this->taskdatadir, [], $this->taskbinfile); diff --git a/src/Exceptions/TaskwarriorCommandException.php b/src/Exceptions/TaskwarriorCommandException.php new file mode 100644 index 0000000..b4c7278 --- /dev/null +++ b/src/Exceptions/TaskwarriorCommandException.php @@ -0,0 +1,7 @@ + diff --git a/src/Plugin.php b/src/Plugin.php index e54ca3e..0ab834a 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -57,24 +57,7 @@ class Plugin extends ServerPlugin { function initialize(Server $server) { $this->server = $server; - $server->on('method:GET', [$this, 'httpGet']); - $server->on('method:OPTIONS', [$this, 'httpOptions']); - $server->on('method:HEAD', [$this, 'httpHead']); - $server->on('method:DELETE', [$this, 'httpDelete']); - $server->on('method:PROPFIND', [$this, 'httpPropFind']); - $server->on('method:PROPPATCH', [$this, 'httpPropPatch']); - $server->on('method:PUT', [$this, 'httpPut']); - $server->on('method:MKCOL', [$this, 'httpMkcol']); - $server->on('method:MOVE', [$this, 'httpMove']); - $server->on('method:COPY', [$this, 'httpCopy']); - $server->on('method:REPORT', [$this, 'httpReport']); - - $server->on('propPatch', [$this, 'propPatchProtectedPropertyCheck'], 90); - $server->on('propPatch', [$this, 'propPatchNodeUpdate'], 200); $server->on('calendarObjectChange', [$this, 'calendarObjectChange']); - //$server->on('propFind', [$this, 'propFind']); - //$server->on('propFind', [$this, 'propFindNode'], 120); - //$server->on('propFind', [$this, 'propFindLate'], 200); } @@ -99,12 +82,16 @@ class Plugin extends ServerPlugin { */ function processCalendarEventForTaskwarrior(Document $vCal){ try { - $this->twCalManager->importTask($vCal->VTODO); + if(isset($vCal->VTODO)){ + $response = $this->twCalManager->importTask($vCal->VTODO); + } } catch(BadRequest $e){ throw new BadRequest($e->getMessage(), null, $e); } catch(Exception $e){ throw new Exception($e->getMessage(), null, $e); } + + return $response; } /** * * This method is triggered whenever there was a calendar object gets @@ -120,704 +107,19 @@ class Plugin extends ServerPlugin { * */ function calendarObjectChange(RequestInterface $request, ResponseInterface $response, Document $vCal, $calendarPath, &$modified, $isNew) { $calendarNode = $this->server->tree->getNodeForPath($calendarPath); + $body = ''; if ($isNew) { try { - $this->processCalendarEventForTaskwarrior($vCal); + $body = $this->processCalendarEventForTaskwarrior($vCal); } catch(Exception\BadRequest $e){ - $response->setStatus(200); - $response->setBody(''); - $response->setHeader('Content-Type', 'text/plain'); $response->setHeader('X-Sabre-Real-Status', $e->getHTTPCode()); } } + $response->setStatus(200); + $response->setBody(''); + $response->setHeader('Content-Type', 'text/plain'); + return false; } - /** - * This is the default implementation for the GET method. - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpGet(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - $node = $this->server->tree->getNodeForPath($path); - - if (!$node instanceof IFile) return; - - $body = $node->get(); - - echo($body); - - } - - /** - * HTTP OPTIONS - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpOptions(RequestInterface $request, ResponseInterface $response) { - - $methods = $this->server->getAllowedMethods($request->getPath()); - echo('httpOptions ' . $response); - - $response->setHeader('Allow', strtoupper(implode(', ', $methods))); - $features = ['1', '3', 'extended-mkcol']; - - foreach ($this->server->getPlugins() as $plugin) { - $features = array_merge($features, $plugin->getFeatures()); - } - - $response->setHeader('DAV', implode(', ', $features)); - $response->setHeader('MS-Author-Via', 'DAV'); - $response->setHeader('Accept-Ranges', 'bytes'); - $response->setHeader('Content-Length', '0'); - $response->setStatus(200); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * HTTP HEAD - * - * This method is normally used to take a peak at a url, and only get the - * HTTP response headers, without the body. This is used by clients to - * determine if a remote file was changed, so they can use a local cached - * version, instead of downloading it again - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpHead(RequestInterface $request, ResponseInterface $response) { - - // This is implemented by changing the HEAD request to a GET request, - // and dropping the response body. - $subRequest = clone $request; - $subRequest->setMethod('GET'); - - try { - $this->server->invokeMethod($subRequest, $response, false); - $response->setBody(''); - } catch (Exception\NotImplemented $e) { - // Some clients may do HEAD requests on collections, however, GET - // requests and HEAD requests _may_ not be defined on a collection, - // which would trigger a 501. - // This breaks some clients though, so we're transforming these - // 501s into 200s. - $response->setStatus(200); - $response->setBody(''); - $response->setHeader('Content-Type', 'text/plain'); - $response->setHeader('X-Sabre-Real-Status', $e->getHTTPCode()); - } - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * HTTP Delete - * - * The HTTP delete method, deletes a given uri - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return void - */ - function httpDelete(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - echo('httpDelete.path ' . $path); - - if (!$this->server->emit('beforeUnbind', [$path])) return false; - $this->server->tree->delete($path); - $this->server->emit('afterUnbind', [$path]); - - $response->setStatus(204); - $response->setHeader('Content-Length', '0'); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * WebDAV PROPFIND - * - * This WebDAV method requests information about an uri resource, or a list of resources - * If a client wants to receive the properties for a single resource it will add an HTTP Depth: header with a 0 value - * If the value is 1, it means that it also expects a list of sub-resources (e.g.: files in a directory) - * - * The request body contains an XML data structure that has a list of properties the client understands - * The response body is also an xml document, containing information about every uri resource and the requested properties - * - * It has to return a HTTP 207 Multi-status status code - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return void - */ - function httpPropFind(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - - $requestBody = $request->getBodyAsString(); - if (strlen($requestBody)) { - try { - $propFindXml = $this->server->xml->expect('{DAV:}propfind', $requestBody); - } catch (ParseException $e) { - throw new BadRequest($e->getMessage(), null, $e); - } - } else { - $propFindXml = new Xml\Request\PropFind(); - $propFindXml->allProp = true; - $propFindXml->properties = []; - } - - $depth = $this->server->getHTTPDepth(1); - // The only two options for the depth of a propfind is 0 or 1 - as long as depth infinity is not enabled - if (!$this->server->enablePropfindDepthInfinity && $depth != 0) $depth = 1; - - $newProperties = $this->server->getPropertiesForPath($path, $propFindXml->properties, $depth); - - // This is a multi-status response - $response->setStatus(207); - $response->setHeader('Content-Type', 'application/xml; charset=utf-8'); - $response->setHeader('Vary', 'Brief,Prefer'); - - // Normally this header is only needed for OPTIONS responses, however.. - // iCal seems to also depend on these being set for PROPFIND. Since - // this is not harmful, we'll add it. - $features = ['1', '3', 'extended-mkcol']; - foreach ($this->server->getPlugins() as $plugin) { - $features = array_merge($features, $plugin->getFeatures()); - } - $response->setHeader('DAV', implode(', ', $features)); - - $prefer = $this->server->getHTTPPrefer(); - $minimal = $prefer['return'] === 'minimal'; - - $data = $this->server->generateMultiStatus($newProperties, $minimal); - echo('httppropfind ' . $data); - - $response->setBody($data); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * WebDAV PROPPATCH - * - * This method is called to update properties on a Node. The request is an XML body with all the mutations. - * In this XML body it is specified which properties should be set/updated and/or deleted - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpPropPatch(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - - try { - $propPatch = $this->server->xml->expect('{DAV:}propertyupdate', $request->getBody()); - } catch (ParseException $e) { - throw new BadRequest($e->getMessage(), null, $e); - } - $newProperties = $propPatch->properties; - - $result = $this->server->updateProperties($path, $newProperties); - - $prefer = $this->server->getHTTPPrefer(); - $response->setHeader('Vary', 'Brief,Prefer'); - - if ($prefer['return'] === 'minimal') { - - // If return-minimal is specified, we only have to check if the - // request was succesful, and don't need to return the - // multi-status. - $ok = true; - foreach ($result as $prop => $code) { - if ((int)$code > 299) { - $ok = false; - } - } - - if ($ok) { - - $response->setStatus(204); - return false; - - } - - } - - $response->setStatus(207); - $response->setHeader('Content-Type', 'application/xml; charset=utf-8'); - - - // Reorganizing the result for generateMultiStatus - $multiStatus = []; - foreach ($result as $propertyName => $code) { - if (isset($multiStatus[$code])) { - $multiStatus[$code][$propertyName] = null; - } else { - $multiStatus[$code] = [$propertyName => null]; - } - } - $multiStatus['href'] = $path; - - $response->setBody( - $this->server->generateMultiStatus([$multiStatus]) - ); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * HTTP PUT method - * - * This HTTP method updates a file, or creates a new one. - * - * If a new resource was created, a 201 Created status code should be returned. If an existing resource is updated, it's a 204 No Content - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpPut(RequestInterface $request, ResponseInterface $response) { - - $body = $request->getBodyAsStream(); - $path = $request->getPath(); - - // Intercepting Content-Range - if ($request->getHeader('Content-Range')) { - /* - An origin server that allows PUT on a given target resource MUST send - a 400 (Bad Request) response to a PUT request that contains a - Content-Range header field. - - Reference: http://tools.ietf.org/html/rfc7231#section-4.3.4 - */ - throw new Exception\BadRequest('Content-Range on PUT requests are forbidden.'); - } - - // Intercepting the Finder problem - if (($expected = $request->getHeader('X-Expected-Entity-Length')) && $expected > 0) { - - /* - Many webservers will not cooperate well with Finder PUT requests, - because it uses 'Chunked' transfer encoding for the request body. - - The symptom of this problem is that Finder sends files to the - server, but they arrive as 0-length files in PHP. - - If we don't do anything, the user might think they are uploading - files successfully, but they end up empty on the server. Instead, - we throw back an error if we detect this. - - The reason Finder uses Chunked, is because it thinks the files - might change as it's being uploaded, and therefore the - Content-Length can vary. - - Instead it sends the X-Expected-Entity-Length header with the size - of the file at the very start of the request. If this header is set, - but we don't get a request body we will fail the request to - protect the end-user. - */ - - // Only reading first byte - $firstByte = fread($body, 1); - if (strlen($firstByte) !== 1) { - throw new Exception\Forbidden('This server is not compatible with OS/X finder. Consider using a different WebDAV client or webserver.'); - } - - // The body needs to stay intact, so we copy everything to a - // temporary stream. - - $newBody = fopen('php://temp', 'r+'); - fwrite($newBody, $firstByte); - stream_copy_to_stream($body, $newBody); - rewind($newBody); - - $body = $newBody; - - } - - if ($this->server->tree->nodeExists($path)) { - - $node = $this->server->tree->getNodeForPath($path); - - // If the node is a collection, we'll deny it - if (!($node instanceof IFile)) throw new Exception\Conflict('PUT is not allowed on non-files.'); - - if (!$this->server->updateFile($path, $body, $etag)) { - return false; - } - - $response->setHeader('Content-Length', '0'); - if ($etag) $response->setHeader('ETag', $etag); - $response->setStatus(204); - - } else { - - $etag = null; - // If we got here, the resource didn't exist yet. - if (!$this->server->createFile($path, $body, $etag)) { - // For one reason or another the file was not created. - return false; - } - - $response->setHeader('Content-Length', '0'); - if ($etag) $response->setHeader('ETag', $etag); - $response->setStatus(201); - - } - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - - /** - * WebDAV MKCOL - * - * The MKCOL method is used to create a new collection (directory) on the server - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpMkcol(RequestInterface $request, ResponseInterface $response) { - - $requestBody = $request->getBodyAsString(); - $path = $request->getPath(); - - if ($requestBody) { - - $contentType = $request->getHeader('Content-Type'); - if (strpos($contentType, 'application/xml') !== 0 && strpos($contentType, 'text/xml') !== 0) { - - // We must throw 415 for unsupported mkcol bodies - throw new Exception\UnsupportedMediaType('The request body for the MKCOL request must have an xml Content-Type'); - - } - - try { - $mkcol = $this->server->xml->expect('{DAV:}mkcol', $requestBody); - } catch (\Sabre\Xml\ParseException $e) { - throw new Exception\BadRequest($e->getMessage(), null, $e); - } - - $properties = $mkcol->getProperties(); - - if (!isset($properties['{DAV:}resourcetype'])) - throw new Exception\BadRequest('The mkcol request must include a {DAV:}resourcetype property'); - - $resourceType = $properties['{DAV:}resourcetype']->getValue(); - unset($properties['{DAV:}resourcetype']); - - } else { - - $properties = []; - $resourceType = ['{DAV:}collection']; - - } - - $mkcol = new MkCol($resourceType, $properties); - - $result = $this->server->createCollection($path, $mkcol); - - if (is_array($result)) { - $response->setStatus(207); - $response->setHeader('Content-Type', 'application/xml; charset=utf-8'); - - $response->setBody( - $this->server->generateMultiStatus([$result]) - ); - - } else { - $response->setHeader('Content-Length', '0'); - $response->setStatus(201); - } - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * WebDAV HTTP MOVE method - * - * This method moves one uri to a different uri. A lot of the actual request processing is done in getCopyMoveInfo - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpMove(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - - $moveInfo = $this->server->getCopyAndMoveInfo($request); - - if ($moveInfo['destinationExists']) { - - if (!$this->server->emit('beforeUnbind', [$moveInfo['destination']])) return false; - - } - if (!$this->server->emit('beforeUnbind', [$path])) return false; - if (!$this->server->emit('beforeBind', [$moveInfo['destination']])) return false; - if (!$this->server->emit('beforeMove', [$path, $moveInfo['destination']])) return false; - - if ($moveInfo['destinationExists']) { - - $this->server->tree->delete($moveInfo['destination']); - $this->server->emit('afterUnbind', [$moveInfo['destination']]); - - } - - $this->server->tree->move($path, $moveInfo['destination']); - - // Its important afterMove is called before afterUnbind, because it - // allows systems to transfer data from one path to another. - // PropertyStorage uses this. If afterUnbind was first, it would clean - // up all the properties before it has a chance. - $this->server->emit('afterMove', [$path, $moveInfo['destination']]); - $this->server->emit('afterUnbind', [$path]); - $this->server->emit('afterBind', [$moveInfo['destination']]); - - // If a resource was overwritten we should send a 204, otherwise a 201 - $response->setHeader('Content-Length', '0'); - $response->setStatus($moveInfo['destinationExists'] ? 204 : 201); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * WebDAV HTTP COPY method - * - * This method copies one uri to a different uri, and works much like the MOVE request - * A lot of the actual request processing is done in getCopyMoveInfo - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpCopy(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - - $copyInfo = $this->server->getCopyAndMoveInfo($request); - - if (!$this->server->emit('beforeBind', [$copyInfo['destination']])) return false; - if ($copyInfo['destinationExists']) { - if (!$this->server->emit('beforeUnbind', [$copyInfo['destination']])) return false; - $this->server->tree->delete($copyInfo['destination']); - } - - $this->server->tree->copy($path, $copyInfo['destination']); - $this->server->emit('afterBind', [$copyInfo['destination']]); - - // If a resource was overwritten we should send a 204, otherwise a 201 - $response->setHeader('Content-Length', '0'); - $response->setStatus($copyInfo['destinationExists'] ? 204 : 201); - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - - } - - /** - * HTTP REPORT method implementation - * - * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253) - * It's used in a lot of extensions, so it made sense to implement it into the core. - * - * @param RequestInterface $request - * @param ResponseInterface $response - * @return bool - */ - function httpReport(RequestInterface $request, ResponseInterface $response) { - - $path = $request->getPath(); - - $result = $this->server->xml->parse( - $request->getBody(), - $request->getUrl(), - $rootElementName - ); - - if ($this->server->emit('report', [$rootElementName, $result, $path])) { - - // If emit returned true, it means the report was not supported - throw new Exception\ReportNotSupported(); - - } - - // Sending back false will interupt the event chain and tell the server - // we've handled this method. - return false; - - } - - /** - * This method is called during property updates. - * - * Here we check if a user attempted to update a protected property and - * ensure that the process fails if this is the case. - * - * @param string $path - * @param PropPatch $propPatch - * @return void - */ - function propPatchProtectedPropertyCheck($path, PropPatch $propPatch) { - - // Comparing the mutation list to the list of propetected properties. - $mutations = $propPatch->getMutations(); - - $protected = array_intersect( - $this->server->protectedProperties, - array_keys($mutations) - ); - - if ($protected) { - $propPatch->setResultCode($protected, 403); - } - - } - - /** - * This method is called during property updates. - * - * Here we check if a node implements IProperties and let the node handle - * updating of (some) properties. - * - * @param string $path - * @param PropPatch $propPatch - * @return void - */ - function propPatchNodeUpdate($path, PropPatch $propPatch) { - - // This should trigger a 404 if the node doesn't exist. - $node = $this->server->tree->getNodeForPath($path); - - if ($node instanceof IProperties) { - $node->propPatch($propPatch); - } - - } - - /** - * This method is called when properties are retrieved. - * - * Here we add all the default properties. - * - * @param PropFind $propFind - * @param INode $node - * @return void - */ - function propFind(PropFind $propFind, INode $node) { - - - } - - /** - * Fetches properties for a node. - * - * This event is called a bit later, so plugins have a chance first to - * populate the result. - * - * @param PropFind $propFind - * @param INode $node - * @return void - */ - function propFindNode(PropFind $propFind, INode $node) { - - if ($node instanceof IProperties && $propertyNames = $propFind->get404Properties()) { - - $nodeProperties = $node->getProperties($propertyNames); - foreach ($propertyNames as $propertyName) { - if (array_key_exists($propertyName, $nodeProperties)) { - $propFind->set($propertyName, $nodeProperties[$propertyName], 200); - } - } - - } - - } - - /** - * This method is called when properties are retrieved. - * - * This specific handler is called very late in the process, because we - * want other systems to first have a chance to handle the properties. - * - * @param PropFind $propFind - * @param INode $node - * @return void - */ - function propFindLate(PropFind $propFind, INode $node) { - - $propFind->handle('{http://calendarserver.org/ns/}getctag', function() use ($propFind) { - - // If we already have a sync-token from the current propFind - // request, we can re-use that. - $val = $propFind->get('{http://sabredav.org/ns}sync-token'); - if ($val) return $val; - - $val = $propFind->get('{DAV:}sync-token'); - if ($val && is_scalar($val)) { - return $val; - } - if ($val && $val instanceof Xml\Property\Href) { - return substr($val->getHref(), strlen(Sync\Plugin::SYNCTOKEN_PREFIX)); - } - - // If we got here, the earlier two properties may simply not have - // been part of the earlier request. We're going to fetch them. - $result = $this->server->getProperties($propFind->getPath(), [ - '{http://sabredav.org/ns}sync-token', - '{DAV:}sync-token', - ]); - - if (isset($result['{http://sabredav.org/ns}sync-token'])) { - return $result['{http://sabredav.org/ns}sync-token']; - } - if (isset($result['{DAV:}sync-token'])) { - $val = $result['{DAV:}sync-token']; - if (is_scalar($val)) { - return $val; - } elseif ($val instanceof Xml\Property\Href) { - return substr($val->getHref(), strlen(Sync\Plugin::SYNCTOKEN_PREFIX)); - } - } - - }); - - } /** * Returns a bunch of meta-data about the plugin. diff --git a/src/Taskwarrior/Commands/IStrategy.php b/src/Taskwarrior/Commands/IStrategy.php index 020ca18..569a010 100644 --- a/src/Taskwarrior/Commands/IStrategy.php +++ b/src/Taskwarrior/Commands/IStrategy.php @@ -3,8 +3,9 @@ namespace Aerex\TaskwarriorPlugin\Taskwarrior\Commands; use Aerex\TaskwarriorPlugin\Taskwarrior\Task; -interface Strategy { +interface IStrategy { public function add(Task $task); + public function count(Task $task); } ?> diff --git a/src/Taskwarrior/Commands/TodoStrategy.php b/src/Taskwarrior/Commands/TodoStrategy.php index 64a035e..f96d15f 100644 --- a/src/Taskwarrior/Commands/TodoStrategy.php +++ b/src/Taskwarrior/Commands/TodoStrategy.php @@ -1,60 +1,78 @@ config = $config; - $this->cmd[] = $this->config->taskBin(); } public function add(Task $task){ - $this->cmd[] = 'add'; + $cmd[] = $this->config->getTaskBin(); + $cmd[] = 'add'; if($task->getDescription() != null){ - $this->cmd[] = sprintf('"%s"', $task->getDescription()); + $cmd[] = sprintf('"%s"', (string)$task->getDescription()); } if($task->getCategories() != null){ - $categories = implode(' +', $task->getCategories()); - $this->cmd[] = $categories; + $categories = implode(' +', (string)$task->getCategories()); + $cmd[] = $categories; } if($task->getDue() != null){ - $this->cmd[] = $task->getDue('Y-m-dTH:i:s'); + $cmd[] = sprintf("due:%s",$task->getDue('Y-m-dTH:i:s')); } if($task->getRecurrence() != null){ $rrule = $task->getRecurrence()->getParts(); - $this->cmd[] = sprintf('recur:%s', $rrule['FREQ']); + $cmd[] = sprintf('recur:%s', $rrule['FREQ']); if(isset($rrule['UNTIL'])){ - $this->cmd[] = sprintf('until:%s', $rrule['UNTIL']); + $cmd[] = sprintf('until:%s', $rrule['UNTIL']); } } if($task->getStatus() != null){ - $this->cmd[] = sprintf('status:%s', $task->getStatus()); + $cmd[] = sprintf('status:%s', (string)$task->getStatus()); } return $this->executeCommand($cmd); } + public function count($uuid){ + $cmd[] = $this->config->getTaskBin(); + $cmd[] = sprintf('%s count', $uuid); + return $this->executeCommand($cmd); + } + private function executeCommand($command){ + $rcOptions = $this->config->getOptions(); + foreach ($rcOptions as $rcOption) { + $command[] = $rcOption; + } $cmdString = implode(' ', $command); + echo $cmdString; $process = new Process($cmdString); $process->run(); if(!$process->isSuccessful()){ + echo $process; throw new TaskwarriorCommandLineException($process); } + // clear cmd queue + $this->cmd = []; return $process->getOutput(); } diff --git a/src/Taskwarrior/Task.php b/src/Taskwarrior/Task.php index eb6ff2b..b57e977 100644 --- a/src/Taskwarrior/Task.php +++ b/src/Taskwarrior/Task.php @@ -13,118 +13,100 @@ class Task { /** * @var string - * - * @JMS\Type("string") */ private $uuid; /** * @var string * - * @JMS\Type("string") */ private $description; /** * @var string * - * @JMS\Type("string") */ private $priority; /** * @var string * - * @JMS\Type("string") */ private $project; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $due; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $wait; /** * @var array * - * @JMS\Type("array") */ private $tags; /** * @var float * - * @JMS\Type("float") */ private $urgency; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $entry; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $start; /** * @var string * - * @JMS\Type("Recurring") */ private $recur; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $until; /** * @var Annotation[] * - * @JMS\Type("array") */ private $annotations = []; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $modified; /** * @var Carbon * - * @JMS\Type("Carbon") */ private $end; /** * @var string * - * @JMS\Type("string") */ private $status; /** - * @var Task[]|ArrayCollection * * @JMS\Type("Depends") */ @@ -144,10 +126,13 @@ class Task { } + public function getUuid(){ + return $this->uuid; + } + /** * - * {@inheritDoc} * * If description is not available attempt to summary, otherwise throw Exception */ @@ -155,7 +140,7 @@ public function setDescription(VTodo $component){ if(!isset($component->DESCRIPTION) && isset($component->SUMMARY)){ $this->description = $component->SUMMARY; } else if(!isset($component->DESCRIPTION) && !isset($component->SUMMARY)){ - throw new Exception("Task must have a description or summary"); + throw new Exception('Task must have a description or summary'); } else { $this->description = $component->DESCRIPTION; } @@ -247,6 +232,11 @@ public function setStatus(VTodo $document){ } } +public function getRecurrence(){ + return $this->recur; + +} + public function setRecurrence(VTodo $document){ if(isset($document->RRULE)){ $this->recur = $document->RRULE; diff --git a/src/Taskwarrior/Taskwarrior.php b/src/Taskwarrior/Taskwarrior.php index 4266a6c..c5dcd63 100644 --- a/src/Taskwarrior/Taskwarrior.php +++ b/src/Taskwarrior/Taskwarrior.php @@ -7,9 +7,6 @@ use Aerex\TaskwarriorPlugin\Config; class Taskwarrior { - const EXPORT = 'export'; - const IMPORT = 'import'; - const ADD = 'add'; /** * @var TaskwarriorConfig @@ -26,6 +23,7 @@ class Taskwarrior { */ private $taskrc; + /** * @var string */ @@ -36,6 +34,11 @@ class Taskwarrior { */ private $rcOptions; + /** + * @var IStrategy + */ + + private $strategy; /** * @var string */ @@ -58,9 +61,14 @@ class Taskwarrior { public function add($task){ - $this->strategy($task); + $this->strategy->add($task); } + public function count($uuid){ + return $this->strategy->cound($uuid); + } + + } diff --git a/src/Taskwarrior/TaskwarriorManager.php b/src/Taskwarrior/TaskwarriorManager.php index 6014722..fa489f0 100644 --- a/src/Taskwarrior/TaskwarriorManager.php +++ b/src/Taskwarrior/TaskwarriorManager.php @@ -8,17 +8,11 @@ use Sabre\VObject\Component\VTodo; class TaskwarriorManager { - const DESCRIPTION = 'description'; - const CATEGORIES = 'categories'; - const TASK_UUID = 'uuid'; - const ICAL_UID = 'uid'; - private $tasks; - - const ENTRY = 'entry'; - const START = 'start'; - const MODIFIED = 'modified'; - const END = 'end'; + /** + * @var TodoStrategy + */ + private $todoStrategy; public function __construct($taskwarrior){ if(!isset($taskwarrior)){ @@ -26,39 +20,29 @@ class TaskwarriorManager { } else { $this->taskwarrior = $taskwarrior; } + // Initialize strategies + $this->todoStrategy = new TodoStrategy($this->taskwarrior->getConfig()); } - public function createTask($UUID){ - $task = new Task(); - } - - public function export(VTodo $document){ - - } public function addTask(VTodo $document){ + $this->taskwarrior->setStrategy($this->todoStrategy); - $task = $this->taskwarrior->createTask((string)$document->UID); + $task = $this->taskwarrior->createTask((string)$document->UID); - $task->setDescription($document); + $task->setDescription($document); - $task->setEntry($document); + $task->setEntryTime($document); - $task->setStartTime($document); + $task->setDue($document); - $task->setModifiedTime($document); + $task->setCategories($document); - $task->setStopTime($document); + $task->setStatus($document); - $task->setDue($document); + $task->setRecurrence($document); - $task->setCategories($document); - - $task->setStatus($document); - - $task->setRecurrence($document); - - return $this->taskwarrior->add($task); + return $this->taskwarrior->add($task); } @@ -89,73 +73,11 @@ class TaskwarriorManager { return $upatedTask; } - - function setEntryTime($entry){ - } - - function exists($UUID){} - - function setEndTime($end){} - function setModifiedTime($modifiedTime){} - function setSummary($description){ - if(!isset($description)){ - return; - } - $this->taskWarriorJSON[self::DESCRIPTION] = $description; - } - - function setStartTime($startTime){} - function setCategories($categories){ - if(!isset($categories)){ - return; - } - - if(!is_array($catergories)){ - return; - } - - $this->taskWarriorJSON[self::CATEGORIES] = $categories; - } - - - public function taskExists($taskUuid){ - $taskIsInCache = isset($this->cachedTasks[$taskUuid]); - - if($taskIsInCache){ - return true; - } - - $jsonArray = $this->taskwarrior->export($taskUuid); - $taskWithUuidExists = count($jsonArray) > 0; - - return $taskWithUuidExists; - + $this->taskwarrior->setStrategy($this->$todoStrategy); + return $this->taskwarrior->count((string)$taskUuid); } - public function save(){ - - } - public function build(){ - - } - /** - * @param Task $task - * @param string $attr - * @param mixed $value - */ - public function setValue(Task $task, $attr, $value) - { - $refClass = new \ReflectionClass(Task::class); - $refProp = $refClass->getProperty($attr); - $refProp->setAccessible(true); - $refProp->setValue($task, $value); - } - - - function setDescription($description){} - function parseiCalDateTime($iCalDateTime){} - function convertToStringArray($categories){} } ?>