This commit is contained in:
mbecker20
2024-04-28 01:04:36 -07:00
parent e7a4a364c2
commit d06b2abea4
16 changed files with 211 additions and 63 deletions

View File

@@ -4,8 +4,9 @@ use anyhow::{anyhow, Context};
use async_trait::async_trait;
use futures::future::join_all;
use monitor_client::{
api::execute::{
CancelBuild, CancelBuildResponse, Deploy, RunBuild,
api::{
execute::{CancelBuild, CancelBuildResponse, Deploy, RunBuild},
write::LaunchAwsServerConfig,
},
entities::{
all_logs_success,
@@ -342,8 +343,11 @@ async fn get_aws_builder(
build.name,
build.config.version.to_string()
);
let Ec2Instance { instance_id, ip } =
launch_ec2_instance(&instance_name, &config).await?;
let Ec2Instance { instance_id, ip } = launch_ec2_instance(
&instance_name,
LaunchAwsServerConfig::from_builder_config(&config),
)
.await?;
info!("ec2 instance launched");

View File

@@ -39,6 +39,11 @@ impl Resolve<CreateBuild, User> for State {
CreateBuild { name, mut config }: CreateBuild,
user: User,
) -> anyhow::Result<Build> {
if !user.admin && !user.create_build_permissions {
return Err(anyhow!(
"User does not have create build permissions."
));
}
let name = to_monitor_name(&name);
if ObjectId::from_str(&name).is_ok() {
return Err(anyhow!("valid ObjectIds cannot be used as names"));
@@ -102,6 +107,11 @@ impl Resolve<CopyBuild, User> for State {
CopyBuild { name, id }: CopyBuild,
user: User,
) -> anyhow::Result<Build> {
if !user.admin && !user.create_build_permissions {
return Err(anyhow!(
"User does not have create build permissions."
));
}
let name = to_monitor_name(&name);
let Build {
config,

View File

@@ -286,11 +286,11 @@ impl Resolve<CreateNetwork, User> for State {
#[instrument(name = "CreateNetwork", skip(self, user))]
async fn resolve(
&self,
CreateNetwork { server_id, name }: CreateNetwork,
CreateNetwork { server, name }: CreateNetwork,
user: User,
) -> anyhow::Result<Update> {
let server = Server::get_resource_check_permissions(
&server_id,
&server,
&user,
PermissionLevel::Write,
)
@@ -324,11 +324,11 @@ impl Resolve<DeleteNetwork, User> for State {
#[instrument(name = "DeleteNetwork", skip(self, user))]
async fn resolve(
&self,
DeleteNetwork { server_id, name }: DeleteNetwork,
DeleteNetwork { server, name }: DeleteNetwork,
user: User,
) -> anyhow::Result<Update> {
let server = Server::get_resource_check_permissions(
&server_id,
&server,
&user,
PermissionLevel::Write,
)

View File

@@ -52,13 +52,10 @@ async fn create_ec2_client(region: String) -> Client {
}
#[instrument]
pub async fn launch_ec2_instance<T>(
pub async fn launch_ec2_instance(
name: &str,
config: T,
) -> anyhow::Result<Ec2Instance>
where
T: Into<LaunchAwsServerConfig> + std::fmt::Debug,
{
config: LaunchAwsServerConfig,
) -> anyhow::Result<Ec2Instance> {
let LaunchAwsServerConfig {
region,
instance_type,
@@ -69,7 +66,7 @@ where
key_pair_name,
assign_public_ip,
use_public_ip,
} = config.into();
} = config;
let instance_type = handle_unknown_instance_type(
InstanceType::from(instance_type.as_str()),
)?;

View File

@@ -177,7 +177,8 @@ pub struct CoreConfig {
#[serde(default = "default_title")]
pub title: String,
/// The host to use with oauth redirect url, whatever host the user hits to access monitor. eg 'https://monitor.mogh.tech'
/// The host to use with oauth redirect url, whatever host
/// the user hits to access monitor. eg `https://monitor.mogh.tech`
#[serde(default)]
pub host: String,

View File

@@ -7,8 +7,19 @@ use crate::entities::user::User;
pub trait MonitorAuthRequest: HasResponse {}
/// JSON containing an authentication token.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct JwtResponse {
/// A token the user can use to authenticate their requests.
pub jwt: String,
}
//
/// Non authenticated route to see the available options
/// users have to login to monitor, eg. local auth, github, google.
/// Response: [GetLoginOptionsResponse].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -17,16 +28,25 @@ pub trait MonitorAuthRequest: HasResponse {}
#[response(GetLoginOptionsResponse)]
pub struct GetLoginOptions {}
/// The response for [GetLoginOptions].
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct GetLoginOptionsResponse {
/// Whether local auth is enabled.
pub local: bool,
/// Whether github login is enabled.
pub github: bool,
/// Whether google login is enabled.
pub google: bool,
}
//
/// Create a new local user account. Will fail if a user with the
/// given username already exists.
/// Response: [CreateLocalUserResponse].
///
/// Note. This method is only available if the core api has `local_auth` enabled.
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -34,18 +54,23 @@ pub struct GetLoginOptionsResponse {
#[empty_traits(MonitorAuthRequest)]
#[response(CreateLocalUserResponse)]
pub struct CreateLocalUser {
/// The username for the new user.
pub username: String,
/// The password for the new user.
/// This cannot be retreived later.
pub password: String,
}
/// Response for [CreateLocalUser].
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CreateLocalUserResponse {
pub jwt: String,
}
pub type CreateLocalUserResponse = JwtResponse;
//
/// Login as a local user. Will fail if the users credentials don't match
/// any local user.
///
/// Note. This method is only available if the core api has `local_auth` enabled.
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -53,18 +78,21 @@ pub struct CreateLocalUserResponse {
#[empty_traits(MonitorAuthRequest)]
#[response(LoginLocalUserResponse)]
pub struct LoginLocalUser {
/// The user's username
pub username: String,
/// The user's password
pub password: String,
}
/// The response for [LoginLocalUser]
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LoginLocalUserResponse {
pub jwt: String,
}
pub type LoginLocalUserResponse = JwtResponse;
//
/// Exchange a single use exchange token (safe for transport in url query)
/// for a jwt.
/// Response: [ExchangeForJwtResponse].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -72,17 +100,18 @@ pub struct LoginLocalUserResponse {
#[empty_traits(MonitorAuthRequest)]
#[response(ExchangeForJwtResponse)]
pub struct ExchangeForJwt {
/// The 'exchange token'
pub token: String,
}
/// Response for [ExchangeForJwt].
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ExchangeForJwtResponse {
pub jwt: String,
}
pub type ExchangeForJwtResponse = JwtResponse;
//
/// Get the user extracted from the request headers.
/// Response: [User].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,

View File

@@ -1,3 +1,8 @@
//! # Monitor core API
//!
//! Monitor core exposes an HTTP api using standard JSON serialization.
//!
pub mod auth;
pub mod execute;
pub mod read;

View File

@@ -3,12 +3,17 @@ use resolver_api::derive::Request;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::I64;
use crate::entities::{NoData, I64};
use super::MonitorWriteRequest;
//
/// Create an api key for the calling user.
/// Response: [CreateApiKeyResponse].
///
/// Note. After the response is served, there will be no way
/// to get the secret later.
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -16,12 +21,16 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(CreateApiKeyResponse)]
pub struct CreateApiKey {
/// The name for the api key.
pub name: String,
/// A unix timestamp in millseconds specifying api key expire time.
/// Default is 0, which means no expiry.
#[serde(default)]
pub expires: I64,
}
/// Response for [CreateApiKey].
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CreateApiKeyResponse {
@@ -29,12 +38,16 @@ pub struct CreateApiKeyResponse {
pub key: String,
/// X-API-SECRET
///
/// Note.
/// There is no way to get the secret again after it is distributed in this message
pub secret: String,
}
//
/// Delete an api key for the calling user.
/// Response: [NoData]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -42,16 +55,17 @@ pub struct CreateApiKeyResponse {
#[empty_traits(MonitorWriteRequest)]
#[response(DeleteApiKeyResponse)]
pub struct DeleteApiKey {
/// The key which the user intends to delete.
pub key: String,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeleteApiKeyResponse {}
pub type DeleteApiKeyResponse = NoData;
//
/// ADMIN ONLY
/// Admin only method to create an api key for a service user.
/// Response: [CreateApiKeyResponse].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -61,7 +75,10 @@ pub struct DeleteApiKeyResponse {}
pub struct CreateApiKeyForServiceUser {
/// Must be service user
pub user_id: String,
/// The name for the api key
pub name: String,
/// A unix timestamp in millseconds specifying api key expire time.
/// Default is 0, which means no expiry.
#[serde(default)]
pub expires: I64,
}
@@ -71,7 +88,8 @@ pub type CreateApiKeyForServiceUserResponse = CreateApiKeyResponse;
//
/// ADMIN ONLY
/// Admin only method to delete an api key for a service user.
/// Response: [NoData].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -83,5 +101,4 @@ pub struct DeleteApiKeyForServiceUser {
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeleteApiKeyForServiceUserResponse {}
pub type DeleteApiKeyForServiceUserResponse = NoData;

View File

@@ -3,10 +3,12 @@ use resolver_api::derive::Request;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::update::ResourceTarget;
use crate::entities::{update::ResourceTarget, NoData};
use super::MonitorWriteRequest;
/// Update a resources description.
/// Response: [NoData].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -19,5 +21,4 @@ pub struct UpdateDescription {
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdateDescriptionResponse {}
pub type UpdateDescriptionResponse = NoData;

View File

@@ -7,6 +7,8 @@ use crate::entities::{builder::AwsBuilderConfig, update::Update};
use super::MonitorWriteRequest;
/// Launch an EC2 instance with the specified config.
/// Response: [Update].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -14,43 +16,66 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(Update)]
pub struct LaunchServer {
/// The name of the created server.
pub name: String,
/// The configuration used to launch the server.
pub config: LaunchServerConfig,
}
/// The cloud specific config.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", content = "params")]
pub enum LaunchServerConfig {
/// Launch a server on AWS.
Aws(LaunchAwsServerConfig),
}
/// Aws EC2 instance config.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LaunchAwsServerConfig {
/// The aws region to launch the server in, eg. us-east-1
pub region: String,
/// The instance type to launch, eg. c5.2xlarge
pub instance_type: String,
/// Specify the EBS volumes to attach.
pub volumes: Vec<AwsVolume>,
/// Specify the ami id to use. Must be set up to start the periphery binary on startup.
pub ami_id: String,
/// The subnet to assign to the instance.
pub subnet_id: String,
/// The security groups to give to the instance.
pub security_group_ids: Vec<String>,
/// The key pair name to give to the instance in case SSH access required.
pub key_pair_name: String,
/// Assign a public ip to the instance. Depending on how your network is
/// setup, this may be required for the instance to reach the public internet.
pub assign_public_ip: bool,
/// Use the instances public ip as the address for the server.
/// Could be used when build instances are created in another non-interconnected network to the core api.
pub use_public_ip: bool,
}
/// For information on AWS volumes, see
/// `<https://docs.aws.amazon.com/ebs/latest/userguide/ebs-volume-types.html>`.
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct AwsVolume {
/// The device name (for example, `/dev/sda1` or `xvdh`).
pub device_name: String,
/// The size of the volume in GB
pub size_gb: i32,
/// The type of volume, eg gp2, gp3, io1
pub volume_type: Option<String>,
/// The iops of the volume, or AWS default.
pub iops: Option<i32>,
/// The throughput of the volume, or AWS default.
pub throughput: Option<i32>,
}
impl From<&AwsBuilderConfig> for LaunchAwsServerConfig {
fn from(value: &AwsBuilderConfig) -> Self {
impl LaunchAwsServerConfig {
pub fn from_builder_config(value: &AwsBuilderConfig) -> Self {
Self {
region: value.region.clone(),
instance_type: value.instance_type.clone(),

View File

@@ -6,10 +6,13 @@ use typeshare::typeshare;
use crate::entities::{
permission::{PermissionLevel, UserTarget},
update::ResourceTarget,
NoData,
};
use super::MonitorWriteRequest;
/// Update a user or user groups permission on a resource.
/// Response: [NoData].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -17,17 +20,21 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(UpdatePermissionOnTargetResponse)]
pub struct UpdatePermissionOnTarget {
/// Specify the user or user group.
pub user_target: UserTarget,
/// Specify the target resource.
pub resource_target: ResourceTarget,
/// Specify the permission level.
pub permission: PermissionLevel,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdatePermissionOnTargetResponse {}
pub type UpdatePermissionOnTargetResponse = NoData;
//
/// Update a user's "base" permissions, eg. "enabled".
/// Response: [NoData].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -35,12 +42,15 @@ pub struct UpdatePermissionOnTargetResponse {}
#[empty_traits(MonitorWriteRequest)]
#[response(UpdateUserBasePermissionsResponse)]
pub struct UpdateUserBasePermissions {
/// The target user.
pub user_id: String,
/// If specified, will update users enabled state.
pub enabled: Option<bool>,
/// If specified, will update user's ability to create servers.
pub create_servers: Option<bool>,
/// If specified, will update user's ability to create builds.
pub create_builds: Option<bool>,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdateUserBasePermissionsResponse {}
pub type UpdateUserBasePermissionsResponse = NoData;

View File

@@ -11,6 +11,7 @@ use super::MonitorWriteRequest;
//
/// Create a procedure. Response: [Procedure].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -18,7 +19,9 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(CreateProcedureResponse)]
pub struct CreateProcedure {
/// The name given to newly created build.
pub name: String,
/// Optional partial config to initialize the procedure with.
pub config: _PartialProcedureConfig,
}
@@ -27,6 +30,8 @@ pub type CreateProcedureResponse = Procedure;
//
/// Creates a new procedure with given `name` and the configuration
/// of the procedure at the given `id`. Response: [Procedure].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -34,7 +39,9 @@ pub type CreateProcedureResponse = Procedure;
#[empty_traits(MonitorWriteRequest)]
#[response(CopyProcedureResponse)]
pub struct CopyProcedure {
/// The name of the new procedure.
pub name: String,
/// The id of the procedure to copy.
pub id: String,
}
@@ -43,6 +50,8 @@ pub type CopyProcedureResponse = Procedure;
//
/// Deletes the procedure at the given id, and returns the deleted procedure.
/// Response: [Procedure]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -50,6 +59,7 @@ pub type CopyProcedureResponse = Procedure;
#[empty_traits(MonitorWriteRequest)]
#[response(DeleteProcedureResponse)]
pub struct DeleteProcedure {
/// The id of the procedure to delete.
pub id: String,
}
@@ -58,6 +68,14 @@ pub type DeleteProcedureResponse = Procedure;
//
/// Update the procedure at the given id, and return the updated procedure.
/// Response: [Procedure].
///
/// Note. This method updates only the fields which are set in the [_PartialProcedureConfig],
/// effectively merging diffs into the final document.
/// This is helpful when multiple users are using
/// the same resources concurrently by ensuring no unintentional
/// field changes occur from out of date local state.
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,

View File

@@ -45,7 +45,7 @@ pub struct DeleteServer {
/// Update the server at the given id, and return the updated server.
/// Response: [Server].
///
///
/// Note. This method updates only the fields which are set in the [_PartialServerConfig],
/// effectively merging diffs into the final document.
/// This is helpful when multiple users are using
@@ -82,6 +82,8 @@ pub struct RenameServer {
//
/// Create a docker network on the server.
/// Respone: [Update]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -89,12 +91,16 @@ pub struct RenameServer {
#[empty_traits(MonitorWriteRequest)]
#[response(Update)]
pub struct CreateNetwork {
pub server_id: String,
/// Id or name
pub server: String,
/// The name of the network to create.
pub name: String,
}
//
/// Delete a docker network.
/// Response: [Update]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -102,6 +108,8 @@ pub struct CreateNetwork {
#[empty_traits(MonitorWriteRequest)]
#[response(Update)]
pub struct DeleteNetwork {
pub server_id: String,
/// Id or name.
pub server: String,
/// The name of the network to delete.
pub name: String,
}

View File

@@ -3,12 +3,13 @@ use resolver_api::derive::Request;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::{tag::Tag, update::ResourceTarget};
use crate::entities::{tag::Tag, update::ResourceTarget, NoData};
use super::MonitorWriteRequest;
//
/// Create a tag. Response: [Tag].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -16,11 +17,15 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(Tag)]
pub struct CreateTag {
/// The name of the tag.
pub name: String,
}
//
/// Delete a tag, and return the deleted tag. Response: [Tag].
///
/// Note. Will also remove this tag from all attached resources.
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -28,11 +33,13 @@ pub struct CreateTag {
#[empty_traits(MonitorWriteRequest)]
#[response(Tag)]
pub struct DeleteTag {
/// The id of the tag to delete.
pub id: String,
}
//
/// Rename a tag at id. Response: [Tag].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -40,12 +47,16 @@ pub struct DeleteTag {
#[empty_traits(MonitorWriteRequest)]
#[response(Tag)]
pub struct RenameTag {
/// The id of the tag to rename.
pub id: String,
/// The new name of the tag.
pub name: String,
}
//
/// Update the tags on a resource.
/// Response: [NoData]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -59,7 +70,6 @@ pub struct UpdateTagsOnResource {
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UpdateTagsOnResourceResponse {}
pub type UpdateTagsOnResourceResponse = NoData;
//

View File

@@ -3,12 +3,14 @@ use resolver_api::derive::Request;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::{update::ResourceTarget, user::User};
use crate::entities::{update::ResourceTarget, user::User, NoData};
use super::MonitorWriteRequest;
//
/// Push a resource to the front of the users 10 most recently viewed resources.
/// Response: [NoData].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -16,15 +18,18 @@ use super::MonitorWriteRequest;
#[empty_traits(MonitorWriteRequest)]
#[response(PushRecentlyViewedResponse)]
pub struct PushRecentlyViewed {
/// The target to push.
pub resource: ResourceTarget,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PushRecentlyViewedResponse {}
pub type PushRecentlyViewedResponse = NoData;
//
/// Set the time the user last opened the UI updates.
/// Used for unseen notification dot.
/// Response: [NoData]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -34,12 +39,12 @@ pub struct PushRecentlyViewedResponse {}
pub struct SetLastSeenUpdate {}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SetLastSeenUpdateResponse {}
pub type SetLastSeenUpdateResponse = NoData;
//
/// ADMIN ONLY
/// **Admin only.** Create a service user.
/// Response: [User].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -47,7 +52,9 @@ pub struct SetLastSeenUpdateResponse {}
#[empty_traits(MonitorWriteRequest)]
#[response(CreateServiceUserResponse)]
pub struct CreateServiceUser {
/// The username for the service user.
pub username: String,
/// A description for the service user.
pub description: String,
}
@@ -56,7 +63,8 @@ pub type CreateServiceUserResponse = User;
//
/// ADMIN ONLY
/// **Admin only.** Update a service user's description.
/// Response: [User].
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -64,7 +72,9 @@ pub type CreateServiceUserResponse = User;
#[empty_traits(MonitorWriteRequest)]
#[response(UpdateServiceUserDescriptionResponse)]
pub struct UpdateServiceUserDescription {
/// The service user's username
pub username: String,
/// A new description for the service user.
pub description: String,
}

View File

@@ -7,7 +7,7 @@ use crate::entities::user_group::UserGroup;
use super::MonitorWriteRequest;
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Create a user group. Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -21,7 +21,7 @@ pub struct CreateUserGroup {
//
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Rename a user group. Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -37,7 +37,7 @@ pub struct RenameUserGroup {
//
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Delete a user group. Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -51,7 +51,7 @@ pub struct DeleteUserGroup {
//
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Add a user to a user group. Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -67,7 +67,7 @@ pub struct AddUserToUserGroup {
//
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Remove a user from a user group. Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -83,7 +83,8 @@ pub struct RemoveUserFromUserGroup {
//
/// **Admin only.** Response: [UserGroup]
/// **Admin only.** Completely override the user in the group.
/// Response: [UserGroup]
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Request, EmptyTraits,
@@ -91,6 +92,8 @@ pub struct RemoveUserFromUserGroup {
#[empty_traits(MonitorWriteRequest)]
#[response(UserGroup)]
pub struct SetUsersInUserGroup {
/// Id or name.
pub user_group: String,
/// The user ids or usernames to hard set as the group's users.
pub users: Vec<String>,
}