Skip to content
Clone

feat(urls): add URL resolution functions for space images and user avatars

ZhenYi committed
parent a0f4acb commit 17d1f1a Browse files

8 files changed

+50 −29

File tree 8
Modified lib/admin/src/services/users.rs View lib/admin/src/services/users.rs
@@ -142,7 +142,7 @@
142142 uid: row.uid,
143143 username: row.username.clone(),
144144 display_name: row.display_name.clone(),
145 avatar_url: row.avatar_url.clone(),
145 avatar_url: export::resolve_user_avatar_url(row.uid, &row.avatar_url),
146146 is_active: row.is_active,
147147 is_restricted: row.is_restricted,
148148 prohibit_login: row.prohibit_login,
Modified lib/auth/src/services/login.rs View lib/auth/src/services/login.rs
@@ -285,7 +285,7 @@
285285 uid: user.uid,
286286 username: user.username.clone(),
287287 display_name: Some(user.display_name.clone()),
288 avatar_url: Some(user.avatar_url.clone()),
288 avatar_url: Some(export::resolve_user_avatar_url(user.uid, &user.avatar_url)),
289289 email,
290290 };
291291 session::share::session::apply_login(session, auth_user, user.passwd_version);
Modified lib/chat/src/services/voice.rs View lib/chat/src/services/voice.rs
@@ -250,10 +250,11 @@
250250 Err(_) => return map,
251251 };
252252 for (uid, user) in users {
253 let avatar = if user.avatar_url.trim().is_empty() {
253 let avatar_url = export::resolve_user_avatar_url(uid, &user.avatar_url);
254 let avatar = if avatar_url.trim().is_empty() {
254255 None
255256 } else {
256 Some(user.avatar_url)
257 Some(avatar_url)
257258 };
258259 let name = if user.display_name.trim().is_empty() {
259260 user.username
Modified lib/export/src/lib.rs View lib/export/src/lib.rs
@@ -10,6 +10,7 @@
1010pub mod rest;
1111pub mod storage;
1212pub mod telemetry;
13pub mod urls;
1314
1415use std::sync::Arc;
1516
@@ -19,6 +20,7 @@
1920pub use error::ExportError;
2021pub use redis::{AppRedis, RedisConnection};
2122pub use storage::AppStorage;
23pub use urls::{resolve_space_image_url, resolve_user_avatar_url};
2224
2325pub use email::EmailService;
2426
Added lib/export/src/urls.rs View lib/export/src/urls.rs
@@ -0,0 +1,40 @@
1use uuid::Uuid;
2
3/// Object-storage locator prefix written by every upload endpoint.
4const STORAGE_SCHEME: &str = "storage://";
5
6/// Browser-facing URL for one space image.
7///
8/// `storage://` locators become the redirect endpoint that hands out a
9/// presigned object-storage URL, so the database never stores a link with a
10/// signature on it and no client ever sees a URL that can expire.
11#[must_use]
12pub fn resolve_space_image_url(
13 space_lower: &str,
14 kind: &str,
15 raw: Option<String>,
16) -> Option<String> {
17 raw.map(|u| {
18 if u.starts_with(STORAGE_SCHEME) {
19 format!("/api/v1/spaces/{space_lower}/images/{kind}/file")
20 } else {
21 u
22 }
23 })
24}
25
26/// Browser-facing URL for one user avatar.
27///
28/// An empty locator stays empty (the UI renders initials instead), and a
29/// non-`storage://` value — e.g. an avatar URL imported from another host —
30/// is passed through untouched.
31#[must_use]
32pub fn resolve_user_avatar_url(uid: Uuid, raw: &str) -> String {
33 if raw.is_empty() {
34 String::new()
35 } else if raw.starts_with(STORAGE_SCHEME) {
36 format!("/api/v1/users/{uid}/avatar")
37 } else {
38 raw.to_string()
39 }
40}
Modified lib/git/src/service/stars.rs View lib/git/src/service/stars.rs
@@ -146,7 +146,7 @@
146146 user_id: u.uid,
147147 username: u.username.clone(),
148148 display_name: u.display_name.clone(),
149 avatar_url: u.avatar_url.clone(),
149 avatar_url: export::resolve_user_avatar_url(u.uid, &u.avatar_url),
150150 starred_at: row.created_at,
151151 })
152152 })
Modified lib/git/src/service/watches.rs View lib/git/src/service/watches.rs
@@ -172,7 +172,7 @@
172172 user_id: u.uid,
173173 username: u.username.clone(),
174174 display_name: u.display_name.clone(),
175 avatar_url: u.avatar_url.clone(),
175 avatar_url: export::resolve_user_avatar_url(u.uid, &u.avatar_url),
176176 mode: row.mode,
177177 watching_since: row.created_at,
178178 })
Modified lib/space/src/services/spaces.rs View lib/space/src/services/spaces.rs
@@ -47,29 +47,7 @@
4747 }
4848}
4949
50pub fn resolve_space_image_url(
51 space_lower: &str,
52 kind: &str,
53 raw: Option<String>,
54) -> Option<String> {
55 raw.map(|u| {
56 if u.starts_with("storage://") {
57 format!("/api/v1/spaces/{space_lower}/images/{kind}/file")
58 } else {
59 u
60 }
61 })
62}
63
64pub fn resolve_user_avatar_url(uid: uuid::Uuid, raw: &str) -> String {
65 if raw.is_empty() {
66 String::new()
67 } else if raw.starts_with("storage://") {
68 format!("/api/v1/users/{uid}/avatar")
69 } else {
70 raw.to_string()
71 }
72}
50pub use export::{resolve_space_image_url, resolve_user_avatar_url};
7351
7452#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
7553pub struct SpaceDto {