feat(domain): models
This commit is contained in:
1
crates/domain/src/events.rs
Normal file
1
crates/domain/src/events.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// filled in Task 4
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod events;
|
||||||
|
pub mod models;
|
||||||
|
pub mod ports;
|
||||||
pub mod value_objects;
|
pub mod value_objects;
|
||||||
// remaining modules added in later tasks
|
|
||||||
|
#[cfg(any(test, feature = "test-helpers"))]
|
||||||
|
pub mod testing;
|
||||||
|
|||||||
11
crates/domain/src/models/api_key.rs
Normal file
11
crates/domain/src/models/api_key.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use crate::value_objects::{ApiKeyId, UserId};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ApiKey {
|
||||||
|
pub id: ApiKeyId,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub key_hash: String,
|
||||||
|
pub name: String,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
40
crates/domain/src/models/feed.rs
Normal file
40
crates/domain/src/models/feed.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use crate::models::{user::User, thought::Thought};
|
||||||
|
use crate::value_objects::UserId;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct UserSummary {
|
||||||
|
pub id: UserId,
|
||||||
|
pub username: String,
|
||||||
|
pub display_name: Option<String>,
|
||||||
|
pub avatar_url: Option<String>,
|
||||||
|
pub bio: Option<String>,
|
||||||
|
pub thought_count: i64,
|
||||||
|
pub follower_count: i64,
|
||||||
|
pub following_count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FeedEntry {
|
||||||
|
pub thought: Thought,
|
||||||
|
pub author: User,
|
||||||
|
pub like_count: i64,
|
||||||
|
pub boost_count: i64,
|
||||||
|
pub reply_count: i64,
|
||||||
|
pub liked_by_viewer: bool,
|
||||||
|
pub boosted_by_viewer: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PageParams { pub page: u64, pub per_page: u64 }
|
||||||
|
impl PageParams {
|
||||||
|
pub fn offset(&self) -> i64 { ((self.page.saturating_sub(1)) * self.per_page) as i64 }
|
||||||
|
pub fn limit(&self) -> i64 { self.per_page as i64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Paginated<T> {
|
||||||
|
pub items: Vec<T>,
|
||||||
|
pub total: i64,
|
||||||
|
pub page: u64,
|
||||||
|
pub per_page: u64,
|
||||||
|
}
|
||||||
9
crates/domain/src/models/mod.rs
Normal file
9
crates/domain/src/models/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pub mod api_key;
|
||||||
|
pub mod feed;
|
||||||
|
pub mod notification;
|
||||||
|
pub mod remote_actor;
|
||||||
|
pub mod social;
|
||||||
|
pub mod tag;
|
||||||
|
pub mod thought;
|
||||||
|
pub mod top_friend;
|
||||||
|
pub mod user;
|
||||||
24
crates/domain/src/models/notification.rs
Normal file
24
crates/domain/src/models/notification.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use crate::value_objects::{NotificationId, UserId, ThoughtId};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum NotificationType { Like, Boost, Follow, Mention, Reply }
|
||||||
|
impl NotificationType {
|
||||||
|
pub fn from_str(s: &str) -> Self {
|
||||||
|
match s { "like" => Self::Like, "boost" => Self::Boost, "follow" => Self::Follow, "mention" => Self::Mention, _ => Self::Reply }
|
||||||
|
}
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self { Self::Like => "like", Self::Boost => "boost", Self::Follow => "follow", Self::Mention => "mention", Self::Reply => "reply" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Notification {
|
||||||
|
pub id: NotificationId,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub notification_type: NotificationType,
|
||||||
|
pub from_user_id: Option<UserId>,
|
||||||
|
pub thought_id: Option<ThoughtId>,
|
||||||
|
pub read: bool,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
12
crates/domain/src/models/remote_actor.rs
Normal file
12
crates/domain/src/models/remote_actor.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct RemoteActor {
|
||||||
|
pub url: String,
|
||||||
|
pub handle: String,
|
||||||
|
pub display_name: Option<String>,
|
||||||
|
pub inbox_url: String,
|
||||||
|
pub shared_inbox_url: Option<String>,
|
||||||
|
pub public_key: String,
|
||||||
|
pub last_fetched_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
47
crates/domain/src/models/social.rs
Normal file
47
crates/domain/src/models/social.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use crate::value_objects::{UserId, ThoughtId, LikeId, BoostId};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Like {
|
||||||
|
pub id: LikeId,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub thought_id: ThoughtId,
|
||||||
|
pub ap_id: Option<String>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Boost {
|
||||||
|
pub id: BoostId,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub thought_id: ThoughtId,
|
||||||
|
pub ap_id: Option<String>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FollowState { Pending, Accepted, Rejected }
|
||||||
|
impl FollowState {
|
||||||
|
pub fn from_str(s: &str) -> Self {
|
||||||
|
match s { "pending" => Self::Pending, "rejected" => Self::Rejected, _ => Self::Accepted }
|
||||||
|
}
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self { Self::Pending => "pending", Self::Accepted => "accepted", Self::Rejected => "rejected" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Follow {
|
||||||
|
pub follower_id: UserId,
|
||||||
|
pub following_id: UserId,
|
||||||
|
pub state: FollowState,
|
||||||
|
pub ap_id: Option<String>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Block {
|
||||||
|
pub blocker_id: UserId,
|
||||||
|
pub blocked_id: UserId,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
2
crates/domain/src/models/tag.rs
Normal file
2
crates/domain/src/models/tag.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Tag { pub id: i32, pub name: String }
|
||||||
45
crates/domain/src/models/thought.rs
Normal file
45
crates/domain/src/models/thought.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use crate::value_objects::{ThoughtId, UserId, Content};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum Visibility {
|
||||||
|
Public, Followers, Unlisted, Direct,
|
||||||
|
}
|
||||||
|
impl Visibility {
|
||||||
|
pub fn from_str(s: &str) -> Self {
|
||||||
|
match s { "followers" => Self::Followers, "unlisted" => Self::Unlisted, "direct" => Self::Direct, _ => Self::Public }
|
||||||
|
}
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self { Self::Public => "public", Self::Followers => "followers", Self::Unlisted => "unlisted", Self::Direct => "direct" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Thought {
|
||||||
|
pub id: ThoughtId,
|
||||||
|
pub user_id: UserId,
|
||||||
|
pub content: Content,
|
||||||
|
pub in_reply_to_id: Option<ThoughtId>,
|
||||||
|
pub in_reply_to_url: Option<String>,
|
||||||
|
pub ap_id: Option<String>,
|
||||||
|
pub visibility: Visibility,
|
||||||
|
pub content_warning: Option<String>,
|
||||||
|
pub sensitive: bool,
|
||||||
|
pub local: bool,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: Option<DateTime<Utc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Thought {
|
||||||
|
pub fn new_local(
|
||||||
|
id: ThoughtId, user_id: UserId, content: Content,
|
||||||
|
in_reply_to_id: Option<ThoughtId>, visibility: Visibility,
|
||||||
|
content_warning: Option<String>, sensitive: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id, user_id, content, in_reply_to_id, in_reply_to_url: None, ap_id: None,
|
||||||
|
visibility, content_warning, sensitive, local: true,
|
||||||
|
created_at: Utc::now(), updated_at: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
crates/domain/src/models/top_friend.rs
Normal file
4
crates/domain/src/models/top_friend.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
use crate::value_objects::UserId;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TopFriend { pub user_id: UserId, pub friend_id: UserId, pub position: i16 }
|
||||||
35
crates/domain/src/models/user.rs
Normal file
35
crates/domain/src/models/user.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use crate::value_objects::{UserId, Username, Email, PasswordHash};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: UserId,
|
||||||
|
pub username: Username,
|
||||||
|
pub email: Email,
|
||||||
|
pub password_hash: PasswordHash,
|
||||||
|
pub display_name: Option<String>,
|
||||||
|
pub bio: Option<String>,
|
||||||
|
pub avatar_url: Option<String>,
|
||||||
|
pub header_url: Option<String>,
|
||||||
|
pub custom_css: Option<String>,
|
||||||
|
pub local: bool,
|
||||||
|
pub ap_id: Option<String>,
|
||||||
|
pub inbox_url: Option<String>,
|
||||||
|
pub public_key: Option<String>,
|
||||||
|
pub private_key: Option<String>,
|
||||||
|
pub created_at: DateTime<Utc>,
|
||||||
|
pub updated_at: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub fn new_local(id: UserId, username: Username, email: Email, password_hash: PasswordHash) -> Self {
|
||||||
|
let now = Utc::now();
|
||||||
|
Self {
|
||||||
|
id, username, email, password_hash,
|
||||||
|
display_name: None, bio: None, avatar_url: None, header_url: None,
|
||||||
|
custom_css: None, local: true, ap_id: None, inbox_url: None,
|
||||||
|
public_key: None, private_key: None,
|
||||||
|
created_at: now, updated_at: now,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
crates/domain/src/ports.rs
Normal file
1
crates/domain/src/ports.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// filled in Task 4
|
||||||
1
crates/domain/src/testing.rs
Normal file
1
crates/domain/src/testing.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// filled in Task 4
|
||||||
Reference in New Issue
Block a user