Skip to content

Conversation

julitafalcondusza
Copy link
Contributor

Question Answer
JIRA Ticket
Versions
Edition

Collaborative editing - configuration for v5.0

Checklist

  • Text renders correctly
  • Text has been checked with vale
  • Description metadata is up to date
  • Redirects cover removed/moved pages
  • Code samples are working
  • PHP code samples have been fixed with PHP CS fixer
  • Added link to this PR in relevant JIRA ticket or code PR

@julitafalcondusza julitafalcondusza marked this pull request as ready for review October 14, 2025 10:26
Copy link
Contributor

@mnocon mnocon left a comment

Choose a reason for hiding this comment

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

One small comment

Copy link

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/back_office/notifications/src/Notification/ListRenderer.php


code_samples/back_office/notifications/src/Notification/ListRenderer.php

docs/administration/back_office/notifications.md@95:```php
docs/administration/back_office/notifications.md@96:[[= include_file('code_samples/back_office/notifications/src/Notification/ListRenderer.php') =]]
docs/administration/back_office/notifications.md@97:```
docs/administration/back_office/notifications.md@94:```php
docs/administration/back_office/notifications.md@95:[[= include_file('code_samples/back_office/notifications/src/Notification/ListRenderer.php') =]]
docs/administration/back_office/notifications.md@96:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Notification;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
008⫶use Ibexa\Core\Notification\Renderer\NotificationRenderer;
009⫶use Ibexa\Core\Notification\Renderer\TypedNotificationRendererInterface;
010⫶use Symfony\Component\HttpFoundation\RequestStack;
011⫶use Symfony\Component\Routing\RouterInterface;
012⫶use Twig\Environment;
013⫶
014⫶class ListRenderer implements NotificationRenderer, TypedNotificationRendererInterface
015⫶{

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Notification;
006⫶
007⫶use Ibexa\Contracts\Core\Repository\Values\Notification\Notification;
008⫶use Ibexa\Core\Notification\Renderer\NotificationRenderer;
009⫶use Ibexa\Core\Notification\Renderer\TypedNotificationRendererInterface;
010⫶use Symfony\Component\HttpFoundation\RequestStack;
011⫶use Symfony\Component\Routing\RouterInterface;
012⫶use Twig\Environment;
013⫶
014⫶class ListRenderer implements NotificationRenderer, TypedNotificationRendererInterface
015⫶{
016⫶    protected Environment $twig;
017⫶
018⫶ protected RouterInterface $router;
016⫶    public function __construct(protected Environment $twig, protected RouterInterface $router, protected RequestStack $requestStack)
017⫶ {
018⫶ }
019⫶
019⫶
020⫶    protected RequestStack $requestStack;
021⫶
022⫶ public function __construct(Environment $twig, RouterInterface $router, RequestStack $requestStack)
023⫶ {
024⫶ $this->twig = $twig;
025⫶ $this->router = $router;
026⫶ $this->requestStack = $requestStack;
027⫶ }
028⫶
029⫶ public function render(Notification $notification): string
030⫶ {
031⫶ $templateToExtend = '@ibexadesign/account/notifications/list_item.html.twig';
032⫶ $currentRequest = $this->requestStack->getCurrentRequest();
033⫶ if ($currentRequest && $currentRequest->attributes->getBoolean('render_all')) {
034⫶ $templateToExtend = '@ibexadesign/account/notifications/list_item_all.html.twig';
035⫶ }
036⫶
037⫶ return $this->twig->render('@ibexadesign/notification.html.twig', [
038⫶ 'notification' => $notification,
039⫶ 'template_to_extend' => $templateToExtend,
040⫶ ]);
041⫶ }
042⫶
043⫶ public function generateUrl(Notification $notification): ?string
044⫶ {
045⫶ if (array_key_exists('content_id', $notification->data)) {
046⫶ return $this->router->generate('ibexa.content.view', [
047⫶ 'contentId' => $notification->data['content_id'],
048⫶ ]);
049⫶ }
050⫶
051⫶ return null;
052⫶ }
053⫶
054⫶ public function getTypeLabel(): string
055⫶ {
056⫶ return /** @Desc("Workflow stage changed") */
057⫶ $this->translator->trans(
058⫶ 'workflow.notification.stage_change.label',
059⫶ [],
060⫶ 'ibexa_workflow'
061⫶ );
062⫶ }
063⫶}
020⫶    public function render(Notification $notification): string
021⫶ {
022⫶ $templateToExtend = '@ibexadesign/account/notifications/list_item.html.twig';
023⫶ $currentRequest = $this->requestStack->getCurrentRequest();
024⫶ if ($currentRequest && $currentRequest->attributes->getBoolean('render_all')) {
025⫶ $templateToExtend = '@ibexadesign/account/notifications/list_item_all.html.twig';
026⫶ }
027⫶
028⫶ return $this->twig->render('@ibexadesign/notification.html.twig', [
029⫶ 'notification' => $notification,
030⫶ 'template_to_extend' => $templateToExtend,
031⫶ ]);
032⫶ }
033⫶
034⫶ public function generateUrl(Notification $notification): ?string
035⫶ {
036⫶ if (array_key_exists('content_id', $notification->data)) {
037⫶ return $this->router->generate('ibexa.content.view', [
038⫶ 'contentId' => $notification->data['content_id'],
039⫶ ]);
040⫶ }
041⫶
042⫶ return null;
043⫶ }
044⫶
045⫶ public function getTypeLabel(): string
046⫶ {
047⫶ return /** @Desc("Workflow stage changed") */
048⫶ $this->translator->trans(
049⫶ 'workflow.notification.stage_change.label',
050⫶ [],
051⫶ 'ibexa_workflow'
052⫶ );
053⫶ }
054⫶}


code_samples/collaboration/src/Command/ManageSessionsCommand.php



code_samples/collaboration/src/Command/ManageSessionsCommand.php

docs/content_management/collaborative_editing/collaborative_editing_api.md@19:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@20:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 53, 65) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@21:```

