- mergeUrlIntoDescription

- friendly error if no Personal calendar
- use users timezone if possible
This commit is contained in:
stefan.tollkuehn committed 2026-10-07 22:20:07 +02:00
1 parent 8a647ad1a8
commit a2925ac6d1
4 files changed
+85 -27

No files matched your search

+2 -1
View File
@@ -26,7 +26,8 @@ class Application extends App
$c->get('Request'), $c->get('Request'),
$c->get(\OCP\Calendar\IManager::class), $c->get(\OCP\Calendar\IManager::class),
$c->get(\OCP\IUserSession::class), $c->get(\OCP\IUserSession::class),
$c->get(\OCP\IURLGenerator::class) $c->get(\OCP\IURLGenerator::class),
$c->get(\OCP\IDateTimeZone::class)
); );
} }
); );
+69 -26
View File
@@ -13,6 +13,7 @@ use OCP\Calendar\IManager;
use OCP\IRequest; use OCP\IRequest;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\IDateTimeZone;
class CalendarController extends Controller class CalendarController extends Controller
{ {
@@ -30,19 +31,22 @@ class CalendarController extends Controller
private IManager $calendarManager; private IManager $calendarManager;
private IUserSession $userSession; private IUserSession $userSession;
private IURLGenerator $urlGenerator; private IURLGenerator $urlGenerator;
private IDateTimeZone $dateTimeZone;
public function __construct( public function __construct(
string $appName, string $appName,
IRequest $request, IRequest $request,
IManager $calendarManager, IManager $calendarManager,
IUserSession $userSession, IUserSession $userSession,
IURLGenerator $urlGenerator IURLGenerator $urlGenerator,
IDateTimeZone $dateTimeZone
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
$this->calendarManager = $calendarManager; $this->calendarManager = $calendarManager;
$this->userSession = $userSession; $this->userSession = $userSession;
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->dateTimeZone = $dateTimeZone;
} }
/** /**
@@ -71,22 +75,7 @@ class CalendarController extends Controller
$url $url
); );
return new TemplateResponse( return $this->renderConfirm($data);
Application::APP_ID,
'confirm',
[
'summary' => $data['summary'],
'description' => $data['description'],
'start' => $data['start']->format(self::DATETIME_LOCAL),
'end' => $data['end']->format(self::DATETIME_LOCAL),
'organizer' => $data['organizer'],
'location' => $data['location'],
'url' => $data['url'],
'createUrl' => $this->urlGenerator->linkToRoute(
Application::APP_ID . '.calendar.create'
),
]
);
} }
/** /**
@@ -100,7 +89,7 @@ class CalendarController extends Controller
string $organizer = '', string $organizer = '',
string $location = '', string $location = '',
string $url = '' string $url = ''
): RedirectResponse { ): RedirectResponse|TemplateResponse {
$data = $this->validateEventData( $data = $this->validateEventData(
$summary, $summary,
$description, $description,
@@ -119,11 +108,16 @@ class CalendarController extends Controller
$calendar = $this->findWritableCalendar($user->getUID()); $calendar = $this->findWritableCalendar($user->getUID());
/*
* Friendly error instead of a hard server error page.
*/
if ($calendar === null) { if ($calendar === null) {
throw new \RuntimeException( return $this->renderConfirm(
$data,
'No writable calendar named "' 'No writable calendar named "'
. self::CALENDAR_NAME . self::CALENDAR_NAME
. '" is available for this user.' . '" was found in your account. Create it in the '
. 'Nextcloud Calendar app, then try again.'
); );
} }
@@ -162,6 +156,30 @@ class CalendarController extends Controller
return null; return null;
} }
/**
* Render the confirmation page, optionally with an error message.
*/
private function renderConfirm(array $data, string $error = ''): TemplateResponse
{
return new TemplateResponse(
Application::APP_ID,
'confirm',
[
'summary' => $data['summary'],
'description' => $data['description'],
'start' => $data['start']->format(self::DATETIME_LOCAL),
'end' => $data['end']->format(self::DATETIME_LOCAL),
'organizer' => $data['organizer'],
'location' => $data['location'],
'url' => $data['url'],
'error' => $error,
'createUrl' => $this->urlGenerator->linkToRoute(
Application::APP_ID . '.calendar.create'
),
]
);
}
/** /**
* Create the event through the platform event builder, * Create the event through the platform event builder,
* which handles escaping and ICS serialization. * which handles escaping and ICS serialization.
@@ -174,8 +192,10 @@ class CalendarController extends Controller
$builder->setEndDate($data['end']); $builder->setEndDate($data['end']);
$builder->setSummary($data['summary']); $builder->setSummary($data['summary']);
if ($data['description'] !== '') { $description = $this->mergeUrlIntoDescription($data);
$builder->setDescription($data['description']);
if ($description !== '') {
$builder->setDescription($description);
} }
if ($data['location'] !== '') { if ($data['location'] !== '') {
@@ -189,6 +209,24 @@ class CalendarController extends Controller
$builder->createInCalendar($calendar); $builder->createInCalendar($calendar);
} }
/**
* The event builder has no URL property, so a URL that
* differs from the location is kept in the description.
*/
private function mergeUrlIntoDescription(array $data): string
{
$urlOnly = $data['url'] !== ''
&& $data['url'] !== $data['location'];
if (!$urlOnly) {
return $data['description'];
}
$prefix = $data['description'] === '' ? '' : $data['description'] . "\n\n";
return $prefix . $data['url'];
}
/** /**
* Validate and normalize all event input. * Validate and normalize all event input.
*/ */
@@ -280,20 +318,25 @@ class CalendarController extends Controller
/** /**
* Parse datetime-local values. * Parse datetime-local values.
* *
* datetime-local has no timezone information, so we intentionally * datetime-local carries no timezone, so it is interpreted
* interpret the value in the Nextcloud server's configured timezone. * in the user's Nextcloud timezone. It falls back to the
* server default timezone if the user has none set.
*/ */
private function parseLocalDateTime(string $value): \DateTimeImmutable private function parseLocalDateTime(string $value): \DateTimeImmutable
{ {
$timeZone = $this->dateTimeZone->getTimeZone();
$date = \DateTimeImmutable::createFromFormat( $date = \DateTimeImmutable::createFromFormat(
self::DATETIME_LOCAL, self::DATETIME_LOCAL,
$value $value,
$timeZone
); );
if ($date === false) { if ($date === false) {
$date = \DateTimeImmutable::createFromFormat( $date = \DateTimeImmutable::createFromFormat(
'Y-m-d\TH:i:s', 'Y-m-d\TH:i:s',
$value $value,
$timeZone
); );
} }
+6
View File
@@ -25,6 +25,12 @@ $h = static function (string $value): string {
Nextcloud Calendar. Nextcloud Calendar.
</p> </p>
<?php if ($_['error'] !== ''): ?>
<div class="jitsi-calendar-error">
<?= $h($_['error']) ?>
</div>
<?php endif; ?>
<div class="jitsi-calendar-details"> <div class="jitsi-calendar-details">
<div class="jitsi-calendar-row"> <div class="jitsi-calendar-row">
+8
View File
@@ -22,6 +22,14 @@
margin-bottom: 28px; margin-bottom: 28px;
} }
.jitsi-calendar-error {
background: var(--color-error);
color: var(--color-error-text);
border-radius: 6px;
padding: 12px 16px;
margin-bottom: 28px;
}
.jitsi-calendar-details { .jitsi-calendar-details {
border-top: 1px solid var(--color-border); border-top: 1px solid var(--color-border);
border-bottom: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);