use std::convert::TryFrom;
use std::fmt::Debug;
use tonic::transport::Channel;
use tracing::{instrument, trace};
use crate::data::DamlResult;
use crate::data::user::{DamlUser, DamlUserRight};
use crate::grpc_protobuf::com::daml::ledger::api::v2::admin::user_management_service_client::UserManagementServiceClient;
use crate::grpc_protobuf::com::daml::ledger::api::v2::admin::{
CreateUserRequest, DeleteUserRequest, GetUserRequest, GrantUserRightsRequest, ListUserRightsRequest,
ListUsersRequest, RevokeUserRightsRequest, Right, UpdateUserIdentityProviderIdRequest, UpdateUserRequest,
};
use crate::service::common::make_request;
use crate::util::Required;
#[derive(Debug)]
pub struct DamlUserManagementService<'a> {
channel: Channel,
auth_token: Option<&'a str>,
}
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct DamlUserPage {
pub users: Vec<DamlUser>,
pub next_page_token: String,
}
impl<'a> DamlUserManagementService<'a> {
pub fn new(channel: Channel, auth_token: Option<&'a str>) -> Self {
Self {
channel,
auth_token,
}
}
pub fn with_token(self, auth_token: &'a str) -> Self {
Self {
auth_token: Some(auth_token),
..self
}
}
#[instrument(skip(self, rights))]
pub async fn create_user(
&self,
user: DamlUser,
rights: impl IntoIterator<Item = DamlUserRight>,
) -> DamlResult<DamlUser> {
let payload = CreateUserRequest {
user: Some(user.into()),
rights: rights.into_iter().map(Right::from).collect(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().create_user(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
Ok(DamlUser::from(response.user.req()?))
}
#[instrument(skip(self))]
pub async fn get_user(
&self,
user_id: impl Into<String> + Debug,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<DamlUser> {
let payload = GetUserRequest {
user_id: user_id.into(),
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().get_user(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
Ok(DamlUser::from(response.user.req()?))
}
#[instrument(skip(self, update_paths))]
pub async fn update_user(
&self,
user: DamlUser,
update_paths: impl IntoIterator<Item = String>,
) -> DamlResult<DamlUser> {
let payload = UpdateUserRequest {
user: Some(user.into()),
update_mask: Some(prost_types::FieldMask {
paths: update_paths.into_iter().collect(),
}),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().update_user(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
Ok(DamlUser::from(response.user.req()?))
}
#[instrument(skip(self))]
pub async fn delete_user(
&self,
user_id: impl Into<String> + Debug,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<()> {
let payload = DeleteUserRequest {
user_id: user_id.into(),
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
self.client().delete_user(make_request(payload, self.auth_token)?).await?;
Ok(())
}
#[instrument(skip(self))]
pub async fn list_users(
&self,
page_token: impl Into<String> + Debug,
page_size: i32,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<DamlUserPage> {
let payload = ListUsersRequest {
page_token: page_token.into(),
page_size,
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().list_users(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
Ok(DamlUserPage {
users: response.users.into_iter().map(DamlUser::from).collect(),
next_page_token: response.next_page_token,
})
}
#[instrument(skip(self, rights))]
pub async fn grant_user_rights(
&self,
user_id: impl Into<String> + Debug,
rights: impl IntoIterator<Item = DamlUserRight>,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<Vec<DamlUserRight>> {
let payload = GrantUserRightsRequest {
user_id: user_id.into(),
rights: rights.into_iter().map(Right::from).collect(),
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().grant_user_rights(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
response.newly_granted_rights.into_iter().map(DamlUserRight::try_from).collect()
}
#[instrument(skip(self, rights))]
pub async fn revoke_user_rights(
&self,
user_id: impl Into<String> + Debug,
rights: impl IntoIterator<Item = DamlUserRight>,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<Vec<DamlUserRight>> {
let payload = RevokeUserRightsRequest {
user_id: user_id.into(),
rights: rights.into_iter().map(Right::from).collect(),
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().revoke_user_rights(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
response.newly_revoked_rights.into_iter().map(DamlUserRight::try_from).collect()
}
#[instrument(skip(self))]
pub async fn list_user_rights(
&self,
user_id: impl Into<String> + Debug,
identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<Vec<DamlUserRight>> {
let payload = ListUserRightsRequest {
user_id: user_id.into(),
identity_provider_id: identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
let response = self.client().list_user_rights(make_request(payload, self.auth_token)?).await?.into_inner();
trace!(?response);
response.rights.into_iter().map(DamlUserRight::try_from).collect()
}
#[instrument(skip(self))]
pub async fn update_user_identity_provider_id(
&self,
user_id: impl Into<String> + Debug,
source_identity_provider_id: impl Into<String> + Debug,
target_identity_provider_id: impl Into<String> + Debug,
) -> DamlResult<()> {
let payload = UpdateUserIdentityProviderIdRequest {
user_id: user_id.into(),
source_identity_provider_id: source_identity_provider_id.into(),
target_identity_provider_id: target_identity_provider_id.into(),
};
trace!(payload = ?payload, token = ?self.auth_token);
self.client().update_user_identity_provider_id(make_request(payload, self.auth_token)?).await?;
Ok(())
}
fn client(&self) -> UserManagementServiceClient<Channel> {
UserManagementServiceClient::new(self.channel.clone())
}
}