Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/dav/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
['name' => 'invitation_response#decline', 'url' => '/invitation/decline/{token}', 'verb' => 'GET'],
['name' => 'invitation_response#options', 'url' => '/invitation/moreOptions/{token}', 'verb' => 'GET'],
['name' => 'invitation_response#processMoreOptionsResult', 'url' => '/invitation/moreOptions/{token}', 'verb' => 'POST'],
['name' => 'example_content#getDefaultContact', 'url' => '/api/defaultcontact/contact', 'verb' => 'GET'],
['name' => 'example_content#setDefaultContact', 'url' => '/api/defaultcontact/contact', 'verb' => 'PUT'],
['name' => 'example_content#setEnableDefaultContact', 'url' => '/api/defaultcontact/config', 'verb' => 'PUT'],
],
Expand Down
3 changes: 3 additions & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => $baseDir . '/../lib/Events/SubscriptionCreatedEvent.php',
'OCA\\DAV\\Events\\SubscriptionDeletedEvent' => $baseDir . '/../lib/Events/SubscriptionDeletedEvent.php',
'OCA\\DAV\\Events\\SubscriptionUpdatedEvent' => $baseDir . '/../lib/Events/SubscriptionUpdatedEvent.php',
'OCA\\DAV\\Exception\\ExampleEventException' => $baseDir . '/../lib/Exception/ExampleEventException.php',
'OCA\\DAV\\Exception\\ServerMaintenanceMode' => $baseDir . '/../lib/Exception/ServerMaintenanceMode.php',
'OCA\\DAV\\Exception\\UnsupportedLimitOnInitialSyncException' => $baseDir . '/../lib/Exception/UnsupportedLimitOnInitialSyncException.php',
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => $baseDir . '/../lib/Files/BrowserErrorPagePlugin.php',
Expand Down Expand Up @@ -349,6 +350,7 @@
'OCA\\DAV\\Migration\\Version1029Date20231004091403' => $baseDir . '/../lib/Migration/Version1029Date20231004091403.php',
'OCA\\DAV\\Migration\\Version1030Date20240205103243' => $baseDir . '/../lib/Migration/Version1030Date20240205103243.php',
'OCA\\DAV\\Migration\\Version1031Date20240610134258' => $baseDir . '/../lib/Migration/Version1031Date20240610134258.php',
'OCA\\DAV\\Model\\ExampleEvent' => $baseDir . '/../lib/Model/ExampleEvent.php',
'OCA\\DAV\\Paginate\\LimitedCopyIterator' => $baseDir . '/../lib/Paginate/LimitedCopyIterator.php',
'OCA\\DAV\\Paginate\\PaginateCache' => $baseDir . '/../lib/Paginate/PaginateCache.php',
'OCA\\DAV\\Paginate\\PaginatePlugin' => $baseDir . '/../lib/Paginate/PaginatePlugin.php',
Expand All @@ -365,6 +367,7 @@
'OCA\\DAV\\ServerFactory' => $baseDir . '/../lib/ServerFactory.php',
'OCA\\DAV\\Service\\AbsenceService' => $baseDir . '/../lib/Service/AbsenceService.php',
'OCA\\DAV\\Service\\DefaultContactService' => $baseDir . '/../lib/Service/DefaultContactService.php',
'OCA\\DAV\\Service\\ExampleEventService' => $baseDir . '/../lib/Service/ExampleEventService.php',
'OCA\\DAV\\Settings\\Admin\\SystemAddressBookSettings' => $baseDir . '/../lib/Settings/Admin/SystemAddressBookSettings.php',
'OCA\\DAV\\Settings\\AvailabilitySettings' => $baseDir . '/../lib/Settings/AvailabilitySettings.php',
'OCA\\DAV\\Settings\\CalDAVSettings' => $baseDir . '/../lib/Settings/CalDAVSettings.php',
Expand Down
3 changes: 3 additions & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Events\\SubscriptionCreatedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionCreatedEvent.php',
'OCA\\DAV\\Events\\SubscriptionDeletedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionDeletedEvent.php',
'OCA\\DAV\\Events\\SubscriptionUpdatedEvent' => __DIR__ . '/..' . '/../lib/Events/SubscriptionUpdatedEvent.php',
'OCA\\DAV\\Exception\\ExampleEventException' => __DIR__ . '/..' . '/../lib/Exception/ExampleEventException.php',
'OCA\\DAV\\Exception\\ServerMaintenanceMode' => __DIR__ . '/..' . '/../lib/Exception/ServerMaintenanceMode.php',
'OCA\\DAV\\Exception\\UnsupportedLimitOnInitialSyncException' => __DIR__ . '/..' . '/../lib/Exception/UnsupportedLimitOnInitialSyncException.php',
'OCA\\DAV\\Files\\BrowserErrorPagePlugin' => __DIR__ . '/..' . '/../lib/Files/BrowserErrorPagePlugin.php',
Expand Down Expand Up @@ -364,6 +365,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Migration\\Version1029Date20231004091403' => __DIR__ . '/..' . '/../lib/Migration/Version1029Date20231004091403.php',
'OCA\\DAV\\Migration\\Version1030Date20240205103243' => __DIR__ . '/..' . '/../lib/Migration/Version1030Date20240205103243.php',
'OCA\\DAV\\Migration\\Version1031Date20240610134258' => __DIR__ . '/..' . '/../lib/Migration/Version1031Date20240610134258.php',
'OCA\\DAV\\Model\\ExampleEvent' => __DIR__ . '/..' . '/../lib/Model/ExampleEvent.php',
'OCA\\DAV\\Paginate\\LimitedCopyIterator' => __DIR__ . '/..' . '/../lib/Paginate/LimitedCopyIterator.php',
'OCA\\DAV\\Paginate\\PaginateCache' => __DIR__ . '/..' . '/../lib/Paginate/PaginateCache.php',
'OCA\\DAV\\Paginate\\PaginatePlugin' => __DIR__ . '/..' . '/../lib/Paginate/PaginatePlugin.php',
Expand All @@ -380,6 +382,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\ServerFactory' => __DIR__ . '/..' . '/../lib/ServerFactory.php',
'OCA\\DAV\\Service\\AbsenceService' => __DIR__ . '/..' . '/../lib/Service/AbsenceService.php',
'OCA\\DAV\\Service\\DefaultContactService' => __DIR__ . '/..' . '/../lib/Service/DefaultContactService.php',
'OCA\\DAV\\Service\\ExampleEventService' => __DIR__ . '/..' . '/../lib/Service/ExampleEventService.php',
'OCA\\DAV\\Settings\\Admin\\SystemAddressBookSettings' => __DIR__ . '/..' . '/../lib/Settings/Admin/SystemAddressBookSettings.php',
'OCA\\DAV\\Settings\\AvailabilitySettings' => __DIR__ . '/..' . '/../lib/Settings/AvailabilitySettings.php',
'OCA\\DAV\\Settings\\CalDAVSettings' => __DIR__ . '/..' . '/../lib/Settings/CalDAVSettings.php',
Expand Down
70 changes: 67 additions & 3 deletions apps/dav/lib/Controller/ExampleContentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,31 @@
namespace OCA\DAV\Controller;

