diff --git a/code_samples/back_office/notifications/src/Notification/ListRenderer.php b/code_samples/back_office/notifications/src/Notification/ListRenderer.php index ced5b5dd1d..4c7153a582 100644 --- a/code_samples/back_office/notifications/src/Notification/ListRenderer.php +++ b/code_samples/back_office/notifications/src/Notification/ListRenderer.php @@ -13,17 +13,8 @@ class ListRenderer implements NotificationRenderer, TypedNotificationRendererInterface { - protected Environment $twig; - - protected RouterInterface $router; - - protected RequestStack $requestStack; - - public function __construct(Environment $twig, RouterInterface $router, RequestStack $requestStack) + public function __construct(protected Environment $twig, protected RouterInterface $router, protected RequestStack $requestStack) { - $this->twig = $twig; - $this->router = $router; - $this->requestStack = $requestStack; } public function render(Notification $notification): string diff --git a/code_samples/collaboration/src/Command/ManageSessionsCommand.php b/code_samples/collaboration/src/Command/ManageSessionsCommand.php new file mode 100644 index 0000000000..1eebd931c6 --- /dev/null +++ b/code_samples/collaboration/src/Command/ManageSessionsCommand.php @@ -0,0 +1,158 @@ +permissionResolver->setCurrentUserReference( + $this->userService->loadUserByLogin('admin') + ); + + // Create a sharing session for Content + $versionInfo = $this->contentService->loadContent(52)->getVersionInfo(); + $createStruct = new ContentSessionCreateStruct( + $versionInfo, + $versionInfo->getInitialLanguage() + ); + $createStruct->setHasPublicLink(false); + + $token = 'my-secret-token-12345'; + $createStruct->setToken($token); + + $sessionId = $this->sessionService->createSession($createStruct)->getId(); + + // Get a session by ID or token + $session = $this->sessionService->getSession($sessionId); + $session = $this->sessionService->getSessionByToken($token); + + // Find sessions + $sessionQuery = new SessionQuery(new Token($token)); + $session = $this->sessionService->findSessions($sessionQuery)->getFirst(); + + // Update a session + $updateStruct = new ContentSessionUpdateStruct(); + $updateStruct->setHasPublicLink(true); + + $this->sessionService->updateSession($session, $updateStruct); + + // Deactivate a session + $updateStruct = new ContentSessionUpdateStruct(); + $updateStruct->setIsActive(false); + + $this->sessionService->updateSession($session, $updateStruct); + + // Manage participants + $user = $this->userService->loadUserByLogin('another_user'); + $internalParticipantCreateStruct = new InternalParticipantCreateStruct( + $user, + ContentSessionScope::VIEW + ); + $externalParticipantCreateStruct = new ExternalParticipantCreateStruct( + 'external@example.com', + ContentSessionScope::VIEW, + 'personal-secret-token-12345' + ); + + $internalParticipant = $this->sessionService->addParticipant($session, $internalParticipantCreateStruct); + $externalParticipant = $this->sessionService->addParticipant($session, $externalParticipantCreateStruct); + + // Get and update participants + $participant = $this->sessionService + ->getSession($session->getId()) + ->getParticipants() + ->getByEmail($user->email); + + $internalParticipantUpdateStruct = new InternalParticipantUpdateStruct(ContentSessionScope::EDIT); + $this->sessionService->updateParticipant($session, $participant, $internalParticipantUpdateStruct); + + // Remove participant + $this->sessionService->removeParticipant($session, $externalParticipant); + + // Check ownerships. If no user is provided, current user is used. + $this->sessionService->isSessionOwner( + $session, + $this->userService->loadUserByLogin('another_user') + ); + + // Check participation + $this->sessionService->isSessionParticipant( + $session, + $this->permissionResolver->getCurrentUserReference() + ); + + // Manage invitations + $invitationQuery = new InvitationQuery(new Session($session)); + $invitations = $this->invitationService->findInvitations($invitationQuery)->getInvitations(); + + foreach ($invitations as $invitation) { + $output->writeln('Invitation ID: ' . $invitation->getId() . ' Status: ' . $invitation->getStatus()); + } + + $invitation = $this->invitationService->getInvitationByParticipant($participant); + + // Create invitation - use when auto-inviting participants is not enabled + $invitationCreateStruct = new InvitationCreateStruct( + $session, + $internalParticipant + ); + + $this->invitationService->createInvitation($invitationCreateStruct); + + // Update invitation + $invitationUpdateStruct = new InvitationUpdateStruct(); + $invitationUpdateStruct->setStatus(InvitationStatus::STATUS_REJECTED); + + $this->invitationService->updateInvitation($invitation, $invitationUpdateStruct); + + // Delete invitation + $invitation = $this->invitationService->getInvitation(2); + $this->invitationService->deleteInvitation($invitation); + + // Delete a session + $this->sessionService->deleteSession($session); + + return Command::SUCCESS; + } +} diff --git a/composer.json b/composer.json index b21f1dc068..8b5f82b043 100644 --- a/composer.json +++ b/composer.json @@ -75,7 +75,9 @@ "ibexa/discounts-codes": "~5.0.x-dev", "ibexa/core-search": "~5.0.x-dev", "ibexa/product-catalog-symbol-attribute": "~5.0.x-dev", - "ibexa/messenger": "~5.0.x-dev" + "ibexa/messenger": "~5.0.x-dev", + "ibexa/collaboration": "~5.0.x-dev", + "ibexa/share": "~5.0.x-dev" }, "scripts": { "fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots", diff --git a/docs/content_management/collaborative_editing/collaborative_editing.md b/docs/content_management/collaborative_editing/collaborative_editing.md new file mode 100644 index 0000000000..e627d60d0e --- /dev/null +++ b/docs/content_management/collaborative_editing/collaborative_editing.md @@ -0,0 +1,22 @@ +--- +description: Collaborative editing enables multiple users to work on the same content simultaneously. +page_type: landing_page +month_change: true +--- + +# Collaborative editing + +With Collaborative editing feature multiple users can work on the same content created in [[= product_name =]] simultaneously, streamlining the content creation and review process. + +Users can invite both internal and external collaborators to a session, giving them access for editing or previewing. + +Additionaly, they can collaborate using a Real-time collaboration, an advanced part of the collaboration feature, to write and review content in a live mode thanks to CKEditor. +Real-time collaboration syncs changes instantly and shows user avatars and colored tags to indicate who is editing specific part of the Rich Text field. + +This feature also introduces new dashboard tabs for managing shared drafts and joining collaboration sessions easily. + +[[= cards([ +"content_management/collaborative_editing/collaborative_editing_guide", +"content_management/collaborative_editing/configure_collaborative_editing", +"content_management/collaborative_editing/collaborative_editing_api" +], columns=3) =]] \ No newline at end of file diff --git a/docs/content_management/collaborative_editing/collaborative_editing_api.md b/docs/content_management/collaborative_editing/collaborative_editing_api.md new file mode 100644 index 0000000000..c8dec678bb --- /dev/null +++ b/docs/content_management/collaborative_editing/collaborative_editing_api.md @@ -0,0 +1,158 @@ +--- +description: Use PHP API to manage invitations, sessions, and participants while using collaborative editing feature. +month_change: true +--- + +# Collaborative editing API + +[[= product_name =]]'s Collaborative editing API provides two services for managing sessions and invitations, which differ in function: + +- [`InvitationServiceInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html) is used to manage collaboration sessions invitations +- [`SessionServiceInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html) is used to manage collaboration sessions + +## Managing sessions + +### Create session + +You can create new collaboration session with [`SessionService::createSession()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_createSession): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 53, 65) =]] +``` + +### Get session + +You can get an existing collaboration session with [`SessionService::getSession()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_getSession): + +- using given id - with [`SessionService::getSession()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_getSession) + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 66, 67) =]] +``` + +- using given token - with [`SessionService::getSessionByToken()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_getSessionByToken) + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 67, 68) =]] +``` + +### Find sessions + +You can find an existing session with [`SessionService::findSessions()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_findSessions) by passing a SessionQuery object: + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 70, 73) =]] +``` + +### Update session + +You can update existing invitation with [`SessionService::updateSession()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_updateSession): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 74, 79) =]] +``` + +### Delete session + +You can delete session with [`SessionService::deleteSession()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_deleteSession): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 153, 154) =]] +``` + +## Managing participants + +### Add participant + +You can add participant to the collaboration session with [`SessionService::addParticipant()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_addParticipant): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 86, 100) =]] +``` + +### Get and update participant + +You can update participant added to the collaboration session with [`SessionService::updateParticipant()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_updateParticipant): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 101, 109) =]] +``` + +The example below updates participant's permissions to allow for editing of shared content, not only previewing. + +### Remove participant + +You can remove participant from the collaboration session with [`SessionService::removeParticipant()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_removeParticipant): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 110, 111) =]] +``` + +### Check session owner + +You can check whether a user belongs to a collaboration session with [`SessionService::isSessionOwner()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceDecorator.html#method_isSessionOwner): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 113, 118) =]] +``` + +If no user is provided, current user is used. + +### Check session participant + +You can check the participant of the collaboration session with [`SessionService::isSessionParticipant()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-SessionServiceInterface.html#method_isSessionParticipant): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 119, 124) =]] +``` + +## Managing invitations + +### Manage invitation + +You can get an invitation with [`InvitationService::getInvitation()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html#method_getInvitation): + + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 125, 134) =]] +``` + +### Create invitation + +You can create new invitation for the collaborative session using the [`InvitationService::createInvitation()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html#method_createInvitation) method: + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 135, 142) =]] +``` + +You can use it when auto-inviting participants is not enabled. + +### Update invitation + +You can update existing invitation with [`InvitationService::updateInvitation()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html#method_updateInvitation): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 143, 148) =]] +``` + +### Delete invitation + +You can delete an invitation with [`InvitationService::deleteInvitation()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html#method_deleteInvitation): + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 149, 152) =]] +``` + +### Find invitations + +You can find an invitation with [`InvitationService::findInvitations()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Collaboration-InvitationServiceInterface.html#method_findInvitations). + +To learn more about the available search options, see Search Criteria and Sort Clauses for Collaborative editing. + +## Example API usage + +Below you can see an example of API usage for Collaborative editing: + +``` php +[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php') =]] +``` \ No newline at end of file diff --git a/docs/content_management/collaborative_editing/configure_collaborative_editing.md b/docs/content_management/collaborative_editing/configure_collaborative_editing.md new file mode 100644 index 0000000000..1e3094673e --- /dev/null +++ b/docs/content_management/collaborative_editing/configure_collaborative_editing.md @@ -0,0 +1,98 @@ +--- +description: Configure the Collaborative editing feature. +month_change: true +--- + +# Collaborative editing + +Collaborative editing feature is available in [[= product_name =]] starting with version v5.0.2 or higher, regardless of its edition. + +## Installation + +### Install Real-time editing feature package + +If you have an arrangements with [[= product_name_base =]] to use Real-time editing feature, you need to install following package: + +``` bash +composer require ibexa/fieldtype-richtext-rte +``` + +This command installs also `ibexa/ckeditor-premium` package and adds the new real-time editing functionality to the Rich Text field type. +It also modifies the permission system to account for the new functionality. + +### Modify the bundles file + +Then, if not using Symfony Flex, add the following code to the `config/bundles.php` file: + +``` php + ['all' => true], + Ibexa\Bundle\CkeditorPremium\IbexaCkeditorPremiumBundle::class => ['all' => true], +]; +``` + +## Configure Collaborative editing + +Before you can start Collaborative editing feature, you must enable it by following these instructions. + +### Security configuration + +After an installation process is finished, go to `config/packages/security.yaml` and make following changes: + +- uncomment following lines with `shared` user provider under the `providers` key: + +```yaml +security: + providers: + # ... + shared: + id: Ibexa\Collaboration\Security\User\ShareableLinkUserProvider +``` + +- uncomment following lines under the `ibexa_shareable_link` key: + +```yaml +security: + # ... + ibexa_shareable_link: + request_matcher: Ibexa\Collaboration\Security\RequestMatcher\ShareableLinkRequestMatcher + pattern: ^/ + provider: shared + stateless: true + user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker + custom_authenticators: + - Ibexa\Collaboration\Security\Authenticator\ShareableLinkAuthenticator +``` + +### Configuration + +You can configure Collaborative editing per [Repository](repository_configuration.md). + +Under `ibexa.repositories..collaboration` [configuration key](configuration.md#configuration-files), indicate the settings for collaboration: + +``` yaml +ibexa: + repositories: + : + collaboration: + participants: + allowed_types: + - internal + - external + auto_invite: + session: + public_link_enabled: +``` + +The following settings are available: + +- participants: + - `allowed_types` - defines allowed user types, values: `internal`, `external`, you can set one or both of the values + - `auto_invite` - determines whether invitations should be sent automatically when inviting someone to a session, default value: `true`, available values: `true`, `false` +- session: + - `public_link_enabled` - determines whether the public link is available, default value: `false`, available values: `true`, `false` + +You can now restart you application and start working with the Collaborative editing feature. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ca209a9202..f2d4409aaf 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -280,7 +280,10 @@ nav: - URL field type: content_management/field_types/field_type_reference/urlfield.md - User field type: content_management/field_types/field_type_reference/userfield.md - Collaborative editing: + - Collaborative editing: content_management/collaborative_editing/collaborative_editing.md - Collaborative editing product guide: content_management/collaborative_editing/collaborative_editing_guide.md + - Configure Collaborative editing: content_management/collaborative_editing/configure_collaborative_editing.md + - Collaborative editing API: content_management/collaborative_editing/collaborative_editing_api.md - Templating: - Templating: templating/templating.md - Render content: