use chrono::Utc; use crate::common::value_objects::{DateTimeStamp, StructuredData, SystemId}; // --- ShareScope --- #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ScopeType { Private, User, Group, Link, Public, } #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ShareableType { Asset, Album, Collection, Directory, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct ShareScope { pub scope_id: SystemId, pub scope_type: ScopeType, pub shareable_type: ShareableType, pub shareable_id: SystemId, pub created_by_user_id: SystemId, pub expires_at: Option, pub created_at: DateTimeStamp, } impl ShareScope { pub fn new( scope_type: ScopeType, shareable_type: ShareableType, shareable_id: SystemId, created_by: SystemId, ) -> Self { Self { scope_id: SystemId::new(), scope_type, shareable_type, shareable_id, created_by_user_id: created_by, expires_at: None, created_at: DateTimeStamp::now(), } } pub fn is_expired(&self) -> bool { match &self.expires_at { Some(exp) => exp.as_datetime() < &Utc::now(), None => false, } } } // --- ShareTarget --- #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum TargetType { User, Group, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct ShareTarget { pub scope_id: SystemId, pub target_type: TargetType, pub target_id: SystemId, pub role_id: SystemId, } impl ShareTarget { pub fn new(scope_id: SystemId, target_type: TargetType, target_id: SystemId, role_id: SystemId) -> Self { Self { scope_id, target_type, target_id, role_id } } } // --- ShareLink --- #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum LinkAccessLevel { ViewOnly, LimitedSearch, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct ShareLink { pub scope_id: SystemId, pub token: String, pub expires_at: Option, pub access_level: LinkAccessLevel, pub is_active: bool, pub max_uses: Option, pub use_count: u32, } impl ShareLink { pub fn new(scope_id: SystemId, token: impl Into, access_level: LinkAccessLevel) -> Self { Self { scope_id, token: token.into(), expires_at: None, access_level, is_active: true, max_uses: None, use_count: 0, } } pub fn is_valid(&self) -> bool { if !self.is_active { return false; } if self.expires_at.is_some_and(|exp| exp.as_datetime() < &Utc::now()) { return false; } if self.max_uses.is_some_and(|max| self.use_count >= max) { return false; } true } pub fn record_use(&mut self) { self.use_count += 1; } pub fn deactivate(&mut self) { self.is_active = false; } } // --- InviteCode --- #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct InviteCode { pub code_id: SystemId, pub scope_id: SystemId, pub created_by_user_id: SystemId, pub expires_at: Option, pub max_uses: Option, pub use_count: u32, pub assigned_role_id: SystemId, } impl InviteCode { pub fn new(scope_id: SystemId, created_by: SystemId, role_id: SystemId) -> Self { Self { code_id: SystemId::new(), scope_id, created_by_user_id: created_by, expires_at: None, max_uses: None, use_count: 0, assigned_role_id: role_id, } } pub fn is_valid(&self) -> bool { if self.expires_at.is_some_and(|exp| exp.as_datetime() < &Utc::now()) { return false; } if self.max_uses.is_some_and(|max| self.use_count >= max) { return false; } true } pub fn record_use(&mut self) { self.use_count += 1; } } // --- VisibilityFilter --- #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct VisibilityFilter { pub filter_id: SystemId, pub scope_id: SystemId, pub role_id: SystemId, pub hidden_fields: Vec, } impl VisibilityFilter { pub fn new(scope_id: SystemId, role_id: SystemId, hidden_fields: Vec) -> Self { Self { filter_id: SystemId::new(), scope_id, role_id, hidden_fields, } } pub fn apply(&self, data: &StructuredData) -> StructuredData { let mut result = data.clone(); for field in &self.hidden_fields { result.remove(field); } result } }