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 events;
|
||||
pub mod models;
|
||||
pub mod ports;
|
||||
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