From 4ed71812a4c664e6cf9c2149a815d88719178b84 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Sun, 21 Apr 2024 15:01:58 -0700 Subject: [PATCH] rename GetUsers to ListUsers for consistency --- bin/core/src/api/read/mod.rs | 2 +- bin/core/src/api/read/user.rs | 10 ++-- client/core/rs/src/api/read/mod.rs | 48 +--------------- client/core/rs/src/api/read/user.rs | 57 +++++++++++++++++++ client/core/ts/src/responses.ts | 2 +- client/core/ts/src/types.ts | 81 +++++++++++++++------------ frontend/src/lib/utils.ts | 27 ++++++++- frontend/src/pages/resource.tsx | 10 ++-- frontend/src/pages/users.tsx | 86 ++++++++++++++--------------- 9 files changed, 186 insertions(+), 137 deletions(-) create mode 100644 client/core/rs/src/api/read/user.rs diff --git a/bin/core/src/api/read/mod.rs b/bin/core/src/api/read/mod.rs index 1d35b309a..e6ff2ae89 100644 --- a/bin/core/src/api/read/mod.rs +++ b/bin/core/src/api/read/mod.rs @@ -40,7 +40,7 @@ enum ReadRequest { GetCoreInfo(GetCoreInfo), // ==== USER ==== - GetUsers(GetUsers), + ListUsers(ListUsers), GetUsername(GetUsername), ListApiKeys(ListApiKeys), ListPermissions(ListPermissions), diff --git a/bin/core/src/api/read/user.rs b/bin/core/src/api/read/user.rs index 35eb2f980..8c7098e30 100644 --- a/bin/core/src/api/read/user.rs +++ b/bin/core/src/api/read/user.rs @@ -2,8 +2,8 @@ use anyhow::{anyhow, Context}; use async_trait::async_trait; use monitor_client::{ api::read::{ - GetUsername, GetUsernameResponse, GetUsers, ListApiKeys, - ListApiKeysResponse, + GetUsername, GetUsernameResponse, ListApiKeys, + ListApiKeysResponse, ListUsers, ListUsersResponse, }, entities::user::User, }; @@ -33,12 +33,12 @@ impl Resolve for State { } #[async_trait] -impl Resolve for State { +impl Resolve for State { async fn resolve( &self, - GetUsers {}: GetUsers, + ListUsers {}: ListUsers, user: User, - ) -> anyhow::Result> { + ) -> anyhow::Result { if !user.admin { return Err(anyhow!("this route is only accessable by admins")); } diff --git a/client/core/rs/src/api/read/mod.rs b/client/core/rs/src/api/read/mod.rs index 1aa7e426e..addb6b528 100644 --- a/client/core/rs/src/api/read/mod.rs +++ b/client/core/rs/src/api/read/mod.rs @@ -15,6 +15,7 @@ mod search; mod server; mod tag; mod update; +mod user; mod user_group; pub use alert::*; @@ -29,9 +30,10 @@ pub use search::*; pub use server::*; pub use tag::*; pub use update::*; +pub use user::*; pub use user_group::*; -use crate::entities::{api_key::ApiKey, user::User, Timelength}; +use crate::entities::Timelength; pub trait MonitorReadRequest: HasResponse {} @@ -53,50 +55,6 @@ pub struct GetVersionResponse { // -#[typeshare] -#[derive( - Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, -)] -#[empty_traits(MonitorReadRequest)] -#[response(ListApiKeysResponse)] -pub struct ListApiKeys {} - -#[typeshare] -pub type ListApiKeysResponse = Vec; - -// - -#[typeshare] -#[derive( - Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, -)] -#[empty_traits(MonitorReadRequest)] -#[response(GetUsersResponse)] -pub struct GetUsers {} - -#[typeshare] -pub type GetUsersResponse = Vec; - -// - -#[typeshare] -#[derive( - Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, -)] -#[empty_traits(MonitorReadRequest)] -#[response(GetUsernameResponse)] -pub struct GetUsername { - pub user_id: String, -} - -#[typeshare] -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetUsernameResponse { - pub username: String, -} - -// - #[typeshare] #[derive( Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, diff --git a/client/core/rs/src/api/read/user.rs b/client/core/rs/src/api/read/user.rs new file mode 100644 index 000000000..35edfbbd7 --- /dev/null +++ b/client/core/rs/src/api/read/user.rs @@ -0,0 +1,57 @@ +use derive_empty_traits::EmptyTraits; +use resolver_api::derive::Request; +use serde::{Deserialize, Serialize}; +use typeshare::typeshare; + +use crate::entities::{api_key::ApiKey, user::User}; + +use super::MonitorReadRequest; + +/// Gets list of api keys for the calling user. +/// Response: [ListApiKeysResponse] +#[typeshare] +#[derive( + Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, +)] +#[empty_traits(MonitorReadRequest)] +#[response(ListApiKeysResponse)] +pub struct ListApiKeys {} + +#[typeshare] +pub type ListApiKeysResponse = Vec; + +// + +/// Gets list of monitor users. +/// **Admin only.** +/// Response: [ListUsersResponse] +#[typeshare] +#[derive( + Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, +)] +#[empty_traits(MonitorReadRequest)] +#[response(ListUsersResponse)] +pub struct ListUsers {} + +#[typeshare] +pub type ListUsersResponse = Vec; + +// + +/// Gets the username of a specific user. +/// Response: [GetUsernameResponse] +#[typeshare] +#[derive( + Serialize, Deserialize, Debug, Clone, Request, EmptyTraits, +)] +#[empty_traits(MonitorReadRequest)] +#[response(GetUsernameResponse)] +pub struct GetUsername { + pub user_id: String, +} + +#[typeshare] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct GetUsernameResponse { + pub username: String, +} diff --git a/client/core/ts/src/responses.ts b/client/core/ts/src/responses.ts index e2e65cfd4..8838a87ee 100644 --- a/client/core/ts/src/responses.ts +++ b/client/core/ts/src/responses.ts @@ -13,7 +13,7 @@ export type ReadResponses = { GetCoreInfo: Types.GetCoreInfoResponse; // ==== USER ==== - GetUsers: Types.GetUsersResponse; + ListUsers: Types.ListUsersResponse; GetUsername: Types.GetUsernameResponse; ListApiKeys: Types.ListApiKeysResponse; ListPermissions: Types.ListPermissionsResponse; diff --git a/client/core/ts/src/types.ts b/client/core/ts/src/types.ts index 04244b515..1e614a1a6 100644 --- a/client/core/ts/src/types.ts +++ b/client/core/ts/src/types.ts @@ -500,25 +500,6 @@ export interface DeploymentActionState { export type GetDeploymentActionStateResponse = DeploymentActionState; -export interface ApiKey { - /** Unique key associated with secret */ - key: string; - /** Hash of the secret */ - secret: string; - /** User associated with the api key */ - user_id: string; - /** Name associated with the api key for management */ - name: string; - /** Timestamp of key creation */ - created_at: I64; - /** Expiry of key, or 0 if never expires */ - expires: I64; -} - -export type ListApiKeysResponse = ApiKey[]; - -export type GetUsersResponse = User[]; - export type UserTarget = /** User Id */ | { type: "User", id: string } @@ -1005,6 +986,25 @@ export interface Update { export type GetUpdateResponse = Update; +export interface ApiKey { + /** Unique key associated with secret */ + key: string; + /** Hash of the secret */ + secret: string; + /** User associated with the api key */ + user_id: string; + /** Name associated with the api key for management */ + name: string; + /** Timestamp of key creation */ + created_at: I64; + /** Expiry of key, or 0 if never expires */ + expires: I64; +} + +export type ListApiKeysResponse = ApiKey[]; + +export type ListUsersResponse = User[]; + export interface UserGroup { /** * The Mongo ID of the UserGroup. @@ -1443,20 +1443,6 @@ export interface GetVersionResponse { version: string; } -export interface ListApiKeys { -} - -export interface GetUsers { -} - -export interface GetUsername { - user_id: string; -} - -export interface GetUsernameResponse { - username: string; -} - export interface GetCoreInfo { } @@ -1699,6 +1685,33 @@ export interface ListUpdatesResponse { next_page?: number; } +/** + * Gets list of api keys for the calling user. + * Response: [ListApiKeysResponse] + */ +export interface ListApiKeys { +} + +/** + * Gets list of monitor users. + * **Admin only.** + * Response: [ListUsersResponse] + */ +export interface ListUsers { +} + +/** + * Gets the username of a specific user. + * Response: [GetUsernameResponse] + */ +export interface GetUsername { + user_id: string; +} + +export interface GetUsernameResponse { + username: string; +} + export interface GetUserGroup { /** Name or Id */ user_group: string; @@ -2135,7 +2148,7 @@ export type ExecuteRequest = export type ReadRequest = | { type: "GetVersion", params: GetVersion } | { type: "GetCoreInfo", params: GetCoreInfo } - | { type: "GetUsers", params: GetUsers } + | { type: "ListUsers", params: ListUsers } | { type: "GetUsername", params: GetUsername } | { type: "ListApiKeys", params: ListApiKeys } | { type: "ListPermissions", params: ListPermissions } diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 1cebcb3d7..7071183b6 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -60,5 +60,28 @@ export function version_is_none({ major, minor, patch }: Types.Version) { export function resource_name(type: UsableResource, id: string) { const Components = ResourceComponents[type]; - return Components.name(id) -} \ No newline at end of file + return Components.name(id); +} + +export const level_to_number = (level: Types.PermissionLevel | undefined) => { + switch (level) { + case undefined: + return 0; + case Types.PermissionLevel.None: + return 0; + case Types.PermissionLevel.Read: + return 1; + case Types.PermissionLevel.Execute: + return 2; + case Types.PermissionLevel.Write: + return 3; + } +}; + +export const has_minimum_permissions = ( + level: Types.PermissionLevel | undefined, + greater_than: Types.PermissionLevel +) => { + if (!level) return false; + return level_to_number(level) >= level_to_number(greater_than); +}; diff --git a/frontend/src/pages/resource.tsx b/frontend/src/pages/resource.tsx index b6716b00b..0499e4389 100644 --- a/frontend/src/pages/resource.tsx +++ b/frontend/src/pages/resource.tsx @@ -12,6 +12,7 @@ import { useResourceParamType, useSetTitle, } from "@lib/hooks"; +import { has_minimum_permissions } from "@lib/utils"; import { Types } from "@monitor/client"; import { AlertTriangle, Clapperboard } from "lucide-react"; import { Fragment } from "react"; @@ -29,11 +30,10 @@ export const Resource = () => { const Components = ResourceComponents[type]; - const canExecute = perms - ? [Types.PermissionLevel.Execute, Types.PermissionLevel.Write].includes( - perms - ) - : false; + const canExecute = has_minimum_permissions( + perms, + Types.PermissionLevel.Execute + ); const canWrite = perms === Types.PermissionLevel.Write; return ( diff --git a/frontend/src/pages/users.tsx b/frontend/src/pages/users.tsx index 51dc2a072..6e0d9a349 100644 --- a/frontend/src/pages/users.tsx +++ b/frontend/src/pages/users.tsx @@ -4,7 +4,7 @@ import { ResourceLink } from "@components/resources/common"; import { ConfirmButton } from "@components/util"; import { text_color_class_by_intention } from "@lib/color"; import { useInvalidate, useRead, useSetTitle, useWrite } from "@lib/hooks"; -import { resource_name } from "@lib/utils"; +import { level_to_number, resource_name } from "@lib/utils"; import { Types } from "@monitor/client"; import { UsableResource } from "@types"; import { DataTable, SortableHeader } from "@ui/data-table"; @@ -26,35 +26,48 @@ import { useNavigate, useParams } from "react-router-dom"; export const UsersPage = () => { useSetTitle("Users"); const nav = useNavigate(); + const groups = useRead("ListUserGroups", {}).data; const users = useRead("GetUsers", {}).data; + const [search, setSearch] = useState(""); return ( - - (user.admin ? "Admin" : "User"), - }, - { - header: "Enabled", - cell: ({ row }) => { - const enabledClass = row.original.enabled - ? text_color_class_by_intention("Good") - : text_color_class_by_intention("Critical"); - return ( -
- {row.original.enabled ? "Enabled" : "Disabled"} -
- ); + setSearch(e.target.value)} + className="w-[250px]" + /> + } + > +
+ (user.admin ? "Admin" : "User"), }, - }, - ]} - onRowClick={(user) => nav(`/users/${user._id!.$oid}`)} - /> + { + header: "Enabled", + cell: ({ row }) => { + const enabledClass = row.original.enabled + ? text_color_class_by_intention("Good") + : text_color_class_by_intention("Critical"); + return ( +
+ {row.original.enabled ? "Enabled" : "Disabled"} +
+ ); + }, + }, + ]} + onRowClick={(user) => nav(`/users/${user._id!.$oid}`)} + /> +
); }; @@ -323,8 +336,8 @@ const PermissionsTable = ({ { accessorKey: "level", sortingFn: (a, b) => { - const al = levelToNumber(a.original.level); - const bl = levelToNumber(b.original.level); + const al = level_to_number(a.original.level); + const bl = level_to_number(b.original.level); const dif = al - bl; return dif === 0 ? 0 : dif / Math.abs(dif); }, @@ -364,18 +377,3 @@ const PermissionsTable = ({ ); }; - -const levelToNumber = (level: Types.PermissionLevel | undefined) => { - switch (level) { - case undefined: - return 0; - case Types.PermissionLevel.None: - return 0; - case Types.PermissionLevel.Read: - return 1; - case Types.PermissionLevel.Execute: - return 2; - case Types.PermissionLevel.Write: - return 3; - } -};