Skip to main content

kcode_k1_groups_domain/
lib.rs

1pub use kcode_k1_invites::UserId;
2pub use kcode_k1_txn_ordering::TxId;
3#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
4pub struct GroupId(TxId);
5#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
6pub enum SentinelGroup {
7    AllUsers,
8    AllModels,
9    LocalModels,
10}
11pub const ALL_USERS: GroupId = GroupId::new(TxId::from_bytes([
12    255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 1,
13]));
14pub const ALL_MODELS: GroupId = GroupId::new(TxId::from_bytes([
15    255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 2,
16]));
17pub const LOCAL_MODELS: GroupId = GroupId::new(TxId::from_bytes([
18    255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 3,
19]));
20impl GroupId {
21    pub const fn new(txid: TxId) -> Self {
22        Self(txid)
23    }
24    pub const fn txid(self) -> TxId {
25        self.0
26    }
27    pub const fn sentinel(self) -> Option<SentinelGroup> {
28        match self {
29            ALL_USERS => Some(SentinelGroup::AllUsers),
30            ALL_MODELS => Some(SentinelGroup::AllModels),
31            LOCAL_MODELS => Some(SentinelGroup::LocalModels),
32            _ => None,
33        }
34    }
35}
36#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
37pub struct ModelId([u8; 32]);
38pub const ALL_MODELS_MEMBER: ModelId = ModelId::from_bytes(*b"ALL_MODELS......................");
39impl ModelId {
40    pub const fn from_bytes(bytes: [u8; 32]) -> Self {
41        Self(bytes)
42    }
43    pub const fn as_bytes(&self) -> &[u8; 32] {
44        &self.0
45    }
46    pub const fn into_bytes(self) -> [u8; 32] {
47        self.0
48    }
49}
50#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
51pub struct GroupName(String);
52impl GroupName {
53    pub fn new(value: String) -> Result<Self, String> {
54        if !(1..=128).contains(&value.len()) {
55            return Err("group name must be 1 through 128 UTF-8 bytes".to_owned());
56        }
57        if value.chars().any(char::is_control) {
58            return Err("group name must not contain control characters".to_owned());
59        }
60        if !value.chars().any(|c| !c.is_whitespace()) {
61            return Err("group name must contain a non-whitespace character".to_owned());
62        }
63        Ok(Self(value))
64    }
65    pub fn as_str(&self) -> &str {
66        &self.0
67    }
68    pub fn into_string(self) -> String {
69        self.0
70    }
71}
72#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
73pub enum GroupRole {
74    User,
75    Admin,
76    Owner,
77}
78#[derive(Clone, Debug, Eq, PartialEq)]
79pub struct GroupUser {
80    user_id: UserId,
81    role: GroupRole,
82}
83impl GroupUser {
84    pub fn user_id(&self) -> UserId {
85        self.user_id
86    }
87    pub fn role(&self) -> GroupRole {
88        self.role
89    }
90}
91#[derive(Clone, Debug, Eq, PartialEq)]
92pub struct GroupRevision {
93    group_id: GroupId,
94    txid: TxId,
95}
96impl GroupRevision {
97    pub fn group_id(&self) -> GroupId {
98        self.group_id
99    }
100    pub fn txid(&self) -> TxId {
101        self.txid
102    }
103}
104#[derive(Clone, Debug, Eq, PartialEq)]
105pub struct Group {
106    id: GroupId,
107    name: GroupName,
108    revision: GroupRevision,
109    users: Vec<GroupUser>,
110    models: Vec<ModelId>,
111}
112impl Group {
113    pub fn id(&self) -> GroupId {
114        self.id
115    }
116    pub fn name(&self) -> &GroupName {
117        &self.name
118    }
119    pub fn revision(&self) -> &GroupRevision {
120        &self.revision
121    }
122    pub fn users(&self) -> &[GroupUser] {
123        &self.users
124    }
125    pub fn models(&self) -> &[ModelId] {
126        &self.models
127    }
128}
129#[derive(Clone, Debug, Eq, PartialEq)]
130pub struct GroupMemberships {
131    revision: Option<TxId>,
132    user_groups: Vec<GroupId>,
133    model_groups: Vec<GroupId>,
134    shared_groups: Vec<GroupId>,
135}
136impl GroupMemberships {
137    pub fn revision(&self) -> Option<TxId> {
138        self.revision
139    }
140    pub fn user_groups(&self) -> &[GroupId] {
141        &self.user_groups
142    }
143    pub fn model_groups(&self) -> &[GroupId] {
144        &self.model_groups
145    }
146    pub fn shared_groups(&self) -> &[GroupId] {
147        &self.shared_groups
148    }
149}
150#[derive(Clone, Debug, Eq, PartialEq)]
151pub enum GroupAction {
152    Create {
153        owner: UserId,
154        name: GroupName,
155    },
156    Rename {
157        group: GroupId,
158        actor: UserId,
159        name: GroupName,
160    },
161    SetUserRole {
162        group: GroupId,
163        actor: UserId,
164        user: UserId,
165        role: Option<GroupRole>,
166    },
167    SetModelMembership {
168        group: GroupId,
169        actor: UserId,
170        model: ModelId,
171        present: bool,
172    },
173}
174#[derive(Clone, Debug, Eq, PartialEq)]
175pub enum ApplyOutcome {
176    Applied(GroupRevision),
177    Unchanged(GroupRevision),
178    Rejected(String),
179}
180pub mod projection_values {
181    use super::{
182        Group, GroupId, GroupMemberships, GroupName, GroupRevision, GroupRole, GroupUser, ModelId,
183        TxId, UserId,
184    };
185    pub fn group_user(user_id: UserId, role: GroupRole) -> GroupUser {
186        GroupUser { user_id, role }
187    }
188    pub fn group_revision(group_id: GroupId, txid: TxId) -> GroupRevision {
189        GroupRevision { group_id, txid }
190    }
191    pub fn group(
192        id: GroupId,
193        name: GroupName,
194        revision: GroupRevision,
195        users: Vec<GroupUser>,
196        models: Vec<ModelId>,
197    ) -> Group {
198        Group {
199            id,
200            name,
201            revision,
202            users,
203            models,
204        }
205    }
206    pub fn group_memberships(
207        revision: Option<TxId>,
208        user_groups: Vec<GroupId>,
209        model_groups: Vec<GroupId>,
210        shared_groups: Vec<GroupId>,
211    ) -> GroupMemberships {
212        GroupMemberships {
213            revision,
214            user_groups,
215            model_groups,
216            shared_groups,
217        }
218    }
219}