- rename from jitsi_calendar to atocal, to reflect more the usage. This plugin allows to create events

- add initial documentation
This commit is contained in:
stefan.tollkuehn committed 2026-10-08 09:48:54 +02:00
1 parent 8c5d19375e
commit b100d9c986
6 files changed
+118 -38

No files matched your search

+80
View File
@@ -0,0 +1,80 @@
# AToCal — Add To Calendar
A Nextcloud app that lets remote applications create events in the
authenticated user's Nextcloud Calendar via a simple link.
## How it works
```
remote app Nextcloud (atocal)
| |
| GET /apps/atocal/confirm |
| summary, start, end, ... |
|----------------------------->|
| | confirm page
|<-----------------------------|
| |
| POST /apps/atocal/create | (CSRF token from form)
|----------------------------->|
| | event in "Personal" calendar
|<-----------------------------| redirect to Calendar app
```
The remote app links the user to the confirm page. The user reviews
the event and submits the form. The event lands in the user's
"Personal" calendar and the browser opens the Calendar app.
## Routes
| Method | Path | Purpose |
|--------|------|---------|
| GET | `/apps/atocal/confirm` | Show confirmation page |
| POST | `/apps/atocal/create` | Create the event |
## Link parameters (GET `/confirm` and form POST `/create`)
| Parameter | Required | Rules |
|-----------|----------|-------|
| `summary` | yes | max 255 chars |
| `start` | yes | datetime-local, e.g. `2026-10-07T14:15` |
| `end` | yes | after `start`, same format |
| `description` | no | max 10000 chars |
| `location` | no | HTTPS URL |
| `url` | no | HTTPS URL; merged into description |
| `organizer` | no | email address |
Dates carry no timezone and are interpreted in the user's Nextcloud
timezone (server default as fallback).
Example:
```
https://cloud.example.com/apps/atocal/confirm?summary=Kickoff&start=2026-10-12T10:00&end=2026-10-12T11:00&location=https%3A%2F%2Fmeet.example.com%2Fkickoff
```
## Requirements
- Nextcloud 34 or 35
- Calendar app enabled
- A writable calendar named "Personal"
(event creation fails with a friendly error otherwise)
## Install
Copy this directory to the Nextcloud server as
`custom_apps/atocal`, then:
```
occ app:enable atocal
```
## Structure
```
appinfo/info.xml app metadata
appinfo/routes.php routes
lib/AppInfo/Application.php container setup
lib/Controller/CalendarController.php confirm/create logic
templates/confirm.php confirmation page
templates/style.css page styles
```
+5 -5
View File
@@ -1,15 +1,15 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> <info xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>jitsi_calendar</id> <id>atocal</id>
<name>Jitsi Calendar</name> <name>Add To Calendar</name>
<summary>Create Jitsi meetings in the user's Nextcloud Calendar</summary> <summary>Create events in the user's Nextcloud Calendar</summary>
<description> <description>
Allows the Jitsi meeting launcher to create calendar events in the authenticated user's Nextcloud Calendar. Allows remote applications to create calendar events in the authenticated user's Nextcloud Calendar.
</description> </description>
<version>1.0.0</version> <version>1.0.0</version>
<licence>AGPL</licence> <licence>AGPL</licence>
<author>Stefan Tollkühn s.tollkuehn@bnvb-ingenieure.de</author> <author>Stefan Tollkühn s.tollkuehn@bnvb-ingenieure.de</author>
<namespace>JitsiCalendar</namespace> <namespace>AToCal</namespace>
<category>integration</category> <category>integration</category>
<dependencies> <dependencies>
<nextcloud min-version="34" max-version="35"/> <nextcloud min-version="34" max-version="35"/>
+3 -3
View File
@@ -2,15 +2,15 @@
declare(strict_types=1); declare(strict_types=1);
namespace OCA\JitsiCalendar\AppInfo; namespace OCA\AToCal\AppInfo;
use OCA\JitsiCalendar\Controller\CalendarController; use OCA\AToCal\Controller\CalendarController;
use OCP\AppFramework\App; use OCP\AppFramework\App;
use OCP\AppFramework\IAppContainer; use OCP\AppFramework\IAppContainer;
class Application extends App class Application extends App
{ {
public const APP_ID = 'jitsi_calendar'; public const APP_ID = 'atocal';
public function __construct(array $urlParams = []) public function __construct(array $urlParams = [])
{ {
+2 -2
View File
@@ -2,9 +2,9 @@
declare(strict_types=1); declare(strict_types=1);
namespace OCA\JitsiCalendar\Controller; namespace OCA\AToCal\Controller;
use OCA\JitsiCalendar\AppInfo\Application; use OCA\AToCal\AppInfo\Application;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
+13 -13
View File
@@ -12,34 +12,34 @@ $h = static function (string $value): string {
?> ?>
<div id="app-content"> <div id="app-content">
<div class="jitsi-calendar-container"> <div class="atocal-container">
<div class="jitsi-calendar-card"> <div class="atocal-card">
<h1> <h1>
Add Jitsi Meeting to Calendar Add To Calendar
</h1> </h1>
<p class="jitsi-calendar-intro"> <p class="atocal-intro">
The following meeting will be added to your The following meeting will be added to your
Nextcloud Calendar. Nextcloud Calendar.
</p> </p>
<?php if ($_['error'] !== ''): ?> <?php if ($_['error'] !== ''): ?>
<div class="jitsi-calendar-error"> <div class="atocal-error">
<?= $h($_['error']) ?> <?= $h($_['error']) ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<div class="jitsi-calendar-details"> <div class="atocal-details">
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>Title</strong> <strong>Title</strong>
<span><?= $h($_['summary']) ?></span> <span><?= $h($_['summary']) ?></span>
</div> </div>
<?php if ($_['description'] !== ''): ?> <?php if ($_['description'] !== ''): ?>
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>Description</strong> <strong>Description</strong>
<span class="description"> <span class="description">
<?= nl2br($h($_['description'])) ?> <?= nl2br($h($_['description'])) ?>
@@ -47,25 +47,25 @@ $h = static function (string $value): string {
</div> </div>
<?php endif; ?> <?php endif; ?>
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>Start</strong> <strong>Start</strong>
<span><?= $h(str_replace('T', ' ', $_['start'])) ?></span> <span><?= $h(str_replace('T', ' ', $_['start'])) ?></span>
</div> </div>
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>End</strong> <strong>End</strong>
<span><?= $h(str_replace('T', ' ', $_['end'])) ?></span> <span><?= $h(str_replace('T', ' ', $_['end'])) ?></span>
</div> </div>
<?php if ($_['organizer'] !== ''): ?> <?php if ($_['organizer'] !== ''): ?>
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>Organizer</strong> <strong>Organizer</strong>
<span><?= $h($_['organizer']) ?></span> <span><?= $h($_['organizer']) ?></span>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ($_['location'] !== ''): ?> <?php if ($_['location'] !== ''): ?>
<div class="jitsi-calendar-row"> <div class="atocal-row">
<strong>Location</strong> <strong>Location</strong>
<span> <span>
<a <a
@@ -133,7 +133,7 @@ $h = static function (string $value): string {
value="<?= $h($_['url']) ?>" value="<?= $h($_['url']) ?>"
> >
<div class="jitsi-calendar-actions"> <div class="atocal-actions">
<button <button
type="submit" type="submit"
+15 -15
View File
@@ -1,10 +1,10 @@
.jitsi-calendar-container { .atocal-container {
max-width: 760px; max-width: 760px;
margin: 60px auto; margin: 60px auto;
padding: 20px; padding: 20px;
} }
.jitsi-calendar-card { .atocal-card {
background: var(--color-main-background); background: var(--color-main-background);
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
border-radius: 12px; border-radius: 12px;
@@ -12,17 +12,17 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
} }
.jitsi-calendar-card h1 { .atocal-card h1 {
margin-top: 0; margin-top: 0;
margin-bottom: 12px; margin-bottom: 12px;
} }
.jitsi-calendar-intro { .atocal-intro {
color: var(--color-text-maxcontrast); color: var(--color-text-maxcontrast);
margin-bottom: 28px; margin-bottom: 28px;
} }
.jitsi-calendar-error { .atocal-error {
background: var(--color-error); background: var(--color-error);
color: var(--color-error-text); color: var(--color-error-text);
border-radius: 6px; border-radius: 6px;
@@ -30,13 +30,13 @@
margin-bottom: 28px; margin-bottom: 28px;
} }
.jitsi-calendar-details { .atocal-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);
margin-bottom: 28px; margin-bottom: 28px;
} }
.jitsi-calendar-row { .atocal-row {
display: grid; display: grid;
grid-template-columns: 150px 1fr; grid-template-columns: 150px 1fr;
gap: 16px; gap: 16px;
@@ -44,26 +44,26 @@
border-bottom: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
} }
.jitsi-calendar-row:last-child { .atocal-row:last-child {
border-bottom: 0; border-bottom: 0;
} }
.jitsi-calendar-row span { .atocal-row span {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.jitsi-calendar-row .description { .atocal-row .description {
white-space: normal; white-space: normal;
} }
.jitsi-calendar-actions { .atocal-actions {
display: flex; display: flex;
gap: 12px; gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.jitsi-calendar-actions button, .atocal-actions button,
.jitsi-calendar-actions a { .atocal-actions a {
display: inline-block; display: inline-block;
padding: 10px 18px; padding: 10px 18px;
border-radius: 6px; border-radius: 6px;
@@ -71,13 +71,13 @@
cursor: pointer; cursor: pointer;
} }
.jitsi-calendar-actions button.primary { .atocal-actions button.primary {
background: var(--color-primary-element); background: var(--color-primary-element);
color: var(--color-primary-element-text); color: var(--color-primary-element-text);
border: 0; border: 0;
} }
.jitsi-calendar-actions a.secondary { .atocal-actions a.secondary {
border: 1px solid var(--color-border); border: 1px solid var(--color-border);
color: var(--color-main-text); color: var(--color-main-text);
} }