style: remove unused code and updated plugin
This commit is contained in:
parent
a2b2073bad
commit
68470e3dee
@ -28,14 +28,34 @@ 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);
|
||||
|
7
src/Exceptions/TaskwarriorCommandException.php
Normal file
7
src/Exceptions/TaskwarriorCommandException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
class TaskwarriorCommandException extends Exception {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
712
src/Plugin.php
712
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,703 +107,18 @@ 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -1,60 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Aerex\TaskwarriorPlugin\Taskwarrior\Commands;
|
||||
use Aerex\TaskwarriorPlugin\Taskwarrior\Task;
|
||||
use Aerex\TaskwarriorPlugin\Config;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class TodoStrategy implements IStrategy {
|
||||
|
||||
public function __construct(TaskwarriorConfig $config){
|
||||
$this->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();
|
||||
|
||||
}
|
||||
|
@ -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<string>")
|
||||
*/
|
||||
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<Aerex\Taskwarrior\Annotation>")
|
||||
*/
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,29 +20,19 @@ 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->setDescription($document);
|
||||
|
||||
$task->setEntry($document);
|
||||
|
||||
$task->setStartTime($document);
|
||||
|
||||
$task->setModifiedTime($document);
|
||||
|
||||
$task->setStopTime($document);
|
||||
$task->setEntryTime($document);
|
||||
|
||||
$task->setDue($document);
|
||||
|
||||
@ -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;
|
||||
$this->taskwarrior->setStrategy($this->$todoStrategy);
|
||||
return $this->taskwarrior->count((string)$taskUuid);
|
||||
}
|
||||
|
||||
$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){}
|
||||
}
|
||||
|
||||
?>
|
||||
|
Loading…
Reference in New Issue
Block a user