bios_iam/console_app/api/
iam_ca_role_api.rs

1use itertools::Itertools;
2use tardis::basic::error::TardisError;
3use tardis::futures::future::join_all;
4use tardis::web::context_extractor::TardisContextExtractor;
5use tardis::web::poem::Request;
6use tardis::web::poem_openapi;
7use tardis::web::poem_openapi::{param::Path, param::Query, payload::Json};
8use tardis::web::web_resp::{TardisApiResult, TardisPage, TardisResp, Void};
9
10use bios_basic::helper::request_helper::try_set_real_ip_from_req_to_ctx;
11use bios_basic::process::task_processor::TaskProcessor;
12use bios_basic::rbum::dto::rbum_filer_dto::{RbumBasicFilterReq, RbumItemRelFilterReq};
13use bios_basic::rbum::dto::rbum_rel_dto::RbumRelBoneResp;
14use bios_basic::rbum::rbum_enumeration::RbumRelFromKind;
15use bios_basic::rbum::serv::rbum_item_serv::RbumItemCrudOperation;
16
17use crate::basic::dto::iam_filer_dto::{IamAccountFilterReq, IamRoleFilterReq};
18use crate::basic::dto::iam_role_dto::{IamRoleAggAddReq, IamRoleAggCopyReq, IamRoleAggModifyReq, IamRoleDetailResp, IamRoleSummaryResp};
19use crate::basic::serv::iam_account_serv::IamAccountServ;
20use crate::basic::serv::iam_app_serv::IamAppServ;
21use crate::basic::serv::iam_role_serv::IamRoleServ;
22use crate::iam_constants;
23use crate::iam_constants::RBUM_SCOPE_LEVEL_APP;
24use crate::iam_enumeration::{IamRelKind, IamRoleKind};
25
26#[derive(Clone, Default)]
27pub struct IamCaRoleApi;
28
29/// App Console Role API
30/// 应用控制台角色API
31#[poem_openapi::OpenApi(prefix_path = "/ca/role", tag = "bios_basic::ApiTag::App")]
32impl IamCaRoleApi {
33    /// Add Role
34    /// 添加角色
35    #[oai(path = "/", method = "post")]
36    async fn add(&self, mut add_req: Json<IamRoleAggAddReq>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
37        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
38        let mut funs = iam_constants::get_tardis_inst();
39        funs.begin().await?;
40        add_req.0.role.kind = Some(IamRoleKind::App);
41        let result = IamRoleServ::add_role_agg(&mut add_req.0, &funs, &ctx.0).await?;
42        funs.commit().await?;
43        ctx.0.execute_task().await?;
44        TardisResp::ok(result)
45    }
46
47    /// copy Role
48    /// 复制角色
49    #[oai(path = "/copy", method = "post")]
50    async fn copy(&self, mut copy_req: Json<IamRoleAggCopyReq>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<String> {
51        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
52        let mut funs = iam_constants::get_tardis_inst();
53        funs.begin().await?;
54        copy_req.0.role.kind = Some(IamRoleKind::App);
55        let result = IamRoleServ::copy_role_agg(&mut copy_req.0, &funs, &ctx.0).await?;
56        funs.commit().await?;
57        ctx.0.execute_task().await?;
58        TardisResp::ok(result)
59    }
60
61    /// Modify Role By Role Id
62    /// 根据角色ID修改角色
63    ///
64    /// When code = 202, the return value is the asynchronous task id
65    /// 当 code = 202 时,返回值为异步任务ID
66    #[oai(path = "/:id", method = "put")]
67    async fn modify(&self, id: Path<String>, mut modify_req: Json<IamRoleAggModifyReq>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Option<String>> {
68        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
69        let mut funs = iam_constants::get_tardis_inst();
70        funs.begin().await?;
71        IamRoleServ::modify_role_agg(&id.0, &mut modify_req.0, &funs, &ctx.0).await?;
72        funs.commit().await?;
73        ctx.0.execute_task().await?;
74        if let Some(task_id) = TaskProcessor::get_task_id_with_ctx(&ctx.0).await? {
75            TardisResp::accepted(Some(task_id))
76        } else {
77            TardisResp::ok(None)
78        }
79    }
80
81    /// Get Role By Role Id
82    /// 根据角色ID获取角色
83    #[oai(path = "/:id", method = "get")]
84    async fn get(&self, id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<IamRoleDetailResp> {
85        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
86        let funs = iam_constants::get_tardis_inst();
87        let result = IamRoleServ::get_item(
88            &id.0,
89            &IamRoleFilterReq {
90                basic: RbumBasicFilterReq { ..Default::default() },
91                // Only fetch app-level roles
92                kind: Some(IamRoleKind::App),
93                ..Default::default()
94            },
95            &funs,
96            &ctx.0,
97        )
98        .await?;
99        ctx.0.execute_task().await?;
100        TardisResp::ok(result)
101    }
102
103    /// Find Roles
104    /// 查找角色
105    #[oai(path = "/", method = "get")]
106    async fn paginate(
107        &self,
108        id: Query<Option<String>>,
109        name: Query<Option<String>>,
110        in_base: Query<Option<bool>>,
111        in_embed: Query<Option<bool>>,
112        extend_role_id: Query<Option<String>>,
113        page_number: Query<u32>,
114        page_size: Query<u32>,
115        desc_by_create: Query<Option<bool>>,
116        desc_by_update: Query<Option<bool>>,
117        ctx: TardisContextExtractor,
118        request: &Request,
119    ) -> TardisApiResult<TardisPage<IamRoleSummaryResp>> {
120        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
121        let funs = iam_constants::get_tardis_inst();
122        let result = IamRoleServ::paginate_items(
123            &IamRoleFilterReq {
124                basic: RbumBasicFilterReq {
125                    // Only fetch app-level roles
126                    // scope_level: Some(RBUM_SCOPE_LEVEL_APP),
127                    ids: id.0.map(|id| vec![id]),
128                    name: name.0,
129                    ..Default::default()
130                },
131                kind: Some(IamRoleKind::App),
132                in_base: in_base.0,
133                in_embed: in_embed.0,
134                extend_role_id: extend_role_id.0,
135                ..Default::default()
136            },
137            page_number.0,
138            page_size.0,
139            desc_by_create.0,
140            desc_by_update.0,
141            &funs,
142            &ctx.0,
143        )
144        .await?;
145        ctx.0.execute_task().await?;
146        TardisResp::ok(result)
147    }
148
149    /// Delete Role By Role Id
150    /// 根据角色ID删除角色
151    #[oai(path = "/:id", method = "delete")]
152    async fn delete(&self, id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Option<String>> {
153        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
154        let mut funs = iam_constants::get_tardis_inst();
155        funs.begin().await?;
156        let app_role = IamRoleServ::get_item(
157            &id.0,
158            &IamRoleFilterReq {
159                basic: RbumBasicFilterReq {
160                    with_sub_own_paths: true,
161                    ..Default::default()
162                },
163                ..Default::default()
164            },
165            &funs,
166            &ctx.0,
167        )
168        .await?;
169        if app_role.kind != IamRoleKind::App {
170            Err(funs.err().conflict(
171                &IamRoleServ::get_obj_name(),
172                "delete",
173                "This role is not an app role, cannot be deleted",
174                "409-role-is-not-app",
175            ))?;
176        }
177        if app_role.extend_role_id != *"" {
178            Err(funs.err().conflict(&IamRoleServ::get_obj_name(), "delete", "This role is extend role, cannot be deleted", "409-role-is-extend"))?;
179        }
180        IamRoleServ::delete_item_with_all_rels(&id.0, &funs, &ctx.0).await?;
181        funs.commit().await?;
182        ctx.0.execute_task().await?;
183        if let Some(task_id) = TaskProcessor::get_task_id_with_ctx(&ctx.0).await? {
184            TardisResp::accepted(Some(task_id))
185        } else {
186            TardisResp::ok(None)
187        }
188    }
189
190    /// Add Role Rel Account
191    /// 添加角色关联账号
192    #[oai(path = "/:id/account/:account_id", method = "put")]
193    async fn add_rel_account(&self, id: Path<String>, account_id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
194        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
195        let mut funs = iam_constants::get_tardis_inst();
196        funs.begin().await?;
197        let app_id = IamAppServ::get_id_by_ctx(&ctx.0, &funs)?;
198        IamAppServ::add_rel_account(&app_id, &account_id.0, true, &funs, &ctx.0).await?;
199        IamRoleServ::add_rel_account(&id.0, &account_id.0, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
200        funs.commit().await?;
201        ctx.0.execute_task().await?;
202        TardisResp::ok(Void {})
203    }
204
205    /// Batch add Role Rel Account
206    /// 批量添加角色关联账号
207    #[oai(path = "/:id/account/batch/:account_ids", method = "put")]
208    async fn batch_add_rel_account(&self, id: Path<String>, account_ids: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
209        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
210        let mut funs = iam_constants::get_tardis_inst();
211        funs.begin().await?;
212        let app_id = IamAppServ::get_id_by_ctx(&ctx.0, &funs)?;
213        // let split = account_ids.0.split(',').collect::<Vec<_>>();
214        join_all(
215            account_ids
216                .0
217                .split(',')
218                .map(|account_id| async {
219                    IamAppServ::add_rel_account(&app_id, account_id, true, &funs, &ctx.0).await?;
220                    IamRoleServ::add_rel_account(&id.0, account_id, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await
221                })
222                .collect_vec(),
223        )
224        .await
225        .into_iter()
226        .collect::<Result<Vec<()>, TardisError>>()?;
227        // for s in split {
228        //     IamAppServ::add_rel_account(&app_id, s, true, &funs, &ctx.0).await?;
229        //     IamRoleServ::add_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
230        // }
231        funs.commit().await?;
232        ctx.0.execute_task().await?;
233        TardisResp::ok(Void {})
234    }
235
236    /// Delete Role Rel Account
237    /// 删除角色关联账号
238    #[oai(path = "/:id/account/:account_id", method = "delete")]
239    async fn delete_rel_account(&self, id: Path<String>, account_id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
240        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
241        let mut funs = iam_constants::get_tardis_inst();
242        funs.begin().await?;
243        IamRoleServ::delete_rel_account(&id.0, &account_id.0, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
244        funs.commit().await?;
245        ctx.0.execute_task().await?;
246        TardisResp::ok(Void {})
247    }
248
249    /// Batch delete Role Rel Account
250    /// 批量删除角色关联账号
251    #[oai(path = "/:id/account/batch/:account_ids", method = "delete")]
252    async fn batch_delete_rel_account(&self, id: Path<String>, account_ids: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
253        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
254        let mut funs = iam_constants::get_tardis_inst();
255        funs.begin().await?;
256        let split = account_ids.0.split(',').collect::<Vec<_>>();
257        for s in split {
258            IamRoleServ::delete_rel_account(&id.0, s, Some(RBUM_SCOPE_LEVEL_APP), &funs, &ctx.0).await?;
259        }
260        funs.commit().await?;
261        ctx.0.execute_task().await?;
262        TardisResp::ok(Void {})
263    }
264
265    /// Count Rel Accounts By Role Id
266    /// 根据角色ID统计关联账号
267    #[oai(path = "/:id/account/total", method = "get")]
268    async fn count_rel_accounts(&self, id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<u64> {
269        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
270        let funs = iam_constants::get_tardis_inst();
271        let result = IamAccountServ::count_items(
272            &IamAccountFilterReq {
273                rel: IamAppServ::with_app_rel_filter(&ctx.0, &funs)?,
274                rel2: Some(RbumItemRelFilterReq {
275                    rel_by_from: true,
276                    tag: Some(IamRelKind::IamAccountRole.to_string()),
277                    from_rbum_kind: Some(RbumRelFromKind::Item),
278                    rel_item_id: Some(id.0.to_string()),
279                    ..Default::default()
280                }),
281                ..Default::default()
282            },
283            &funs,
284            &ctx.0,
285        )
286        .await?;
287        ctx.0.execute_task().await?;
288        TardisResp::ok(result)
289    }
290
291    /// Add Role Rel Res
292    /// 添加角色关联资源
293    #[oai(path = "/:id/res/:res_id", method = "put")]
294    async fn add_rel_res(&self, id: Path<String>, res_id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
295        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
296        let mut funs = iam_constants::get_tardis_inst();
297        funs.begin().await?;
298        IamRoleServ::add_rel_res(&id.0, &res_id.0, &funs, &ctx.0).await?;
299        funs.commit().await?;
300        ctx.0.execute_task().await?;
301        TardisResp::ok(Void {})
302    }
303
304    /// Delete Role Rel Res
305    /// 删除角色关联资源
306    #[oai(path = "/:id/res/:res_id", method = "delete")]
307    async fn delete_rel_res(&self, id: Path<String>, res_id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<Void> {
308        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
309        let mut funs = iam_constants::get_tardis_inst();
310        funs.begin().await?;
311        IamRoleServ::delete_rel_res(&id.0, &res_id.0, &funs, &ctx.0).await?;
312        funs.commit().await?;
313        ctx.0.execute_task().await?;
314        TardisResp::ok(Void {})
315    }
316
317    /// Count Rel Res By Role Id
318    /// 根据角色ID统计关联资源
319    #[oai(path = "/:id/res/total", method = "get")]
320    async fn count_rel_res(&self, id: Path<String>, ctx: TardisContextExtractor, request: &Request) -> TardisApiResult<u64> {
321        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
322        let funs = iam_constants::get_tardis_inst();
323        let result = IamRoleServ::count_rel_res(&id.0, &funs, &ctx.0).await?;
324        ctx.0.execute_task().await?;
325        TardisResp::ok(result)
326    }
327
328    /// Find Rel Res By Role Id
329    /// 根据角色ID查找关联资源
330    #[oai(path = "/:id/res", method = "get")]
331    async fn find_rel_res(
332        &self,
333        id: Path<String>,
334        desc_by_create: Query<Option<bool>>,
335        desc_by_update: Query<Option<bool>>,
336        ctx: TardisContextExtractor,
337        request: &Request,
338    ) -> TardisApiResult<Vec<RbumRelBoneResp>> {
339        try_set_real_ip_from_req_to_ctx(request, &ctx.0).await?;
340        let funs = iam_constants::get_tardis_inst();
341        let result = IamRoleServ::find_simple_rel_res(&id.0, desc_by_create.0, desc_by_update.0, &funs, &ctx.0).await?;
342        ctx.0.execute_task().await?;
343        TardisResp::ok(result)
344    }
345}