use OCA\DAV\AppInfo\Application;
use OCP\App\IAppManager;
use OCA\DAV\Service\ExampleEventService;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataDownloadResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Files\AppData\IAppDataFactory;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

class ExampleContentController extends ApiController {
private IAppData $appData;

public function __construct(
IRequest $request,
private IConfig $config,
private IAppConfig $appConfig,
private IAppDataFactory $appDataFactory,
private IAppManager $appManager,
private LoggerInterface $logger,
private ExampleEventService $exampleEventService,
) {
parent::__construct(Application::APP_ID, $request);
$this->appData = $this->appDataFactory->get('dav');
Expand All @@ -47,23 +53,46 @@ public function setEnableDefaultContact($allow) {
return new JSONResponse([], Http::STATUS_OK);
}

#[NoCSRFRequired]
public function getDefaultContact(): DataDownloadResponse {
$cardData = $this->getCard()
?? file_get_contents(__DIR__ . '/../ExampleContentFiles/exampleContact.vcf');
return new DataDownloadResponse($cardData, 'example_contact.vcf', 'text/vcard');
}

public function setDefaultContact(?string $contactData = null) {
if (!$this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'no')) {
if (!$this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'yes')) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}
$this->setCard($contactData);
return new JSONResponse([], Http::STATUS_OK);
}

private function getCard(): ?string {
try {
$folder = $this->appData->getFolder('defaultContact');
} catch (NotFoundException $e) {
return null;
}

if (!$folder->fileExists('defaultContact.vcf')) {
return null;
}

return $folder->getFile('defaultContact.vcf')->getContent();
}

