bonsaidb_core/admin/
user.rs1use itertools::Itertools;
2use serde::{Deserialize, Serialize};
3
4use crate::admin::{group, role};
5use crate::connection::{
6 AsyncStorageConnection, Connection, IdentityReference, SensitiveString, StorageConnection,
7};
8use crate::define_basic_unique_mapped_view;
9use crate::document::{CollectionDocument, Emit, KeyId};
10use crate::permissions::Permissions;
11use crate::schema::{Collection, Nameable, NamedCollection, SerializedCollection};
12
13#[derive(Clone, Debug, Serialize, Deserialize, Default, Collection)]
15#[collection(name = "user", authority = "khonsulabs", views = [ByName])]
16#[collection(encryption_key = Some(KeyId::Master), encryption_optional, core = crate)]
17pub struct User {
18 pub username: String,
20 pub groups: Vec<u64>,
22 pub roles: Vec<u64>,
24
25 #[serde(default)]
31 pub argon_hash: Option<SensitiveString>,
32}
33
34impl User {
35 pub fn assume_identity<'name, Storage: StorageConnection>(
36 name_or_id: impl Nameable<'name, u64>,
37 storage: &Storage,
38 ) -> Result<Storage::Authenticated, crate::Error> {
39 storage.assume_identity(IdentityReference::User(name_or_id.name()?))
40 }
41
42 pub async fn assume_identity_async<'name, Storage: AsyncStorageConnection>(
43 name_or_id: impl Nameable<'name, u64> + Send,
44 storage: &Storage,
45 ) -> Result<Storage::Authenticated, crate::Error> {
46 storage
47 .assume_identity(IdentityReference::User(name_or_id.name()?))
48 .await
49 }
50
51 pub fn default_with_username(username: impl Into<String>) -> Self {
53 Self {
54 username: username.into(),
55 ..Self::default()
56 }
57 }
58
59 pub fn effective_permissions<C: Connection>(
62 &self,
63 admin: &C,
64 inherit_permissions: &Permissions,
65 ) -> Result<Permissions, crate::Error> {
66 let role_groups = if self.roles.is_empty() {
68 Vec::default()
69 } else {
70 let roles = role::Role::get_multiple(self.groups.iter(), admin)?;
71 roles
72 .into_iter()
73 .flat_map(|doc| doc.contents.groups)
74 .unique()
75 .collect::<Vec<_>>()
76 };
77 let groups = if role_groups.is_empty() {
79 group::PermissionGroup::get_multiple(self.groups.iter(), admin)?
80 } else {
81 let mut all_groups = role_groups;
82 all_groups.extend(self.groups.iter().copied());
83 all_groups.dedup();
84 group::PermissionGroup::get_multiple(&all_groups, admin)?
85 };
86
87 let merged_permissions = Permissions::merged(
89 groups
90 .into_iter()
91 .map(|group| Permissions::from(group.contents.statements))
92 .collect::<Vec<_>>()
93 .iter()
94 .chain(std::iter::once(inherit_permissions)),
95 );
96
97 Ok(merged_permissions)
98 }
99}
100
101impl NamedCollection for User {
102 type ByNameView = ByName;
103}
104
105define_basic_unique_mapped_view!(
106 ByName,
107 User,
108 1,
109 "by-name",
110 String,
111 |document: CollectionDocument<User>| { document.header.emit_key(document.contents.username) }
112);