001⫶ $versionInfo = $this->contentService->loadContent(52)->getVersionInfo();
002⫶ $createStruct = new ContentSessionCreateStruct(
003⫶ $versionInfo,
004⫶ $versionInfo->getInitialLanguage()
005⫶ );
006⫶ $createStruct->setHasPublicLink(false);
007⫶
008⫶ $token = 'my-secret-token-12345';
009⫶ $createStruct->setToken($token);
010⫶
011⫶ $sessionId = $this->sessionService->createSession($createStruct)->getId();

docs/content_management/collaborative_editing/collaborative_editing_api.md@29:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@30:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 66, 67) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@31:```

001⫶ $session = $this->sessionService->getSession($sessionId);

docs/content_management/collaborative_editing/collaborative_editing_api.md@35:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@36:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 67, 68) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@37:```

001⫶ $session = $this->sessionService->getSessionByToken($token);

docs/content_management/collaborative_editing/collaborative_editing_api.md@43:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@44:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 70, 73) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@45:```

001⫶ $sessionQuery = new SessionQuery(new Token($token));
002⫶ $session = $this->sessionService->findSessions($sessionQuery)->getFirst();

docs/content_management/collaborative_editing/collaborative_editing_api.md@51:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@52:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 74, 79) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@53:```

001⫶ $updateStruct = new ContentSessionUpdateStruct();
002⫶ $updateStruct->setHasPublicLink(true);
003⫶
004⫶ $this->sessionService->updateSession($session, $updateStruct);

docs/content_management/collaborative_editing/collaborative_editing_api.md@59:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@60:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 153, 154) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@61:```

001⫶ $this->sessionService->deleteSession($session);

docs/content_management/collaborative_editing/collaborative_editing_api.md@69:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@70:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 86, 100) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@71:```

