Skip to content

Commit 0cd3da8

Browse files
mnoconjulitafalconduszaadriendupuisdabrt
authored
Installation and configuration for Collaborative Editing (#2902)
* Installation and configuration for Collaborative Editing * fixes after review * fixes * fixes - part 2 * api condensed on one page, configuration added * PHP & JS CS Fixes * Update build.yaml Python version (#2907) * IBX-9060: Document revamped notifications (#2797) * IBX-9060: Document revamped notifications * Add modified query examples * Apply suggestion from @mnocon Co-authored-by: Marek Nocoń <[email protected]> --------- Co-authored-by: dabrt <[email protected]> Co-authored-by: Marek Nocoń <[email protected]> * Reworded section for updating LTS Updates (#2905) * Reworded section for updating LTS Updates * [WIP] Updated Python * Fixed EOLWhitespace * Fixed Symbol attribute * 4.6 PHP API Ref + Collaboration (#2913) * fixes * fixes, code added * fixes * fixes * links fixed * fixes after review * fixes after review * composer fixes * sql files updated * fixes --------- Co-authored-by: julitafalcondusza <[email protected]> Co-authored-by: julitafalcondusza <[email protected]> Co-authored-by: Adrien Dupuis <[email protected]> Co-authored-by: Tomasz Dąbrowski <[email protected]> Co-authored-by: dabrt <[email protected]>
1 parent 600331d commit 0cd3da8

File tree

8 files changed

+737
-1
lines changed

8 files changed

+737
-1
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
CREATE TABLE ibexa_collaboration
2+
(
3+
id INT AUTO_INCREMENT NOT NULL,
4+
owner_id INT NOT NULL,
5+
token VARCHAR(160) NOT NULL,
6+
discriminator VARCHAR(190) NOT NULL,
7+
is_active TINYINT(1) NOT NULL,
8+
has_public_link TINYINT(1) NOT NULL,
9+
created_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
10+
updated_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
11+
UNIQUE INDEX ibexa_collaboration_token_idx (token),
12+
INDEX ibexa_collaboration_owner_idx (owner_id),
13+
UNIQUE INDEX ibexa_collaboration_token_uc (token),
14+
PRIMARY KEY (id)
15+
) DEFAULT CHARACTER SET utf8mb4
16+
COLLATE `utf8mb4_unicode_520_ci`
17+
ENGINE = InnoDB;
18+
CREATE TABLE ibexa_collaboration_participant
19+
(
20+
id INT AUTO_INCREMENT NOT NULL,
21+
session_id INT NOT NULL,
22+
discriminator VARCHAR(190) NOT NULL,
23+
scope VARCHAR(255) DEFAULT NULL,
24+
token VARCHAR(255) DEFAULT NULL,
25+
created_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
26+
updated_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
27+
INDEX IDX_9C5C6401613FECDF (session_id),
28+
UNIQUE INDEX ibexa_collaboration_participant_token_idx (token),
29+
PRIMARY KEY (id)
30+
) DEFAULT CHARACTER SET utf8mb4
31+
COLLATE `utf8mb4_unicode_520_ci`
32+
ENGINE = InnoDB;
33+
CREATE TABLE ibexa_collaboration_participant_internal
34+
(
35+
id INT NOT NULL,
36+
user_id INT NOT NULL,
37+
INDEX IDX_E838B79AA76ED395 (user_id),
38+
PRIMARY KEY (id)
39+
) DEFAULT CHARACTER SET utf8mb4
40+
COLLATE `utf8mb4_unicode_520_ci`
41+
ENGINE = InnoDB;
42+
CREATE TABLE ibexa_collaboration_participant_external
43+
(
44+
id INT NOT NULL,
45+
email VARCHAR(255) NOT NULL,
46+
PRIMARY KEY (id)
47+
) DEFAULT CHARACTER SET utf8mb4
48+
COLLATE `utf8mb4_unicode_520_ci`
49+
ENGINE = InnoDB;
50+
CREATE TABLE ibexa_collaboration_invitation
51+
(
52+
id INT AUTO_INCREMENT NOT NULL,
53+
session_id INT NOT NULL,
54+
participant_id INT NOT NULL,
55+
sender_id INT NOT NULL,
56+
status VARCHAR(64) NOT NULL,
57+
context LONGTEXT DEFAULT NULL COMMENT '(DC2Type:json)',
58+
created_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
59+
updated_at DATETIME NOT NULL COMMENT '(DC2Type:datetimetz_immutable)',
60+
INDEX IDX_36C63687613FECDF (session_id),
61+
INDEX IDX_36C636879D1C3019 (participant_id),
62+
INDEX IDX_36C63687F624B39D (sender_id),
63+
PRIMARY KEY (id)
64+
) DEFAULT CHARACTER SET utf8mb4
65+
COLLATE `utf8mb4_unicode_520_ci`
66+
ENGINE = InnoDB;
67+
ALTER TABLE ibexa_collaboration
68+
ADD CONSTRAINT ibexa_collaboration_owner_id_fk FOREIGN KEY (owner_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT;
69+
ALTER TABLE ibexa_collaboration_participant
70+
ADD CONSTRAINT ibexa_collaboration_participant_session_id_fk FOREIGN KEY (session_id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE;
71+
ALTER TABLE ibexa_collaboration_participant_internal
72+
ADD CONSTRAINT ibexa_collaboration_participant_internal_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE;
73+
ALTER TABLE ibexa_collaboration_participant_internal
74+
ADD CONSTRAINT ibexa_collaboration_participant_internal_user_id_fk FOREIGN KEY (user_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT;
75+
ALTER TABLE ibexa_collaboration_participant_external
76+
ADD CONSTRAINT ibexa_collaboration_participant_external_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE;
77+
ALTER TABLE ibexa_collaboration_invitation
78+
ADD CONSTRAINT ibexa_collaboration_invitation_session_id_fk FOREIGN KEY (session_id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE;
79+
ALTER TABLE ibexa_collaboration_invitation
80+
ADD CONSTRAINT ibexa_collaboration_invitation_participant_id_fk FOREIGN KEY (participant_id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE;
81+
ALTER TABLE ibexa_collaboration_invitation
82+
ADD CONSTRAINT ibexa_collaboration_invitation_sender_id_fk FOREIGN KEY (sender_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT;
83+
CREATE TABLE ibexa_collaboration_content
84+
(
85+
id INT NOT NULL,
86+
content_id INT NOT NULL,
87+
version_no INT NOT NULL,
88+
language_id BIGINT NOT NULL,
89+
INDEX ibexa_collaboration_session_content_version_language_idx (content_id, version_no, language_id),
90+
PRIMARY KEY(id)
91+
) DEFAULT CHARACTER SET utf8 COLLATE `utf8mb4_unicode_520_ci` ENGINE = InnoDB;
92+
ALTER TABLE
93+
ibexa_collaboration_content
94+
ADD
95+
CONSTRAINT ibexa_collaboration_content_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
CREATE TABLE ibexa_collaboration
2+
(
3+
id SERIAL NOT NULL,
4+
owner_id INT NOT NULL,
5+
token VARCHAR(160) NOT NULL,
6+
discriminator VARCHAR(190) NOT NULL,
7+
is_active BOOLEAN NOT NULL,
8+
has_public_link BOOLEAN NOT NULL,
9+
created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
10+
updated_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
11+
PRIMARY KEY (id)
12+
);
13+
CREATE UNIQUE INDEX ibexa_collaboration_token_idx ON ibexa_collaboration (token);
14+
CREATE INDEX ibexa_collaboration_owner_idx ON ibexa_collaboration (owner_id);
15+
CREATE UNIQUE INDEX ibexa_collaboration_token_uc ON ibexa_collaboration (token);
16+
COMMENT
17+
ON COLUMN ibexa_collaboration.created_at IS '(DC2Type:datetimetz_immutable)';
18+
COMMENT
19+
ON COLUMN ibexa_collaboration.updated_at IS '(DC2Type:datetimetz_immutable)';
20+
CREATE TABLE ibexa_collaboration_participant
21+
(
22+
id SERIAL NOT NULL,
23+
session_id INT NOT NULL,
24+
discriminator VARCHAR(190) NOT NULL,
25+
scope VARCHAR(255) DEFAULT NULL,
26+
token VARCHAR(255) DEFAULT NULL,
27+
created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
28+
updated_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
29+
PRIMARY KEY (id)
30+
);
31+
CREATE INDEX ibexa_collaboration_participant_idx ON ibexa_collaboration_participant (session_id);
32+
CREATE UNIQUE INDEX ibexa_collaboration_participant_token_idx ON ibexa_collaboration_participant (token);
33+
COMMENT
34+
ON COLUMN ibexa_collaboration_participant.created_at IS '(DC2Type:datetimetz_immutable)';
35+
COMMENT
36+
ON COLUMN ibexa_collaboration_participant.updated_at IS '(DC2Type:datetimetz_immutable)';
37+
CREATE TABLE ibexa_collaboration_participant_internal
38+
(
39+
id INT NOT NULL,
40+
user_id INT NOT NULL,
41+
PRIMARY KEY (id)
42+
);
43+
CREATE INDEX ibexa_collaboration_participant_internal_idx ON ibexa_collaboration_participant_internal (user_id);
44+
CREATE TABLE ibexa_collaboration_participant_external
45+
(
46+
id INT NOT NULL,
47+
email VARCHAR(255) NOT NULL,
48+
PRIMARY KEY (id)
49+
);
50+
CREATE TABLE ibexa_collaboration_invitation
51+
(
52+
id SERIAL NOT NULL,
53+
session_id INT NOT NULL,
54+
participant_id INT NOT NULL,
55+
sender_id INT NOT NULL,
56+
status VARCHAR(64) NOT NULL,
57+
context JSON DEFAULT NULL,
58+
created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
59+
updated_at TIMESTAMP(0) WITH TIME ZONE NOT NULL,
60+
PRIMARY KEY (id)
61+
);
62+
CREATE INDEX ibexa_collaboration_invitation_idx ON ibexa_collaboration_invitation (session_id);
63+
CREATE INDEX ibexa_collaboration_invitation_idx ON ibexa_collaboration_invitation (participant_id);
64+
CREATE INDEX ibexa_collaboration_invitation_idx ON ibexa_collaboration_invitation (sender_id);
65+
COMMENT
66+
ON COLUMN ibexa_collaboration_invitation.created_at IS '(DC2Type:datetimetz_immutable)';
67+
COMMENT
68+
ON COLUMN ibexa_collaboration_invitation.updated_at IS '(DC2Type:datetimetz_immutable)';
69+
ALTER TABLE ibexa_collaboration
70+
ADD CONSTRAINT ibexa_collaboration_owner_id_fk FOREIGN KEY (owner_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
71+
ALTER TABLE ibexa_collaboration_participant
72+
ADD CONSTRAINT ibexa_collaboration_participant_session_id_fk FOREIGN KEY (session_id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
73+
ALTER TABLE ibexa_collaboration_participant_internal
74+
ADD CONSTRAINT ibexa_collaboration_participant_internal_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
75+
ALTER TABLE ibexa_collaboration_participant_internal
76+
ADD CONSTRAINT ibexa_collaboration_participant_internal_user_id_fk FOREIGN KEY (user_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
77+
ALTER TABLE ibexa_collaboration_participant_external
78+
ADD CONSTRAINT ibexa_collaboration_participant_external_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
79+
ALTER TABLE ibexa_collaboration_invitation
80+
ADD CONSTRAINT ibexa_collaboration_invitation_session_id_fk FOREIGN KEY (session_id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
81+
ALTER TABLE ibexa_collaboration_invitation
82+
ADD CONSTRAINT ibexa_collaboration_invitation_participant_id_fk FOREIGN KEY (participant_id) REFERENCES ibexa_collaboration_participant (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
83+
ALTER TABLE ibexa_collaboration_invitation
84+
ADD CONSTRAINT ibexa_collaboration_invitation_sender_id_fk FOREIGN KEY (sender_id) REFERENCES ezuser (contentobject_id) ON DELETE RESTRICT NOT DEFERRABLE INITIALLY IMMEDIATE;
85+
CREATE TABLE ibexa_collaboration_content
86+
(
87+
id INT NOT NULL,
88+
content_id INT NOT NULL,
89+
version_no INT NOT NULL,
90+
language_id BIGINT NOT NULL,
91+
PRIMARY KEY (id)
92+
);
93+
94+
CREATE INDEX ibexa_collaboration_session_content_version_language_idx ON ibexa_collaboration_content (content_id, version_no, language_id);
95+
96+
ALTER TABLE ibexa_collaboration_content
97+
ADD CONSTRAINT ibexa_collaboration_content_pk FOREIGN KEY (id) REFERENCES ibexa_collaboration (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace App\Command;
10+
11+
use Ibexa\Contracts\Collaboration\Invitation\InvitationCreateStruct;
12+
use Ibexa\Contracts\Collaboration\Invitation\InvitationQuery;
13+
use Ibexa\Contracts\Collaboration\Invitation\InvitationStatus;
14+
use Ibexa\Contracts\Collaboration\Invitation\InvitationUpdateStruct;
15+
use Ibexa\Contracts\Collaboration\Invitation\Query\Criterion\Session;
16+
use Ibexa\Contracts\Collaboration\InvitationServiceInterface;
17+
use Ibexa\Contracts\Collaboration\Participant\ExternalParticipantCreateStruct;
18+
use Ibexa\Contracts\Collaboration\Participant\InternalParticipantCreateStruct;
19+
use Ibexa\Contracts\Collaboration\Participant\InternalParticipantUpdateStruct;
20+
use Ibexa\Contracts\Collaboration\Session\Query\Criterion\Token;
21+
use Ibexa\Contracts\Collaboration\Session\SessionQuery;
22+
use Ibexa\Contracts\Collaboration\SessionServiceInterface;
23+
use Ibexa\Contracts\Core\Repository\ContentService;
24+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
25+
use Ibexa\Contracts\Core\Repository\UserService;
26+
use Ibexa\Contracts\Share\Collaboration\ContentSessionCreateStruct;
27+
use Ibexa\Contracts\Share\Collaboration\ContentSessionScope;
28+
use Ibexa\Contracts\Share\Collaboration\ContentSessionUpdateStruct;
29+
use Symfony\Component\Console\Command\Command;
30+
use Symfony\Component\Console\Input\InputInterface;
31+
use Symfony\Component\Console\Output\OutputInterface;
32+
33+
final class ManageSessionsCommand extends Command
34+
{
35+
protected static $defaultName = 'app:manage-sessions';
36+
37+
private InvitationServiceInterface $invitationService;
38+
39+
private SessionServiceInterface $sessionService;
40+
41+
private ContentService $contentService;
42+
43+
private UserService $userService;
44+
45+
private PermissionResolver $permissionResolver;
46+
47+
public function __construct(
48+
InvitationServiceInterface $invitationService,
49+
SessionServiceInterface $sessionService,
50+
ContentService $contentService,
51+
UserService $userService,
52+
PermissionResolver $permissionResolver
53+
) {
54+
parent::__construct(self::$defaultName);
55+
56+
$this->invitationService = $invitationService;
57+
$this->sessionService = $sessionService;
58+
$this->contentService = $contentService;
59+
$this->userService = $userService;
60+
$this->permissionResolver = $permissionResolver;
61+
}
62+
63+
public function execute(InputInterface $input, OutputInterface $output): int
64+
{
65+
$this->permissionResolver->setCurrentUserReference(
66+
$this->userService->loadUserByLogin('admin')
67+
);
68+
69+
// Create a sharing session for Content
70+
$versionInfo = $this->contentService->loadContent(52)->getVersionInfo();
71+
$createStruct = new ContentSessionCreateStruct(
72+
$versionInfo,
73+
$versionInfo->getInitialLanguage()
74+
);
75+
$createStruct->setHasPublicLink(false);
76+
77+
$token = 'my-secret-token-12345';
78+
$createStruct->setToken($token);
79+
80+
$sessionId = $this->sessionService->createSession($createStruct)->getId();
81+
82+
// Get a session by ID or token
83+
$session = $this->sessionService->getSession($sessionId);
84+
$session = $this->sessionService->getSessionByToken($token);
85+
86+
// Find sessions
87+
$sessionQuery = new SessionQuery(new Token($token));
88+
$session = $this->sessionService->findSessions($sessionQuery)->getFirst();
89+
90+
// Update a session
91+
$updateStruct = new ContentSessionUpdateStruct();
92+
$updateStruct->setHasPublicLink(true);
93+
94+
$this->sessionService->updateSession($session, $updateStruct);
95+
96+
// Deactivate a session
97+
$updateStruct = new ContentSessionUpdateStruct();
98+
$updateStruct->setIsActive(false);
99+
100+
$this->sessionService->updateSession($session, $updateStruct);
101+
102+
// Manage participants
103+
$user = $this->userService->loadUserByLogin('another_user');
104+
$internalParticipantCreateStruct = new InternalParticipantCreateStruct(
105+
$user,
106+
ContentSessionScope::VIEW
107+
);
108+
$externalParticipantCreateStruct = new ExternalParticipantCreateStruct(
109+
110+
ContentSessionScope::VIEW,
111+
'personal-secret-token-12345'
112+
);
113+
114+
$internalParticipant = $this->sessionService->addParticipant($session, $internalParticipantCreateStruct);
115+
$externalParticipant = $this->sessionService->addParticipant($session, $externalParticipantCreateStruct);
116+
117+
// Get and update participants
118+
$participant = $this->sessionService
119+
->getSession($session->getId())
120+
->getParticipants()
121+
->getByEmail($user->email);
122+
123+
$internalParticipantUpdateStruct = new InternalParticipantUpdateStruct(ContentSessionScope::EDIT);
124+
$this->sessionService->updateParticipant($session, $participant, $internalParticipantUpdateStruct);
125+
126+
// Remove participant
127+
$this->sessionService->removeParticipant($session, $externalParticipant);
128+
129+
// Check ownerships. If no user is provided, current user is used.
130+
$this->sessionService->isSessionOwner(
131+
$session,
132+
$this->userService->loadUserByLogin('another_user')
133+
);
134+
135+
// Check participation
136+
$this->sessionService->isSessionParticipant(
137+
$session,
138+
$this->permissionResolver->getCurrentUserReference()
139+
);
140+
141+
// Manage invitations
142+
$invitationQuery = new InvitationQuery(new Session($session));
143+
$invitations = $this->invitationService->findInvitations($invitationQuery)->getInvitations();
144+
145+
foreach ($invitations as $invitation) {
146+
$output->writeln('Invitation ID: ' . $invitation->getId() . ' Status: ' . $invitation->getStatus());
147+
}
148+
149+
$invitation = $this->invitationService->getInvitationByParticipant($participant);
150+
151+
// Create invitation - use when auto-inviting participants is not enabled
152+
$invitationCreateStruct = new InvitationCreateStruct(
153+
$session,
154+
$internalParticipant
155+
);
156+
157+
$this->invitationService->createInvitation($invitationCreateStruct);
158+
159+
// Update invitation
160+
$invitationUpdateStruct = new InvitationUpdateStruct();
161+
$invitationUpdateStruct->setStatus(InvitationStatus::STATUS_REJECTED);
162+
163+
$this->invitationService->updateInvitation($invitation, $invitationUpdateStruct);
164+
165+
// Delete invitation
166+
$invitation = $this->invitationService->getInvitation(2);
167+
$this->invitationService->deleteInvitation($invitation);
168+
169+
// Delete a session
170+
$this->sessionService->deleteSession($session);
171+
172+
return Command::SUCCESS;
173+
}
174+
}

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@
7272
"ibexa/discounts": "~4.6.x-dev",
7373
"ibexa/discounts-codes": "~4.6.x-dev",
7474
"ibexa/product-catalog-symbol-attribute": "~4.6.x-dev",
75-
"ibexa/messenger": "~4.6.x-dev"
75+
"ibexa/messenger": "~4.6.x-dev",
76+
"ibexa/collaboration": "~4.6.x-dev",
77+
"ibexa/share": "~4.6.x-dev"
7678
},
7779
"scripts": {
7880
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php -v --show-progress=dots",

0 commit comments

Comments
 (0)