Discussions

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

 XWiki
 Design
 Completed
 
 

https://forum.xwiki.org/t/brainstorming-about-xwiki-discussions/
https://jira.xwiki.org/browse/XWIKI-15966
https://jira.xwiki.org/browse/XWIKI-8088
https://jira.xwiki.org/browse/XWIKI-9104
https://design.xwiki.org/xwiki/bin/view/Proposal/UserMessageNotifications#HInbox
https://extensions.xwiki.org/xwiki/bin/view/Extension/XMPP%20Chat%20Application
https://extensions.xwiki.org/xwiki/bin/view/Extension/ChatApplication
https://markmail.org/message/pw6wtx2lkn72rupv
https://markmail.org/message/vwtfgyf4yyvne4g2

Description

Introduction

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).

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 (e.g., Mastodon).

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.

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.

Table of content

  1. Introduction
  2. Table of content
  3. Architecture Overview
  4. Domain Overview
  5. Illustrating use cases
    1. Comments
      1. Description
      2. Realization
        1. Commenting
        2. Other actions
    2. Starting a discussion from a notification
    3. Private messages between two users
    4. Forum
  6. Missing features
  7. Architecture
    1. Detailed domain
      1. DiscussionContext
      2. Discussion
      3. Message
    2. xwiki-platform-discussion-api
      1. Create
        1. DiscussionContext createDiscussionContext(String name, String description, String referenceType, String entityReference)
        2. Discussion createDiscussion(String title, List<DiscussionContext> discussionContexts)
        3. Message createMessage(String content, Discussion discussion)
        4. Other operations
      2. Read
        1. List<DiscussionContext> getDiscussionContexts(int offset, int limit)
        2. int countDiscussionContexts()
        3. Optional<DiscussionContext> getDiscussionContext(String reference)
        4. List<Discussion> getDiscussions(List<DiscussionContext> discussionContexts, int offset, int limit)
        5. int countDiscussions(DiscussionContext discussionContext)
        6. Optional<Discussion> getDiscussion(String discussionReference)
        7. List<Messages> getMessages(Discussion discussion, int offset, int limit)
        8. List<Messages> getRootMessages(Discussuion discussion, int offset, int limit)
        9. List<Message> getMessage(Message message, int offset, int limit)
        10. int countMessages(Discussion discussion)
        11. int countRootMessages(Discussion discussion)
        12. int countMessages(Message message)
        13. Optional<Message> getMessage(String messageReference)
        14. Date getLastUpdate(Discussion discussion)
      3. Update
        1. void updateDiscussionContext(String reference, String name, String description)
        2. void updateDiscussion(String reference, String title, String description)
        3. void linkDiscussionContext(Discussion discussion, DIscussionContext discussionContext)
        4. void unlinkDiscussionContext(Discussion discussion, DiscussionContext discussionContext)
        5. void updateMessage(String reference, String context)
        6. void pinDiscussion(Discussion discussion)
        7. void unpinDiscussion(Discussion discussion)
        8. void pinMessage(Message message)
        9. void unpinMessage(Message message)
        10. void updateStates(DiscussionContext discussionContext, List<String> states)
        11. void updateStates(Discussion discussion, List<String> states)
        12. void updateStates(Message message, List<String> states)
        13. addAdminGroup(DiscussionContext discussionContext, Group group)
        14. addAdminUser(DiscussionContext discussionContext, User user)
        15. removeAdminGroup(DiscussionContext discussionContext, Group group)
        16. removeAdminUser(DiscussionContext discussionContext, User user)
        17. addAdminGroup(Discussion discussion, Group group)
        18. addAdminUser(Discussion discussion, User user)
        19. removeAdminGroup(Discussion discussion, Group group)
        20. removeAdminUser(Discussion discussion, User user)
        21. addReadGroup(Discussion discussion, Group group)
        22. addReadUser(Discussion discussion, Group group)
        23. removeReadGroup(Discussion discussion, User user)
        24. removeReadUser(Discussion discussion, User user)
        25. addWriteGroup(Discussion discussion, Group group)
        26. addWriteUser(Discussion discussion, Group group)
        27. removeWriteGroup(DiscussionContext discussion, User user)
        28. removeWriteUser(DiscussionContext discussion, User user)
      4. Delete
        1. void deleteDiscussionContext(DiscussionContext forum)
        2. void deleteDiscussion(Discussion discussion)
        3. void deleteMessage(Message message)
      5. void pinDiscussionContext(String reference)
      6. void unpinDiscussionContext(String reference)
      7. void pinDiscussion(String reference)
      8. void unpinDiscussion(String reference)
      9. void pinMessage(String reference)
      10. void unpinMessage(String reference)
    3. xwiki-platform-discussion-rest
    4. xwiki-platform-discussion-store-api
      1. DiscussionContextService
        1. DiscussionContext create(String entityReferenceType, String entityReference, String name, String description)
        2. Optional<DiscussionContext> get(String reference)
        3. List<DiscussionContext> list(String type, int offset, int limit)
        4. List<DiscussionContext> listByDiscussion(String discussionReference, int offset, int limit)
        5. void update(String reference, String name, String description)
        6. void updateAdministrators(String reference, List<User> users, List<Group> groups)
        7. void setState(String reference, String state)
        8. void pin(String reference)
        9. void unpin(String reference)
        10. void attachDiscussion(String discussionContextReference, String discussionReference)
        11. void detachDiscussion(String discussionContextReference, String discussionReference)
        12. void delete(String reference)
      2. DiscussionService
        1. Discussion create(String title, String description)
        2. Optional<Discussion> get(String reference)
        3. void update(String reference, String title, String description)
        4. void updateAdministrators(String reference, List<User> users, List<Group> groups)
        5. void setState(String reference, String state)
        6. void pin(String reference)
        7. void unpin(String reference)
        8. void attachDiscussionContext(String discussionReference, String discussionContextReference)
        9. void detachDiscussionContext(String discussionReference, String discussionContextReference)
        10. void delete(String reference)
      3. MessageService
        1. Message create(String content, User author)
        2. Message create(String content, User author, String replyToReference)
        3. void update(String reference, String content)
        4. void delete(String reference)
    5. xwiki-platform-discussion-store-default
    6. xwiki-platform-discussion-ui
  8. User Interface Specifications
    1. TODO
    2. Main page
      1. View a discussion
      2. Administrate a discussion
      3. Administrate a discussion rights
      4. ActivityPub integration
        1. Sending a message to the fediverse
        2. Receiving a message from the fediverse
  9. Tasks
    1. UC1 - Creating a new discussion
    2. UC1.1 - Creation a discussion from the notifications
    3. UC2 - Listing the discussions
    4. UC3 - Displaying a discussion
    5. UC4 - Editing an existing message
    6. UC5  - ActivityPub Specific UCs