001⫶ $user = $this->userService->loadUserByLogin('another_user');
002⫶ $internalParticipantCreateStruct = new InternalParticipantCreateStruct(
003⫶ $user,
004⫶ ContentSessionScope::VIEW
005⫶ );
006⫶ $externalParticipantCreateStruct = new ExternalParticipantCreateStruct(
007⫶ '[email protected]',
008⫶ ContentSessionScope::VIEW,
009⫶ 'personal-secret-token-12345'
010⫶ );
011⫶
012⫶ $internalParticipant = $this->sessionService->addParticipant($session, $internalParticipantCreateStruct);
013⫶ $externalParticipant = $this->sessionService->addParticipant($session, $externalParticipantCreateStruct);

docs/content_management/collaborative_editing/collaborative_editing_api.md@77:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@78:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 101, 109) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@79:```

001⫶ $participant = $this->sessionService
002⫶ ->getSession($session->getId())
003⫶ ->getParticipants()
004⫶ ->getByEmail($user->email);
005⫶
006⫶ $internalParticipantUpdateStruct = new InternalParticipantUpdateStruct(ContentSessionScope::EDIT);
007⫶ $this->sessionService->updateParticipant($session, $participant, $internalParticipantUpdateStruct);

docs/content_management/collaborative_editing/collaborative_editing_api.md@87:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@88:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 110, 111) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@89:```

001⫶ $this->sessionService->removeParticipant($session, $externalParticipant);

docs/content_management/collaborative_editing/collaborative_editing_api.md@95:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@96:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 113, 118) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@97:```

001⫶ $this->sessionService->isSessionOwner(
002⫶ $session,
003⫶ $this->userService->loadUserByLogin('another_user')
004⫶ );

docs/content_management/collaborative_editing/collaborative_editing_api.md@105:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@106:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 119, 124) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@107:```

001⫶ $this->sessionService->isSessionParticipant(
002⫶ $session,
003⫶ $this->permissionResolver->getCurrentUserReference()
004⫶ );

docs/content_management/collaborative_editing/collaborative_editing_api.md@116:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@117:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 125, 134) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@118:```

001⫶ $invitationQuery = new InvitationQuery(new Session($session));
002⫶ $invitations = $this->invitationService->findInvitations($invitationQuery)->getInvitations();
003⫶
004⫶ foreach ($invitations as $invitation) {
005⫶ $output->writeln('Invitation ID: ' . $invitation->getId() . ' Status: ' . $invitation->getStatus());
006⫶ }
007⫶
008⫶ $invitation = $this->invitationService->getInvitationByParticipant($participant);

docs/content_management/collaborative_editing/collaborative_editing_api.md@124:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@125:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 135, 142) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@126:```

001⫶ $invitationCreateStruct = new InvitationCreateStruct(
002⫶ $session,
003⫶ $internalParticipant
004⫶ );
005⫶
006⫶ $this->invitationService->createInvitation($invitationCreateStruct);

docs/content_management/collaborative_editing/collaborative_editing_api.md@134:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@135:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 143, 148) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@136:```

001⫶ $invitationUpdateStruct = new InvitationUpdateStruct();
002⫶ $invitationUpdateStruct->setStatus(InvitationStatus::STATUS_REJECTED);
003⫶
004⫶ $this->invitationService->updateInvitation($invitation, $invitationUpdateStruct);

docs/content_management/collaborative_editing/collaborative_editing_api.md@142:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@143:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php', 149, 152) =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@144:```

001⫶ $invitation = $this->invitationService->getInvitation(2);
002⫶ $this->invitationService->deleteInvitation($invitation);

docs/content_management/collaborative_editing/collaborative_editing_api.md@156:``` php
docs/content_management/collaborative_editing/collaborative_editing_api.md@157:[[= include_file('code_samples/collaboration/src/Command/ManageSessionsCommand.php') =]]
docs/content_management/collaborative_editing/collaborative_editing_api.md@158:```

