Files
k-photos/crates/domain/src/sharing/entities.rs

205 lines
4.9 KiB
Rust

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<DateTimeStamp>,
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<DateTimeStamp>,
pub access_level: LinkAccessLevel,
pub is_active: bool,
pub max_uses: Option<u32>,
pub use_count: u32,
}
impl ShareLink {
pub fn new(scope_id: SystemId, token: impl Into<String>, 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<DateTimeStamp>,
pub max_uses: Option<u32>,
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<String>,
}
impl VisibilityFilter {
pub fn new(scope_id: SystemId, role_id: SystemId, hidden_fields: Vec<String>) -> 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
}
}