Architecture Overview

The proposed name for the application is discussion, it will be used in the remainder of the document but might be subject to change.

I'm also considering it to be part of xwiki platform for the naming, but that also might change.

  • xwiki-platform-discussion-api: Provides the operations to interact with the discussions
  • xwiki-platform-discussion-default: Default implementation of the discussions API
  • xwiki-platform-discussion-rest: Provides the REST operations to interact with the discussion
  • xwiki-platform-discussion-store-api: Provides the operations to interact with the discussion store
  • xwiki-platform-discussion-store-default: Default implementation of the store API, where the discussion entities are stored in xpages
  • 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

Domain Overview

This section describes the main concepts manipulated in the context of the discussions

Discussion Context

A discussion context represents a group of discussions sharing a relation to the same entity.

A discussion can be part of several discussion contexts.

Entity Reference

An entity reference stores the reference to an entity in the wiki.

It is composed of the type of the referenced entity, and a serialized reference, expected to be read according to the type referenced entity.

Discussion

A discussion represents a collection of messages sharing a common topic.

A discussion can be part of several discussion contexts.

Message

A message is a textual contribution to a discussion. Messages are usually displayed ordered by their creation dates.

A message can be a reply to another message, forming arborescent discussions.

Illustrating use cases

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.

This is also a way to verify that the current design is general enough to fit a reasonable range of application use cases.