001⫶<?php
002⫶
003⫶/**
004⫶ * @copyright Copyright (C) Ibexa AS. All rights reserved.
005⫶ * @license For full copyright and license information view LICENSE file distributed with this source code.
006⫶ */
007⫶declare(strict_types=1);
008⫶
009⫶namespace App\Command;
010⫶
011⫶use Ibexa\Contracts\Collaboration\Invitation\InvitationCreateStruct;
012⫶use Ibexa\Contracts\Collaboration\Invitation\InvitationQuery;
013⫶use Ibexa\Contracts\Collaboration\Invitation\InvitationStatus;
014⫶use Ibexa\Contracts\Collaboration\Invitation\InvitationUpdateStruct;
015⫶use Ibexa\Contracts\Collaboration\Invitation\Query\Criterion\Session;
016⫶use Ibexa\Contracts\Collaboration\InvitationServiceInterface;
017⫶use Ibexa\Contracts\Collaboration\Participant\ExternalParticipantCreateStruct;
018⫶use Ibexa\Contracts\Collaboration\Participant\InternalParticipantCreateStruct;
019⫶use Ibexa\Contracts\Collaboration\Participant\InternalParticipantUpdateStruct;
020⫶use Ibexa\Contracts\Collaboration\Session\Query\Criterion\Token;
021⫶use Ibexa\Contracts\Collaboration\Session\SessionQuery;
022⫶use Ibexa\Contracts\Collaboration\SessionServiceInterface;
023⫶use Ibexa\Contracts\Core\Repository\ContentService;
024⫶use Ibexa\Contracts\Core\Repository\PermissionResolver;
025⫶use Ibexa\Contracts\Core\Repository\UserService;
026⫶use Ibexa\Contracts\Share\Collaboration\ContentSessionCreateStruct;
027⫶use Ibexa\Contracts\Share\Collaboration\ContentSessionScope;
028⫶use Ibexa\Contracts\Share\Collaboration\ContentSessionUpdateStruct;
029⫶use Symfony\Component\Console\Attribute\AsCommand;
030⫶use Symfony\Component\Console\Command\Command;
031⫶use Symfony\Component\Console\Input\InputInterface;
032⫶use Symfony\Component\Console\Output\OutputInterface;
033⫶
034⫶#[AsCommand(name: 'app:manage-sessions')]
035⫶final class ManageSessionsCommand extends Command
036⫶{
037⫶ public function __construct(
038⫶ private readonly InvitationServiceInterface $invitationService,
039⫶ private readonly SessionServiceInterface $sessionService,
040⫶ private readonly ContentService $contentService,
041⫶ private readonly UserService $userService,
042⫶ private readonly PermissionResolver $permissionResolver
043⫶ ) {
044⫶ parent::__construct();
045⫶ }
046⫶
047⫶ public function execute(InputInterface $input, OutputInterface $output): int
048⫶ {
049⫶ $this->permissionResolver->setCurrentUserReference(
050⫶ $this->userService->loadUserByLogin('admin')
051⫶ );
052⫶
053⫶ // Create a sharing session for Content
054⫶ $versionInfo = $this->contentService->loadContent(52)->getVersionInfo();
055⫶ $createStruct = new ContentSessionCreateStruct(
056⫶ $versionInfo,
057⫶ $versionInfo->getInitialLanguage()
058⫶ );
059⫶ $createStruct->setHasPublicLink(false);
060⫶
061⫶ $token = 'my-secret-token-12345';
062⫶ $createStruct->setToken($token);
063⫶
064⫶ $sessionId = $this->sessionService->createSession($createStruct)->getId();
065⫶
066⫶ // Get a session by ID or token
067⫶ $session = $this->sessionService->getSession($sessionId);
068⫶ $session = $this->sessionService->getSessionByToken($token);
069⫶
070⫶ // Find sessions
071⫶ $sessionQuery = new SessionQuery(new Token($token));
072⫶ $session = $this->sessionService->findSessions($sessionQuery)->getFirst();
073⫶
074⫶ // Update a session
075⫶ $updateStruct = new ContentSessionUpdateStruct();
076⫶ $updateStruct->setHasPublicLink(true);
077⫶
078⫶ $this->sessionService->updateSession($session, $updateStruct);
079⫶
080⫶ // Deactivate a session
081⫶ $updateStruct = new ContentSessionUpdateStruct();
082⫶ $updateStruct->setIsActive(false);
083⫶
084⫶ $this->sessionService->updateSession($session, $updateStruct);
085⫶
086⫶ // Manage participants
087⫶ $user = $this->userService->loadUserByLogin('another_user');
088⫶ $internalParticipantCreateStruct = new InternalParticipantCreateStruct(
089⫶ $user,
090⫶ ContentSessionScope::VIEW
091⫶ );
092⫶ $externalParticipantCreateStruct = new ExternalParticipantCreateStruct(
093⫶ '[email protected]',
094⫶ ContentSessionScope::VIEW,
095⫶ 'personal-secret-token-12345'
096⫶ );
097⫶
098⫶ $internalParticipant = $this->sessionService->addParticipant($session, $internalParticipantCreateStruct);
099⫶ $externalParticipant = $this->sessionService->addParticipant($session, $externalParticipantCreateStruct);
100⫶
101⫶ // Get and update participants
102⫶ $participant = $this->sessionService
103⫶ ->getSession($session->getId())
104⫶ ->getParticipants()
105⫶ ->getByEmail($user->email);
106⫶
107⫶ $internalParticipantUpdateStruct = new InternalParticipantUpdateStruct(ContentSessionScope::EDIT);
108⫶ $this->sessionService->updateParticipant($session, $participant, $internalParticipantUpdateStruct);
109⫶
110⫶ // Remove participant
111⫶ $this->sessionService->removeParticipant($session, $externalParticipant);
112⫶
113⫶ // Check ownerships. If no user is provided, current user is used.
114⫶ $this->sessionService->isSessionOwner(
115⫶ $session,
116⫶ $this->userService->loadUserByLogin('another_user')
117⫶ );
118⫶
119⫶ // Check participation
120⫶ $this->sessionService->isSessionParticipant(
121⫶ $session,
122⫶ $this->permissionResolver->getCurrentUserReference()
123⫶ );
124⫶
125⫶ // Manage invitations
126⫶ $invitationQuery = new InvitationQuery(new Session($session));
127⫶ $invitations = $this->invitationService->findInvitations($invitationQuery)->getInvitations();
128⫶
129⫶ foreach ($invitations as $invitation) {
130⫶ $output->writeln('Invitation ID: ' . $invitation->getId() . ' Status: ' . $invitation->getStatus());
131⫶ }
132⫶
133⫶ $invitation = $this->invitationService->getInvitationByParticipant($participant);
134⫶
135⫶ // Create invitation - use when auto-inviting participants is not enabled
136⫶ $invitationCreateStruct = new InvitationCreateStruct(
137⫶ $session,
138⫶ $internalParticipant
139⫶ );
140⫶
141⫶ $this->invitationService->createInvitation($invitationCreateStruct);
142⫶
143⫶ // Update invitation
144⫶ $invitationUpdateStruct = new InvitationUpdateStruct();
145⫶ $invitationUpdateStruct->setStatus(InvitationStatus::STATUS_REJECTED);
146⫶
147⫶ $this->invitationService->updateInvitation($invitation, $invitationUpdateStruct);
148⫶
149⫶ // Delete invitation
150⫶ $invitation = $this->invitationService->getInvitation(2);
151⫶ $this->invitationService->deleteInvitation($invitation);
152⫶
153⫶ // Delete a session
154⫶ $this->sessionService->deleteSession($session);
155⫶
156⫶ return Command::SUCCESS;
157⫶ }
158⫶}

Download colorized diff

@julitafalcondusza julitafalcondusza merged commit b5ca958 into 5.0 Oct 16, 2025
6 of 7 checks passed
@julitafalcondusza julitafalcondusza deleted the IBX-9737-installation-only-5.0 branch October 16, 2025 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants