mirror of
https://github.com/moghtech/komodo.git
synced 2026-03-09 07:13:36 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb270f4dff | ||
|
|
21666cf9b3 |
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -41,7 +41,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "alerter"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -943,7 +943,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "command"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"komodo_client",
|
||||
"run_command",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "environment_file"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
@@ -1439,7 +1439,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "formatting"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"serror",
|
||||
]
|
||||
@@ -1571,7 +1571,7 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "git"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"command",
|
||||
@@ -2192,7 +2192,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_cli"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2208,7 +2208,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_client"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2239,7 +2239,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_core"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2296,7 +2296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "komodo_periphery"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async_timing_util",
|
||||
@@ -2383,7 +2383,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "logger"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -3089,7 +3089,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "periphery_client"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
@@ -4867,7 +4867,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "update_logger"
|
||||
version = "1.15.10"
|
||||
version = "1.15.12"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"komodo_client",
|
||||
|
||||
@@ -9,7 +9,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.15.11"
|
||||
version = "1.15.12"
|
||||
edition = "2021"
|
||||
authors = ["mbecker20 <becker.maxh@gmail.com>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
@@ -3,7 +3,10 @@ use komodo_client::{
|
||||
api::read::{
|
||||
GetAlert, GetAlertResponse, ListAlerts, ListAlertsResponse,
|
||||
},
|
||||
entities::{deployment::Deployment, server::Server, user::User},
|
||||
entities::{
|
||||
deployment::Deployment, server::Server, stack::Stack,
|
||||
sync::ResourceSync, user::User,
|
||||
},
|
||||
};
|
||||
use mungos::{
|
||||
by_id::find_one_by_id,
|
||||
@@ -30,12 +33,18 @@ impl Resolve<ListAlerts, User> for State {
|
||||
if !user.admin && !core_config().transparent_mode {
|
||||
let server_ids =
|
||||
get_resource_ids_for_user::<Server>(&user).await?;
|
||||
let stack_ids =
|
||||
get_resource_ids_for_user::<Stack>(&user).await?;
|
||||
let deployment_ids =
|
||||
get_resource_ids_for_user::<Deployment>(&user).await?;
|
||||
let sync_ids =
|
||||
get_resource_ids_for_user::<ResourceSync>(&user).await?;
|
||||
query.extend(doc! {
|
||||
"$or": [
|
||||
{ "target.type": "Server", "target.id": { "$in": &server_ids } },
|
||||
{ "target.type": "Stack", "target.id": { "$in": &stack_ids } },
|
||||
{ "target.type": "Deployment", "target.id": { "$in": &deployment_ids } },
|
||||
{ "target.type": "ResourceSync", "target.id": { "$in": &sync_ids } },
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ impl Resolve<GetAlertersSummary, User> for State {
|
||||
user: User,
|
||||
) -> anyhow::Result<GetAlertersSummaryResponse> {
|
||||
let query =
|
||||
match resource::get_resource_ids_for_user::<Alerter>(&user)
|
||||
match resource::get_resource_object_ids_for_user::<Alerter>(&user)
|
||||
.await?
|
||||
{
|
||||
Some(ids) => doc! {
|
||||
|
||||
@@ -70,7 +70,7 @@ impl Resolve<GetBuildersSummary, User> for State {
|
||||
user: User,
|
||||
) -> anyhow::Result<GetBuildersSummaryResponse> {
|
||||
let query =
|
||||
match resource::get_resource_ids_for_user::<Builder>(&user)
|
||||
match resource::get_resource_object_ids_for_user::<Builder>(&user)
|
||||
.await?
|
||||
{
|
||||
Some(ids) => doc! {
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Resolve<GetServerTemplatesSummary, User> for State {
|
||||
GetServerTemplatesSummary {}: GetServerTemplatesSummary,
|
||||
user: User,
|
||||
) -> anyhow::Result<GetServerTemplatesSummaryResponse> {
|
||||
let query = match resource::get_resource_ids_for_user::<
|
||||
let query = match resource::get_resource_object_ids_for_user::<
|
||||
ServerTemplate,
|
||||
>(&user)
|
||||
.await?
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context;
|
||||
use komodo_client::{
|
||||
api::read::{
|
||||
ExportAllResourcesToToml, ExportAllResourcesToTomlResponse,
|
||||
ExportResourcesToToml, ExportResourcesToTomlResponse,
|
||||
GetUserGroup, ListUserTargetPermissions,
|
||||
ListUserGroups,
|
||||
},
|
||||
entities::{
|
||||
alerter::Alerter,
|
||||
build::Build,
|
||||
builder::Builder,
|
||||
deployment::Deployment,
|
||||
permission::{PermissionLevel, UserTarget},
|
||||
procedure::Procedure,
|
||||
repo::Repo,
|
||||
resource::ResourceQuery,
|
||||
server::Server,
|
||||
server_template::ServerTemplate,
|
||||
stack::Stack,
|
||||
sync::ResourceSync,
|
||||
toml::{PermissionToml, ResourcesToml, UserGroupToml},
|
||||
user::User,
|
||||
alerter::Alerter, build::Build, builder::Builder,
|
||||
deployment::Deployment, permission::PermissionLevel,
|
||||
procedure::Procedure, repo::Repo, resource::ResourceQuery,
|
||||
server::Server, server_template::ServerTemplate, stack::Stack,
|
||||
sync::ResourceSync, toml::ResourcesToml, user::User,
|
||||
ResourceTarget,
|
||||
},
|
||||
};
|
||||
@@ -36,6 +25,7 @@ use crate::{
|
||||
state::{db_client, State},
|
||||
sync::{
|
||||
toml::{convert_resource, ToToml, TOML_PRETTY_OPTIONS},
|
||||
user_groups::convert_user_groups,
|
||||
AllResourcesById,
|
||||
},
|
||||
};
|
||||
@@ -385,122 +375,17 @@ async fn add_user_groups(
|
||||
all: &AllResourcesById,
|
||||
user: &User,
|
||||
) -> anyhow::Result<()> {
|
||||
let db = db_client();
|
||||
|
||||
let usernames = find_collect(&db.users, None, None)
|
||||
let user_groups = State
|
||||
.resolve(ListUserGroups {}, user.clone())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|user| (user.id, user.username))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for user_group in user_groups {
|
||||
let ug = State
|
||||
.resolve(GetUserGroup { user_group }, user.clone())
|
||||
.await?;
|
||||
// this method is admin only, but we already know user can see user group if above does not return Err
|
||||
let permissions = State
|
||||
.resolve(
|
||||
ListUserTargetPermissions {
|
||||
user_target: UserTarget::UserGroup(ug.id),
|
||||
},
|
||||
User {
|
||||
admin: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|mut permission| {
|
||||
match &mut permission.resource_target {
|
||||
ResourceTarget::Build(id) => {
|
||||
*id = all
|
||||
.builds
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Builder(id) => {
|
||||
*id = all
|
||||
.builders
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Deployment(id) => {
|
||||
*id = all
|
||||
.deployments
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Server(id) => {
|
||||
*id = all
|
||||
.servers
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Repo(id) => {
|
||||
*id = all
|
||||
.repos
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Alerter(id) => {
|
||||
*id = all
|
||||
.alerters
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Procedure(id) => {
|
||||
*id = all
|
||||
.procedures
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ServerTemplate(id) => {
|
||||
*id = all
|
||||
.templates
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ResourceSync(id) => {
|
||||
*id = all
|
||||
.syncs
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Stack(id) => {
|
||||
*id = all
|
||||
.stacks
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::System(_) => {}
|
||||
}
|
||||
PermissionToml {
|
||||
target: permission.resource_target,
|
||||
level: permission.level,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
res.user_groups.push(UserGroupToml {
|
||||
name: ug.name,
|
||||
users: ug
|
||||
.users
|
||||
.into_iter()
|
||||
.filter_map(|user_id| usernames.get(&user_id).cloned())
|
||||
.collect(),
|
||||
all: ug.all,
|
||||
permissions,
|
||||
.filter(|ug| {
|
||||
user_groups.contains(&ug.name) || user_groups.contains(&ug.id)
|
||||
});
|
||||
}
|
||||
let mut ug = Vec::with_capacity(user_groups.size_hint().0);
|
||||
convert_user_groups(user_groups, all, &mut ug).await?;
|
||||
res.user_groups = ug.into_iter().map(|ug| ug.1).collect();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,16 @@ impl Resolve<ListUpdates, User> for State {
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "Procedure" });
|
||||
|
||||
// let action_query =
|
||||
// resource::get_resource_ids_for_user::<Action>(&user)
|
||||
// .await?
|
||||
// .map(|ids| {
|
||||
// doc! {
|
||||
// "target.type": "Action", "target.id": { "$in": ids }
|
||||
// }
|
||||
// })
|
||||
// .unwrap_or_else(|| doc! { "target.type": "Action" });
|
||||
|
||||
let builder_query =
|
||||
resource::get_resource_ids_for_user::<Builder>(&user)
|
||||
.await?
|
||||
@@ -124,27 +134,27 @@ impl Resolve<ListUpdates, User> for State {
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "Alerter" });
|
||||
|
||||
let server_template_query = resource::get_resource_ids_for_user::<ServerTemplate>(
|
||||
&user,
|
||||
)
|
||||
.await?
|
||||
.map(|ids| {
|
||||
doc! {
|
||||
"target.type": "ServerTemplate", "target.id": { "$in": ids }
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "ServerTemplate" });
|
||||
let server_template_query =
|
||||
resource::get_resource_ids_for_user::<ServerTemplate>(&user)
|
||||
.await?
|
||||
.map(|ids| {
|
||||
doc! {
|
||||
"target.type": "ServerTemplate", "target.id": { "$in": ids }
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "ServerTemplate" });
|
||||
|
||||
let resource_sync_query = resource::get_resource_ids_for_user::<ResourceSync>(
|
||||
&user,
|
||||
)
|
||||
.await?
|
||||
.map(|ids| {
|
||||
doc! {
|
||||
"target.type": "ResourceSync", "target.id": { "$in": ids }
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "ResourceSync" });
|
||||
let resource_sync_query =
|
||||
resource::get_resource_ids_for_user::<ResourceSync>(
|
||||
&user,
|
||||
)
|
||||
.await?
|
||||
.map(|ids| {
|
||||
doc! {
|
||||
"target.type": "ResourceSync", "target.id": { "$in": ids }
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| doc! { "target.type": "ResourceSync" });
|
||||
|
||||
let mut query = query.unwrap_or_default();
|
||||
query.extend(doc! {
|
||||
@@ -155,6 +165,7 @@ impl Resolve<ListUpdates, User> for State {
|
||||
build_query,
|
||||
repo_query,
|
||||
procedure_query,
|
||||
// action_query,
|
||||
alerter_query,
|
||||
builder_query,
|
||||
server_template_query,
|
||||
|
||||
@@ -584,8 +584,7 @@ impl Resolve<RefreshResourceSyncPending, User> for State {
|
||||
let variable_updates = if sync.config.match_tags.is_empty() {
|
||||
crate::sync::variables::get_updates_for_view(
|
||||
&resources.variables,
|
||||
// Delete doesn't work with variables when match tags are set
|
||||
sync.config.match_tags.is_empty() && delete,
|
||||
delete,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
@@ -595,8 +594,7 @@ impl Resolve<RefreshResourceSyncPending, User> for State {
|
||||
let user_group_updates = if sync.config.match_tags.is_empty() {
|
||||
crate::sync::user_groups::get_updates_for_view(
|
||||
resources.user_groups,
|
||||
// Delete doesn't work with user groups when match tags are set
|
||||
sync.config.match_tags.is_empty() && delete,
|
||||
delete,
|
||||
&all_resources,
|
||||
)
|
||||
.await?
|
||||
|
||||
@@ -316,8 +316,8 @@ pub async fn alert_servers(
|
||||
Some(mut alert),
|
||||
_,
|
||||
) => {
|
||||
// Disk is persistent, update alert if health changes regardless of direction
|
||||
if health.level != alert.level {
|
||||
// modify alert level only if it has increased
|
||||
if health.level < alert.level {
|
||||
let disk =
|
||||
server_status.stats.as_ref().and_then(|stats| {
|
||||
stats.disks.iter().find(|disk| disk.mount == *path)
|
||||
|
||||
@@ -240,9 +240,24 @@ pub async fn get_check_permissions<T: KomodoResource>(
|
||||
|
||||
/// Returns None if still no need to filter by resource id (eg transparent mode, group membership with all access).
|
||||
#[instrument(level = "debug")]
|
||||
pub async fn get_resource_ids_for_user<T: KomodoResource>(
|
||||
pub async fn get_resource_object_ids_for_user<T: KomodoResource>(
|
||||
user: &User,
|
||||
) -> anyhow::Result<Option<Vec<ObjectId>>> {
|
||||
get_resource_ids_for_user::<T>(user).await.map(|ids| {
|
||||
ids.map(|ids| {
|
||||
ids
|
||||
.into_iter()
|
||||
.flat_map(|id| ObjectId::from_str(&id))
|
||||
.collect()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns None if still no need to filter by resource id (eg transparent mode, group membership with all access).
|
||||
#[instrument(level = "debug")]
|
||||
pub async fn get_resource_ids_for_user<T: KomodoResource>(
|
||||
user: &User,
|
||||
) -> anyhow::Result<Option<Vec<String>>> {
|
||||
// Check admin or transparent mode
|
||||
if user.admin || core_config().transparent_mode {
|
||||
return Ok(None);
|
||||
@@ -271,7 +286,7 @@ pub async fn get_resource_ids_for_user<T: KomodoResource>(
|
||||
// Get any resources with non-none base permission,
|
||||
find_collect(
|
||||
T::coll().await,
|
||||
doc! { "base_permission": { "$ne": "None" } },
|
||||
doc! { "base_permission": { "$exists": true, "$ne": "None" } },
|
||||
None,
|
||||
)
|
||||
.map(|res| res.with_context(|| format!(
|
||||
@@ -283,7 +298,7 @@ pub async fn get_resource_ids_for_user<T: KomodoResource>(
|
||||
doc! {
|
||||
"$or": user_target_query(&user.id, &groups)?,
|
||||
"resource_target.type": resource_type.as_ref(),
|
||||
"level": { "$in": ["Read", "Execute", "Write"] }
|
||||
"level": { "$exists": true, "$ne": "None" }
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -297,9 +312,6 @@ pub async fn get_resource_ids_for_user<T: KomodoResource>(
|
||||
// Chain in the ones with non-None base permissions
|
||||
.chain(base.into_iter().map(|res| res.id))
|
||||
// collect into hashset first to remove any duplicates
|
||||
.collect::<HashSet<_>>()
|
||||
.into_iter()
|
||||
.flat_map(|id| ObjectId::from_str(&id))
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
Ok(Some(ids.into_iter().collect()))
|
||||
@@ -418,7 +430,9 @@ pub async fn list_full_for_user_using_document<T: KomodoResource>(
|
||||
mut filters: Document,
|
||||
user: &User,
|
||||
) -> anyhow::Result<Vec<Resource<T::Config, T::Info>>> {
|
||||
if let Some(ids) = get_resource_ids_for_user::<T>(user).await? {
|
||||
if let Some(ids) =
|
||||
get_resource_object_ids_for_user::<T>(user).await?
|
||||
{
|
||||
filters.insert("_id", doc! { "$in": ids });
|
||||
}
|
||||
find_collect(
|
||||
|
||||
@@ -15,7 +15,8 @@ use komodo_client::{
|
||||
sync::DiffData,
|
||||
toml::{PermissionToml, UserGroupToml},
|
||||
update::Log,
|
||||
user::sync_user,
|
||||
user::{sync_user, User},
|
||||
user_group::UserGroup,
|
||||
ResourceTarget, ResourceTargetVariant,
|
||||
},
|
||||
};
|
||||
@@ -43,17 +44,21 @@ pub async fn get_updates_for_view(
|
||||
delete: bool,
|
||||
all_resources: &AllResourcesById,
|
||||
) -> anyhow::Result<Vec<DiffData>> {
|
||||
let map = find_collect(&db_client().user_groups, None, None)
|
||||
let _curr = find_collect(&db_client().user_groups, None, None)
|
||||
.await
|
||||
.context("failed to query db for UserGroups")?
|
||||
.context("failed to query db for UserGroups")?;
|
||||
let mut curr = Vec::with_capacity(_curr.capacity());
|
||||
convert_user_groups(_curr.into_iter(), all_resources, &mut curr)
|
||||
.await?;
|
||||
let map = curr
|
||||
.into_iter()
|
||||
.map(|ug| (ug.name.clone(), ug))
|
||||
.map(|ug| (ug.1.name.clone(), ug))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
let mut diffs = Vec::<DiffData>::new();
|
||||
|
||||
if delete {
|
||||
for user_group in map.values() {
|
||||
for (_id, user_group) in map.values() {
|
||||
if !user_groups.iter().any(|ug| ug.name == user_group.name) {
|
||||
diffs.push(DiffData::Delete {
|
||||
current: format!(
|
||||
@@ -66,13 +71,6 @@ pub async fn get_updates_for_view(
|
||||
}
|
||||
}
|
||||
|
||||
let id_to_user = find_collect(&db_client().users, None, None)
|
||||
.await
|
||||
.context("failed to query db for Users")?
|
||||
.into_iter()
|
||||
.map(|user| (user.id.clone(), user))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for mut user_group in user_groups {
|
||||
user_group
|
||||
.permissions
|
||||
@@ -90,7 +88,10 @@ pub async fn get_updates_for_view(
|
||||
)
|
||||
})?;
|
||||
|
||||
let original = match map.get(&user_group.name).cloned() {
|
||||
let (_original_id, original) = match map
|
||||
.get(&user_group.name)
|
||||
.cloned()
|
||||
{
|
||||
Some(original) => original,
|
||||
None => {
|
||||
diffs.push(DiffData::Create {
|
||||
@@ -104,121 +105,16 @@ pub async fn get_updates_for_view(
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut original_users = original
|
||||
.users
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|user_id| {
|
||||
id_to_user.get(&user_id).map(|u| u.username.clone())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut original_permissions = State
|
||||
.resolve(
|
||||
ListUserTargetPermissions {
|
||||
user_target: UserTarget::UserGroup(original.id.clone()),
|
||||
},
|
||||
sync_user().to_owned(),
|
||||
)
|
||||
.await
|
||||
.context("failed to query for existing UserGroup permissions")?
|
||||
.into_iter()
|
||||
.filter(|p| p.level > PermissionLevel::None)
|
||||
.map(|mut p| {
|
||||
// replace the ids with names
|
||||
match &mut p.resource_target {
|
||||
ResourceTarget::System(_) => {}
|
||||
ResourceTarget::Build(id) => {
|
||||
*id = all_resources
|
||||
.builds
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Builder(id) => {
|
||||
*id = all_resources
|
||||
.builders
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Deployment(id) => {
|
||||
*id = all_resources
|
||||
.deployments
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Server(id) => {
|
||||
*id = all_resources
|
||||
.servers
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Repo(id) => {
|
||||
*id = all_resources
|
||||
.repos
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Alerter(id) => {
|
||||
*id = all_resources
|
||||
.alerters
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Procedure(id) => {
|
||||
*id = all_resources
|
||||
.procedures
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ServerTemplate(id) => {
|
||||
*id = all_resources
|
||||
.templates
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ResourceSync(id) => {
|
||||
*id = all_resources
|
||||
.syncs
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Stack(id) => {
|
||||
*id = all_resources
|
||||
.stacks
|
||||
.get(id)
|
||||
.map(|b| b.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
PermissionToml {
|
||||
target: p.resource_target,
|
||||
level: p.level,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
original_users.sort();
|
||||
user_group.users.sort();
|
||||
|
||||
let all_diff = diff_group_all(&original.all, &user_group.all);
|
||||
|
||||
user_group.permissions.sort_by(sort_permissions);
|
||||
original_permissions.sort_by(sort_permissions);
|
||||
|
||||
let update_users = user_group.users != original_users;
|
||||
let update_users = user_group.users != original.users;
|
||||
let update_all = !all_diff.is_empty();
|
||||
let update_permissions =
|
||||
user_group.permissions != original_permissions;
|
||||
user_group.permissions != original.permissions;
|
||||
|
||||
// only add log after diff detected
|
||||
if update_users || update_all || update_permissions {
|
||||
@@ -900,3 +796,132 @@ fn diff_group_all(
|
||||
|
||||
to_update
|
||||
}
|
||||
|
||||
pub async fn convert_user_groups(
|
||||
user_groups: impl Iterator<Item = UserGroup>,
|
||||
all: &AllResourcesById,
|
||||
res: &mut Vec<(String, UserGroupToml)>,
|
||||
) -> anyhow::Result<()> {
|
||||
let db = db_client();
|
||||
|
||||
let usernames = find_collect(&db.users, None, None)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|user| (user.id, user.username))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
for user_group in user_groups {
|
||||
// this method is admin only, but we already know user can see user group if above does not return Err
|
||||
let mut permissions = State
|
||||
.resolve(
|
||||
ListUserTargetPermissions {
|
||||
user_target: UserTarget::UserGroup(user_group.id.clone()),
|
||||
},
|
||||
User {
|
||||
admin: true,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|mut permission| {
|
||||
match &mut permission.resource_target {
|
||||
ResourceTarget::Build(id) => {
|
||||
*id = all
|
||||
.builds
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Builder(id) => {
|
||||
*id = all
|
||||
.builders
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Deployment(id) => {
|
||||
*id = all
|
||||
.deployments
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Server(id) => {
|
||||
*id = all
|
||||
.servers
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Repo(id) => {
|
||||
*id = all
|
||||
.repos
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Alerter(id) => {
|
||||
*id = all
|
||||
.alerters
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Procedure(id) => {
|
||||
*id = all
|
||||
.procedures
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ServerTemplate(id) => {
|
||||
*id = all
|
||||
.templates
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::ResourceSync(id) => {
|
||||
*id = all
|
||||
.syncs
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::Stack(id) => {
|
||||
*id = all
|
||||
.stacks
|
||||
.get(id)
|
||||
.map(|r| r.name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
ResourceTarget::System(_) => {}
|
||||
}
|
||||
PermissionToml {
|
||||
target: permission.resource_target,
|
||||
level: permission.level,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut users = user_group
|
||||
.users
|
||||
.into_iter()
|
||||
.filter_map(|user_id| usernames.get(&user_id).cloned())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
permissions.sort_by(sort_permissions);
|
||||
users.sort();
|
||||
|
||||
res.push((
|
||||
user_group.id,
|
||||
UserGroupToml {
|
||||
name: user_group.name,
|
||||
users,
|
||||
all: user_group.all,
|
||||
permissions,
|
||||
},
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
FileQuestion,
|
||||
FolderTree,
|
||||
Keyboard,
|
||||
LayoutDashboard,
|
||||
Settings,
|
||||
User,
|
||||
Users,
|
||||
@@ -66,7 +67,10 @@ export const Topbar = () => {
|
||||
<div className="flex justify-end items-center gap-2">
|
||||
<MobileDropdown />
|
||||
<OmniSearch setOpen={setOmniOpen} className="lg:hidden" />
|
||||
<Version />
|
||||
<div className="flex gap-0">
|
||||
<Docs />
|
||||
<Version />
|
||||
</div>
|
||||
<WsStatusIndicator />
|
||||
<KeyboardShortcuts />
|
||||
<TopbarAlerts />
|
||||
@@ -80,6 +84,18 @@ export const Topbar = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const Docs = () => (
|
||||
<a
|
||||
href="https://komo.do/docs/intro"
|
||||
target="_blank"
|
||||
className="hidden lg:block"
|
||||
>
|
||||
<Button variant="link" size="sm">
|
||||
<div>Docs</div>
|
||||
</Button>
|
||||
</a>
|
||||
);
|
||||
|
||||
const Version = () => {
|
||||
const version = useRead("GetVersion", {}).data?.version;
|
||||
|
||||
@@ -112,11 +128,13 @@ const MobileDropdown = () => {
|
||||
: type) + "s",
|
||||
]
|
||||
: location.pathname === "/" && view === "Dashboard"
|
||||
? [<Box className="w-4 h-4" />, "Dashboard"]
|
||||
? [<LayoutDashboard className="w-4 h-4" />, "Dashboard"]
|
||||
: location.pathname === "/" && view === "Resources"
|
||||
? [<Boxes className="w-4 h-4" />, "Resources"]
|
||||
: location.pathname === "/" && view === "Tree"
|
||||
? [<FolderTree className="w-4 h-4" />, "Tree"]
|
||||
: location.pathname === "/containers"
|
||||
? [<Box className="w-4 h-4" />, "Containers"]
|
||||
: location.pathname === "/settings"
|
||||
? [<Settings className="w-4 h-4" />, "Settings"]
|
||||
: location.pathname === "/alerts"
|
||||
@@ -144,7 +162,7 @@ const MobileDropdown = () => {
|
||||
<DropdownMenuGroup>
|
||||
<DropdownLinkItem
|
||||
label="Dashboard"
|
||||
icon={<Box className="w-4 h-4" />}
|
||||
icon={<LayoutDashboard className="w-4 h-4" />}
|
||||
to="/"
|
||||
onClick={() => setView("Dashboard")}
|
||||
/>
|
||||
@@ -154,12 +172,11 @@ const MobileDropdown = () => {
|
||||
to="/"
|
||||
onClick={() => setView("Resources")}
|
||||
/>
|
||||
{/* <DropdownLinkItem
|
||||
label="Tree"
|
||||
icon={<FolderTree className="w-4 h-4" />}
|
||||
to="/"
|
||||
onClick={() => setView("Tree")}
|
||||
/> */}
|
||||
<DropdownLinkItem
|
||||
label="Containers"
|
||||
icon={<Box className="w-4 h-4" />}
|
||||
to="/containers"
|
||||
/>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user