Each section starts with a short description of the use case then describes the use of the discussion APIs to realize it.

Comments

Description

Comment are sequences of messages that can answer each other and are attached to a wiki page.

They are displayed at the bottom of the page.

Comments can be posted by anonymous or logged in users that can view the page and are allowed to comment.

Administrators can edit and remove all the messages.

Users can edit and remove their messages.

Realization

Commenting

When a comment is added:

  1. We check for the author right to verify he/she is allowed to post a message on this page
  2. We look for a discussion context with entityReferenceType="document", entityeReference="xwiki:XWiki.MyPage".
  3. If it does not exist
    1. 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.
    2. 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
    3. The created discussion is returned
  4. If it does exist:
    1. We look for the only discussion linked to the discussion context and return it
  5. The message is created in the returned discussion

Other actions

Editing, removing, pining are straightforward and should be realized by generic actions provided by the reusable UI.

Starting a discussion from a notification

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

In the notifications pane, a button is provided to answer the notification, opening a modal window with a form to add a message.

When the comment is sent:

  1. Check if a discussion exists with relations to exactly two discussion contexts:
    1. activitystream:the-event-id
    2. activitypub:the AP Page ID
  2. Create the two discussion contexts if they respectively do not exist.
  3. Create the discussion linked exactly to the two discussion contexts, otherwise returns it.
  4. Add the message to the discussion
  5. 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.

Consulting the discussion:

Now the discussion could be seen in three places, if the applications listed application made the effort to integrate them:

  • The general view of all the discussions the user can see (provided by the discussions application)
  • The view of the discussions started from notifications (provided by activity stream)
  • The view of the discussions link to the AP Page (provided by AP)

Private messages between two users

User U1 wants to start a discussion with user U2.

U1 goes to the profile page of U2.

A discussion tab is proposed and is currently empty.

U1 type a first message.

  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):
    1. document:xwiki:XWiki.U1
    2. document:xwiki:XWiki.U2
  2. Creates the two discussion contexts and the discussion if they do not exist.
  3. Add the message to the discussion
  4. U2 is notified of the new message through the notifications mechanism.
  5. The discussion is now displayed in the discussion lists of U1 and U2 in their profiles.

Forum

In the context of a forum application, different discussion spaces called forums can be created by administrators.

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.

A discussion, in the case, is created and linked to a single discussion context.

Messages are created as usual.

Missing features

This section lists missing features that must be integrated to the design

  • Anonymous users can post messages
  • Captcha integration

Architecture

Detailed domain

DiscussionContext

A group of discussions share a common context.

  • reference: String
  • entityReferenceType: String
  • entityReference: String
  • name: String
  • description: String
  • creation date: Date
  • update date: Date
  • states: List<String>
  • pined: boolean

Discussion

A group of messages

  • reference: String
  • title: String
  • description: String
  • creation date: Date
  • update date: Date
  • states: List<String>
  • pined: boolean
  • 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

Message

A message on a discussion

  • reference: String
  • content: String
  • Discussion id: String
  • author: UserReference
  • creation date: date
  • update date: date
  • states: List<String>
  • replyTo: Message
  • pined: boolean

xwiki-platform-discussion-api

Create

DiscussionContext createDiscussionContext(String name, String description, String referenceType, String entityReference)

Create and save a discussion context.

Two discussion can have the same name.

Throw an error if the the actor does not have the right to create a discussion context.

Set the creation date of the discussion context.

Must send a NewDiscussionContext event.

Discussion createDiscussion(String title, List<DiscussionContext> discussionContexts)

Create and save a discussion, and link it to the provided list of discussion contexts.

Two discussions can have the same title.

Throw an error if the actor does not have the right to create a discussion.

Set the creation date of the discussion.

Must send a NewDiscussion event.

