1use crate::algebra::{MonoidAction, Semigroup};
4use crate::calculation::HasPermissions;
5use crate::permission::{
6 AtomicPermission, GrantDenialPair, PermissionDelta, PermissionSet, TemporalPermissionSet,
7 Timestamp,
8};
9use std::fmt;
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum BuilderError {
18 MissingField(&'static str),
20}
21
22impl fmt::Display for BuilderError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 BuilderError::MissingField(field) => write!(f, "missing required field: {}", field),
26 }
27 }
28}
29
30impl std::error::Error for BuilderError {}
31
32#[derive(Debug, Clone)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub struct Subject {
36 pub id: String,
38 pub permissions: GrantDenialPair,
40 pub roles: Vec<String>,
42 pub temporal_permissions: TemporalPermissionSet,
44}
45
46impl Subject {
47 pub fn new(id: impl Into<String>) -> Self {
49 Self {
50 id: id.into(),
51 permissions: GrantDenialPair::empty(),
52 roles: Vec::new(),
53 temporal_permissions: TemporalPermissionSet::new(),
54 }
55 }
56
57 pub fn effective_permissions(&self) -> PermissionSet {
59 let base = self.permissions.effective_permissions();
60 let temporal = self.temporal_permissions.currently_effective();
61 base.combine(temporal)
62 }
63
64 pub fn effective_permissions_at(&self, time: Timestamp) -> PermissionSet {
66 let base = self.permissions.effective_permissions();
67 let temporal = self.temporal_permissions.effective_at(time);
68 base.combine(temporal)
69 }
70
71 pub fn has_permission(&self, perm: &AtomicPermission) -> bool {
73 self.effective_permissions().contains(perm)
74 }
75
76 pub fn grant(&mut self, perm: AtomicPermission) {
78 self.permissions.grants.extend([perm]);
79 }
80
81 pub fn revoke(&mut self, perm: AtomicPermission) {
83 self.permissions.grants = self
84 .permissions
85 .grants
86 .difference(&PermissionSet::from([perm]));
87 }
88
89 pub fn deny(&mut self, perm: AtomicPermission) {
91 self.permissions.denials.extend([perm]);
92 }
93
94 pub fn builder() -> SubjectBuilder {
96 SubjectBuilder::default()
97 }
98}
99
100impl Default for SubjectBuilder {
101 fn default() -> Self {
102 Self {
103 id: None,
104 permissions: GrantDenialPair::empty(),
105 roles: Vec::new(),
106 }
107 }
108}
109pub struct SubjectBuilder {
111 id: Option<String>,
112 permissions: GrantDenialPair,
113 roles: Vec<String>,
114}
115
116impl SubjectBuilder {
117 pub fn id(mut self, id: impl Into<String>) -> Self {
119 self.id = Some(id.into());
120 self
121 }
122
123 pub fn role(mut self, role: impl Into<String>) -> Self {
125 self.roles.push(role.into());
126 self
127 }
128
129 pub fn grant(mut self, perm: AtomicPermission) -> Self {
131 self.permissions.grants.extend([perm]);
132 self
133 }
134
135 pub fn deny(mut self, perm: AtomicPermission) -> Self {
137 self.permissions.denials.extend([perm]);
138 self
139 }
140
141 pub fn build(self) -> Result<Subject, BuilderError> {
143 Ok(Subject {
144 id: self.id.ok_or(BuilderError::MissingField("id"))?,
145 permissions: self.permissions,
146 roles: self.roles,
147 temporal_permissions: TemporalPermissionSet::new(),
148 })
149 }
150}
151
152impl MonoidAction<PermissionDelta, Subject> for PermissionDelta {
154 fn act(delta: PermissionDelta, mut subject: Subject) -> Subject {
155 subject.permissions.grants = delta.apply_to(subject.permissions.grants);
156 subject
157 }
158}
159
160impl HasPermissions for Subject {
162 fn permissions(&self) -> &GrantDenialPair {
163 &self.permissions
164 }
165
166 fn permissions_mut(&mut self) -> &mut GrantDenialPair {
167 &mut self.permissions
168 }
169
170 fn effective_permissions_at(&self, time: Timestamp) -> PermissionSet {
171 self.effective_permissions_at(time)
172 }
173}