This module holds the basic content and structure of a hierarchical topic based forum with trivial sudo moderation. It allows a blockchain to have direct assertible custody of the forum governance and function. Systems which depend critical on reliable and fair asynchronous public discourse will benefit from this functionality.
The structure of the forum is a collection of category trees. A category tree has of two types of nodes, a category or a thread. A category node represents a topic category, with a name and associated intended scope of discussion topics. A thread node represents an actual thread of one or more posts.
A thread is a sequence of posts, in a given category, which has some initial post from the original author, and title. A post exists in the context of a thread, and has some position in thread post sequence, as well as a body text. Both have a corresponding author and creation date. The text in a post can be edited by any time by the original author, however the history of all texts are available in the state.
Forum users can create threads in categories, and post to existing threads. This module does not maintain its own set of forum users, but rather depends on some external module for this. The rationale for this is to allow reuse of the module with a diversity of user management systems, without requiring that runtime developer must keep user set synchronised, or waste state space.
There will be a single account, called the forum sudo account. This account is set by the Sudo of the runtime, and can
Create a category: Can either be a new root category, or if parent category is referenced, it would be a subcategory.
Archive|Delete (Unarchive|Undelete) a category: Results in category being marked as archived or deleted, while it and all corresponding threads, posts and subcategories remain in the state. It is however no longer possible to delete or mutate anything in the category in any way, such as adding posts, creating threads or subcategories, etc. Well-behaved UIs will not render deleted categories. In what follows a category is said to be directly archived or deleted, if its applying directly to that category, and indirectly if it applies to some ancestor category. The only distinction between archiving and deletion in the runtime is that a directly deleted category cannot be unarchived.
Moderate a post in a thread: Results in post being marked as moderated, with a corresponding rationale for the moderation added, but it remains in the system state. It is not longer possible to edit the post text, and well-behaved UIs will not render such posts.
Moderate a thread: Results in thread being marked as moderated, with a corresponding rationale for the moderation added, but it remains in the system state. It is not longer possible to moderate posts, edit post texts or add posts to the thread. Well-behaved UIs will not render such threads.
There is a maximum depth to a category tree. This is because doing any mutation will require traversing the category tree to the root to check for whether there has been any deletion or archiving along the path to the root, and there needs to be a bound on this, herein called MAX_CATEGORY_DEPTH
.
Forum
ForumUserRegistry
: An external module which holds actual user state, allowing it to be queried based on a corresponding account, and recovering some representation of a user.ForumUser
: Represents an actual forum user, which is provided by ForumUserRegistry
dependency.
ForumSudoId
: Identifies a forum sudo authority.
ModerationAction
: Represents a moderation outcome applied to a post or a thread. Includes a moderation date, a text rationale and the ForumSudoId
of moderator.
Post
: Represents a thread post, and includes initial text, identifier for the corresponding Thread
, a position, an optional ModerationAction
, a vector of identifiers for PostTextEdit
instances ordered chronologically by edit time, creation date and identifier of ForumUser
creator. Is identified with an integer which is unique across all instances in all categories.
PostTextEdit
: Represents a revision of the text of a Post
, includes new text and revision date.
Thread
: Represents a thread, and includes a title, identifier for the corresponding Category
, a position, an optional ModerationAction
, number of unmoderated posts, number of moderated posts, creation date and identifier of ForumUser
creator. Is identified with an integer which is unique across all instances in all categories.
Category
: Represents a forum category, and includes a title, short topic description text, creation date, deletion status, archival status, number of subcategories, number of unmoderated threads, number of moderated threads, optional Category
identifier for parent category and ForumSudoId
of creator. Is identified with an integer which is unique across all instances in all categories.
categoryById
: Map Category
identifier to corresponding instance.
nextCategoryId
: Identifier value to be used for the next Category
created.
threadById
: Map Thread
identifier to corresponding instance.
nextThreadId
: Identifier value to be used for next Thread
in threadById
postById
: Map Post
identifier to corresponding instance.
nextPostId
: Identifier value to be used for next Post
created.
forumSudo
: Optional ForumSudoId
of forum sudo.
Each event has payload as sublist
CategoryCreated
: A category was introduced
CategoryUpdated
: A category had its direct archival and/or deletion status updated to a new value.
ThreadCreated
: A thread was created with.
ThreadModerated
: A thread was moderated.
PostAdded
: A post was introduced.
PostModerated
: A post was moderated.
PostTextUpdated
: A post had the post text edited.
ForumSudoSet
: A new forum sudo was set by root.
origin
: call originparent
: not set, or category identifier of parenttitle
: text titledescription
: description textAdd a new category.
forumSudo
does not match signatureparent
is set, but does not existparent
is set, but is (directly or indirectly) archived or deleted categoryMAX_CATEGORY_DEPTH
.title
invaliddescription
invalidcategoryById
extended with new Category
under old value of nextCategoryId
as identifiernextCategoryId
incrementedparent
is not root, then subcategory countCategoryCreated
origin
: call origincategoryId
: id of category to updatearchive
: whether to archivedeleted
: whether it is deletedUpdate a category.
forumSudo
does not match signaturecategoryId
does not match any categorycategoryId
is directly deleted, cannot be unarchivedcategoryId
is indirectly archived or deleted, cannot be updated in any wayNote: We don't mind directly archived/deleted categories from being re-archived/deleted respectively, we just ignore
categoryById
under key categoryId
has archival and deletion status equal to archive
and delete
, respectively, and if parent is set, then it will have number of subcategories decremented if delete
is true, but category was perviously not.CategoryUpdated
with new status values, as they applyorigin
: call origincategoryId
: identifier of category where thread should be createdtitle
: thread title texttext
: text of initial postCreate new thread in category.
categoryId
not a valid categorycategoryId
is (directly or indirectly) archivedcategoryId
is (directly or indirectly) deletedtitle
not validtext
not validthreadById
extended with new Thread
instance under old value of nextThreadId
as identifiercategoryId
nextThreadId
incrementedThreadCreated
origin
: call originthreadId
: identifier of Thread
to deleterationale
: text rationaleModerate thread.
forumSudo
does not match signaturethreadId
does not match any threadrationale
invalidThread
instance in threadById
has ModerationAction
setThreadModerated
origin
: call originthreadId
: thread in which to add posttext
: text of postAdding post to thread
threadId
does not existthreadId
is moderatedpostById
extended with new Post
instance with under old value of nextPostId
as identifiernextPostId
updatedPostAdded
origin
: call originpostId
: post to be editednew_text
: new textEdit post text
postId
does not correspond to a postpostId
postId
is moderatedpostId
has its edit vector with new PostTextEdit
instance at frontPostTextUpdated
origin
: call originpostId
: post to be editedrationale
: text rationaleModerate post
forumSudo
does not match signaturepostId
does not match any postrationale
invalidPost
instance in postById
has ModerationAction
setPostModerated
Note: I am not sure how to do this one, I am not familiar with Substrate Sudo functionality.
newForumSudo
: optional account of new proposed forum sudoSet forum sudo.
forumSudo
equals newForumSudo
ForumSudoSet