fetch writeable calendars of user and display a dropdown in confirm dialog with list of calendars to choose for the event

This commit is contained in:
stefan.tollkuehn committed 2026-10-08 12:53:40 +02:00
1 parent f51bb830ab
commit fa398f5b36
3 files changed
+110 -15

No files matched your search

+81 -15
View File
@@ -21,7 +21,7 @@ use Sabre\VObject\Reader;
class CalendarController extends Controller class CalendarController extends Controller
{ {
/* /*
* Target calendar for created events. * Preferred calendar, preselected in the dropdown if present.
*/ */
private const CALENDAR_NAME = 'Personal'; private const CALENDAR_NAME = 'Personal';
@@ -88,7 +88,17 @@ class CalendarController extends Controller
$url $url
); );
return $this->renderConfirm($data); $user = $this->userSession->getUser();
$calendars = $user === null
? []
: $this->findWritableCalendars($user->getUID());
return $this->renderConfirm(
$data,
$calendars,
$this->defaultCalendarId($calendars)
);
} }
/** /**
@@ -105,7 +115,8 @@ class CalendarController extends Controller
string $end = '', string $end = '',
string $organizer = '', string $organizer = '',
string $location = '', string $location = '',
string $url = '' string $url = '',
string $calendarId = ''
): RedirectResponse|TemplateResponse { ): RedirectResponse|TemplateResponse {
$data = $this->validateEventData( $data = $this->validateEventData(
$summary, $summary,
@@ -123,7 +134,13 @@ class CalendarController extends Controller
throw new \RuntimeException('No authenticated Nextcloud user.'); throw new \RuntimeException('No authenticated Nextcloud user.');
} }
$calendar = $this->findWritableCalendar($user->getUID()); $calendars = $this->findWritableCalendars($user->getUID());
if ($calendarId === '') {
$calendarId = $this->defaultCalendarId($calendars);
}
$calendar = $this->selectCalendar($calendars, $calendarId);
/* /*
* Friendly error instead of a hard server error page. * Friendly error instead of a hard server error page.
@@ -131,10 +148,14 @@ class CalendarController extends Controller
if ($calendar === null) { if ($calendar === null) {
return $this->renderConfirm( return $this->renderConfirm(
$data, $data,
'No writable calendar named "' $calendars,
. self::CALENDAR_NAME $calendarId,
. '" was found in your account. Create it in the ' $calendars === []
. 'Nextcloud Calendar app, then try again.' ? 'No writable calendar was found in your account. '
. 'Create one in the Nextcloud Calendar app, '
. 'then try again.'
: 'The selected calendar is no longer writable. '
. 'Pick another one and try again.'
); );
} }
@@ -151,12 +172,12 @@ class CalendarController extends Controller
} }
/** /**
* The user's "Personal" calendar. * All writable calendars of the given principal.
* *
* getCalendarsForPrincipal() returns ICalendar objects. * getCalendarsForPrincipal() returns ICalendar objects.
* Only calendars implementing ICreateFromString are writable. * Only calendars implementing ICreateFromString are writable.
*/ */
private function findWritableCalendar(string $userId): ?ICreateFromString private function findWritableCalendars(string $userId): array
{ {
/* /*
* IManager calendars are queried via the principal URI. * IManager calendars are queried via the principal URI.
@@ -165,12 +186,24 @@ class CalendarController extends Controller
$calendars = $this->calendarManager->getCalendarsForPrincipal($principalUri); $calendars = $this->calendarManager->getCalendarsForPrincipal($principalUri);
$writable = [];
foreach ($calendars as $calendar) { foreach ($calendars as $calendar) {
if (!$calendar instanceof ICreateFromString) { if ($calendar instanceof ICreateFromString) {
continue; $writable[] = $calendar;
}
} }
if ($calendar->getDisplayName() === self::CALENDAR_NAME) { return $writable;
}
/**
* The calendar with the given key, if it is writable.
*/
private function selectCalendar(array $calendars, string $calendarId): ?ICreateFromString
{
foreach ($calendars as $calendar) {
if ($calendar->getKey() === $calendarId) {
return $calendar; return $calendar;
} }
} }
@@ -178,11 +211,34 @@ class CalendarController extends Controller
return null; return null;
} }
/**
* Key of the calendar to preselect: the preferred
* CALENDAR_NAME if present, otherwise the first one.
*/
private function defaultCalendarId(array $calendars): string
{
foreach ($calendars as $calendar) {
if ($calendar->getDisplayName() === self::CALENDAR_NAME) {
return $calendar->getKey();
}
}
if (isset($calendars[0])) {
return $calendars[0]->getKey();
}
return '';
}
/** /**
* Render the confirmation page, optionally with an error message. * Render the confirmation page, optionally with an error message.
*/ */
private function renderConfirm(array $data, string $error = ''): TemplateResponse private function renderConfirm(
{ array $data,
array $calendars,
string $calendarId = '',
string $error = ''
): TemplateResponse {
return new TemplateResponse( return new TemplateResponse(
Application::APP_ID, Application::APP_ID,
'confirm', 'confirm',
@@ -195,6 +251,16 @@ class CalendarController extends Controller
'location' => $data['location'], 'location' => $data['location'],
'url' => $data['url'], 'url' => $data['url'],
'error' => $error, 'error' => $error,
'calendars' => array_map(
static function (ICreateFromString $calendar): array {
return [
'id' => $calendar->getKey(),
'displayName' => $calendar->getDisplayName() ?? '',
];
},
$calendars
),
'calendarId' => $calendarId,
'cancelUrl' => $this->urlGenerator->getAbsoluteURL('/'), 'cancelUrl' => $this->urlGenerator->getAbsoluteURL('/'),
'createUrl' => $this->urlGenerator->linkToRoute( 'createUrl' => $this->urlGenerator->linkToRoute(
Application::APP_ID . '.calendar.create' Application::APP_ID . '.calendar.create'
+18
View File
@@ -100,6 +100,24 @@ $h = static function (string $value): string {
method="post" method="post"
action="<?= $h($_['createUrl']) ?>" action="<?= $h($_['createUrl']) ?>"
> >
<?php if ($_['calendars'] !== []): ?>
<div class="atocal-row">
<label for="atocal-calendar">
<strong>Calendar</strong>
</label>
<select id="atocal-calendar" name="calendarId">
<?php foreach ($_['calendars'] as $calendar): ?>
<option
value="<?= $h($calendar['id']) ?>"
<?= $calendar['id'] === $_['calendarId'] ? 'selected' : '' ?>
>
<?= $h($calendar['displayName']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<input <input
type="hidden" type="hidden"
name="requesttoken" name="requesttoken"
+11
View File
@@ -52,6 +52,17 @@
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.atocal-row select {
align-self: center;
width: 100%;
max-width: 280px;
padding: 6px 8px;
border: 1px solid var(--color-border);
border-radius: 6px;
background: var(--color-main-background);
color: var(--color-main-text);
}
.atocal-row .description { .atocal-row .description {
white-space: normal; white-space: normal;
} }