private function setCard(?string $cardData = null) {
try {
$folder = $this->appData->getFolder('defaultContact');
} catch (NotFoundException $e) {
$folder = $this->appData->newFolder('defaultContact');
}

$isCustom = true;
if (is_null($cardData)) {
$cardData = file_get_contents(__DIR__ . '/../ExampleContentFiles/exampleContact.vcf');
$isCustom = false;
}

if (!$cardData) {
Expand All @@ -72,6 +101,8 @@ private function setCard(?string $cardData = null) {

$file = (!$folder->fileExists('defaultContact.vcf')) ? $folder->newFile('defaultContact.vcf') : $folder->getFile('defaultContact.vcf');
$file->putContent($cardData);

$this->appConfig->setValueBool(Application::APP_ID, 'hasCustomDefaultContact', $isCustom);
}

private function defaultContactExists(): bool {
Expand All @@ -83,4 +114,37 @@ private function defaultContactExists(): bool {
return $folder->fileExists('defaultContact.vcf');
}

#[FrontpageRoute(verb: 'POST', url: '/api/exampleEvent/enable')]
public function setCreateExampleEvent(bool $enable): JSONResponse {
$this->exampleEventService->setCreateExampleEvent($enable);
return new JsonResponse([]);
}

#[FrontpageRoute(verb: 'GET', url: '/api/exampleEvent/event')]
#[NoCSRFRequired]
public function downloadExampleEvent(): DataDownloadResponse {
$exampleEvent = $this->exampleEventService->getExampleEvent();
return new DataDownloadResponse(
$exampleEvent->getIcs(),
'example_event.ics',
'text/calendar',
);
}

#[FrontpageRoute(verb: 'POST', url: '/api/exampleEvent/event')]
public function uploadExampleEvent(string $ics): JSONResponse {
if (!$this->exampleEventService->shouldCreateExampleEvent()) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}

$this->exampleEventService->saveCustomExampleEvent($ics);
return new JsonResponse([]);
}

#[FrontpageRoute(verb: 'DELETE', url: '/api/exampleEvent/event')]
public function deleteExampleEvent(): JSONResponse {
$this->exampleEventService->deleteCustomExampleEvent();
return new JsonResponse([]);
}

}
13 changes: 13 additions & 0 deletions apps/dav/lib/Exception/ExampleEventException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAV\Exception;

class ExampleEventException extends \Exception {
}
24 changes: 20 additions & 4 deletions apps/dav/lib/Listener/UserEventsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
use OCA\DAV\CardDAV\CardDavBackend;
use OCA\DAV\CardDAV\SyncService;
use OCA\DAV\Service\DefaultContactService;
use OCA\DAV\Service\ExampleEventService;
use OCP\Accounts\UserUpdatedEvent;
use OCP\Defaults;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Server;
use OCP\User\Events\BeforeUserDeletedEvent;
use OCP\User\Events\BeforeUserIdUnassignedEvent;
use OCP\User\Events\UserChangedEvent;
Expand Down Expand Up @@ -47,6 +47,8 @@ public function __construct(
private CardDavBackend $cardDav,
private Defaults $themingDefaults,
private DefaultContactService $defaultContactService,
private ExampleEventService $exampleEventService,
private LoggerInterface $logger,
) {
}

Expand Down Expand Up @@ -137,25 +139,39 @@ public function changeUser(IUser $user, string $feature): void {

public function firstLogin(IUser $user): void {
$principal = 'principals/users/' . $user->getUID();

$calendarId = null;
if ($this->calDav->getCalendarsForUserCount($principal) === 0) {
try {
$this->calDav->createCalendar($principal, CalDavBackend::PERSONAL_CALENDAR_URI, [
$calendarId = $this->calDav->createCalendar($principal, CalDavBackend::PERSONAL_CALENDAR_URI, [
'{DAV:}displayname' => CalDavBackend::PERSONAL_CALENDAR_NAME,
'{http://apple.com/ns/ical/}calendar-color' => $this->themingDefaults->getColorPrimary(),
'components' => 'VEVENT'
]);
} catch (\Exception $e) {
Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]);
$this->logger->error($e->getMessage(), ['exception' => $e]);
}
}
if ($calendarId !== null) {
try {
$this->exampleEventService->createExampleEvent($calendarId);
} catch (\Exception $e) {
$this->logger->error('Failed to create example event: ' . $e->getMessage(), [
'exception' => $e,
'userId' => $user->getUID(),
'calendarId' => $calendarId,
]);
}
}

$addressBookId = null;
if ($this->cardDav->getAddressBooksForUserCount($principal) === 0) {
try {
$addressBookId = $this->cardDav->createAddressBook($principal, CardDavBackend::PERSONAL_ADDRESSBOOK_URI, [
'{DAV:}displayname' => CardDavBackend::PERSONAL_ADDRESSBOOK_NAME,
]);
} catch (\Exception $e) {
Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]);
$this->logger->error($e->getMessage(), ['exception' => $e]);
}
}
if ($addressBookId) {
Expand Down
31 changes: 31 additions & 0 deletions apps/dav/lib/Model/ExampleEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAV\Model;

use Sabre\VObject\Component\VCalendar;

/**
* Simple DTO to store a parsed example event and its UID.
*/
final class ExampleEvent {
public function __construct(
private readonly VCalendar $vCalendar,
private readonly string $uid,
) {
}

public function getUid(): string {
return $this->uid;
}

public function getIcs(): string {
return $this->vCalendar->serialize();
}
}
2 changes: 1 addition & 1 deletion apps/dav/lib/Service/DefaultContactService.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function __construct(
}

public function createDefaultContact(int $addressBookId): void {
$enableDefaultContact = $this->config->getValueString(Application::APP_ID, 'enableDefaultContact', 'no');
$enableDefaultContact = $this->config->getValueString(Application::APP_ID, 'enableDefaultContact', 'yes');
if ($enableDefaultContact !== 'yes') {
return;
}
Expand Down
Loading
Loading