Plugin.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\DAV\CalDAV\Trashbin;
  8. use Closure;
  9. use DateTimeImmutable;
  10. use DateTimeInterface;
  11. use OCA\DAV\CalDAV\Calendar;
  12. use OCA\DAV\CalDAV\RetentionService;
  13. use OCP\IRequest;
  14. use Sabre\DAV\Exception\NotFound;
  15. use Sabre\DAV\INode;
  16. use Sabre\DAV\PropFind;
  17. use Sabre\DAV\Server;
  18. use Sabre\DAV\ServerPlugin;
  19. use Sabre\HTTP\RequestInterface;
  20. use Sabre\HTTP\ResponseInterface;
  21. use function array_slice;
  22. use function implode;
  23. class Plugin extends ServerPlugin {
  24. public const PROPERTY_DELETED_AT = '{http://nextcloud.com/ns}deleted-at';
  25. public const PROPERTY_CALENDAR_URI = '{http://nextcloud.com/ns}calendar-uri';
  26. public const PROPERTY_RETENTION_DURATION = '{http://nextcloud.com/ns}trash-bin-retention-duration';
  27. /** @var bool */
  28. private $disableTrashbin;
  29. /** @var Server */
  30. private $server;
  31. public function __construct(
  32. IRequest $request,
  33. private RetentionService $retentionService,
  34. ) {
  35. $this->disableTrashbin = $request->getHeader('X-NC-CalDAV-No-Trashbin') === '1';
  36. }
  37. public function initialize(Server $server): void {
  38. $this->server = $server;
  39. $server->on('beforeMethod:*', [$this, 'beforeMethod']);
  40. $server->on('propFind', Closure::fromCallable([$this, 'propFind']));
  41. }
  42. public function beforeMethod(RequestInterface $request, ResponseInterface $response): void {
  43. if (!$this->disableTrashbin) {
  44. return;
  45. }
  46. $path = $request->getPath();
  47. $pathParts = explode('/', ltrim($path, '/'));
  48. if (\count($pathParts) < 3) {
  49. // We are looking for a path like calendars/username/calendarname
  50. return;
  51. }
  52. // $calendarPath will look like calendars/username/calendarname
  53. $calendarPath = implode(
  54. '/',
  55. array_slice($pathParts, 0, 3)
  56. );
  57. try {
  58. $calendar = $this->server->tree->getNodeForPath($calendarPath);
  59. if (!($calendar instanceof Calendar)) {
  60. // This is odd
  61. return;
  62. }
  63. /** @var Calendar $calendar */
  64. $calendar->disableTrashbin();
  65. } catch (NotFound $ex) {
  66. return;
  67. }
  68. }
  69. private function propFind(
  70. PropFind $propFind,
  71. INode $node): void {
  72. if ($node instanceof DeletedCalendarObject) {
  73. $propFind->handle(self::PROPERTY_DELETED_AT, function () use ($node) {
  74. $ts = $node->getDeletedAt();
  75. if ($ts === null) {
  76. return null;
  77. }
  78. return (new DateTimeImmutable())
  79. ->setTimestamp($ts)
  80. ->format(DateTimeInterface::ATOM);
  81. });
  82. $propFind->handle(self::PROPERTY_CALENDAR_URI, function () use ($node) {
  83. return $node->getCalendarUri();
  84. });
  85. }
  86. if ($node instanceof TrashbinHome) {
  87. $propFind->handle(self::PROPERTY_RETENTION_DURATION, function () use ($node) {
  88. return $this->retentionService->getDuration();
  89. });
  90. }
  91. }
  92. public function getFeatures(): array {
  93. return ['nc-calendar-trashbin'];
  94. }
  95. public function getPluginName(): string {
  96. return 'nc-calendar-trashbin';
  97. }
  98. }