mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-25 00:53:48 +00:00
Webdav: fully implements the controller and response
The controller is tested from real request scraped from apache mod_dav implementation. The requests were scraped using a wireshark-like tool. Those requests have been adapted to suit to our xml.
This commit is contained in:
232
src/Bundle/ChillDocStoreBundle/Controller/WebdavController.php
Normal file
232
src/Bundle/ChillDocStoreBundle/Controller/WebdavController.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\DocStoreBundle\Controller;
|
||||
|
||||
use Chill\DocStoreBundle\Dav\Request\PropfindRequestAnalyzer;
|
||||
use Chill\DocStoreBundle\Dav\Response\DavResponse;
|
||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
|
||||
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
final readonly class WebdavController
|
||||
{
|
||||
private PropfindRequestAnalyzer $requestAnalyzer;
|
||||
|
||||
public function __construct(
|
||||
private \Twig\Environment $engine,
|
||||
private StoredObjectManagerInterface $storedObjectManager,
|
||||
) {
|
||||
$this->requestAnalyzer = new PropfindRequestAnalyzer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/open/{uuid}")
|
||||
*/
|
||||
public function open(StoredObject $storedObject): Response
|
||||
{
|
||||
/*$accessToken = $this->JWTTokenManager->createFromPayload($this->security->getUser(), [
|
||||
'UserCanWrite' => true,
|
||||
'UserCanAttend' => true,
|
||||
'UserCanPresent' => true,
|
||||
'fileId' => $storedObject->getUuid(),
|
||||
]);*/
|
||||
|
||||
return new DavResponse($this->engine->render('@ChillDocStore/Webdav/open_in_browser.html.twig', [
|
||||
'stored_object' => $storedObject, 'access_token' => '',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/", methods={"GET", "HEAD"}, name="chill_docstore_dav_directory_get")
|
||||
*/
|
||||
public function getDirectory(StoredObject $storedObject): Response
|
||||
{
|
||||
return new DavResponse(
|
||||
$this->engine->render('@ChillDocStore/Webdav/directory.html.twig', [
|
||||
'stored_object' => $storedObject
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/", methods={"OPTIONS"})
|
||||
*/
|
||||
public function optionsDirectory(StoredObject $storedObject): Response
|
||||
{
|
||||
$response = (new DavResponse(""))
|
||||
->setEtag($this->storedObjectManager->etag($storedObject))
|
||||
;
|
||||
|
||||
$response->headers->add(['Allow' => 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT,PROPPATCH,COPY,MOVE,REPORT,PATCH,POST,TRACE']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/", methods={"PROPFIND"})
|
||||
*/
|
||||
public function propfindDirectory(StoredObject $storedObject, Request $request): Response
|
||||
{
|
||||
$depth = $request->headers->get('depth');
|
||||
|
||||
if ("0" !== $depth && "1" !== $depth) {
|
||||
throw new BadRequestHttpException("only 1 and 0 are accepted for Depth header");
|
||||
}
|
||||
|
||||
$content = $request->getContent();
|
||||
$xml = new \DOMDocument();
|
||||
$xml->loadXML($content);
|
||||
|
||||
$properties = $this->requestAnalyzer->getRequestedProperties($xml);
|
||||
$requested = array_keys(array_filter($properties, fn ($item) => true === $item));
|
||||
|
||||
if (
|
||||
in_array('lastModified', $requested, true)
|
||||
|| in_array('etag', $requested, true)
|
||||
) {
|
||||
$lastModified = $this->storedObjectManager->getLastModified($storedObject);
|
||||
$etag = $this->storedObjectManager->etag($storedObject);
|
||||
|
||||
}
|
||||
if (in_array('contentLength', $requested, true)) {
|
||||
$length = $this->storedObjectManager->getContentLength($storedObject);
|
||||
}
|
||||
|
||||
$response = new DavResponse(
|
||||
$this->engine->render('@ChillDocStore/Webdav/directory_propfind.xml.twig', [
|
||||
'stored_object' => $storedObject,
|
||||
'properties' => $properties,
|
||||
'last_modified' => $lastModified ?? null,
|
||||
'etag' => $etag ?? null,
|
||||
'content_length' => $length ?? null,
|
||||
'depth' => (int) $depth
|
||||
]),
|
||||
207
|
||||
);
|
||||
|
||||
$response->headers->add([
|
||||
'Content-Type' => 'text/xml'
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/d", name="chill_docstore_dav_document_get", methods={"GET"})
|
||||
*/
|
||||
public function getDocument(StoredObject $storedObject): Response
|
||||
{
|
||||
return (new DavResponse($this->storedObjectManager->read($storedObject)))
|
||||
->setEtag($this->storedObjectManager->etag($storedObject));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/d", methods={"HEAD"})
|
||||
*/
|
||||
public function headDocument(StoredObject $storedObject): Response
|
||||
{
|
||||
$response = new DavResponse("");
|
||||
|
||||
$response->headers->add(
|
||||
[
|
||||
'Content-Length' => $this->storedObjectManager->getContentLength($storedObject),
|
||||
'Content-Type' => $storedObject->getType(),
|
||||
'Etag' => $this->storedObjectManager->etag($storedObject)
|
||||
]
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/d", methods={"OPTIONS"})
|
||||
*/
|
||||
public function optionsDocument(StoredObject $storedObject): Response
|
||||
{
|
||||
$response = (new DavResponse(""))
|
||||
->setEtag($this->storedObjectManager->etag($storedObject))
|
||||
;
|
||||
|
||||
$response->headers->add(['Allow' => /*sprintf(
|
||||
'%s, %s, %s, %s, %s',
|
||||
Request::METHOD_OPTIONS,
|
||||
Request::METHOD_GET,
|
||||
Request::METHOD_HEAD,
|
||||
Request::METHOD_PUT,
|
||||
'PROPFIND'
|
||||
) */ 'OPTIONS,GET,HEAD,DELETE,PROPFIND,PUT,PROPPATCH,COPY,MOVE,REPORT,PATCH,POST,TRACE'
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/d", methods={"PROPFIND"})
|
||||
*/
|
||||
public function propfindDocument(StoredObject $storedObject, Request $request): Response
|
||||
{
|
||||
$content = $request->getContent();
|
||||
$xml = new \DOMDocument();
|
||||
$xml->loadXML($content);
|
||||
|
||||
$properties = $this->requestAnalyzer->getRequestedProperties($xml);
|
||||
$requested = array_keys(array_filter($properties, fn ($item) => true === $item));
|
||||
|
||||
if (
|
||||
in_array('lastModified', $requested, true)
|
||||
|| in_array('etag', $requested, true)
|
||||
) {
|
||||
$lastModified = $this->storedObjectManager->getLastModified($storedObject);
|
||||
$etag = $this->storedObjectManager->etag($storedObject);
|
||||
}
|
||||
if (in_array('contentLength', $requested, true)) {
|
||||
$length = $this->storedObjectManager->getContentLength($storedObject);
|
||||
}
|
||||
|
||||
$response = new DavResponse(
|
||||
$this->engine->render(
|
||||
'@ChillDocStore/Webdav/doc_props.xml.twig',
|
||||
[
|
||||
'stored_object' => $storedObject,
|
||||
'properties' => $properties,
|
||||
'etag' => $etag ?? null,
|
||||
'last_modified' => $lastModified ?? null,
|
||||
'content_length' => $length ?? null,
|
||||
]
|
||||
),
|
||||
207
|
||||
);
|
||||
|
||||
$response
|
||||
->headers->add([
|
||||
'Content-Type' => 'text/xml'
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/dav/get/{uuid}/d", methods={"PUT"})
|
||||
*/
|
||||
public function putDocument(StoredObject $storedObject, Request $request): Response
|
||||
{
|
||||
$this->storedObjectManager->write($storedObject, $request->getContent());
|
||||
|
||||
return (new DavResponse("", Response::HTTP_NO_CONTENT));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user