mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
feat(sidebar): mutual upcoming events API
Signed-off-by: Anna Larch <anna@nextcloud.com>
This commit is contained in:
parent
779aceb7a1
commit
e324c076f7
16 changed files with 1017 additions and 443 deletions
|
|
@ -12,10 +12,10 @@ return array_merge_recursive(
|
|||
include(__DIR__ . '/routes/routesBanController.php'),
|
||||
include(__DIR__ . '/routes/routesBotController.php'),
|
||||
include(__DIR__ . '/routes/routesBreakoutRoomController.php'),
|
||||
include(__DIR__ . '/routes/routesCalendarIntegrationController.php'),
|
||||
include(__DIR__ . '/routes/routesCallController.php'),
|
||||
include(__DIR__ . '/routes/routesCertificateController.php'),
|
||||
include(__DIR__ . '/routes/routesChatController.php'),
|
||||
include(__DIR__ . '/routes/routesDashboardController.php'),
|
||||
include(__DIR__ . '/routes/routesFederationController.php'),
|
||||
include(__DIR__ . '/routes/routesFilesIntegrationController.php'),
|
||||
include(__DIR__ . '/routes/routesGuestController.php'),
|
||||
|
|
|
|||
25
appinfo/routes/routesCalendarIntegrationController.php
Normal file
25
appinfo/routes/routesCalendarIntegrationController.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
$requirements = [
|
||||
'apiVersion' => '(v4)',
|
||||
];
|
||||
|
||||
$requirementsWithToken = [
|
||||
'apiVersion' => '(v4)',
|
||||
'token' => '[a-z0-9]{4,30}',
|
||||
];
|
||||
|
||||
return [
|
||||
'ocs' => [
|
||||
/** @see \OCA\Talk\Controller\CalendarIntegrationController::getDashboardEvents() */
|
||||
['name' => 'CalendarIntegration#getDashboardEvents', 'url' => '/api/{apiVersion}/dashboard/events', 'verb' => 'GET', 'requirements' => $requirements],
|
||||
/** @see \OCA\Talk\Controller\CalendarIntegrationController::getMutualEvents() */
|
||||
['name' => 'CalendarIntegration#getMutualEvents', 'url' => '/api/{apiVersion}/room/{token}/mutual-events', 'verb' => 'GET', 'requirements' => $requirementsWithToken],
|
||||
],
|
||||
];
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
$requirements = [
|
||||
'apiVersion' => '(v4)',
|
||||
];
|
||||
|
||||
return [
|
||||
'ocs' => [
|
||||
/** @see \OCA\Talk\Controller\DashboardController::getEventRooms() */
|
||||
['name' => 'Dashboard#getEventRooms', 'url' => '/api/{apiVersion}/dashboard/events', 'verb' => 'GET', 'requirements' => $requirements],
|
||||
],
|
||||
];
|
||||
|
|
@ -185,3 +185,4 @@
|
|||
* `important-conversations` (local) - Whether important conversations are supported
|
||||
* `config => call => predefined-backgrounds-v2` (local) - Whether virtual backgrounds should be read from the theming directory
|
||||
* `dashboard-event-rooms` (local) - Whether Talk APIs offer functionality for Dashboard requests
|
||||
* `mutual-calendar-events` (local) - Whether Talk APIs offer mutual calendar events for 1:1 rooms
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ class Capabilities implements IPublicCapability {
|
|||
'important-conversations',
|
||||
'sip-direct-dialin',
|
||||
'dashboard-event-rooms',
|
||||
'mutual-calendar-events',
|
||||
];
|
||||
|
||||
public const CONDITIONAL_FEATURES = [
|
||||
|
|
@ -145,6 +146,7 @@ class Capabilities implements IPublicCapability {
|
|||
'important-conversations',
|
||||
'sip-direct-dialin',
|
||||
'dashboard-event-rooms',
|
||||
'mutual-calendar-events',
|
||||
];
|
||||
|
||||
public const LOCAL_CONFIGS = [
|
||||
|
|
|
|||
77
lib/Controller/CalendarIntegrationController.php
Normal file
77
lib/Controller/CalendarIntegrationController.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Controller;
|
||||
|
||||
use OCA\Talk\Exceptions\InvalidRoomException;
|
||||
use OCA\Talk\Exceptions\ParticipantNotFoundException;
|
||||
use OCA\Talk\Middleware\Attribute\RequireParticipant;
|
||||
use OCA\Talk\ResponseDefinitions;
|
||||
use OCA\Talk\Service\CalendarIntegrationService;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUserSession;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-import-type TalkDashboardEvent from ResponseDefinitions
|
||||
*/
|
||||
class CalendarIntegrationController extends AEnvironmentAwareOCSController {
|
||||
public function __construct(
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
protected IUserSession $userSession,
|
||||
protected LoggerInterface $logger,
|
||||
protected CalendarIntegrationService $service,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days
|
||||
* sorted by their start timestamp ascending
|
||||
*
|
||||
* Required capability: `dashboard-event-rooms`
|
||||
*
|
||||
* @return DataResponse<Http::STATUS_OK, list<TalkDashboardEvent>, array{}>
|
||||
*
|
||||
* 200: A list of dashboard entries or an empty array
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function getDashboardEvents(): DataResponse {
|
||||
$userId = $this->userSession->getUser()?->getUID();
|
||||
$entries = $this->service->getDashboardEvents($userId);
|
||||
return new DataResponse($entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get up to 3 events in the next 7 days
|
||||
* sorted by their start timestamp ascending
|
||||
*
|
||||
* Required capability: `mutual-calendar-events`
|
||||
*
|
||||
* @return DataResponse<Http::STATUS_OK, list<TalkDashboardEvent>, array{}>|DataResponse<Http::STATUS_FORBIDDEN, null, array{}>
|
||||
*
|
||||
* 200: A list of dashboard entries or an empty array
|
||||
* 403: Room is not a 1 to 1 room, room is invalid, or user is not participant
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
#[RequireParticipant]
|
||||
public function getMutualEvents(): DataResponse {
|
||||
$userId = $this->userSession->getUser()?->getUID();
|
||||
try {
|
||||
$entries = $this->service->getMutualEvents($userId, $this->room);
|
||||
} catch (InvalidRoomException|ParticipantNotFoundException) {
|
||||
return new DataResponse(null, Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
return new DataResponse($entries);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Controller;
|
||||
|
||||
use OCA\Talk\ResponseDefinitions;
|
||||
use OCA\Talk\Service\DashboardService;
|
||||
use OCA\Talk\Service\ParticipantService;
|
||||
use OCA\Talk\Service\RoomFormatter;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
use OCP\IRequest;
|
||||
use OCP\IUserSession;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-import-type TalkDashboardEvent from ResponseDefinitions
|
||||
*/
|
||||
class DashboardController extends AEnvironmentAwareOCSController {
|
||||
public function __construct(
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
protected IUserSession $userSession,
|
||||
protected LoggerInterface $logger,
|
||||
protected DashboardService $service,
|
||||
protected ParticipantService $participantService,
|
||||
protected RoomFormatter $formatter,
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days
|
||||
* sorted by their start timestamp ascending
|
||||
*
|
||||
* Required capability: `dashboard-event-rooms`
|
||||
*
|
||||
* @return DataResponse<Http::STATUS_OK, list<TalkDashboardEvent>, array{}>
|
||||
*
|
||||
* 200: A list of dashboard entries or an empty array
|
||||
*/
|
||||
#[NoAdminRequired]
|
||||
public function getEventRooms(): DataResponse {
|
||||
$userId = $this->userSession->getUser()?->getUID();
|
||||
$entries = $this->service->getEvents($userId);
|
||||
return new DataResponse($entries);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,20 +10,24 @@ declare(strict_types=1);
|
|||
namespace OCA\Talk\Service;
|
||||
|
||||
use OCA\Talk\Dashboard\Event;
|
||||
use OCA\Talk\Exceptions\InvalidRoomException;
|
||||
use OCA\Talk\Exceptions\ParticipantNotFoundException;
|
||||
use OCA\Talk\Exceptions\RoomNotFoundException;
|
||||
use OCA\Talk\Manager;
|
||||
use OCA\Talk\ResponseDefinitions;
|
||||
use OCA\Talk\Room;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\Calendar\ICalendar;
|
||||
use OCP\Calendar\IManager;
|
||||
use OCP\IDateTimeZone;
|
||||
use OCP\IURLGenerator;
|
||||
use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-import-type TalkDashboardEvent from ResponseDefinitions
|
||||
*/
|
||||
class DashboardService {
|
||||
class CalendarIntegrationService {
|
||||
public function __construct(
|
||||
private Manager $manager,
|
||||
private IManager $calendarManager,
|
||||
|
|
@ -33,6 +37,7 @@ class DashboardService {
|
|||
private IDateTimeZone $dateTimeZone,
|
||||
private AvatarService $avatarService,
|
||||
private IURLGenerator $urlGenerator,
|
||||
private IUserManager $userManager,
|
||||
) {
|
||||
|
||||
}
|
||||
|
|
@ -41,7 +46,7 @@ class DashboardService {
|
|||
* @param string $userId
|
||||
* @return list<TalkDashboardEvent>
|
||||
*/
|
||||
public function getEvents(string $userId): array {
|
||||
public function getDashboardEvents(string $userId): array {
|
||||
$principaluri = 'principals/users/' . $userId;
|
||||
$calendars = $this->calendarManager->getCalendarsForPrincipal($principaluri);
|
||||
if (count($calendars) === 0) {
|
||||
|
|
@ -177,4 +182,151 @@ class DashboardService {
|
|||
return $event->jsonSerialize();
|
||||
}, array_slice($events, 0, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @param Room $room
|
||||
* @return list<TalkDashboardEvent>
|
||||
*/
|
||||
public function getMutualEvents(string $userId, Room $room): array {
|
||||
if ($room->getType() !== Room::TYPE_ONE_TO_ONE) {
|
||||
throw new InvalidRoomException();
|
||||
}
|
||||
|
||||
try {
|
||||
$userIds = json_decode($room->getName(), false, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException) {
|
||||
throw new InvalidRoomException();
|
||||
}
|
||||
|
||||
$participants = array_filter($userIds, static function (string $participantId) use ($userId) {
|
||||
return $participantId !== $userId;
|
||||
});
|
||||
|
||||
if (count($participants) !== 1) {
|
||||
throw new InvalidRoomException();
|
||||
}
|
||||
|
||||
$otherParticipant = $this->userManager->get(array_pop($participants));
|
||||
if ($otherParticipant === null) {
|
||||
// Change to correct exception
|
||||
throw new ParticipantNotFoundException();
|
||||
}
|
||||
|
||||
$pattern = $otherParticipant->getEMailAddress();
|
||||
if ($pattern === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$principaluri = 'principals/users/' . $userId;
|
||||
$calendars = $this->calendarManager->getCalendarsForPrincipal($principaluri);
|
||||
if (count($calendars) === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Only use personal calendars
|
||||
$calendars = array_filter($calendars, static function (ICalendar $calendar) {
|
||||
if (method_exists($calendar, 'isShared')) {
|
||||
return $calendar->isShared() === false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$start = $this->timeFactory->getDateTime();
|
||||
$end = clone($start);
|
||||
$end = $end->add(\DateInterval::createFromDateString('1 week'));
|
||||
$options = [
|
||||
'timerange' => [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
],
|
||||
];
|
||||
|
||||
$userTimezone = $this->dateTimeZone->getTimezone();
|
||||
$searchProperties = ['ATTENDEE', 'ORGANIZER'];
|
||||
$events = [];
|
||||
/** @var ICalendar $calendar */
|
||||
foreach ($calendars as $calendar) {
|
||||
$searchResult = $calendar->search($pattern, $searchProperties, $options);
|
||||
foreach ($searchResult as $calendarEvent) {
|
||||
// Find first recurrence in the future
|
||||
$event = null;
|
||||
$dashboardEvent = new Event();
|
||||
foreach ($calendarEvent['objects'] as $object) {
|
||||
$dashboardEvent->setStart(\DateTime::createFromImmutable($object['DTSTART'][0])->setTimezone($userTimezone)->getTimestamp());
|
||||
$dashboardEvent->setEnd(\DateTime::createFromImmutable($object['DTEND'][0])->setTimezone($userTimezone)->getTimestamp());
|
||||
|
||||
if ($dashboardEvent->getStart() >= $start->getTimestamp()) {
|
||||
$event = $object;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($event === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dashboardEvent->setEventName($event['SUMMARY'][0] ?? '');
|
||||
$dashboardEvent->setEventDescription($event['DESCRIPTION'][0] ?? null);
|
||||
$dashboardEvent->addCalendar($calendar->getUri(), $calendar->getDisplayName(), $calendar->getDisplayColor());
|
||||
|
||||
$location = $event['LOCATION'][0] ?? null;
|
||||
if ($location !== null && str_contains($location, '/call/') === true) {
|
||||
try {
|
||||
$token = $this->roomService->parseRoomTokenFromUrl($location);
|
||||
// Already returns public / open conversations
|
||||
$eventRoom = $this->manager->getRoomForUserByToken($token, $userId);
|
||||
} catch (RoomNotFoundException) {
|
||||
$this->logger->debug("Room for url $location not found in dashboard service");
|
||||
continue;
|
||||
}
|
||||
$dashboardEvent->setRoomType($eventRoom->getType());
|
||||
$dashboardEvent->setRoomName($eventRoom->getName());
|
||||
$dashboardEvent->setRoomToken($eventRoom->getToken());
|
||||
$dashboardEvent->setRoomDisplayName($eventRoom->getDisplayName($userId));
|
||||
$dashboardEvent->setRoomAvatarVersion($this->avatarService->getAvatarVersion($eventRoom));
|
||||
$dashboardEvent->setRoomActiveSince($eventRoom->getActiveSince()?->getTimestamp());
|
||||
}
|
||||
|
||||
if (isset($event['ATTENDEE'])) {
|
||||
$dashboardEvent->generateAttendance($event['ATTENDEE']);
|
||||
}
|
||||
|
||||
if (isset($event['ATTACH'])) {
|
||||
$dashboardEvent->handleCalendarAttachments($calendar->getUri(), $event['ATTACH']);
|
||||
}
|
||||
|
||||
$objectId = base64_encode($this->urlGenerator->getWebroot() . '/remote.php/dav/calendars/' . $userId . '/' . $calendar->getUri() . '/' . $calendarEvent['uri']);
|
||||
if (isset($event['RECURRENCE-ID'])) {
|
||||
$dashboardEvent->setEventLink(
|
||||
$this->urlGenerator->linkToRouteAbsolute(
|
||||
'calendar.view.indexdirect.edit',
|
||||
[
|
||||
'objectId' => $objectId,
|
||||
'recurrenceId' => $event['RECURRENCE-ID'][0],
|
||||
]
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$dashboardEvent->setEventLink(
|
||||
$this->urlGenerator->linkToRouteAbsolute('calendar.view.indexdirect.edit', ['objectId' => $objectId])
|
||||
);
|
||||
}
|
||||
|
||||
$events[] = $dashboardEvent;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($events)) {
|
||||
return $events;
|
||||
}
|
||||
|
||||
usort($events, static function (Event $a, Event $b) {
|
||||
return $a->getStart() - $b->getStart();
|
||||
});
|
||||
|
||||
return array_map(static function (Event $event) {
|
||||
return $event->jsonSerialize();
|
||||
}, array_slice($events, 0, 3));
|
||||
}
|
||||
}
|
||||
|
|
@ -4304,6 +4304,199 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
"get": {
|
||||
"operationId": "calendar_integration-get-dashboard-events",
|
||||
"summary": "Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `dashboard-event-rooms`",
|
||||
"tags": [
|
||||
"calendar_integration"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/mutual-events": {
|
||||
"get": {
|
||||
"operationId": "calendar_integration-get-mutual-events",
|
||||
"summary": "Get up to 3 events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `mutual-calendar-events`",
|
||||
"tags": [
|
||||
"calendar_integration"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]{4,30}$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Room is not a 1 to 1 room, room is invalid, or user is not participant",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}": {
|
||||
"get": {
|
||||
"operationId": "call-get-peers-for-call",
|
||||
|
|
@ -8716,83 +8909,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
"get": {
|
||||
"operationId": "dashboard-get-event-rooms",
|
||||
"summary": "Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `dashboard-event-rooms`",
|
||||
"tags": [
|
||||
"dashboard"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/file/{fileId}": {
|
||||
"get": {
|
||||
"operationId": "files_integration-get-room-by-file-id",
|
||||
|
|
|
|||
270
openapi.json
270
openapi.json
|
|
@ -4209,6 +4209,199 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
"get": {
|
||||
"operationId": "calendar_integration-get-dashboard-events",
|
||||
"summary": "Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `dashboard-event-rooms`",
|
||||
"tags": [
|
||||
"calendar_integration"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/mutual-events": {
|
||||
"get": {
|
||||
"operationId": "calendar_integration-get-mutual-events",
|
||||
"summary": "Get up to 3 events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `mutual-calendar-events`",
|
||||
"tags": [
|
||||
"calendar_integration"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]{4,30}$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Room is not a 1 to 1 room, room is invalid, or user is not participant",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}": {
|
||||
"get": {
|
||||
"operationId": "call-get-peers-for-call",
|
||||
|
|
@ -8621,83 +8814,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
"get": {
|
||||
"operationId": "dashboard-get-event-rooms",
|
||||
"summary": "Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending",
|
||||
"description": "Required capability: `dashboard-event-rooms`",
|
||||
"tags": [
|
||||
"dashboard"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer_auth": []
|
||||
},
|
||||
{
|
||||
"basic_auth": []
|
||||
}
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "apiVersion",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"v4"
|
||||
],
|
||||
"default": "v4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "OCS-APIRequest",
|
||||
"in": "header",
|
||||
"description": "Required to be true for the API request to pass",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A list of dashboard entries or an empty array",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ocs"
|
||||
],
|
||||
"properties": {
|
||||
"ocs": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"meta",
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"meta": {
|
||||
"$ref": "#/components/schemas/OCSMeta"
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/DashboardEvent"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/file/{fileId}": {
|
||||
"get": {
|
||||
"operationId": "files_integration-get-room-by-file-id",
|
||||
|
|
|
|||
|
|
@ -241,6 +241,46 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `dashboard-event-rooms`
|
||||
*/
|
||||
get: operations["calendar_integration-get-dashboard-events"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/mutual-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 3 events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `mutual-calendar-events`
|
||||
*/
|
||||
get: operations["calendar_integration-get-mutual-events"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -528,26 +568,6 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `dashboard-event-rooms`
|
||||
*/
|
||||
get: operations["dashboard-get-event-rooms"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/file/{fileId}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -3593,6 +3613,81 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"calendar_integration-get-dashboard-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"calendar_integration-get-mutual-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
token: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Room is not a 1 to 1 room, room is invalid, or user is not participant */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"call-get-peers-for-call": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -5343,36 +5438,6 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"dashboard-get-event-rooms": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"files_integration-get-room-by-file-id": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
|||
|
|
@ -241,6 +241,46 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `dashboard-event-rooms`
|
||||
*/
|
||||
get: operations["calendar_integration-get-dashboard-events"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/mutual-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 3 events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `mutual-calendar-events`
|
||||
*/
|
||||
get: operations["calendar_integration-get-mutual-events"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/call/{token}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -528,26 +568,6 @@ export type paths = {
|
|||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/dashboard/events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Get up to 10 rooms that have events in the next 7 days sorted by their start timestamp ascending
|
||||
* @description Required capability: `dashboard-event-rooms`
|
||||
*/
|
||||
get: operations["dashboard-get-event-rooms"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/ocs/v2.php/apps/spreed/api/{apiVersion}/file/{fileId}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -3055,6 +3075,81 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"calendar_integration-get-dashboard-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"calendar_integration-get-mutual-events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
token: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Room is not a 1 to 1 room, room is invalid, or user is not participant */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: unknown;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"call-get-peers-for-call": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -4805,36 +4900,6 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
"dashboard-get-event-rooms": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header: {
|
||||
/** @description Required to be true for the API request to pass */
|
||||
"OCS-APIRequest": boolean;
|
||||
};
|
||||
path: {
|
||||
apiVersion: "v4";
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description A list of dashboard entries or an empty array */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": {
|
||||
ocs: {
|
||||
meta: components["schemas"]["OCSMeta"];
|
||||
data: components["schemas"]["DashboardEvent"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
"files_integration-get-room-by-file-id": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
|||
|
|
@ -3456,6 +3456,20 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
}
|
||||
}
|
||||
|
||||
#[Given('/^user "([^"]*)" exists and has an email address$/')]
|
||||
public function assureUserExistsAndHasEmail(string $user): void {
|
||||
$response = $this->userExists($user);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
$this->createUser($user);
|
||||
// Set a display name different than the user ID to be able to
|
||||
// ensure in the tests that the right value was returned.
|
||||
$this->setUserDisplayName($user);
|
||||
$response = $this->userExists($user);
|
||||
$this->assertStatusCode($response, 200);
|
||||
}
|
||||
$this->setUserEmail($user);
|
||||
}
|
||||
|
||||
#[Given('/^(enable|disable) brute force protection$/')]
|
||||
public function enableDisableBruteForceProtection(string $enable): void {
|
||||
if ($enable === 'enable') {
|
||||
|
|
@ -3660,6 +3674,15 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
$this->setCurrentUser($currentUser);
|
||||
}
|
||||
|
||||
private function setUserEmail(string $user): void {
|
||||
$currentUser = $this->setCurrentUser('admin');
|
||||
$this->sendRequest('PUT', '/cloud/users/' . $user, [
|
||||
'key' => 'email',
|
||||
'value' => $user . '@example.tld'
|
||||
]);
|
||||
$this->setCurrentUser($currentUser);
|
||||
}
|
||||
|
||||
#[Given('/^group "([^"]*)" exists$/')]
|
||||
public function assureGroupExists(string $group): void {
|
||||
$currentUser = $this->setCurrentUser('admin');
|
||||
|
|
@ -4378,70 +4401,15 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @param string $identifier
|
||||
* @param int $statusCode
|
||||
* @param string $apiVersion
|
||||
* @param TableNode|null $formData
|
||||
* @return void
|
||||
*
|
||||
* @Given /^user "([^"]*)" creates conversation with event "([^"]*)" \((v4)\)$/
|
||||
*/
|
||||
public function createCalendarEventConversation(string $user, string $identifier, string $apiVersion = 'v1', ?TableNode $formData = null): void {
|
||||
$body = $formData->getRowsHash();
|
||||
$startTime = time() + 86400;
|
||||
$endTime = time() + 90000;
|
||||
if (isset($body['objectId'])) {
|
||||
[$start, $end] = explode('#', $body['objectId']);
|
||||
$startTime = time() + (int)$start;
|
||||
$endTime = time() + (int)$end;
|
||||
$body['objectId'] = $startTime . '#' . $endTime;
|
||||
self::$identifierToObjectId[$identifier] = $body['objectId'];
|
||||
}
|
||||
|
||||
$body['roomName'] = $identifier;
|
||||
|
||||
$this->setCurrentUser($user);
|
||||
$this->sendRequest('POST', '/apps/spreed/api/' . $apiVersion . '/room', $body);
|
||||
$this->assertStatusCode($this->response, 201);
|
||||
|
||||
$response = $this->getDataFromResponse($this->response);
|
||||
|
||||
self::$identifierToToken[$identifier] = $response['token'];
|
||||
self::$identifierToId[$identifier] = $response['id'];
|
||||
self::$tokenToIdentifier[$response['token']] = $identifier;
|
||||
|
||||
$location = self::getRoomLocationForToken($identifier);
|
||||
$this->sendRequest('POST', '/apps/spreedcheats/calendar', [
|
||||
'name' => $identifier,
|
||||
'location' => $location,
|
||||
'start' => $startTime,
|
||||
'end' => $endTime,
|
||||
]);
|
||||
|
||||
$this->assertStatusCode($this->response, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @param string $identifier
|
||||
* @param int $statusCode
|
||||
* @param string $apiVersion
|
||||
* @param TableNode|null $formData
|
||||
* @return void
|
||||
*
|
||||
* @Given /^user "([^"]*)" creates calendar events for a room "([^"]*)" \((v4)\)$/
|
||||
*/
|
||||
#[Given('/^user "([^"]*)" creates calendar events for a room "([^"]*)" \((v4)\)$/')]
|
||||
public function createCalendarEntriesWithRoom(string $user, string $identifier, string $apiVersion = 'v1', ?TableNode $formData = null): void {
|
||||
$body = $formData->getRowsHash();
|
||||
$this->setCurrentUser($user);
|
||||
|
||||
$body = $formData->getRowsHash();
|
||||
$body['roomName'] = $identifier;
|
||||
if (!isset(self::$tokenToIdentifier[$identifier])) {
|
||||
$this->setCurrentUser($user);
|
||||
$this->sendRequest('POST', '/apps/spreed/api/' . $apiVersion . '/room', $body);
|
||||
$this->assertStatusCode($this->response, 201);
|
||||
|
||||
$response = $this->getDataFromResponse($this->response);
|
||||
|
||||
self::$identifierToToken[$identifier] = $response['token'];
|
||||
|
|
@ -4449,7 +4417,6 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
self::$tokenToIdentifier[$response['token']] = $identifier;
|
||||
}
|
||||
|
||||
|
||||
$location = self::getRoomLocationForToken($identifier);
|
||||
$this->sendRequest('POST', '/apps/spreedcheats/dashboardEvents', [
|
||||
'name' => $identifier,
|
||||
|
|
@ -4459,6 +4426,17 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
$this->assertStatusCode($this->response, 200);
|
||||
}
|
||||
|
||||
#[Given('/^user "([^"]*)" creates calendar events inviting user "([^"]*)" \((v4)\)$/')]
|
||||
public function createEventsForOneToOne(string $user, string $participant, string $apiVersion = 'v1', ?TableNode $formData = null): void {
|
||||
$this->setCurrentUser($user);
|
||||
$this->sendRequest('POST', '/apps/spreedcheats/mutualEvents', [
|
||||
'organizer' => $user,
|
||||
'attendee' => $participant,
|
||||
]);
|
||||
|
||||
$this->assertStatusCode($this->response, 200);
|
||||
}
|
||||
|
||||
#[Then('/^user "([^"]*)" sees the following entry when loading the dashboard conversations \((v4)\)$/')]
|
||||
public function userGetsEventConversationsForTalkDashboard(string $user, string $apiVersion, ?TableNode $formData = null): void {
|
||||
$this->setCurrentUser($user);
|
||||
|
|
@ -4474,6 +4452,23 @@ class FeatureContext implements Context, SnippetAcceptingContext {
|
|||
$this->assertDashboardData($data, $formData);
|
||||
}
|
||||
|
||||
#[Then('/^user "([^"]*)" sees the following entry when loading mutual events in room "([^"]*)" \((v4)\)$/')]
|
||||
public function userGetsMutualEventConversations(string $user, string $identifier, string $apiVersion, ?TableNode $formData = null): void {
|
||||
$this->setCurrentUser($user);
|
||||
$token = self::$identifierToToken[$identifier];
|
||||
$this->sendRequest('GET', '/apps/spreed/api/' . $apiVersion . '/room/' . $token . '/mutual-events');
|
||||
$this->assertStatusCode($this->response, 200);
|
||||
|
||||
$data = $this->getDataFromResponse($this->response);
|
||||
if (!$formData instanceof TableNode) {
|
||||
Assert::assertEmpty($data);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->assertDashboardData($data, $formData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $dashboardEvents
|
||||
* @param TableNode $formData
|
||||
|
|
|
|||
|
|
@ -13,3 +13,28 @@ Feature: integration/dashboard-talk
|
|||
|dashboardRoom | 2 | dashboardRoom-attachment | null | null | null | null | 1 | 1 |
|
||||
|dashboardRoom | 2 | dashboardRoom-attendees | 1 | 1 | null | null | 0 | 1 |
|
||||
|dashboardRoom | 2 | dashboardRoom-recurring | null | null | null | null | 0 | 1 |
|
||||
|
||||
Scenario: User gets mutual events for a one to one conversation
|
||||
Given user "participant1" exists and has an email address
|
||||
Given user "participant2" exists and has an email address
|
||||
Given user "participant1" creates room "room1" (v4)
|
||||
| roomType | 1 |
|
||||
| invite | participant2 |
|
||||
Given user "participant2" creates room "room1" with 200 (v4)
|
||||
| roomType | 1 |
|
||||
| invite | participant1 |
|
||||
Then user "participant1" is participant of room "room1" (v4)
|
||||
And user "participant2" is participant of room "room1" (v4)
|
||||
And user "participant1" joins room "room1" with 200 (v4)
|
||||
Given user "participant1" creates calendar events inviting user "participant2" (v4)
|
||||
Then user "participant1" sees the following entry when loading mutual events in room "room1" (v4)
|
||||
| eventName | eventDescription | invited | accepted | declined | tentative | eventAttachments | calendars | roomType |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
Then user "participant2" joins room "room1" with 200 (v4)
|
||||
Then user "participant2" sees the following entry when loading mutual events in room "room1" (v4)
|
||||
| eventName | eventDescription | invited | accepted | declined | tentative | eventAttachments | calendars | roomType |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
| Test | Test | 1 | null | null | null | 0 | 1 | 0 |
|
||||
|
|
|
|||
|
|
@ -12,5 +12,6 @@ return [
|
|||
['name' => 'Api#ageChat', 'url' => '/age', 'verb' => 'POST'],
|
||||
['name' => 'Api#createEventInCalendar', 'url' => '/calendar', 'verb' => 'POST'],
|
||||
['name' => 'Api#createDashboardEvents', 'url' => '/dashboardEvents', 'verb' => 'POST'],
|
||||
['name' => 'Api#createEventAndInviteParticipant', 'url' => '/mutualEvents', 'verb' => 'POST'],
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
|||
use OCP\IDBConnection;
|
||||
use OCP\IRequest;
|
||||
use OCP\Share\IShare;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\UUIDUtil;
|
||||
|
||||
class ApiController extends OCSController {
|
||||
|
|
@ -180,59 +181,6 @@ class ApiController extends OCSController {
|
|||
return new DataResponse();
|
||||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
public function createEventInCalendar(string $name, string $location, string $start, string $end): DataResponse {
|
||||
if ($this->userId === null) {
|
||||
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$calendar = null;
|
||||
// Create a calendar event with LOCATION and time via OCP
|
||||
$calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $this->userId);
|
||||
foreach ($calendars as $c) {
|
||||
if ($c instanceof ICreateFromString) {
|
||||
$calendar = $c;
|
||||
}
|
||||
}
|
||||
|
||||
if ($calendar === null) {
|
||||
return new DataResponse(null, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
$calData = <<<EOF
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:-//IDN nextcloud.com//Calendar app 5.2.0-dev.1//EN
|
||||
CALSCALE:GREGORIAN
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
CREATED:20250310T171800Z
|
||||
DTSTAMP:20250310T171819Z
|
||||
LAST-MODIFIED:20250310T171819Z
|
||||
SEQUENCE:2
|
||||
UID:{{{UID}}}
|
||||
DTSTART:{{{START}}}
|
||||
DTEND:{{{END}}}
|
||||
STATUS:CONFIRMED
|
||||
SUMMARY:{{{NAME}}}
|
||||
LOCATION:{{{LOCATION}}}
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
EOF;
|
||||
|
||||
$start = (new \DateTime())->setTimestamp((int)$start)->format('Ymd\THis');
|
||||
$end = (new \DateTime())->setTimestamp((int)$end)->format('Ymd\THis');
|
||||
$uid = UUIDUtil::getUUID();
|
||||
$calData = str_replace(['{{{NAME}}}', '{{{START}}}', '{{{END}}}', '{{{UID}}}', '{{{LOCATION}}}'], [$name, $start, $end, $uid, $location], $calData);
|
||||
|
||||
try {
|
||||
/** @var ICreateFromString $calendar */
|
||||
$calendar->createFromString((string)random_int(0, 10000), $calData);
|
||||
} catch (CalendarException) {
|
||||
return new DataResponse(null, Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
return new DataResponse();
|
||||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
public function createDashboardEvents(string $name, string $location): DataResponse {
|
||||
if ($this->userId === null) {
|
||||
|
|
@ -258,7 +206,7 @@ EOF;
|
|||
foreach ($events as $event) {
|
||||
try {
|
||||
/** @var ICreateFromString $calendar */
|
||||
$calendar->createFromString((string)random_int(0, 10000), $event);
|
||||
$calendar->createFromString(random_int(0, 10000) . '.ics', $event);
|
||||
} catch (CalendarException) {
|
||||
return new DataResponse(null, Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
|
|
@ -266,4 +214,63 @@ EOF;
|
|||
|
||||
return new DataResponse();
|
||||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
public function createEventAndInviteParticipant(string $organizer, string $attendee): DataResponse {
|
||||
if ($this->userId === null) {
|
||||
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$calendar = null;
|
||||
// Create a calendar event with LOCATION and time via OCP
|
||||
$calendars = $this->calendarManager->getCalendarsForPrincipal('principals/users/' . $this->userId);
|
||||
foreach ($calendars as $c) {
|
||||
if ($c instanceof ICreateFromString) {
|
||||
$calendar = $c;
|
||||
}
|
||||
}
|
||||
|
||||
if ($calendar === null) {
|
||||
return new DataResponse(null, Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
$start = time();
|
||||
$end = $start + 3600;
|
||||
$startTime = (new \DateTime())->setTimestamp($start);
|
||||
$endTime = (new \DateTime())->setTimestamp($end);
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$interval = new \DateInterval('PT2H');
|
||||
$startTime->add($interval);
|
||||
$endTime->add($interval);
|
||||
|
||||
$vCalendar = new VCalendar();
|
||||
$vevent = $vCalendar->createComponent('VEVENT');
|
||||
$vevent->add('UID', UUIDUtil::getUUID());
|
||||
$vevent->add('DTSTART');
|
||||
$vevent->DTSTART->setDateTime($startTime);
|
||||
$vevent->add('DTEND');
|
||||
$vevent->DTEND->setDateTime($endTime);
|
||||
$vevent->add('SUMMARY', 'Test');
|
||||
$vevent->add('DESCRIPTION', 'Test');
|
||||
$vevent->add('ORGANIZER', 'mailto:' . $organizer . '@example.tld', ['CN' => $organizer]);
|
||||
$vevent->add('ATTENDEE', 'mailto:' . $attendee . '@example.tld', [
|
||||
'CN' => $attendee,
|
||||
'CUTYPE' => 'INDIVIDUAL',
|
||||
'PARTSTAT' => 'NEEDS-ACTION',
|
||||
'ROLE' => 'REQ-PARTICIPANT',
|
||||
'RSVP' => 'TRUE'
|
||||
]);
|
||||
$vevent->add('STATUS', 'CONFIRMED');
|
||||
|
||||
$vCalendar->add($vevent);
|
||||
$cal = $vCalendar->serialize();
|
||||
try {
|
||||
/** @var ICreateFromString $calendar */
|
||||
$calendar->createFromString(random_int(0, 10000) . '.ics', $cal);
|
||||
} catch (CalendarException) {
|
||||
return new DataResponse(null, Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
return new DataResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue