use crate::core::{HtmlFragment, Instant, Listing, ListingCount, LocaleId};
use crate::oauth::{OauthClientIdRef, ShortOauthClient};
use crate::types::AnyError;
use crate::user::{ShortUser, UserIdRef, UserRef};
use async_trait::async_trait;
use auto_impl::auto_impl;
#[cfg(feature = "serde")]
use etwin_serde_tools::{Deserialize, Serialize};
use std::str::FromStr;
use thiserror::Error;
pub type MarktwinText = String;
declare_new_uuid! {
pub struct ForumSectionId(Uuid);
pub type ParseError = ForumSectionIdParseError;
const SQL_NAME = "forum_section_id";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumSectionIdRef {
pub id: ForumSectionId,
}
impl ForumSectionIdRef {
pub const fn new(id: ForumSectionId) -> Self {
Self { id }
}
}
impl From<ForumSectionId> for ForumSectionIdRef {
fn from(id: ForumSectionId) -> Self {
Self::new(id)
}
}
declare_new_string! {
pub struct ForumSectionKey(String);
pub type ParseError = ForumSectionKeyParseError;
const PATTERN = r"^[_a-z][_a-z0-9]{0,31}$";
const SQL_NAME = "forum_section_key";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumSectionKeyRef {
pub key: ForumSectionKey,
}
impl From<ForumSectionKey> for ForumSectionKeyRef {
fn from(key: ForumSectionKey) -> Self {
Self { key }
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ForumSectionRef {
Id(ForumSectionIdRef),
Key(ForumSectionKeyRef),
}
impl ForumSectionRef {
pub const fn split(&self) -> (Option<ForumSectionIdRef>, Option<&ForumSectionKeyRef>) {
let mut id: Option<ForumSectionIdRef> = None;
let mut key: Option<&ForumSectionKeyRef> = None;
match self {
Self::Id(r) => id = Some(*r),
Self::Key(r) => key = Some(r),
};
(id, key)
}
pub const fn split_deref(&self) -> (Option<ForumSectionId>, Option<&ForumSectionKey>) {
let mut id: Option<ForumSectionId> = None;
let mut key: Option<&ForumSectionKey> = None;
match self {
Self::Id(r) => id = Some(r.id),
Self::Key(r) => key = Some(&r.key),
};
(id, key)
}
}
impl From<&'_ ForumSection> for ForumSectionRef {
fn from(section: &ForumSection) -> Self {
Self::Id(section.as_ref())
}
}
impl From<ForumSectionIdRef> for ForumSectionRef {
fn from(id: ForumSectionIdRef) -> Self {
Self::Id(id)
}
}
impl From<ForumSectionId> for ForumSectionRef {
fn from(id: ForumSectionId) -> Self {
Self::Id(id.into())
}
}
impl From<ForumSectionKeyRef> for ForumSectionRef {
fn from(key: ForumSectionKeyRef) -> Self {
Self::Key(key)
}
}
impl From<ForumSectionKey> for ForumSectionRef {
fn from(key: ForumSectionKey) -> Self {
Self::Key(key.into())
}
}
#[derive(Debug, Error)]
#[error("invalid forum section id ({id}) or key ({key})")]
pub struct ForumSectionRefParseError {
pub id: ForumSectionIdParseError,
pub key: ForumSectionKeyParseError,
}
impl FromStr for ForumSectionRef {
type Err = ForumSectionRefParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match ForumSectionId::from_str(s) {
Ok(r) => Ok(r.into()),
Err(id) => match ForumSectionKey::from_str(s) {
Ok(r) => Ok(r.into()),
Err(key) => Err(ForumSectionRefParseError { id, key }),
},
}
}
}
declare_new_uuid! {
pub struct ForumThreadId(Uuid);
pub type ParseError = ForumThreadIdParseError;
const SQL_NAME = "forum_thread_id";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumThreadIdRef {
pub id: ForumThreadId,
}
impl ForumThreadIdRef {
pub const fn new(id: ForumThreadId) -> Self {
Self { id }
}
}
impl From<ForumThreadId> for ForumThreadIdRef {
fn from(id: ForumThreadId) -> Self {
Self::new(id)
}
}
declare_new_string! {
pub struct ForumThreadKey(String);
pub type ParseError = ForumThreadKeyParseError;
const PATTERN = r"^[_a-z][_a-z0-9]{0,31}$";
const SQL_NAME = "forum_thread_key";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumThreadKeyRef {
pub key: ForumThreadKey,
}
impl From<ForumThreadKey> for ForumThreadKeyRef {
fn from(key: ForumThreadKey) -> Self {
Self { key }
}
}
#[derive(Debug, Error)]
#[error("invalid forum thread id ({id}) or key ({key})")]
pub struct ForumThreadRefParseError {
pub id: ForumThreadIdParseError,
pub key: ForumThreadKeyParseError,
}
impl FromStr for ForumThreadRef {
type Err = ForumThreadRefParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match ForumThreadId::from_str(s) {
Ok(r) => Ok(r.into()),
Err(id) => match ForumThreadKey::from_str(s) {
Ok(r) => Ok(r.into()),
Err(key) => Err(ForumThreadRefParseError { id, key }),
},
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ForumThreadRef {
Id(ForumThreadIdRef),
Key(ForumThreadKeyRef),
}
impl ForumThreadRef {
pub const fn split(&self) -> (Option<ForumThreadIdRef>, Option<&ForumThreadKeyRef>) {
let mut id: Option<ForumThreadIdRef> = None;
let mut key: Option<&ForumThreadKeyRef> = None;
match self {
Self::Id(r) => id = Some(*r),
Self::Key(r) => key = Some(r),
};
(id, key)
}
pub const fn split_deref(&self) -> (Option<ForumThreadId>, Option<&ForumThreadKey>) {
let mut id: Option<ForumThreadId> = None;
let mut key: Option<&ForumThreadKey> = None;
match self {
Self::Id(r) => id = Some(r.id),
Self::Key(r) => key = Some(&r.key),
};
(id, key)
}
}
impl From<ForumThreadIdRef> for ForumThreadRef {
fn from(id: ForumThreadIdRef) -> Self {
Self::Id(id)
}
}
impl From<ForumThreadId> for ForumThreadRef {
fn from(id: ForumThreadId) -> Self {
Self::Id(id.into())
}
}
impl From<ForumThreadKeyRef> for ForumThreadRef {
fn from(key: ForumThreadKeyRef) -> Self {
Self::Key(key)
}
}
impl From<ForumThreadKey> for ForumThreadRef {
fn from(key: ForumThreadKey) -> Self {
Self::Key(key.into())
}
}
declare_new_enum!(
pub enum ForumRole {
#[str("Administrator")]
Administrator,
#[str("Moderator")]
Moderator,
}
pub type ParseError = ForumRoleParseError;
const SQL_NAME = "forum_role";
);
declare_new_string! {
pub struct ForumSectionDisplayName(String);
pub type ParseError = ForumSectionDisplayNameParseError;
const PATTERN = r"^\S.{0,62}\S$";
const SQL_NAME = "forum_section_display_name";
}
declare_new_string! {
pub struct ForumThreadTitle(String);
pub type ParseError = ForumThreadTitleParseError;
const PATTERN = r"^\S.{0,62}\S$";
const SQL_NAME = "forum_thread_title";
}
declare_new_uuid! {
pub struct ForumPostId(Uuid);
pub type ParseError = ForumPostIdParseError;
const SQL_NAME = "forum_post_id";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumPostIdRef {
pub id: ForumPostId,
}
impl ForumPostIdRef {
pub const fn new(id: ForumPostId) -> Self {
Self { id }
}
}
impl From<ForumPostId> for ForumPostIdRef {
fn from(id: ForumPostId) -> Self {
Self::new(id)
}
}
declare_new_uuid! {
pub struct ForumPostRevisionId(Uuid);
pub type ParseError = ForumPostRevisionIdParseError;
const SQL_NAME = "forum_post_revision_id";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumSection {
pub id: ForumSectionId,
pub key: Option<ForumSectionKey>,
pub display_name: ForumSectionDisplayName,
pub ctime: Instant,
pub locale: Option<LocaleId>,
pub threads: ForumThreadListing,
pub role_grants: Vec<ForumRoleGrant>,
#[cfg_attr(feature = "serde", serde(rename = "self"))]
pub this: ForumSectionSelf,
}
impl ForumSection {
pub fn as_ref(&self) -> ForumSectionIdRef {
ForumSectionIdRef { id: self.id }
}
}
pub type ForumSectionListing = Listing<ForumSectionMeta>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumSectionMeta {
pub id: ForumSectionId,
pub key: Option<ForumSectionKey>,
pub display_name: ForumSectionDisplayName,
pub ctime: Instant,
pub locale: Option<LocaleId>,
pub threads: ListingCount,
#[cfg_attr(feature = "serde", serde(rename = "self"))]
pub this: ForumSectionSelf,
}
impl ForumSectionMeta {
pub const fn as_ref(&self) -> ForumSectionIdRef {
ForumSectionIdRef::new(self.id)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawForumSectionMeta {
pub id: ForumSectionId,
pub key: Option<ForumSectionKey>,
pub display_name: ForumSectionDisplayName,
pub ctime: Instant,
pub locale: Option<LocaleId>,
pub threads: ListingCount,
pub role_grants: Vec<RawForumRoleGrant>,
}
impl RawForumSectionMeta {
pub const fn as_ref(&self) -> ForumSectionIdRef {
ForumSectionIdRef::new(self.id)
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumSectionSelf {
pub roles: Vec<ForumRole>,
}
pub type ForumThreadListing = Listing<ForumThreadMeta>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumRoleGrant {
pub role: ForumRole,
pub user: ShortUser,
pub start_time: Instant,
pub granted_by: ShortUser,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawForumRoleGrant {
pub role: ForumRole,
pub user: UserIdRef,
pub start_time: Instant,
pub granted_by: UserIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumThread {
pub id: ForumThreadId,
pub key: Option<ForumThreadKey>,
pub title: ForumThreadTitle,
pub ctime: Instant,
pub section: ForumSectionMeta,
pub posts: ForumPostListing,
pub is_pinned: bool,
pub is_locked: bool,
}
impl ForumThread {
pub fn as_ref(&self) -> ForumThreadIdRef {
self.id.into()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumThreadMeta {
pub id: ForumThreadId,
pub key: Option<ForumThreadKey>,
pub title: ForumThreadTitle,
pub ctime: Instant,
pub is_pinned: bool,
pub is_locked: bool,
pub posts: ListingCount,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawForumThreadMeta {
pub id: ForumThreadId,
pub key: Option<ForumThreadKey>,
pub title: ForumThreadTitle,
pub section: ForumSectionIdRef,
pub ctime: Instant,
pub is_pinned: bool,
pub is_locked: bool,
pub posts: ListingCount,
}
impl RawForumThreadMeta {
pub fn as_ref(&self) -> ForumThreadIdRef {
self.id.into()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreateForumThreadResult {
pub id: ForumThreadId,
pub key: Option<ForumThreadKey>,
pub title: ForumThreadTitle,
pub section: ForumSectionIdRef,
pub ctime: Instant,
pub is_pinned: bool,
pub is_locked: bool,
pub post_id: ForumPostId,
pub post_revision: RawForumPostRevision,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumThread"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumThreadMetaWithSection {
pub id: ForumThreadId,
pub key: Option<ForumThreadKey>,
pub title: ForumThreadTitle,
pub ctime: Instant,
pub is_pinned: bool,
pub is_locked: bool,
pub posts: ListingCount,
pub section: ForumSectionMeta,
}
pub type ForumPostListing = Listing<ShortForumPost>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPost"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumPost {
pub id: ForumPostId,
pub ctime: Instant,
pub author: ForumActor,
pub revisions: ForumPostRevisionListing,
pub thread: ForumThreadMetaWithSection,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPost"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ShortForumPost {
pub id: ForumPostId,
pub ctime: Instant,
pub author: ForumActor,
pub revisions: LatestForumPostRevisionListing,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPost"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawShortForumPost {
pub id: ForumPostId,
pub ctime: Instant,
pub author: RawForumActor,
pub revisions: RawLatestForumPostRevisionListing,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPost"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawForumPost {
pub id: ForumPostId,
pub ctime: Instant,
pub author: RawForumActor,
pub revisions: RawForumPostRevisionListing,
pub thread: RawForumThreadMeta,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LatestForumPostRevisionListing {
pub count: u32,
pub last: ForumPostRevision,
}
pub type ForumPostRevisionListing = Listing<ForumPostRevision>;
pub type RawForumPostRevisionListing = Listing<RawForumPostRevision>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawLatestForumPostRevisionListing {
pub count: u32,
pub last: RawForumPostRevision,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPostRevision"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumPostRevision {
pub id: ForumPostRevisionId,
pub time: Instant,
pub author: ForumActor,
pub content: Option<ForumPostRevisionContent>,
pub moderation: Option<ForumPostRevisionContent>,
pub comment: Option<ForumPostRevisionComment>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumPostRevision"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawForumPostRevision {
pub id: ForumPostRevisionId,
pub time: Instant,
pub author: RawForumActor,
pub content: Option<ForumPostRevisionContent>,
pub moderation: Option<ForumPostRevisionContent>,
pub comment: Option<ForumPostRevisionComment>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForumPostRevisionContent {
pub marktwin: MarktwinText,
pub html: HtmlFragment,
}
declare_new_string! {
pub struct ForumPostRevisionComment(String);
pub type ParseError = ForumPostRevisionCommentParseError;
const PATTERN = r".";
const SQL_NAME = "forum_post_revision_comment";
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ForumActor {
ClientForumActor(ClientForumActor),
RoleForumActor(RoleForumActor),
UserForumActor(UserForumActor),
}
impl ForumActor {
pub fn to_raw(&self) -> RawForumActor {
match self {
Self::ClientForumActor(a) => RawForumActor::ClientForumActor(a.to_raw()),
Self::RoleForumActor(a) => RawForumActor::RoleForumActor(a.to_raw()),
Self::UserForumActor(a) => RawForumActor::UserForumActor(a.to_raw()),
}
}
}
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(tag = "type", rename = "ClientForumActor")
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ClientForumActor {
pub client: ShortOauthClient,
}
impl ClientForumActor {
pub fn to_raw(&self) -> RawClientForumActor {
RawClientForumActor {
client: self.client.id.into(),
}
}
}
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(tag = "type", rename = "RoleForumActor")
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RoleForumActor {
pub role: ForumRole,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub user: Option<ShortUser>,
}
impl RoleForumActor {
pub fn to_raw(&self) -> RawRoleForumActor {
RawRoleForumActor {
role: self.role,
user: self.user.as_ref().map(ShortUser::as_ref),
}
}
}
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(tag = "type", rename = "UserForumActor")
)]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserForumActor {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub role: Option<ForumRole>,
pub user: ShortUser,
}
impl UserForumActor {
pub fn to_raw(&self) -> RawUserForumActor {
RawUserForumActor {
role: self.role,
user: self.user.as_ref(),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RawForumActor {
ClientForumActor(RawClientForumActor),
RoleForumActor(RawRoleForumActor),
UserForumActor(RawUserForumActor),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawClientForumActor {
pub client: OauthClientIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawRoleForumActor {
pub role: ForumRole,
pub user: Option<UserIdRef>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawUserForumActor {
pub role: Option<ForumRole>,
pub user: UserIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AddModeratorOptions {
pub section: ForumSectionRef,
pub user: UserRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawAddModeratorOptions {
pub section: ForumSectionRef,
pub target: UserIdRef,
pub granter: UserIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeleteModeratorOptions {
pub section: ForumSectionRef,
pub user: UserRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawDeleteModeratorOptions {
pub section: ForumSectionRef,
pub target: UserIdRef,
pub revoker: UserIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreateThreadOptions {
pub section: ForumSectionRef,
pub title: ForumThreadTitle,
pub body: MarktwinText,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreateThreadsOptions {
pub actor: RawForumActor,
pub section: ForumSectionRef,
pub title: ForumThreadTitle,
pub body_mkt: MarktwinText,
pub body_html: HtmlFragment,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UpsertSystemSectionOptions {
pub key: ForumSectionKey,
pub display_name: ForumSectionDisplayName,
pub locale: Option<LocaleId>,
}
#[derive(Error, Debug)]
pub enum UpsertSystemSectionError {
#[error(transparent)]
Other(AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetForumSectionOptions {
pub section: ForumSectionRef,
pub thread_offset: u32,
pub thread_limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetForumSectionMetaOptions {
pub section: ForumSectionRef,
}
#[derive(Error, Debug)]
pub enum GetSectionMetaError {
#[error("section not found")]
NotFound,
#[error(transparent)]
Other(AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetThreadsOptions {
pub section: ForumSectionRef,
pub offset: u32,
pub limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetForumThreadOptions {
pub thread: ForumThreadRef,
pub offset: u32,
pub limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetForumThreadMetaOptions {
pub thread: ForumThreadRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetSectionsOptions {
pub offset: u32,
pub limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetRoleGrantsOptions {
pub section: ForumSectionIdRef,
pub user: Option<UserIdRef>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct CreatePostOptions {
pub thread: ForumThreadRef,
pub body: MarktwinText,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetPostsOptions {
pub thread: ForumThreadRef,
pub offset: u32,
pub limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawGetForumPostOptions {
pub post: ForumPostIdRef,
pub offset: u32,
pub limit: u32,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreatePostOptions {
pub actor: RawForumActor,
pub thread: ForumThreadRef,
pub body: ForumPostRevisionContent,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreateForumPostResult {
pub id: ForumPostId,
pub thread: ForumThreadIdRef,
pub section: ForumSectionIdRef,
pub revision: RawForumPostRevision,
}
#[derive(Error, Debug)]
pub enum CreatePostError {
#[error("thread not found")]
ThreadNotFound,
#[error("current actor does not have the permission to create a post in this thread")]
Forbidden,
#[error("failed to parse provided body")]
FailedToParseBody,
#[error("failed to render provided body")]
FailedToRenderBody,
#[error(transparent)]
Other(AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UpdatePostOptions {
pub post: ForumPostId,
pub revision: ForumPostRevisionId,
pub content: Option<Option<MarktwinText>>,
pub moderation: Option<Option<MarktwinText>>,
pub comment: Option<ForumPostRevisionComment>,
}
#[derive(Error, Debug)]
pub enum UpdatePostError {
#[error("post not found")]
PostNotFound,
#[error("current actor does not have the permission to update this post")]
Forbidden,
#[error("failed to parse provided body")]
FailedToParseBody,
#[error("failed to render provided body")]
FailedToRenderBody,
#[error(transparent)]
Other(AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreatePostRevisionOptions {
pub actor: RawForumActor,
pub post: ForumPostIdRef,
pub body: Option<ForumPostRevisionContent>,
pub mod_body: Option<ForumPostRevisionContent>,
pub comment: Option<ForumPostRevisionComment>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type", rename = "ForumSection"))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawCreateForumPostRevisionResult {
pub revision: RawForumPostRevision,
pub thread: ForumThreadIdRef,
pub section: ForumSectionIdRef,
pub post: ForumPostIdRef,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeletePostOptions {
pub post: ForumPostId,
pub revision: ForumPostRevisionId,
pub comment: Option<ForumPostRevisionComment>,
}
#[derive(Error, Debug)]
pub enum DeletePostError {
#[error(transparent)]
Other(AnyError),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GetThreadOptions {
pub thread: ForumThreadRef,
pub post_offset: u32,
pub post_limit: u32,
}
#[derive(Error, Debug)]
pub enum GetThreadError {
#[error(transparent)]
Other(AnyError),
}
#[derive(Error, Debug)]
pub enum GetThreadMetaError {
#[error("thread not found")]
NotFound,
#[error(transparent)]
Other(AnyError),
}
#[async_trait]
#[auto_impl(&, Arc)]
pub trait ForumStore: Send + Sync {
async fn add_moderator(&self, options: &RawAddModeratorOptions) -> Result<(), AnyError>;
async fn delete_moderator(&self, options: &RawDeleteModeratorOptions) -> Result<(), AnyError>;
async fn get_sections(&self, options: &RawGetSectionsOptions) -> Result<Listing<RawForumSectionMeta>, AnyError>;
async fn get_section_meta(
&self,
options: &GetForumSectionMetaOptions,
) -> Result<RawForumSectionMeta, GetSectionMetaError>;
async fn get_threads(&self, options: &RawGetThreadsOptions) -> Result<Listing<RawForumThreadMeta>, AnyError>;
async fn get_thread_meta(
&self,
options: &RawGetForumThreadMetaOptions,
) -> Result<RawForumThreadMeta, GetThreadMetaError>;
async fn create_thread(&self, options: &RawCreateThreadsOptions) -> Result<RawCreateForumThreadResult, AnyError>;
async fn get_posts(&self, options: &RawGetPostsOptions) -> Result<Listing<RawShortForumPost>, AnyError>;
async fn create_post(&self, options: &RawCreatePostOptions) -> Result<RawCreateForumPostResult, AnyError>;
async fn get_post(&self, options: &RawGetForumPostOptions) -> Result<RawForumPost, AnyError>;
async fn get_role_grants(&self, options: &RawGetRoleGrantsOptions) -> Result<Vec<RawForumRoleGrant>, AnyError>;
async fn create_post_revision(
&self,
options: &RawCreatePostRevisionOptions,
) -> Result<RawCreateForumPostRevisionResult, AnyError>;
async fn upsert_system_section(
&self,
options: &UpsertSystemSectionOptions,
) -> Result<ForumSection, UpsertSystemSectionError>;
}