style: remove unused code and updated plugin

This commit is contained in:
Aerex 2018-11-26 00:58:20 -06:00
parent a2b2073bad
commit 68470e3dee
8 changed files with 108 additions and 840 deletions

View File

@ -28,14 +28,34 @@ class Config {
private $rcOptions; private $rcOptions;
public function __construct($taskrc='~/.taskrc', $taskData='~/.task',$rcOptions = [], $bin='task'){ public function __construct($taskrc='~/.taskrc', $taskData='~/.task',$rcOptions = [], $bin='task'){
$this->taskrc = $taskrc; $this->taskrc = $taskrc;
$this->bin = $bin; $this->bin = $bin;
$this->taskDat = $taskData; $this->taskData = $taskData;
$this->rcOptions = $rcOptions; $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(){ public function getTaskwarriorInstance(){
$this->taskwarrior = new Taskwarrior($this->taskrc,$this->taskdatadir, [], $this->taskbinfile); $this->taskwarrior = new Taskwarrior($this->taskrc,$this->taskdatadir, [], $this->taskbinfile);

View File

@ -0,0 +1,7 @@
<?php
class TaskwarriorCommandException extends Exception {
}
?>

View File

@ -57,24 +57,7 @@ class Plugin extends ServerPlugin {
function initialize(Server $server) { function initialize(Server $server) {
$this->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('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){ function processCalendarEventForTaskwarrior(Document $vCal){
try { try {
$this->twCalManager->importTask($vCal->VTODO); if(isset($vCal->VTODO)){
$response = $this->twCalManager->importTask($vCal->VTODO);
}
} catch(BadRequest $e){ } catch(BadRequest $e){
throw new BadRequest($e->getMessage(), null, $e); throw new BadRequest($e->getMessage(), null, $e);
} catch(Exception $e){ } catch(Exception $e){
throw new Exception($e->getMessage(), null, $e); throw new Exception($e->getMessage(), null, $e);
} }
return $response;
} }
/** /**
* * This method is triggered whenever there was a calendar object gets * * This method is triggered whenever there was a calendar object gets
@ -120,703 +107,18 @@ class Plugin extends ServerPlugin {
* */ * */
function calendarObjectChange(RequestInterface $request, ResponseInterface $response, Document $vCal, $calendarPath, &$modified, $isNew) { function calendarObjectChange(RequestInterface $request, ResponseInterface $response, Document $vCal, $calendarPath, &$modified, $isNew) {
$calendarNode = $this->server->tree->getNodeForPath($calendarPath); $calendarNode = $this->server->tree->getNodeForPath($calendarPath);
$body = '';
if ($isNew) { if ($isNew) {
try { try {
$this->processCalendarEventForTaskwarrior($vCal); $body = $this->processCalendarEventForTaskwarrior($vCal);
} catch(Exception\BadRequest $e){ } catch(Exception\BadRequest $e){
$response->setStatus(200);
$response->setBody('');
$response->setHeader('Content-Type', 'text/plain');
$response->setHeader('X-Sabre-Real-Status', $e->getHTTPCode()); $response->setHeader('X-Sabre-Real-Status', $e->getHTTPCode());
} }
} }
}
/**
* 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->setStatus(200);
$response->setBody(''); $response->setBody('');
$response->setHeader('Content-Type', 'text/plain'); $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; 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));
}
}
});
} }
/** /**

View File

@ -3,8 +3,9 @@ namespace Aerex\TaskwarriorPlugin\Taskwarrior\Commands;
use Aerex\TaskwarriorPlugin\Taskwarrior\Task; use Aerex\TaskwarriorPlugin\Taskwarrior\Task;
interface Strategy { interface IStrategy {
public function add(Task $task); public function add(Task $task);
public function count(Task $task);
} }
?> ?>

View File

@ -1,60 +1,78 @@
<?php <?php
namespace Aerex\TaskwarriorPlugin\Taskwarrior\Commands;
use Aerex\TaskwarriorPlugin\Taskwarrior\Task;
use Aerex\TaskwarriorPlugin\Config;
use Symfony\Component\Process\Process;
class TodoStrategy implements IStrategy { class TodoStrategy implements IStrategy {
public function __construct(TaskwarriorConfig $config){ public function __construct(TaskwarriorConfig $config){
$this->config = $config; $this->config = $config;
$this->cmd[] = $this->config->taskBin();
} }
public function add(Task $task){ public function add(Task $task){
$this->cmd[] = 'add'; $cmd[] = $this->config->getTaskBin();
$cmd[] = 'add';
if($task->getDescription() != null){ if($task->getDescription() != null){
$this->cmd[] = sprintf('"%s"', $task->getDescription()); $cmd[] = sprintf('"%s"', (string)$task->getDescription());
} }
if($task->getCategories() != null){ if($task->getCategories() != null){
$categories = implode(' +', $task->getCategories()); $categories = implode(' +', (string)$task->getCategories());
$this->cmd[] = $categories; $cmd[] = $categories;
} }
if($task->getDue() != null){ 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){ if($task->getRecurrence() != null){
$rrule = $task->getRecurrence()->getParts(); $rrule = $task->getRecurrence()->getParts();
$this->cmd[] = sprintf('recur:%s', $rrule['FREQ']); $cmd[] = sprintf('recur:%s', $rrule['FREQ']);
if(isset($rrule['UNTIL'])){ if(isset($rrule['UNTIL'])){
$this->cmd[] = sprintf('until:%s', $rrule['UNTIL']); $cmd[] = sprintf('until:%s', $rrule['UNTIL']);
} }
} }
if($task->getStatus() != null){ if($task->getStatus() != null){
$this->cmd[] = sprintf('status:%s', $task->getStatus()); $cmd[] = sprintf('status:%s', (string)$task->getStatus());
} }
return $this->executeCommand($cmd); 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){ private function executeCommand($command){
$rcOptions = $this->config->getOptions();
foreach ($rcOptions as $rcOption) {
$command[] = $rcOption;
}
$cmdString = implode(' ', $command); $cmdString = implode(' ', $command);
echo $cmdString;
$process = new Process($cmdString); $process = new Process($cmdString);
$process->run(); $process->run();
if(!$process->isSuccessful()){ if(!$process->isSuccessful()){
echo $process;
throw new TaskwarriorCommandLineException($process); throw new TaskwarriorCommandLineException($process);
} }
// clear cmd queue
$this->cmd = [];
return $process->getOutput(); return $process->getOutput();
} }

View File

@ -13,118 +13,100 @@ class Task {
/** /**
* @var string * @var string
*
* @JMS\Type("string")
*/ */
private $uuid; private $uuid;
/** /**
* @var string * @var string
* *
* @JMS\Type("string")
*/ */
private $description; private $description;
/** /**
* @var string * @var string
* *
* @JMS\Type("string")
*/ */
private $priority; private $priority;
/** /**
* @var string * @var string
* *
* @JMS\Type("string")
*/ */
private $project; private $project;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $due; private $due;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $wait; private $wait;
/** /**
* @var array * @var array
* *
* @JMS\Type("array<string>")
*/ */
private $tags; private $tags;
/** /**
* @var float * @var float
* *
* @JMS\Type("float")
*/ */
private $urgency; private $urgency;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $entry; private $entry;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $start; private $start;
/** /**
* @var string * @var string
* *
* @JMS\Type("Recurring")
*/ */
private $recur; private $recur;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $until; private $until;
/** /**
* @var Annotation[] * @var Annotation[]
* *
* @JMS\Type("array<Aerex\Taskwarrior\Annotation>")
*/ */
private $annotations = []; private $annotations = [];
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $modified; private $modified;
/** /**
* @var Carbon * @var Carbon
* *
* @JMS\Type("Carbon")
*/ */
private $end; private $end;
/** /**
* @var string * @var string
* *
* @JMS\Type("string")
*/ */
private $status; private $status;
/** /**
* @var Task[]|ArrayCollection
* *
* @JMS\Type("Depends") * @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 * 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)){ if(!isset($component->DESCRIPTION) && isset($component->SUMMARY)){
$this->description = $component->SUMMARY; $this->description = $component->SUMMARY;
} else if(!isset($component->DESCRIPTION) && !isset($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 { } else {
$this->description = $component->DESCRIPTION; $this->description = $component->DESCRIPTION;
} }
@ -247,6 +232,11 @@ public function setStatus(VTodo $document){
} }
} }
public function getRecurrence(){
return $this->recur;
}
public function setRecurrence(VTodo $document){ public function setRecurrence(VTodo $document){
if(isset($document->RRULE)){ if(isset($document->RRULE)){
$this->recur = $document->RRULE; $this->recur = $document->RRULE;

View File

@ -7,9 +7,6 @@ use Aerex\TaskwarriorPlugin\Config;
class Taskwarrior { class Taskwarrior {
const EXPORT = 'export';
const IMPORT = 'import';
const ADD = 'add';
/** /**
* @var TaskwarriorConfig * @var TaskwarriorConfig
@ -26,6 +23,7 @@ class Taskwarrior {
*/ */
private $taskrc; private $taskrc;
/** /**
* @var string * @var string
*/ */
@ -36,6 +34,11 @@ class Taskwarrior {
*/ */
private $rcOptions; private $rcOptions;
/**
* @var IStrategy
*/
private $strategy;
/** /**
* @var string * @var string
*/ */
@ -58,9 +61,14 @@ class Taskwarrior {
public function add($task){ public function add($task){
$this->strategy($task); $this->strategy->add($task);
} }
public function count($uuid){
return $this->strategy->cound($uuid);
}
} }

View File

@ -8,17 +8,11 @@ use Sabre\VObject\Component\VTodo;
class TaskwarriorManager { class TaskwarriorManager {
const DESCRIPTION = 'description';
const CATEGORIES = 'categories';
const TASK_UUID = 'uuid';
const ICAL_UID = 'uid';
private $tasks; /**
* @var TodoStrategy
const ENTRY = 'entry'; */
const START = 'start'; private $todoStrategy;
const MODIFIED = 'modified';
const END = 'end';
public function __construct($taskwarrior){ public function __construct($taskwarrior){
if(!isset($taskwarrior)){ if(!isset($taskwarrior)){
@ -26,29 +20,19 @@ class TaskwarriorManager {
} else { } else {
$this->taskwarrior = $taskwarrior; $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){ 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->setModifiedTime($document);
$task->setStopTime($document);
$task->setDue($document); $task->setDue($document);
@ -89,73 +73,11 @@ class TaskwarriorManager {
return $upatedTask; 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){ public function taskExists($taskUuid){
$taskIsInCache = isset($this->cachedTasks[$taskUuid]); $this->taskwarrior->setStrategy($this->$todoStrategy);
return $this->taskwarrior->count((string)$taskUuid);
if($taskIsInCache){
return true;
} }
$jsonArray = $this->taskwarrior->export($taskUuid);
$taskWithUuidExists = count($jsonArray) > 0;
return $taskWithUuidExists;
}
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){}
} }
?> ?>