Message createMessage(String content, Discussion discussion)

Create and save a message in a discussion.

Thrown an error if the actor does not have the right to create a message.

Throw an error if the actor does not have the right to add a message to the discussion.

Set the creation date of the message.

Must send a NewMessage event.

Other operations

To be designed

  • Attach an administrator to a forum
  • Attach an administrator to a discussion
  • Other right management operation

Read

List<DiscussionContext> getDiscussionContexts(int offset, int limit)

Returns a paginated list of the discussion contexts.

The pined discussion contexts are returned first.

int countDiscussionContexts()

Returns a count of the discussion contexts.

Optional<DiscussionContext> getDiscussionContext(String reference)

Returns a discussion by its reference.

The optional is empty if:

  •  the actor does not have the right to access the forum
  •  no forum is found for the reference

List<Discussion> getDiscussions(List<DiscussionContext> discussionContexts, int offset, int limit)

Returns a paginated list of the discussions linked to the list of discussion contexts passed in parameter.

The pined discussions are returned first.

int countDiscussions(DiscussionContext discussionContext)

Returns the count of the discussions attached to a discussion context.

Optional<Discussion> getDiscussion(String discussionReference)

Returns a discussion by its reference.

The optional is empty if:

  • the actor does not have the right to view the discussion
  • no discussion is found for the reference

List<Messages> getMessages(Discussion discussion, int offset, int limit)

Returns a paginated list of the messages of a discussion.

Throw an error if the actor is not allowed to view the discussion.

List<Messages> getRootMessages(Discussuion discussion, int offset, int limit)

Returns a paginated list of the root messages of a discussion (i.e., the messages with an empty replyTo field).

Throw an error if the actor is not allowed to view the discussion.

List<Message> getMessage(Message message, int offset, int limit)

Returns a paginated list of the messages that are replies to the message passed in parameter.

Throw an error if the actor is not allowed to view the discussion.

int countMessages(Discussion discussion)

Returns a count of the messages in a discussion.

int countRootMessages(Discussion discussion)

Returns a count of the root messages in a discussion (i.e., the message with an empty replyTo field).

int countMessages(Message message)

Returns a count of the number of replies to the message passed in parameter.

Optional<Message> getMessage(String messageReference)

Returns a message by its reference.

The optional is empty if:

  • the actor does not have the right to view the message
  • no message is found for the reference

Date getLastUpdate(Discussion discussion)

Returns the date of the last action performed on the discussion, it is the most recent date of:

  • the creation of the discussion
  • an update of a discussion field
  • the creation of a message on the discussion
  • the update of a message of the discussion

Update

void updateDiscussionContext(String reference, String name, String description)

Updates the updatable information of a forum:

  • its name
  • its description

Changes the update date of the discussion context.

Throw an error is the actor is not allowed to update the discussion context.

Must send a UpdatedDiscussionContext event.

void updateDiscussion(String reference, String title, String description)

Updates the updatable information of a discussion:

  • its title
  • its description

Changes the update date of the discussion.

Throw an error if the actor is not allowed to update the discussion.

Must send a UpdateDiscussion event.

void linkDiscussionContext(Discussion discussion, DIscussionContext discussionContext)

Links a discussion to a discussion. The relation is bidirectional.

void unlinkDiscussionContext(Discussion discussion, DiscussionContext discussionContext)

Unlinks a discussion and on of its linked discussion context.

void updateMessage(String reference, String context)

Update the updatable information of a message:

  • its message

Change the update date of the message.

Throw an error if the actor is not allowed to update the message.

Must send a UpdateMessage event.

void pinDiscussion(Discussion discussion)

Pin a discussion.

void unpinDiscussion(Discussion discussion)

Unpin a discussion.

void pinMessage(Message message)

Pin a message.

void unpinMessage(Message message)

Unpin a message.

void updateStates(DiscussionContext discussionContext, List<String> states)

The state are an open mechanism to add custom metadatas to a discussion context.

Updates the list of states of the discussion context.

