Wiki source code of Discussions

Last modified by Vincent Massol on 2024/02/26 17:53

Show last authors
1 = Introduction =
2
3 This is the design of the extension of XWiki to provide new mechanisms to promote discussions between users inside of XWiki (i.e., without having to rely on third-party such as emails, chats, or forums).
4
5 It is worth noting that while participating in discussions from XWiki is the main goal of the extension, a secondary goal is to promote discussions to be possible with third parties using dedicated bridges. The first known use case for this is the interconnection of XWiki discussions with the fediverse, allowing discussions to take place both on XWiki and on other servers supporting the [[ActivityPub protocol>>attach:https://www.w3.org/TR/activitypub/]] (e.g., Mastodon).
6
7 A discussion takes the form of a list of messages sorted by publication time, and centered on a given topic. The discussion can be public, or limited to a set of users and groups.
8
9 A discussion can be linked to an entity, for instance, an XWIki page or an XWiki event. The goal is to allow discussions to be centralized in the discussion application but to allow discussions attached to a given entity type to be contextually displayed. For instance, a discussion started from an event triggered by the creation of a new version of a page could be displayed in a tab when consulting the changes of this version of the page.
10
11 = Table of content =
12
13 {{toc numbered="true"/}}
14
15 = Architecture Overview =
16
17 (% class="box warningmessage" %)
18 (((
19 The proposed name for the application is //discussion//, it will be used in the remainder of the document but might be subject to change.
20 )))
21
22 (% class="box warningmessage" %)
23 (((
24 I'm also considering it to be part of xwiki platform for the naming, but that also might change.
25 )))
26
27 * ##xwiki-platform-discussion-api##: Provides the operations to interact with the discussions
28 * ##xwiki-platform-discussion-default##: Default implementation of the discussions API
29 * ##xwiki-platform-discussion-rest##: Provides the REST operations to interact with the discussion
30 * ##xwiki-platform-discussion-store-api##: Provides the operations to interact with the discussion store
31 * ##xwiki-platform-discussion-store-default##: Default implementation of the store API, where the discussion entities are stored in xpages
32 * ##xwiki-platform-discussion-ui##: Provides the generic user interfaces of the discussions as well as reusable macros to integrate the discussions contextually in XWiki's interfaces
33
34 = Domain Overview =
35
36 This section describes the main concepts manipulated in the context of the discussions
37
38 **Discussion Context**
39
40 A discussion context represents a group of discussions sharing a relation to the same entity.
41
42 A discussion can be part of several discussion contexts.
43
44 **Entity Reference**
45
46 An entity reference stores the reference to an entity in the wiki.
47
48 It is composed of the type of the referenced entity, and a serialized reference, expected to be read according to the type referenced entity.
49
50 **Discussion**
51
52 A discussion represents a collection of messages sharing a common topic.
53
54 A discussion can be part of several discussion contexts.
55
56 **Message**
57
58 A message is a textual contribution to a discussion. Messages are usually displayed ordered by their creation dates.
59
60 A message can be a reply to another message, forming arborescent discussions.
61
62 = Illustrating use cases =
63
64 As this extension is by itself abstract, we propose in this section some application use cases illustrating the use of the extension in some concrete context.
65
66 This is also a way to verify that the current design is general enough to fit a reasonable range of application use cases.
67
68 Each section starts with a short description of the use case then describes the use of the discussion APIs to realize it.
69
70 == Comments ==
71
72 === **Description** ===
73
74 Comment are sequences of messages that can answer each other and are attached to a wiki page.
75
76 They are displayed at the bottom of the page.
77
78 Comments can be posted by anonymous or logged in users that can view the page and are allowed to comment.
79
80 Administrators can edit and remove all the messages.
81
82 Users can edit and remove their messages.
83
84 === **Realization** ===
85
86 ==== Commenting ====
87
88 When a comment is added:
89
90 1. We check for the author right to verify he/she is allowed to post a message on this page
91 1. We look for a discussion context with entityReferenceType="document", entityeReference="xwiki:XWiki.MyPage".
92 1. If it does not exist
93 11. A discussion context is created with entityReferenceType="document", entityeReference="xwiki:XWiki.MyPage", name="Page name", description="Comments of page Page name", administators=defined by the comments administration configuration.
94 11. A discussion is created and linked to the previously created discussion context, with title="Comments of Page name", description="Comments of Page name", administrators=defined by the comments administration configuration
95 11. The created discussion is returned
96 1. If it does exist:
97 11. We look for the only discussion linked to the discussion context and return it
98 1. The message is created in the returned discussion
99
100 ==== Other actions ====
101
102 Editing, removing, pining are straightforward and should be realized by generic actions provided by the reusable UI.
103
104 == Starting a discussion from a notification ==
105
106 A notification is received, let's say for a new message received from ActivityPub (AP). The data attached to the event contains an AP Page object
107
108 In the notifications pane, a button is provided to answer the notification, opening a modal window with a form to add a message.
109
110 When the comment is sent:
111
112 1. Check if a discussion exists with relations to exactly two discussion contexts:
113 11. activitystream:the-event-id
114 11. activitypub:the AP Page ID
115 1. Create the two discussion contexts if they respectively do not exist.
116 1. Create the discussion linked exactly to the two discussion contexts, otherwise returns it.
117 1. Add the message to the discussion
118 1. A new message event is send and listened to by the AP application. The message is send to the fediverse, to the author of the page we replied to.
119
120 Consulting the discussion:
121
122 Now the discussion could be seen in three places, if the applications listed application made the effort to integrate them:
123
124 * The general view of all the discussions the user can see (provided by the discussions application)
125 * The view of the discussions started from notifications (provided by activity stream)
126 * The view of the discussions link to the AP Page (provided by AP)
127
128 == Private messages between two users ==
129
130 User U1 wants to start a discussion with user U2.
131
132 U1 goes to the profile page of U2.
133
134 A discussion tab is proposed and is currently empty.
135
136 U1 type a first message.
137
138 1. Check if a discussion exists with relations to exactly two discussion contexts (admitting the users are identified by their profile page, this will change with the new actors API):
139 11. document:xwiki:XWiki.U1
140 11. document:xwiki:XWiki.U2
141 1. Creates the two discussion contexts and the discussion if they do not exist.
142 1. Add the message to the discussion
143 1. U2 is notified of the new message through the notifications mechanism.
144 1. The discussion is now displayed in the discussion lists of U1 and U2 in their profiles.
145
146 == Forum ==
147
148 In the context of a forum application, different discussion spaces called forums can be created by administrators.
149
150 Creating a forum creates a corresponding discussion contexts, the type of the discussion context entities can either be a new "forum" type, if we want to make the forum independent of XWiki pages for the storage, or otherwise directly of type "page", in a dedicated space.
151
152 A discussion, in the case, is created and linked to a single discussion context.
153
154 Messages are created as usual.
155
156 = Missing features =
157
158 This section lists missing features that must be integrated to the design
159
160 * Anonymous users can post messages
161 * Captcha integration
162
163 = Architecture =
164
165 == Detailed domain ==
166
167 === DiscussionContext ===
168
169 A group of discussions share a common context.
170
171 * reference: String
172 * entityReferenceType: String
173 * entityReference: String
174 * name: String
175 * description: String
176 * creation date: Date
177 * update date: Date
178 * states: List<String>
179 * pined: boolean
180
181 === Discussion ===
182
183 A group of messages
184
185 * reference: String
186 * title: String
187 * description: String
188 * creation date: Date
189 * update date: Date
190 * states: List<String>
191 * pined: boolean
192 * lastActivity: Date (derived) last activity of the discussion, the most recent date of the discussion's update date and the discussion's messages update dates
193
194 === Message ===
195
196 A message on a discussion
197
198 * reference: String
199 * content: String
200 * Discussion id: String
201 * author: UserReference
202 * creation date: date
203 * update date: date
204 * states: List<String>
205 * replyTo: Message
206 * pined: boolean
207
208 == xwiki-platform-discussion-api ==
209
210 === Create ===
211
212 ==== DiscussionContext createDiscussionContext(String name, String description, String referenceType, String entityReference) ====
213
214 Create and save a discussion context.
215
216 Two discussion can have the same name.
217
218 Throw an error if the the actor does not have the right to create a discussion context.
219
220 Set the creation date of the discussion context.
221
222 (% class="box infomessage" %)
223 (((
224 Must send a NewDiscussionContext event.
225 )))
226
227 ==== Discussion createDiscussion(String title, List<DiscussionContext> discussionContexts) ====
228
229 Create and save a discussion, and link it to the provided list of discussion contexts.
230
231 Two discussions can have the same title.
232
233 Throw an error if the actor does not have the right to create a discussion.
234
235 Set the creation date of the discussion.
236
237 (% class="box infomessage" %)
238 (((
239 Must send a NewDiscussion event.
240 )))
241
242 ==== Message createMessage(String content, Discussion discussion) ====
243
244 Create and save a message in a discussion.
245
246 Thrown an error if the actor does not have the right to create a message.
247
248 Throw an error if the actor does not have the right to add a message to the discussion.
249
250 Set the creation date of the message.
251
252 (% class="box infomessage" %)
253 (((
254 Must send a NewMessage event.
255 )))
256
257 ==== Other operations ====
258
259 (% class="box errormessage" %)
260 (((
261 To be designed
262 )))
263
264 * Attach an administrator to a forum
265 * Attach an administrator to a discussion
266 * Other right management operation
267
268 === Read ===
269
270 ==== List<DiscussionContext> getDiscussionContexts(int offset, int limit) ====
271
272 Returns a paginated list of the discussion contexts.
273
274 The pined discussion contexts are returned first.
275
276 ==== int countDiscussionContexts() ====
277
278 Returns a count of the discussion contexts.
279
280 ==== Optional<DiscussionContext> getDiscussionContext(String reference) ====
281
282 Returns a discussion by its reference.
283
284 The optional is empty if:
285
286 * the actor does not have the right to access the forum
287 * no forum is found for the reference
288
289 ==== List<Discussion> getDiscussions(List<DiscussionContext> discussionContexts, int offset, int limit) ====
290
291 Returns a paginated list of the discussions linked to the list of discussion contexts passed in parameter.
292
293 The pined discussions are returned first.
294
295 ==== int countDiscussions(DiscussionContext discussionContext) ====
296
297 Returns the count of the discussions attached to a discussion context.
298
299 ==== Optional<Discussion> getDiscussion(String discussionReference) ====
300
301 Returns a discussion by its reference.
302
303 The optional is empty if:
304
305 * the actor does not have the right to view the discussion
306 * no discussion is found for the reference
307
308 ==== List<Messages> getMessages(Discussion discussion, int offset, int limit) ====
309
310 Returns a paginated list of the messages of a discussion.
311
312 Throw an error if the actor is not allowed to view the discussion.
313
314 ==== List<Messages> getRootMessages(Discussuion discussion, int offset, int limit) ====
315
316 Returns a paginated list of the root messages of a discussion (i.e., the messages with an empty replyTo field).
317
318 Throw an error if the actor is not allowed to view the discussion.
319
320 ==== List<Message> getMessage(Message message, int offset, int limit) ====
321
322 Returns a paginated list of the messages that are replies to the message passed in parameter.
323
324 Throw an error if the actor is not allowed to view the discussion.
325
326 ==== int countMessages(Discussion discussion) ====
327
328 Returns a count of the messages in a discussion.
329
330 ==== int countRootMessages(Discussion discussion) ====
331
332 Returns a count of the root messages in a discussion (i.e., the message with an empty replyTo field).
333
334 ==== int countMessages(Message message) ====
335
336 Returns a count of the number of replies to the message passed in parameter.
337
338 ==== Optional<Message> getMessage(String messageReference) ====
339
340 Returns a message by its reference.
341
342 The optional is empty if:
343
344 * the actor does not have the right to view the message
345 * no message is found for the reference
346
347 ==== Date getLastUpdate(Discussion discussion) ====
348
349 Returns the date of the last action performed on the discussion, it is the most recent date of:
350
351 * the creation of the discussion
352 * an update of a discussion field
353 * the creation of a message on the discussion
354 * the update of a message of the discussion
355
356 === Update ===
357
358 ==== void updateDiscussionContext(String reference, String name, String description) ====
359
360 Updates the updatable information of a forum:
361
362 * its name
363 * its description
364
365 Changes the update date of the discussion context.
366
367 Throw an error is the actor is not allowed to update the discussion context.
368
369 (% class="box infomessage" %)
370 (((
371 Must send a UpdatedDiscussionContext event.
372 )))
373
374 ==== void updateDiscussion(String reference, String title, String description) ====
375
376 Updates the updatable information of a discussion:
377
378 * its title
379 * its description
380
381 Changes the update date of the discussion.
382
383 Throw an error if the actor is not allowed to update the discussion.
384
385 (% class="box infomessage" %)
386 (((
387 Must send a UpdateDiscussion event.
388 )))
389
390 ==== void linkDiscussionContext(Discussion discussion, DIscussionContext discussionContext) ====
391
392 Links a discussion to a discussion. The relation is bidirectional.
393
394 ==== void unlinkDiscussionContext(Discussion discussion, DiscussionContext discussionContext) ====
395
396 Unlinks a discussion and on of its linked discussion context.
397
398 ==== void updateMessage(String reference, String context) ====
399
400 Update the updatable information of a message:
401
402 * its message
403
404 Change the update date of the message.
405
406 Throw an error if the actor is not allowed to update the message.
407
408 (% class="box infomessage" %)
409 (((
410 Must send a UpdateMessage event.
411 )))
412
413 ==== void pinDiscussion(Discussion discussion) ====
414
415 Pin a discussion.
416
417 ==== void unpinDiscussion(Discussion discussion) ====
418
419 Unpin a discussion.
420
421 ==== void pinMessage(Message message) ====
422
423 Pin a message.
424
425 ==== void unpinMessage(Message message) ====
426
427 Unpin a message.
428
429 ==== void updateStates(DiscussionContext discussionContext, List<String> states) ====
430
431 The state are an open mechanism to add custom metadatas to a discussion context.
432
433 Updates the list of states of the discussion context.
434
435 ==== void updateStates(Discussion discussion, List<String> states) ====
436
437 The state are an open mechanism to add custom metadatas to a discussion context.
438
439 Updates the list of states of the discussion.
440
441 ==== void updateStates(Message message, List<String> states) ====
442
443 The state are an open mechanism to add custom metadatas to a discussion context.
444
445 Updates the list of states of the message.
446
447 (% class="box errormessage" %)
448 (((
449 TODO: RIGHTS API
450 )))
451
452 ==== addAdminGroup(DiscussionContext discussionContext, Group group) ====
453
454 Add a group to the list of administrators of the discussion context.
455
456 ==== addAdminUser(DiscussionContext discussionContext, User user) ====
457
458 Add a user to the list of administrators of the discussion context.
459
460 ==== removeAdminGroup(DiscussionContext discussionContext, Group group) ====
461
462 Remove a group from the list of administators  of the discussion context.
463
464 ==== removeAdminUser(DiscussionContext discussionContext, User user) ====
465
466 Remove a user from the list of administrators of the discussion context.
467
468 ==== addAdminGroup(Discussion discussion, Group group) ====
469
470 Add an group of the list of administrators of the discussion.
471
472 ==== addAdminUser(Discussion discussion, User user) ====
473
474 Add a user to the list of administrators of the discussion.
475
476 ==== removeAdminGroup(Discussion discussion, Group group) ====
477
478 Remove an group from the list of administrators of the discussion.
479
480 ==== removeAdminUser(Discussion discussion, User user) ====
481
482 Remove a user from the list of administrators of the discussion
483
484 ==== addReadGroup(Discussion discussion, Group group) ====
485
486 Add a group to the list of readers of the discussion.
487
488 ==== addReadUser(Discussion discussion, Group group) ====
489
490 Add a user to the list of readers of the discussion.
491
492 ==== removeReadGroup(Discussion discussion, User user) ====
493
494 Remove a group from the list of readers of the discussion.
495
496 ==== removeReadUser(Discussion discussion, User user) ====
497
498 Remove a user from the list of readers of the discussion.
499
500 ==== addWriteGroup(Discussion discussion, Group group) ====
501
502 Add a group to the list of writers of the discussion.
503
504 ==== addWriteUser(Discussion discussion, Group group) ====
505
506 Add a user to the list of writers of the discussion.
507
508 ==== removeWriteGroup(DiscussionContext discussion, User user) ====
509
510 Remove a group from the list of writers of the discussion.
511
512 ==== removeWriteUser(DiscussionContext discussion, User user) ====
513
514 Remove a user from tthe list of writers of the discussion.
515
516 === Delete ===
517
518 ==== void deleteDiscussionContext(DiscussionContext forum) ====
519
520 Delete a discussion context.
521
522 Throw an error if the actor does not have the right to delete the discussion context.
523
524 After deleting the discussion context, checks for orphaned discussions and remove them as well ("garbage collection like").
525
526 (% class="box warningmessage" %)
527 (((
528 Only discussion context administrators can remove a discussion context.
529 )))
530
531 (% class="box infomessage" %)
532 (((
533 Must send a DeleteDiscussionContext event. Must also send DeleteDiscussion events if needed.
534 )))
535
536 ==== void deleteDiscussion(Discussion discussion) ====
537
538 Dete a discussion.
539
540 Throw an error if the actor does not have the right do delete the discussion
541
542 After deleting a discussion, checks for orphaned discussion context are remove the as well ("garbage collection like").
543
544 (% class="box warningmessage" %)
545 (((
546 Only discussion administrators can delete a discussion
547 )))
548
549 (% class="box infomessage" %)
550 (((
551 Must send a DeleteDiscussion event. Must also send DeleteDiscussionContext events if needed.
552 )))
553
554 ==== void deleteMessage(Message message) ====
555
556 Delete a message.
557
558 Throw an error if the actor does not have the right to delete the message.
559
560 (% class="box warningmessage" %)
561 (((
562 Only discussion administrators and the author of the message can delete a message.
563 )))
564
565 (% class="box infomessage" %)
566 (((
567 Must send a DeleteMessage event.
568 )))
569
570 === void pinDiscussionContext(String reference) ===
571
572 Switch the status of the discussion context to pined.
573
574 (% class="box warningmessage" %)
575 (((
576 Only administrators of the discussion context can pin the discussion context.
577 )))
578
579 === void unpinDiscussionContext(String reference) ===
580
581 Switch the status of the discussion context to pined.
582
583 (% class="box warningmessage" %)
584 (((
585 Only administrators of the discussion context can unpin the discussion context.
586 )))
587
588 === void pinDiscussion(String reference) ===
589
590 Switch the status of the discussionto pined.
591
592 (% class="box warningmessage" %)
593 (((
594 Only administrators of the discussion can pin the discussion.
595 )))
596
597 === void unpinDiscussion(String reference) ===
598
599 Switch the status of the discussion to pined.
600
601 (% class="box warningmessage" %)
602 (((
603 Only administrators of the discussion can unpin the discussion.
604 )))
605
606 === void pinMessage(String reference) ===
607
608 Switch the status of the message to pined.
609
610 (% class="box warningmessage" %)
611 (((
612 Only administrators of the discussion of the message can pin the message.
613 )))
614
615 === void unpinMessage(String reference) ===
616
617 Switch the status of the message to pined.
618
619 (% class="box warningmessage" %)
620 (((
621 Only administrators of the discussion of the message can unpin the message.
622 )))
623
624 == xwiki-platform-discussion-rest ==
625
626 (% class="box warningmessage" %)
627 (((
628 Note: currently the rest API is designed to offer a way to manipulate the business objects, but not the crosscutting concerns such as user rights.
629 )))
630
631
632 |=Name|=HTTP Method|=Path|=Path param|=Get params|=Body Params|=Response|=Description|=Need authentication?
633 |createDiscussionContext|POST|/discussionContext| | |(((
634 * entityReferenceType: String
635 * entityReference: String
636 * name: String
637 * description:String
638 )))|The created discussion context object|Creates a discussion context|TBD
639 |deleteDiscussionContext|DELETE|/discussionContext/{discussionContextReference}|(((
640 * discussionContextReference: the reference of the discussion context to delete
641 )))| | |a success code|Delete a discussion context|
642 |createDiscussion|POST|/discussion| | |(((
643 * title: String
644 * description: String
645 )))|The created discussion object|Creates a discussion|TBD
646 |delete Discussion|DELETE|/discussion/{discussionReference}|(((
647 * discussionReference: the reference of the discussion to delete
648 )))| | |a success code|Delete a discussion|
649 |createMessage|POST|/message| | |(((
650 * content: String
651 * discussionReference: String
652 * replyTo: String (message reference) (optional)
653 )))|The created message object|Create a message in a discussion|TBD
654 |deleteMessage|DELETE|/message/{messageReference}|(((
655 * messageReference: the message reference to delete
656 )))| | |a success code|Delete a message|
657 |updateDiscussionContext|PUSH|/discussionContext| | |(((
658 * name: String
659 * description:String
660 )))|The updated discussion context|Update the name and description of a discussion context|TBD
661 |updateDisucssion|PUSH|/discussion| | |(((
662 * title: String
663 * description: String
664 )))|The updated discussion|Update the title and description of a discussion|TBD
665 |updateMessage|PUSH|/message| | |(((
666 * content: String
667 )))|The updated message|Update the content of a message|TBD
668 |linkDiscussionAndDiscussionContext|PUSH|/discussionContext/link| |(((
669 * discussionContextReference: String
670 * discussionReference: String
671 )))| |success/error code only|Link a discussion and a discussion context|TBD
672 |unlinkDiscussionAndDiscussionContext|DELETE|/discussionContext/link| |(((
673 * discussionContextReference: String
674 * discussionReference: String
675 )))| |success/error code only|Unlink a discussion and a discussion context|TBD
676 |getDiscussionContexts|GET|/discussionContext| |(((
677 * offset: int
678 * limit: int
679 * type: string (optional)
680 * sortBy (array): creationDate, updateDate,name,description,type
681 )))| |the paginated list of discussion contexts, optionally filtered by type, and sorted by the sort criteria|Returns a paginated list of discussion contexts|TBD
682 |countDiscussionContext|GET|/discussionContexts/count| |same as getDiscussionContexts, except for the pagination and sort| |same as getDiscussionContexts but returns the the number of results instead| |
683 |getDiscussions|GET|/discussion| |(((
684 * offset: int
685 * limit: int
686 * type: string (optional)
687 * entityReference: string (optional)
688 * sortBy (array): creationDate, updateDate,title,description,type
689 )))| |the paginated list of discussions, optionally filtered by type and/or entity reference, and sorted by the sort criteria|Returns a paginated list of discussions|TBD
690 |countDiscussions|GET|/discussion/count| |same as getDiscussions except for the pagination and sort| |same as getDiscussions but returns the number of results instead| |
691 |getMessages|GET|/discussion/{discussionReference}/messages|(((
692 * discussionReference: the reference of the discussion containing the messages
693 )))|(((
694 * offset: int
695 * limit: int
696 * sortBy: creationDate or updateDate (default = updateDate)
697 )))| |the paginated list of messages of a discussion, sort by by sort criterion|Returns a paginated list of messages|TBD
698 |countMessages|GET|/discussion/{discussionReference}/messages/count|same as getMessages|same as getMessages, exception of the pagination and sort| |same as getMessages but returns the number of results instead| |
699 |getDiscussionContext|GET|/discussionContext/{discussionContextReference}|(((
700 * discussionContextReference: the discussion context reference to retrieve
701 )))| | |the object|returns a single discussion context|TBD
702 |getDiscussion|GET|/discussion/{discussionRefernece}|(((
703 * discussionReference: the reference of the discussion to retrieve
704 )))| | |the object|returns a single discussion|TB
705 |getMessage|GET|/message/{messageReference}|(((
706 * messageReference: the message reference
707 )))| | |the object|returns a single message|TBD
708 |pinDiscussion|PUSH|/discussion/{discussionReference}/pin|TODO| | |TBD|pin a discussion|
709 |unpinDiscussion|PUSH|/discussion/{discussionReference}/unpin|TODO| | |TBD|unpin a discussion|
710 |pinMessage|PUSH|/message/{messageReference}/pin|TODO| | |TBD|pin a message|
711 |unpinMessage|PUSH|/message/{messageReference}/unpin|TODO| | |TBD|unping a message|
712
713 == xwiki-platform-discussion-store-api ==
714
715 This module provides the low level operation required to realize the actions proposed by [[xwiki-platform-discussion-api>>doc:||anchor="Hxwiki-platform-discussion-api"]]. For instance no rights control are done before performing the operations.
716
717 This modules is nonetheless in charge of the data concistency of its entities. It must control and raise errors if an operation would break the concistency of the application by being performed.
718
719 The section regroups the operations for each manipulable entity (see the [[detailed domain>>doc:||anchor="HDetaileddomain"]]).
720
721 (% class="box warningmessage" %)
722 (((
723 All entities must provide a unique reference allowing to resolve them, this reference can be derived from the underlying storage implementation.
724 )))
725
726 (% class="box warningmessage" %)
727 (((
728 How do we anticipate a possible store switch? Migration operations ? Unique prefix for the references (for instance, a message reference in with the default "page" storage would be page:xwiki:MySpace.MyDiscussion^Discussions.Message[0]. The way, when we can know statically if we are resolving the reference with the rigth storage.
729 )))
730
731 (% class="box warningmessage" %)
732 (((
733 Do we want to anticipate storing different entities in different storages?
734 )))
735
736 === DiscussionContextService ===
737
738 ==== DiscussionContext create(String entityReferenceType, String entityReference, String name, String description) ====
739
740 Creates and initializes a discussion context.
741
742 The list of administrator users is initialized with the current user.
743
744 This list of administrator groups is empty.
745
746 The creation and update dates are set to now.
747
748 The state is empty.
749
750 This pined field is set to false.
751
752 ==== Optional<DiscussionContext> get(String reference) ====
753
754 Returns a discussion context from its reference.
755
756 ==== List<DiscussionContext> list(String type, int offset, int limit) ====
757
758 Returns a list of discussion contexts of a given type.
759
760 ==== List<DiscussionContext> listByDiscussion(String discussionReference, int offset, int limit) ====
761
762 Returns the list of discussion contexts linked to the passed discussion reference.
763
764 ==== void update(String reference, String name, String description) ====
765
766 Update the name and description of the discussion context.
767
768 Update the update date of the object.
769
770 ==== void updateAdministrators(String reference, List<User> users, List<Group> groups) ====
771
772 Replace the lists of administrator users and groups with the new lists.
773
774 Update the update date of the object.
775
776 (% class="box warningmessage" %)
777 (((
778 Throw an error of the two lists are empty as it would probably lock the object?
779 )))
780
781 ==== void setState(String reference, String state) ====
782
783 Replaces the state of the object.
784
785 Update the update date of the object.
786
787 ==== void pin(String reference) ====
788
789 Pin the object.
790
791 Update the update date of the object.
792
793 ==== void unpin(String reference) ====
794
795 Unpin the object.
796
797 Update the update date of the object.
798
799 ==== void attachDiscussion(String discussionContextReference, String discussionReference) ====
800
801 Links a discussion to a discussion context.
802
803 Update the update date of the discussions context as well as the discussion.
804
805 ==== void detachDiscussion(String discussionContextReference, String discussionReference) ====
806
807 Unlinks a discussion and a discussion context.
808
809 Update the update date of the discussion context as well the discussion.
810
811 Removes the discussion context if it is now connect to 0 discussions.
812
813 Removes the discussion if it is now connect to 0 discussion contexts.
814
815 ==== void delete(String reference) ====
816
817 Delete the object.
818
819 Checks if some discussions are now without discussion contexts and remove them too.
820
821 === DiscussionService ===
822
823 ==== Discussion create(String title, String description) ====
824
825 Creates and initializes the discussion.
826
827 Set the current user as administrator.
828
829 The administator group list is empty.
830
831 Set the creation date to now.
832
833 Set the update date to now.
834
835 The state is empty.
836
837 The discussion is not pined.
838
839 ==== Optional<Discussion> get(String reference) ====
840
841 Returns the discssion
842
843 ==== void update(String reference, String title, String description) ====
844
845 Update the title and description of the object.
846
847 Update the update date.
848
849 ==== void updateAdministrators(String reference, List<User> users, List<Group> groups) ====
850
851 Replace the lists of administrator users and groups with the new lists.
852
853 Update the update date of the object.
854
855 (% class="box warningmessage" %)
856 (((
857 Throw an error of the two lists are empty as it would probably lock the object?
858 )))
859
860 ==== void setState(String reference, String state) ====
861
862 Replaces the state of the object.
863
864 Update the update date of the object.
865
866 ==== void pin(String reference) ====
867
868 Pin the object.
869
870 Update the update date of the object.
871
872 ==== void unpin(String reference) ====
873
874 Unpin the object.
875
876 Update the update date of the object.
877
878 ==== void attachDiscussionContext(String discussionReference, String discussionContextReference) ====
879
880 Links a discussion context to a discussion.
881
882 Update the update date of the discussion as well as the discussion context.
883
884 ==== void detachDiscussionContext(String discussionReference, String discussionContextReference) ====
885
886 Unlinks a discussion and a discussion context.
887
888 Update the update date of the discussion context as well the discussion.
889
890 Removes the discussion if it is now connect to 0 discussion contexts.
891
892 Removes the discussion context if it is now connect to 0 discussions.
893
894 ==== void delete(String reference) ====
895
896 Delete the object.
897
898 Checks if some discussions context are now without discussions and remove them too.
899
900 === MessageService ===
901
902 ==== Message create(String content, User author) ====
903
904 Creates and initializes a message with the content and author.
905
906 Set the creation and update dates to now.
907
908 The state is empty.
909
910 The reply to is empty
911
912 ==== Message create(String content, User author, String replyToReference) ====
913
914 Creates and initializes a message with the content, author and replyToReference.
915
916 Set the creation and update dates to now.
917
918 The state is empty.
919
920 ==== void update(String reference, String content) ====
921
922 Update the content of the message.
923
924 Set the update date to now.
925
926 ==== void delete(String reference) ====
927
928 Delete the message.
929
930 == xwiki-platform-discussion-store-default ==
931
932 (% class="box errormessage" %)
933 (((
934 Do we address [[https:~~/~~/jira.xwiki.org/browse/XWIKI-17174>>https://jira.xwiki.org/browse/XWIKI-17174]] ?
935 )))
936
937 (% class="wikigeneratedid" %)
938 Let's take the hypothesis that [[XWIKI-17174>>https://jira.xwiki.org/browse/XWIKI-17174]] will be addressed.
939
940 (% class="wikigeneratedid" %)
941 **Where are discussion context stored?**
942
943 (% class="wikigeneratedid" %)
944 Discussion Contexts are stored in pages and contains a DiscussionContext XObject.
945
946 (% class="wikigeneratedid" %)
947 Each discussion context is stored in its own page, under a common space Discussions.DiscussionContext.XXXX where XXXX is a unique page name composed of the discussion context title + a random short string.
948
949 (% class="wikigeneratedid" %)
950 **Where are the entity references stored?**
951
952 (% class="wikigeneratedid" %)
953 The entity references are stored directly inside the discussion context. If several discussion contexts references the same entity, they have duplicated references / reference types.
954
955 (% class="wikigeneratedid" %)
956 **Where are relations between entity references and discussion context stored?**
957
958 (% class="wikigeneratedid" %)
959 The discussion contexts contains a list of discussions references.
960
961 (% class="wikigeneratedid" %)
962 The discussion contains a list of discussion contexts.
963
964 (% class="wikigeneratedid" %)
965 The application is in charge of keeping track of the consistency of there relations.
966
967 (% class="wikigeneratedid" %)
968 **Where are discussions stored?**
969
970 (% class="wikigeneratedid" %)
971 Discussions are stored in pages and contains a Discussion object.
972
973 (% class="wikigeneratedid" %)
974 Can a single page contains several discussions? **NO**
975
976 (% class="wikigeneratedid" %)
977 Each discussion is stored in its own page, under a common space Discussions.Discussions.XXXX where XXXX is a unique page name composed of the discussion title + a random short string
978
979 (% class="wikigeneratedid" %)
980 **Where a message stored ?**
981
982 (% class="wikigeneratedid" %)
983 Messages are stored in the page of their discussion in message XObjects.
984
985 (% class="wikigeneratedid" %)
986 If [[XWIKI-17174>>https://jira.xwiki.org/browse/XWIKI-17174]] is not addresed, messages will need to be stored in sub-pages of the discussion page.
987
988 == xwiki-platform-discussion-ui ==
989
990 (% class="box infomessage" %)
991 (((
992 See the specifications below
993
994 TODO: proposed reusable macros to embed the discussions contextually.
995 )))
996
997 = User Interface Specifications =
998
999 (% class="box errormessage" %)
1000 (((
1001 The first application usecase of the discussions will be the ActivityPub use case presented above. Consequently, the interfaces and UC will be prioritized regarding this objective.
1002 )))
1003
1004 == TODO ==
1005
1006 1. Pin a discussion context
1007 11. Should be integrated to the discussion administration
1008 1. Administrate a discussion context
1009 11. Should take the form of a generic administration could be provided. It will take the form of an object editor for the DiscussionContext instance (+ some business rules validation and specific buttons such as remove or pin?).
1010 1. View the discussion context list
1011 11. Should take the form of a macro returning the UI for the list of discussion contexts according to some criteria (for a type of entity and/or an entity reference).
1012 1. Delete a discussion context
1013 11. Programmatically?
1014 1. Create a discussion
1015 11. Should take the form of a macro that can be integrated where needed.
1016 1. Administrate a discussion
1017 11. Should take the form of a generic administration for the discussion. It will take the form of an object editor for the Discussion instance (+ some business rules validation and specific buttons such as remove or pin?)
1018 1. View the paginated list of discussions AKA DISCUSSION INDEX
1019 11. Generic macro to view a paginated list of all the discussions related to a given user
1020 1. View the paginated list of discussions by discussion context
1021 11. Generic macro to view a paginated list of all the discussion related to a given user and a given discussion context
1022 1. View the paginated list of discussions by discussion context type
1023 11. Generic macro to view a paginated list of all the discussion related to a given user and a given discussion context type
1024 1. Implement a specific use of the discussion listing to define the main page of the discussions, show **relevant** discussions to the current user (this one might be complex)
1025 1. View a discussion
1026 11. Generic macro to view a a discussion. It should also be integrated by default and accessible from the discussions lists.
1027 1. Pin a discussion
1028 11. Should be integrated to the discussion context administration (note: can a discussion be pined in one discussion context and not in another one ?)
1029 1. Delete a discussion
1030 11. should be integrated to the discussion administration
1031 1. Create a message
1032 11. should be integrated to the discussion view UI
1033 1. Update a message
1034 11. should be provided as a reusable macro but also accessible easily from the discussion view UI
1035 1. Delete a message
1036 11. should be a button integrated to the discussion view UI
1037 1. Pin a message
1038 11. should be integrated to the discussion administration
1039
1040 == Main page ==
1041
1042 === View a discussion ===
1043
1044 A header presents the title and description of the discussion.
1045
1046 The messages are displayed paginated, the oldest message at the top.
1047
1048 Each message present the avatar of the author and the content of the message, plus the available actions for the message, according to the rights of the current user:
1049
1050 * delete
1051 * edit
1052 * pin
1053 * ...
1054
1055 At the bottom of the page, a form is available if the current user has the right to write to add a new message to the discussion.
1056
1057 {{gallery}}
1058 image:viewdiscussion.png
1059 {{/gallery}}
1060
1061 === Administrate a discussion ===
1062
1063 The administration of the discussion is opened to the administrators of the discussion.
1064
1065 A form is proposed to update the title and description of the discussion.
1066
1067 A button is also proposed to remove the discussion.
1068
1069 {{gallery}}
1070 image:admindiscussion.png
1071 {{/gallery}}
1072
1073 === Administrate a discussion rights ===
1074
1075 A page is available to administrate the discussions rights.
1076
1077
1078 {{gallery}}
1079 image:admin_rights_discussion.png
1080 {{/gallery}}
1081
1082 === ActivityPub integration ===
1083
1084 This section discuss more specifically the integration of ActivityPub with the Discussions but should be seen as a tentative to make the discussions bridgeable with external discussion systems.
1085
1086 ==== Sending a message to the fediverse ====
1087
1088 When creating a discussion, the user pick to select the members of the discussion is extensible and should propose different sources of groups and users.
1089
1090 When the activity pub user source is activated, actors of the fediverse can be added to the list of members of the discussion.
1091
1092 In this case, the messages of the discussion should also be sent to the fediverse, in the form of Notes replying to the most recent message of the discussion by filling the inReplyTo field of the note with the activitypub identifier of the most recent message of the discussion.
1093
1094 ==== Receiving a message from the fediverse ====
1095
1096 When receiving a inReplyTo field containing the identifier of a message of a discussion, the message should be added to the corresponding discussion unless:
1097
1098 * the actor of the fediverse is not a member of the discussion
1099
1100 (% class="box warningmessage" %)
1101 (((
1102 Due to the architecture of the fediverse, message can be received with a significant latency, should we take into account the actual reception date of the message, of its creation date?
1103 )))
1104
1105 = Tasks =
1106
1107 |=UC#|=Depends on|=Title|=Complexity|=Priority
1108 |UC1.1|extensible user picker|[[Creating a new discussion>>doc:||anchor="HUC1-Creatinganewdiscussion"]]| |
1109 |UC1.2|quick actions, extensible user picker|Creating a discussion from the notifications| |
1110 |UC2| |[[Listing the discussions>>url:https://design.xwiki.org/xwiki/bin/view/Proposal/Discussions#HUC2-Listingthediscussions]]| |
1111 |UC3| |[[Displaying a discussion>>url:https://design.xwiki.org/xwiki/bin/view/Proposal/Discussions#HUC3-Displayingadiscussion]]| |
1112 |UC4| |See the messages of a discussion| |
1113 |UC5| |Reply to a discussion| |
1114 |UC6| |Administrate a discussion| |
1115 |UC7| |Administrate a discussion context| |
1116 |UC8| |Create a discussion context| |
1117 |UC9| |Delete a discussion context| |
1118 |UC10| |Delete a discussion| |
1119 |UC11| |Delete a message| |
1120 |UC13| |Link a discussion context and a discussion| |
1121 |UC14| |Unlink a discussion context and a discussion| |
1122 |UC15| |Send event when dicussions context/discussions/messages are created, updated or deleted| |
1123 |UC16| |Administrate a discussion context rights| |
1124 |UC17| |Administrate a discussion rights| |
1125 |UC18| |Pin a discussion context| |
1126 |UC19| |Pin a discussion| |
1127 |UC20| |Pin a message| |
1128 |UC21| |Archive a discussion context| |
1129 |UC22| |Archive a discussion| |
1130 |UC23| |Archive a message| |
1131
1132 == UC1 - Creating a new discussion ==
1133
1134 == UC1.1 - Creation a discussion from the notifications ==
1135
1136 == UC2 - Listing the discussions ==
1137
1138 Definition of the display of the discussions and its integration on the main page.
1139
1140 == UC3 - Displaying a discussion ==
1141
1142 == UC4 - Editing an existing message ==
1143
1144 == UC5  - ActivityPub Specific UCs ==
1145
1146 Sharing a discussion with the

Get Connected