Skip to main content

systemprompt_users/
error.rs

1//! Typed error surface for the users crate.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use systemprompt_database::IdentifierError;
7use systemprompt_identifiers::UserId;
8use systemprompt_models::domain_error;
9
10domain_error! {
11    pub enum UserError {
12        common: [repository, validation],
13
14        #[error("user not found: {0}")]
15        NotFound(UserId),
16
17        #[error("user already exists with email: {0}")]
18        EmailAlreadyExists(String),
19
20        #[error("user {0} exists with a different account kind; the declaration cannot convert it")]
21        AccountKindMismatch(String),
22
23        #[error("invalid status: {0}")]
24        InvalidStatus(String),
25
26        #[error("invalid role: {0}")]
27        InvalidRole(String),
28
29        #[error("invalid roles: {0:?}")]
30        InvalidRoles(Vec<String>),
31
32        #[error("purge {kind} {name} is not a safe SQL identifier")]
33        PurgeIdentifier {
34            kind: &'static str,
35            name: String,
36            #[source]
37            source: IdentifierError,
38        },
39
40        #[error("user {0} is under legal hold and cannot be purged")]
41        LegalHold(UserId),
42
43        #[error("user {0} is not archived; archive before purging")]
44        NotArchived(UserId),
45
46        #[error("user {id} cannot be restored: not archived, or archived more than {window_days} days ago")]
47        RestoreRefused { id: UserId, window_days: u32 },
48
49        #[error("api key expiry {requested} exceeds the {max_days}-day maximum lifetime")]
50        ApiKeyLifetimeExceeded {
51            requested: chrono::DateTime<chrono::Utc>,
52            max_days: u32,
53        },
54
55        #[error("account merge is unavailable: no owner reassignments are configured")]
56        MergeUnavailable,
57
58        #[error("owner reassignment failed in the {domain} domain: {source}")]
59        OwnerReassignment {
60            domain: &'static str,
61            #[source]
62            source: systemprompt_traits::RepositoryError,
63        },
64    }
65}
66
67impl From<sqlx::Error> for UserError {
68    fn from(err: sqlx::Error) -> Self {
69        Self::Repository(systemprompt_traits::RepositoryError::from(err))
70    }
71}
72
73pub type Result<T> = std::result::Result<T, UserError>;
74
75pub type UserResult<T> = Result<T>;