void updateStates(Discussion discussion, List<String> states)

The state are an open mechanism to add custom metadatas to a discussion context.

Updates the list of states of the discussion.

void updateStates(Message message, List<String> states)

The state are an open mechanism to add custom metadatas to a discussion context.

Updates the list of states of the message.

TODO: RIGHTS API

addAdminGroup(DiscussionContext discussionContext, Group group)

Add a group to the list of administrators of the discussion context.

addAdminUser(DiscussionContext discussionContext, User user)

Add a user to the list of administrators of the discussion context.

removeAdminGroup(DiscussionContext discussionContext, Group group)

Remove a group from the list of administators  of the discussion context.

removeAdminUser(DiscussionContext discussionContext, User user)

Remove a user from the list of administrators of the discussion context.

addAdminGroup(Discussion discussion, Group group)

Add an group of the list of administrators of the discussion.

addAdminUser(Discussion discussion, User user)

Add a user to the list of administrators of the discussion.

removeAdminGroup(Discussion discussion, Group group)

Remove an group from the list of administrators of the discussion.

removeAdminUser(Discussion discussion, User user)

Remove a user from the list of administrators of the discussion

addReadGroup(Discussion discussion, Group group)

Add a group to the list of readers of the discussion.

addReadUser(Discussion discussion, Group group)

Add a user to the list of readers of the discussion.

removeReadGroup(Discussion discussion, User user)

Remove a group from the list of readers of the discussion.

removeReadUser(Discussion discussion, User user)

Remove a user from the list of readers of the discussion.

addWriteGroup(Discussion discussion, Group group)

Add a group to the list of writers of the discussion.

addWriteUser(Discussion discussion, Group group)

Add a user to the list of writers of the discussion.

removeWriteGroup(DiscussionContext discussion, User user)

Remove a group from the list of writers of the discussion.

removeWriteUser(DiscussionContext discussion, User user)

Remove a user from tthe list of writers of the discussion.

Delete

void deleteDiscussionContext(DiscussionContext forum)

Delete a discussion context.

Throw an error if the actor does not have the right to delete the discussion context.

After deleting the discussion context, checks for orphaned discussions and remove them as well ("garbage collection like").

Only discussion context administrators can remove a discussion context.

Must send a DeleteDiscussionContext event. Must also send DeleteDiscussion events if needed.

void deleteDiscussion(Discussion discussion)

Dete a discussion.

Throw an error if the actor does not have the right do delete the discussion

After deleting a discussion, checks for orphaned discussion context are remove the as well ("garbage collection like").

Only discussion administrators can delete a discussion

Must send a DeleteDiscussion event. Must also send DeleteDiscussionContext events if needed.

void deleteMessage(Message message)

Delete a message.

Throw an error if the actor does not have the right to delete the message.

Only discussion administrators and the author of the message can delete a message.

Must send a DeleteMessage event.

void pinDiscussionContext(String reference)

Switch the status of the discussion context to pined.

Only administrators of the discussion context can pin the discussion context.

void unpinDiscussionContext(String reference)

Switch the status of the discussion context to pined.

Only administrators of the discussion context can unpin the discussion context.

void pinDiscussion(String reference)

Switch the status of the discussionto pined.

Only administrators of the discussion can pin the discussion.

void unpinDiscussion(String reference)

Switch the status of the discussion to pined.

Only administrators of the discussion can unpin the discussion.

void pinMessage(String reference)

Switch the status of the message to pined.

Only administrators of the discussion of the message can pin the message.

void unpinMessage(String reference)

Switch the status of the message to pined.

Only administrators of the discussion of the message can unpin the message.

xwiki-platform-discussion-rest

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.

NameHTTP MethodPathPath paramGet paramsBody ParamsResponseDescriptionNeed authentication?
createDiscussionContextPOST/discussionContext  
  • entityReferenceType: String
  • entityReference: String
  • name: String
  • description:String
The created discussion context objectCreates a discussion contextTBD
deleteDiscussionContextDELETE/discussionContext/{discussionContextReference}
  • discussionContextReference: the reference of the discussion context to delete
  a success codeDelete a discussion context 
