Skip to content

feat: OCS Calendar Export + Import#55178

Open
SebastianKrupinski wants to merge 3 commits intomasterfrom
feat/calendar-import-export-ocs
Open

feat: OCS Calendar Export + Import#55178
SebastianKrupinski wants to merge 3 commits intomasterfrom
feat/calendar-import-export-ocs

Conversation

@SebastianKrupinski
Copy link
Copy Markdown
Contributor

@SebastianKrupinski SebastianKrupinski commented Sep 18, 2025

Summary

Extracted from #49995

This adds the ability to export and import calendars via the OCS

OCS Export

Endpoint: /ocs/v2.php/calendar/export
Request: POST

{
    "id": "personal",
    "format": "xcal", (optional "ical, jcal, xcal", defaults to "ical")
	"options": {
		"rangeStart": '' or 'UID of previous last event',
		"rangeCount": 100
	},
	"user": "user1" (optional admin permissions required)
}

OCS Import

Endpoint: /ocs/v2.php/calendar/import
Request: POST

{
	"id": "personal",
	"options": {
		"format": "xcal", (optional "ical, jcal, xcal", defaults to "ical")
		"validation": 0, (0 - no validate, 1 - validate and skip, 2 - validate and error)
		"errors": 0, (0 - continue, 1 - fail)
		"supersede": true,
		"showCreated": true,
		"showUpdated": true,
		"showSkipped": true,
		"showErrors": true
	},
	"user": "user1", (optional admin permissions required)
	"data": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><calendar><event><title>Meeting</title><date>2025-02-18</date></event></calendar>"
}

Checklist

@SebastianKrupinski SebastianKrupinski requested a review from a team as a code owner September 18, 2025 19:28
@SebastianKrupinski SebastianKrupinski requested review from CarlSchwan, icewind1991 and nfebe and removed request for a team September 18, 2025 19:28
@SebastianKrupinski SebastianKrupinski self-assigned this Sep 18, 2025
@SebastianKrupinski SebastianKrupinski added the 2. developing Work in progress label Sep 18, 2025
@SebastianKrupinski SebastianKrupinski force-pushed the feat/calendar-import-export-ocs branch from 12ad7af to 6838bbe Compare September 23, 2025 00:15
@SebastianKrupinski SebastianKrupinski force-pushed the feat/calendar-import-export-ocs branch 3 times, most recently from e000a47 to a3431ef Compare September 23, 2025 00:57
Copy link
Copy Markdown
Member

@provokateurin provokateurin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code comments in the controller are a bit useless, you might want to remove them to avoid confusion if the code is refactored later.

* @param array{rangeStart:string,rangeCount:int<1,max>} $options configuration options
* @param string|null $user system user id
*
* @return StreamGeneratorResponse<Http::STATUS_OK, array{Content-Type:string}> | DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_UNAUTHORIZED, array{error?: non-empty-string}, array{}>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could limit the Content-Type type to the possible values, so it's clear in the OpenAPI spec what might be returned.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

#[ApiRoute(verb: 'POST', url: '/export', root: '/calendar')]
#[UserRateLimit(limit: 60, period: 60)]
#[NoAdminRequired]
public function index(string $id, ?string $type = null, ?array $options = null, ?string $user = null) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function index(string $id, ?string $type = null, ?array $options = null, ?string $user = null) {
public function export(string $id, ?string $type = null, ?array $options = null, ?string $user = null) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

#[ApiRoute(verb: 'POST', url: '/import', root: '/calendar')]
#[UserRateLimit(limit: 1, period: 60)]
#[NoAdminRequired]
public function index(string $id, array $options, string $data, ?string $user = null): DataResponse {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function index(string $id, array $options, string $data, ?string $user = null): DataResponse {
public function import(string $id, array $options, string $data, ?string $user = null): DataResponse {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

*
* @param string $id calendar id
* @param string|null $type data format
* @param array{rangeStart:string,rangeCount:int<1,max>} $options configuration options
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param array{rangeStart:string,rangeCount:int<1,max>} $options configuration options
* @param array{rangeStart:string,rangeCount:positive-int} $options configuration options

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* Import calendar data
*
* @param string $id calendar id
* @param array{format?:string, validation?:int<0,2>, errors?:int<0,1>, supersede?:bool, showCreated?:bool, showUpdated?:bool, showSkipped?:bool, showErrors?:bool} $options configuration options
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param array{format?:string, validation?:int<0,2>, errors?:int<0,1>, supersede?:bool, showCreated?:bool, showUpdated?:bool, showSkipped?:bool, showErrors?:bool} $options configuration options
* @param array{format?:string, validation?:0|1|2, errors?:0|1, supersede?:bool, showCreated?:bool, showUpdated?:bool, showSkipped?:bool, showErrors?:bool} $options configuration options

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +64 to +71
$format = isset($options['format']) ? $options['format'] : null;
$validation = isset($options['validation']) ? (int)$options['validation'] : null;
$errors = isset($options['errors']) ? (int)$options['errors'] : null;
$supersede = $options['supersede'] ?? false;
$showCreated = $options['showCreated'] ?? false;
$showUpdated = $options['showUpdated'] ?? false;
$showSkipped = $options['showSkipped'] ?? false;
$showErrors = $options['showErrors'] ?? false;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have this options parameter instead of putting all of them into the parameters right away?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes for nicer json formatting and prevents function parameter bloat.

* 400: invalid parameters
* 401: user not authorized
*/
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]

Not necessary

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

* 400: invalid request
* 401: user not authorized
*/
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

use OCP\AppFramework\Http;

/**
* @since 32.0.0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @since 32.0.0
* @since 33.0.0

All @SInCE are wrong here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +6 to +7
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
@SebastianKrupinski SebastianKrupinski force-pushed the feat/calendar-import-export-ocs branch from 2ac397f to 20a731c Compare October 19, 2025 18:23
@SebastianKrupinski SebastianKrupinski added 3. to review Waiting for reviews and removed 2. developing Work in progress labels Jan 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants