1use crate::basic::dto::iam_filer_dto::IamRoleFilterReq;
2use crate::basic::dto::iam_role_dto::{IamRoleRelAccountCertResp, IamRoleSummaryResp};
3use bios_basic::rbum::helper::rbum_scope_helper::check_without_owner_and_unsafe_fill_ctx;
4use bios_basic::rbum::serv::rbum_crud_serv::RbumCrudOperation;
5use bios_basic::rbum::serv::rbum_item_serv::{RbumItemCrudOperation, RbumItemServ};
6use itertools::Itertools;
7use tardis::log::error;
8
9use crate::basic::serv::iam_app_serv::IamAppServ;
10use crate::basic::serv::iam_cert_serv::IamCertServ;
11use crate::basic::serv::iam_role_serv::IamRoleServ;
12use crate::iam_config::IamBasicConfigApi;
13use crate::iam_constants::{self, RBUM_SCOPE_LEVEL_APP};
14use bios_basic::helper::request_helper::try_set_real_ip_from_req_to_ctx;
15use bios_basic::process::task_processor::TaskProcessor;
16use bios_basic::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumCertFilterReq};
17use tardis::tokio;
18use tardis::web::context_extractor::TardisContextExtractor;
19use tardis::web::poem::Request;
20use tardis::web::poem_openapi;
21use tardis::web::poem_openapi::param::{Path, Query};
22use tardis::web::web_resp::{TardisApiResult, TardisPage, TardisResp, Void};
23
24#[derive(Clone, Default)]
25pub struct IamCiRoleApi;
26
27#[poem_openapi::OpenApi(prefix_path = "/ci/role", tag = "bios_basic::ApiTag::Interface")]
33impl IamCiRoleApi {
34 #[oai(path = "/system/admin", method = "get")]
38 async fn get_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
39 let funs = iam_constants::get_tardis_inst();
40 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
41 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
42 TardisResp::ok(funs.iam_basic_role_sys_admin_id())
43 }
44
45 #[oai(path = "/tenant/admin", method = "get")]
49 async fn get_sub_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
50 let funs = iam_constants::get_tardis_inst();
51 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
52 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
53 let tenant_admin_role_id =
54 IamRoleServ::get_embed_sub_role_id(&funs.iam_basic_role_tenant_admin_id(), &funs, &IamCertServ::use_sys_or_tenant_ctx_unsafe(ctx.0.clone())?).await?;
55 TardisResp::ok(tenant_admin_role_id)
56 }
57
58 #[oai(path = "/app/admin", method = "get")]
62 async fn get_role_app_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
63 let funs = iam_constants::get_tardis_inst();
64 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
65 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
66 let app_admin_role_id = IamRoleServ::get_embed_sub_role_id(&funs.iam_basic_role_app_admin_id(), &funs, &ctx.0).await?;
67 TardisResp::ok(app_admin_role_id)
68 }
69
70 #[oai(path = "/verify/tenant/admin", method = "get")]
73 async fn get_verify_role_tenant_admin(&self, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<bool> {
74 let funs = iam_constants::get_tardis_inst();
75 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
76 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
77 let mut verify_tenant_admin = false;
78 for role in &ctx.0.roles {
79 if role.contains(&funs.iam_basic_role_tenant_admin_id()) {
80 verify_tenant_admin = true;
81 }
82 }
83 TardisResp::ok(verify_tenant_admin)
84 }
85
86 #[oai(path = "/:id/account/batch/:account_ids", method = "put")]
89 async fn batch_add_rel_account(&self, id: Path<String>, account_ids: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
90 let mut funs = iam_constants::get_tardis_inst();
91 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
92 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
93 funs.begin().await?;
94 let app_id = IamAppServ::get_id_by_ctx(&ctx.0, &funs)?;
95 let split = account_ids.0.split(',').collect::<Vec<_>>();
96 for s in split {
97 IamAppServ::add_rel_account(&app_id, s, true, &funs, &ctx.0).await?;
98 IamRoleServ::add_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
99 }
100 funs.commit().await?;
101 ctx.0.execute_task().await?;
102 TardisResp::ok(Void {})
103 }
104
105 #[oai(path = "/:id/account/batch/:account_ids", method = "delete")]
108 async fn batch_delete_rel_account(&self, id: Path<String>, account_ids: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
109 let mut funs = iam_constants::get_tardis_inst();
110 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
111 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
112 funs.begin().await?;
113 let split = account_ids.0.split(',').collect::<Vec<_>>();
114 for s in split {
115 IamRoleServ::delete_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
116 }
117 funs.commit().await?;
118 ctx.0.execute_task().await?;
119 TardisResp::ok(Void {})
120 }
121
122 #[oai(path = "/:id/account/:account_id", method = "delete")]
125 async fn delete_rel_account(&self, id: Path<String>, account_id: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
126 let mut funs = iam_constants::get_tardis_inst();
127 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
128 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
129 funs.begin().await?;
130 IamRoleServ::delete_rel_account(&id.0, &account_id.0, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
131 funs.commit().await?;
132 ctx.0.execute_task().await?;
133 TardisResp::ok(Void {})
134 }
135
136 #[oai(path = "/:id/apps/account/batch", method = "put")]
139 async fn batch_add_apps_rel_account(
140 &self,
141 id: Path<String>,
142 app_ids: Query<String>,
143 account_ids: Query<String>,
144 mut ctx: TardisContextExtractor,
145 request: &Request,
146 ) -> TardisApiResult<Option<String>> {
147 let funs = iam_constants::get_tardis_inst();
148 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
149 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
150 let ctx = ctx.0;
151 let ctx_clone = ctx.clone();
152 ctx.add_async_task(Box::new(|| {
153 Box::pin(async move {
154 let task_handle = tokio::spawn(async move {
155 let mut funs = iam_constants::get_tardis_inst();
156 if let Err(err) = funs.begin().await {
157 error!("[IAM] batch_add_apps_rel_account begin error: {:?}", err);
158 return;
159 }
160 let apps_split: Vec<&str> = app_ids.0.split(',').collect::<Vec<_>>();
161 let account_split: Vec<&str> = account_ids.0.split(',').collect::<Vec<_>>();
162 for app_id in apps_split {
163 let mock_app_ctx = IamCertServ::try_use_app_ctx(ctx_clone.clone(), Some(app_id.to_string())).unwrap_or(ctx_clone.clone());
164 for account_id in account_split.clone() {
165 let _ = IamAppServ::add_rel_account(app_id, account_id, true, &funs, &mock_app_ctx).await;
166 let _ = IamRoleServ::add_rel_account(&id.0, account_id, Some(RBUM_SCOPE_LEVEL_APP), &funs, &mock_app_ctx).await;
167 }
168 }
169 if let Err(err) = funs.commit().await {
170 error!("[IAM] batch_add_apps_rel_account commit error: {:?}", err);
171 }
172 });
173 task_handle.await.unwrap();
174 Ok(())
175 })
176 }))
177 .await?;
178 ctx.execute_task().await?;
179 if let Some(task_id) = TaskProcessor::get_task_id_with_ctx(&ctx).await? {
180 TardisResp::accepted(Some(task_id))
181 } else {
182 TardisResp::ok(None)
183 }
184 }
185
186 #[oai(path = "/:id/apps/account/batch", method = "delete")]
189 async fn batch_delete_apps_rel_account(
190 &self,
191 id: Path<String>,
192 app_ids: Query<String>,
193 account_ids: Query<String>,
194 mut ctx: TardisContextExtractor,
195 request: &Request,
196 ) -> TardisApiResult<Void> {
197 let mut funs = iam_constants::get_tardis_inst();
198 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
199 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
200 let ctx = ctx.0;
201 funs.begin().await?;
202 let apps_split: Vec<&str> = app_ids.0.split(',').collect::<Vec<_>>();
203 let account_split: Vec<&str> = account_ids.0.split(',').collect::<Vec<_>>();
204 for app_id in apps_split {
205 let mock_app_ctx = IamCertServ::try_use_app_ctx(ctx.clone(), Some(app_id.to_string()))?;
206 for account_id in account_split.clone() {
207 IamRoleServ::delete_rel_account(&id.0, account_id, Some(RBUM_SCOPE_LEVEL_APP), &funs, &mock_app_ctx).await?;
208 }
209 }
210 funs.commit().await?;
211 ctx.execute_task().await?;
212 TardisResp::ok(Void {})
213 }
214
215 #[oai(path = "/:role_code/accounts", method = "get")]
218 async fn get_rel_accounts(&self, role_code: Path<String>, mut ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Vec<IamRoleRelAccountCertResp>> {
219 let funs = iam_constants::get_tardis_inst();
220 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
221 try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
222 let role_id = RbumItemServ::find_one_rbum(
223 &RbumBasicFilterReq {
224 code: Some(role_code.0),
225 ..Default::default()
226 },
227 &funs,
228 &ctx.0,
229 )
230 .await?
231 .ok_or_else(|| funs.err().internal_error("iam_ci_role", "get_rel_accounts", "role is not found", "404-iam-res-not-exist"))?
232 .id;
233 let account_ids = IamRoleServ::find_id_rel_accounts(&role_id, None, None, &funs, &ctx.0).await?;
234 let certs = IamCertServ::find_certs(
235 &RbumCertFilterReq {
236 basic: RbumBasicFilterReq {
237 with_sub_own_paths: true,
238 ..Default::default()
239 },
240 rel_rbum_ids: Some(account_ids.clone()),
241 ..Default::default()
242 },
243 None,
244 None,
245 &funs,
246 &ctx.0,
247 )
248 .await?
249 .into_iter()
250 .map(|r| (r.rel_rbum_id, r.rel_rbum_cert_conf_name.unwrap_or_default(), r.ak))
251 .collect_vec();
252 let result = account_ids
253 .iter()
254 .map(|account_id| IamRoleRelAccountCertResp {
255 account_id: account_id.clone(),
256 certs: certs.iter().filter(|cert| &cert.0 == account_id).map(|r| (r.1.clone(), r.2.clone())).collect(),
257 })
258 .collect_vec();
259 TardisResp::ok(result)
260 }
261
262 #[allow(clippy::too_many_arguments)]
265 #[oai(path = "/", method = "get")]
266 async fn paginate(
267 &self,
268 id: Query<Option<String>>,
269 name: Query<Option<String>>,
270 app_id: Query<Option<String>>,
271 in_base: Query<Option<bool>>,
272 in_embed: Query<Option<bool>>,
273 extend_role_id: Query<Option<String>>,
274 with_sub: Query<Option<bool>>,
275 page_number: Query<u32>,
276 page_size: Query<u32>,
277 desc_by_create: Query<Option<bool>>,
278 desc_by_update: Query<Option<bool>>,
279 mut ctx: TardisContextExtractor,
280 request: &Request,
281 ) -> TardisApiResult<TardisPage<IamRoleSummaryResp>> {
282 let funs = iam_constants::get_tardis_inst();
283 check_without_owner_and_unsafe_fill_ctx(request, &funs, &mut ctx.0)?;
284 let ctx = IamCertServ::try_use_app_ctx(ctx.0, app_id.0)?;
285 try_set_real_ip_from_req_to_ctx(request, &ctx).await?;
286 let result = IamRoleServ::paginate_items(
287 &IamRoleFilterReq {
288 basic: RbumBasicFilterReq {
289 ids: id.0.map(|id| vec![id]),
290 name: name.0,
291 with_sub_own_paths: with_sub.0.unwrap_or(false),
292 ..Default::default()
293 },
294 in_base: in_base.0,
295 in_embed: in_embed.0,
296 extend_role_id: extend_role_id.0,
297 ..Default::default()
298 },
299 page_number.0,
300 page_size.0,
301 desc_by_create.0,
302 desc_by_update.0,
303 &funs,
304 &ctx,
305 )
306 .await?;
307 ctx.execute_task().await?;
308 TardisResp::ok(result)
309 }
310}