createDiscussionPOST/discussion  
  • title: String
  • description: String
The created discussion objectCreates a discussionTBD
delete DiscussionDELETE/discussion/{discussionReference}
  • discussionReference: the reference of the discussion to delete
  a success codeDelete a discussion 
createMessagePOST/message  
  • content: String
  • discussionReference: String
  • replyTo: String (message reference) (optional)
The created message objectCreate a message in a discussionTBD
deleteMessageDELETE/message/{messageReference}
  • messageReference: the message reference to delete
  a success codeDelete a message 
updateDiscussionContextPUSH/discussionContext  
  • name: String
  • description:String
The updated discussion contextUpdate the name and description of a discussion contextTBD
updateDisucssionPUSH/discussion  
  • title: String
  • description: String
The updated discussionUpdate the title and description of a discussionTBD
updateMessagePUSH/message  
  • content: String
The updated messageUpdate the content of a messageTBD
linkDiscussionAndDiscussionContextPUSH/discussionContext/link 
  • discussionContextReference: String
  • discussionReference: String
 success/error code onlyLink a discussion and a discussion contextTBD
unlinkDiscussionAndDiscussionContextDELETE/discussionContext/link 
  • discussionContextReference: String
  • discussionReference: String
 success/error code onlyUnlink a discussion and a discussion contextTBD
getDiscussionContextsGET/discussionContext 
  • offset: int
  • limit: int
  • type: string (optional)
  • sortBy (array): creationDate, updateDate,name,description,type
 the paginated list of discussion contexts, optionally filtered by type, and sorted by the sort criteriaReturns a paginated list of discussion contextsTBD
countDiscussionContextGET/discussionContexts/count same as getDiscussionContexts, except for the pagination and sort same as getDiscussionContexts but returns the the number of results instead  
getDiscussionsGET/discussion 
  • offset: int
  • limit: int
  • type: string (optional)
  • entityReference: string (optional)
  • sortBy (array): creationDate, updateDate,title,description,type
 the paginated list of discussions, optionally filtered by type and/or entity reference, and sorted by the sort criteriaReturns a paginated list of discussionsTBD
countDiscussionsGET/discussion/count same as getDiscussions except for the pagination and sort same as getDiscussions but returns the number of results instead  
getMessagesGET/discussion/{discussionReference}/messages
  • discussionReference: the reference of the discussion containing the messages
  • offset: int
  • limit: int
  • sortBy: creationDate or updateDate (default = updateDate)
 the paginated list of messages of a discussion, sort by by sort criterionReturns a paginated list of messagesTBD
countMessagesGET/discussion/{discussionReference}/messages/countsame as getMessagessame as getMessages, exception of the pagination and sort same as getMessages but returns the number of results instead  
getDiscussionContextGET/discussionContext/{discussionContextReference}
  • discussionContextReference: the discussion context reference to retrieve
  the objectreturns a single discussion contextTBD
getDiscussionGET/discussion/{discussionRefernece}
  • discussionReference: the reference of the discussion to retrieve
  the objectreturns a single discussionTB
getMessageGET/message/{messageReference}
  • messageReference: the message reference
  the objectreturns a single messageTBD
pinDiscussionPUSH/discussion/{discussionReference}/pinTODO  TBDpin a discussion 
unpinDiscussionPUSH/discussion/{discussionReference}/unpinTODO  TBDunpin a discussion 
pinMessagePUSH/message/{messageReference}/pinTODO  TBDpin a message 
unpinMessagePUSH/message/{messageReference}/unpinTODO  TBDunping a message 

xwiki-platform-discussion-store-api

This module provides the low level operation required to realize the actions proposed by xwiki-platform-discussion-api. For instance no rights control are done before performing the operations.

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.

The section regroups the operations for each manipulable entity (see the detailed domain).

All entities must provide a unique reference allowing to resolve them, this reference can be derived from the underlying storage implementation.

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.

Do we want to anticipate storing different entities in different storages?

DiscussionContextService

DiscussionContext create(String entityReferenceType, String entityReference, String name, String description)

Creates and initializes a discussion context.

The list of administrator users is initialized with the current user.

This list of administrator groups is empty.

The creation and update dates are set to now.

The state is empty.

This pined field is set to false.

Optional<DiscussionContext> get(String reference)

Returns a discussion context from its reference.

List<DiscussionContext> list(String type, int offset, int limit)

Returns a list of discussion contexts of a given type.

List<DiscussionContext> listByDiscussion(String discussionReference, int offset, int limit)

Returns the list of discussion contexts linked to the passed discussion reference.

void update(String reference, String name, String description)

Update the name and description of the discussion context.

Update the update date of the object.

void updateAdministrators(String reference, List<User> users, List<Group> groups)

Replace the lists of administrator users and groups with the new lists.

Update the update date of the object.

Throw an error of the two lists are empty as it would probably lock the object?

void setState(String reference, String state)

Replaces the state of the object.

Update the update date of the object.

void pin(String reference)

Pin the object.

Update the update date of the object.

void unpin(String reference)

Unpin the object.

Update the update date of the object.

void attachDiscussion(String discussionContextReference, String discussionReference)

Links a discussion to a discussion context.

Update the update date of the discussions context as well as the discussion.

void detachDiscussion(String discussionContextReference, String discussionReference)

Unlinks a discussion and a discussion context.

Update the update date of the discussion context as well the discussion.

Removes the discussion context if it is now connect to 0 discussions.

Removes the discussion if it is now connect to 0 discussion contexts.

void delete(String reference)

Delete the object.

Checks if some discussions are now without discussion contexts and remove them too.

DiscussionService

Discussion create(String title, String description)

Creates and initializes the discussion.

Set the current user as administrator.

The administator group list is empty.

Set the creation date to now.

Set the update date to now.

The state is empty.

The discussion is not pined.

Optional<Discussion> get(String reference)

Returns the discssion

void update(String reference, String title, String description)

Update the title and description of the object.

Update the update date.

void updateAdministrators(String reference, List<User> users, List<Group> groups)

Replace the lists of administrator users and groups with the new lists.

Update the update date of the object.

Throw an error of the two lists are empty as it would probably lock the object?

void setState(String reference, String state)

Replaces the state of the object.

Update the update date of the object.

void pin(String reference)

Pin the object.

Update the update date of the object.

void unpin(String reference)

Unpin the object.

Update the update date of the object.

void attachDiscussionContext(String discussionReference, String discussionContextReference)

Links a discussion context to a discussion.

Update the update date of the discussion as well as the discussion context.

void detachDiscussionContext(String discussionReference, String discussionContextReference)

Unlinks a discussion and a discussion context.

Update the update date of the discussion context as well the discussion.

Removes the discussion if it is now connect to 0 discussion contexts.

Removes the discussion context if it is now connect to 0 discussions.

void delete(String reference)

Delete the object.

Checks if some discussions context are now without discussions and remove them too.

MessageService

Message create(String content, User author)

Creates and initializes a message with the content and author.

Set the creation and update dates to now.

The state is empty.

The reply to is empty

Message create(String content, User author, String replyToReference)

Creates and initializes a message with the content, author and replyToReference.

Set the creation and update dates to now.

The state is empty.

void update(String reference, String content)

Update the content of the message.

Set the update date to now.

void delete(String reference)

Delete the message.

xwiki-platform-discussion-store-default

Let's take the hypothesis that XWIKI-17174 will be addressed.

Where are discussion context stored?

Discussion Contexts are stored in pages and contains a DiscussionContext XObject.

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.

Where are the entity references stored?

The entity references are stored directly inside the discussion context. If several discussion contexts references the same entity, they have duplicated references / reference types.

Where are relations between entity references and discussion context stored?

The discussion contexts contains a list of discussions references.

The discussion contains a list of discussion contexts.

