cloudillo_profile/
list.rs1use axum::{
4 extract::{Path, Query, State},
5 http::StatusCode,
6 Json,
7};
8use serde::{Deserialize, Serialize};
9use serde_with::skip_serializing_none;
10
11use crate::prelude::*;
12use cloudillo_core::extract::OptionalRequestId;
13use cloudillo_types::meta_adapter::ListProfileOptions;
14use cloudillo_types::types::{ApiResponse, ProfileInfo};
15
16#[skip_serializing_none]
18#[derive(Debug, Serialize)]
19#[serde(rename_all = "camelCase")]
20pub struct ProfileWithStatus {
21 pub id_tag: String,
22 pub name: String,
23 #[serde(rename = "type")]
24 pub r#type: Option<String>,
25 pub profile_pic: Option<String>,
26 pub status: Option<String>,
27 pub connected: Option<bool>,
28 pub following: Option<bool>,
29}
30
31#[derive(Debug, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct ListProfilesQuery {
34 #[serde(alias = "q")]
35 search: Option<String>,
36 #[serde(rename = "type")]
37 typ: Option<cloudillo_types::meta_adapter::ProfileType>,
38}
39
40pub async fn list_profiles(
47 State(app): State<App>,
48 tn_id: TnId,
49 OptionalRequestId(req_id): OptionalRequestId,
50 Query(params): Query<ListProfilesQuery>,
51) -> ClResult<(StatusCode, Json<ApiResponse<Vec<ProfileInfo>>>)> {
52 let opts = ListProfileOptions {
54 typ: params.typ,
55 status: None,
56 connected: None,
57 following: None,
58 q: params.search.as_ref().map(|s| s.to_lowercase()),
59 id_tag: None,
60 };
61
62 let profiles_list = app.meta_adapter.list_profiles(tn_id, &opts).await?;
64
65 let profiles: Vec<ProfileInfo> = profiles_list
67 .into_iter()
68 .map(|p| ProfileInfo {
69 id_tag: p.id_tag.to_string(),
70 name: p.name.to_string(),
71 r#type: Some(
72 match p.typ {
73 cloudillo_types::meta_adapter::ProfileType::Person => "person",
74 cloudillo_types::meta_adapter::ProfileType::Community => "community",
75 }
76 .to_string(),
77 ),
78 profile_pic: p.profile_pic.map(|s| s.to_string()),
79 status: None, connected: Some(p.connected.is_connected()),
81 following: Some(p.following),
82 roles: p.roles.map(|r| r.iter().map(|s| s.to_string()).collect()),
83 created_at: None, })
85 .collect();
86
87 let response = ApiResponse::new(profiles).with_req_id(req_id.unwrap_or_default());
88
89 Ok((StatusCode::OK, Json(response)))
90}
91
92pub async fn get_profile_by_id_tag(
96 State(app): State<App>,
97 tn_id: TnId,
98 OptionalRequestId(req_id): OptionalRequestId,
99 Path(id_tag): Path<String>,
100) -> ClResult<(StatusCode, Json<ApiResponse<Option<ProfileWithStatus>>>)> {
101 let profile = match app.meta_adapter.read_profile(tn_id, &id_tag).await {
103 Ok((_etag, p)) => {
104 let typ = match p.typ {
105 cloudillo_types::meta_adapter::ProfileType::Person => None,
106 cloudillo_types::meta_adapter::ProfileType::Community => {
107 Some("community".to_string())
108 }
109 };
110 Some(ProfileWithStatus {
111 id_tag: p.id_tag.to_string(),
112 name: p.name.to_string(),
113 r#type: typ,
114 profile_pic: p.profile_pic.map(|s| s.to_string()),
115 status: None, connected: Some(p.connected.is_connected()),
117 following: Some(p.following),
118 })
119 }
120 Err(Error::NotFound) => None, Err(e) => return Err(e),
122 };
123
124 let response = ApiResponse::new(profile).with_req_id(req_id.unwrap_or_default());
125
126 Ok((StatusCode::OK, Json(response)))
127}
128
129