pub use kcode_k1_invites::UserId;
pub use kcode_k1_txn_ordering::TxId;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct GroupId(TxId);
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum SentinelGroup {
AllUsers,
AllModels,
LocalModels,
}
pub const ALL_USERS: GroupId = GroupId::new(TxId::from_bytes([
255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 1,
]));
pub const ALL_MODELS: GroupId = GroupId::new(TxId::from_bytes([
255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 2,
]));
pub const LOCAL_MODELS: GroupId = GroupId::new(TxId::from_bytes([
255, 75, 49, 71, 82, 80, 0, 0, 0, 0, 0, 3,
]));
impl GroupId {
pub const fn new(txid: TxId) -> Self {
Self(txid)
}
pub const fn txid(self) -> TxId {
self.0
}
pub const fn sentinel(self) -> Option<SentinelGroup> {
match self {
ALL_USERS => Some(SentinelGroup::AllUsers),
ALL_MODELS => Some(SentinelGroup::AllModels),
LOCAL_MODELS => Some(SentinelGroup::LocalModels),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ModelId([u8; 32]);
impl ModelId {
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub const fn into_bytes(self) -> [u8; 32] {
self.0
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct GroupName(String);
impl GroupName {
pub fn new(value: String) -> Result<Self, String> {
if !(1..=128).contains(&value.len()) {
return Err("group name must be 1 through 128 UTF-8 bytes".to_owned());
}
if value.chars().any(char::is_control) {
return Err("group name must not contain control characters".to_owned());
}
if !value.chars().any(|character| !character.is_whitespace()) {
return Err("group name must contain a non-whitespace character".to_owned());
}
Ok(Self(value))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum GroupRole {
User,
Admin,
Owner,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GroupUser {
user_id: UserId,
role: GroupRole,
}
impl GroupUser {
pub fn user_id(&self) -> UserId {
self.user_id
}
pub fn role(&self) -> GroupRole {
self.role
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GroupRevision {
group_id: GroupId,
txid: TxId,
}
impl GroupRevision {
pub fn group_id(&self) -> GroupId {
self.group_id
}
pub fn txid(&self) -> TxId {
self.txid
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Group {
id: GroupId,
name: GroupName,
revision: GroupRevision,
users: Vec<GroupUser>,
models: Vec<ModelId>,
}
impl Group {
pub fn id(&self) -> GroupId {
self.id
}
pub fn name(&self) -> &GroupName {
&self.name
}
pub fn revision(&self) -> &GroupRevision {
&self.revision
}
pub fn users(&self) -> &[GroupUser] {
&self.users
}
pub fn models(&self) -> &[ModelId] {
&self.models
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GroupMemberships {
revision: Option<TxId>,
user_groups: Vec<GroupId>,
model_groups: Vec<GroupId>,
shared_groups: Vec<GroupId>,
}
impl GroupMemberships {
pub fn revision(&self) -> Option<TxId> {
self.revision
}
pub fn user_groups(&self) -> &[GroupId] {
&self.user_groups
}
pub fn model_groups(&self) -> &[GroupId] {
&self.model_groups
}
pub fn shared_groups(&self) -> &[GroupId] {
&self.shared_groups
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum GroupAction {
Create {
owner: UserId,
name: GroupName,
},
Rename {
group: GroupId,
actor: UserId,
name: GroupName,
},
SetUserRole {
group: GroupId,
actor: UserId,
user: UserId,
role: Option<GroupRole>,
},
SetModelMembership {
group: GroupId,
actor: UserId,
model: ModelId,
present: bool,
},
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ApplyOutcome {
Applied(GroupRevision),
Unchanged(GroupRevision),
Rejected(String),
}
pub mod projection_values {
use super::{
Group, GroupId, GroupMemberships, GroupName, GroupRevision, GroupRole, GroupUser, ModelId,
TxId, UserId,
};
pub fn group_user(user_id: UserId, role: GroupRole) -> GroupUser {
GroupUser { user_id, role }
}
pub fn group_revision(group_id: GroupId, txid: TxId) -> GroupRevision {
GroupRevision { group_id, txid }
}
pub fn group(
id: GroupId,
name: GroupName,
revision: GroupRevision,
users: Vec<GroupUser>,
models: Vec<ModelId>,
) -> Group {
Group {
id,
name,
revision,
users,
models,
}
}
pub fn group_memberships(
revision: Option<TxId>,
user_groups: Vec<GroupId>,
model_groups: Vec<GroupId>,
shared_groups: Vec<GroupId>,
) -> GroupMemberships {
GroupMemberships {
revision,
user_groups,
model_groups,
shared_groups,
}
}
}