The application is in charge of keeping track of the consistency of there relations.

Where are discussions stored?

Discussions are stored in pages and contains a Discussion object.

Can a single page contains several discussions? NO

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

Where a message stored ?

Messages are stored in the page of their discussion in message XObjects.

If XWIKI-17174 is not addresed, messages will need to be stored in sub-pages of the discussion page.

xwiki-platform-discussion-ui

See the specifications below

TODO: proposed reusable macros to embed the discussions contextually.

User Interface Specifications

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.

TODO

  1. Pin a discussion context
    1. Should be integrated to the discussion administration
  2. Administrate a discussion context
    1. 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?).
  3. View the discussion context list
    1. 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).
  4. Delete a discussion context
    1. Programmatically?
  5. Create a discussion
    1. Should take the form of a macro that can be integrated where needed.
  6. Administrate a discussion
    1. 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?)
  7. View the paginated list of discussions AKA DISCUSSION INDEX
    1. Generic macro to view a paginated list of all the discussions related to a given user
  8. View the paginated list of discussions by discussion context
    1. Generic macro to view a paginated list of all the discussion related to a given user and a given discussion context
  9. View the paginated list of discussions by discussion context type
    1. Generic macro to view a paginated list of all the discussion related to a given user and a given discussion context type
  10. 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)
  11. View a discussion
    1. Generic macro to view a a discussion. It should also be integrated by default and accessible from the discussions lists.
  12. Pin a discussion
    1. Should be integrated to the discussion context administration (note: can a discussion be pined in one discussion context and not in another one ?)
  13. Delete a discussion
    1. should be integrated to the discussion administration
  14. Create a message
    1. should be integrated to the discussion view UI
  15. Update a message
    1. should be provided as a reusable macro but also accessible easily from the discussion view UI
  16. Delete a message
    1. should be a button integrated to the discussion view UI
  17. Pin a message
    1. should be integrated to the discussion administration

Main page

View a discussion

A header presents the title and description of the discussion.

The messages are displayed paginated, the oldest message at the top.

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:

  • delete
  • edit
  • pin
  • ...

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.

Administrate a discussion

The administration of the discussion is opened to the administrators of the discussion.

A form is proposed to update the title and description of the discussion.

A button is also proposed to remove the discussion.

Administrate a discussion rights

A page is available to administrate the discussions rights.

ActivityPub integration

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.

Sending a message to the fediverse

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.

When the activity pub user source is activated, actors of the fediverse can be added to the list of members of the discussion.

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.

Receiving a message from the fediverse

When receiving a inReplyTo field containing the identifier of a message of a discussion, the message should be added to the corresponding discussion unless:

  • the actor of the fediverse is not a member of the discussion

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?

Tasks

UC#Depends onTitleComplexityPriority
UC1.1extensible user pickerCreating a new discussion  
UC1.2quick actions, extensible user pickerCreating a discussion from the notifications  
UC2 Listing the discussions  
UC3 Displaying a discussion  
UC4 See the messages of a discussion  
UC5 Reply to a discussion  
UC6 Administrate a discussion  
UC7 Administrate a discussion context  
UC8 Create a discussion context  
UC9 Delete a discussion context  
UC10 Delete a discussion  
UC11 Delete a message  
UC13 Link a discussion context and a discussion  
UC14 Unlink a discussion context and a discussion  
UC15 Send event when dicussions context/discussions/messages are created, updated or deleted  
UC16 Administrate a discussion context rights  
UC17 Administrate a discussion rights  
UC18 Pin a discussion context  
UC19 Pin a discussion  
UC20 Pin a message  
UC21 Archive a discussion context  
UC22 Archive a discussion  
UC23 Archive a message  

UC1 - Creating a new discussion

UC1.1 - Creation a discussion from the notifications

UC2 - Listing the discussions

Definition of the display of the discussions and its integration on the main page.

UC3 - Displaying a discussion

UC4 - Editing an existing message

UC5  - ActivityPub Specific UCs

Sharing a discussion with the


 

Get Connected