yggdrasil/api/assets/
mod.rs1#![allow(clippy::unused_unit, deprecated, unused_imports)]
8
9#[cfg(feature = "server")]
14pub(crate) const ASSET_REF_CLAUSE: &str =
15 "(EXISTS (SELECT 1 FROM asset_refs r WHERE r.asset_id = a.id) \
16 OR EXISTS (SELECT 1 FROM comments c \
17 WHERE c.deleted_at IS NULL AND c.content_html LIKE '%' || a.path || '%') \
18 OR EXISTS (SELECT 1 FROM users u WHERE u.avatar_url = '/uploads/' || a.path) \
19 OR EXISTS (SELECT 1 FROM friend_links f WHERE f.avatar_url = '/uploads/' || a.path))";
20
21#[cfg(feature = "server")]
23pub(crate) const COMMENT_REF_CLAUSE: &str = "EXISTS (SELECT 1 FROM comments c \
24 WHERE c.deleted_at IS NULL AND c.content_html LIKE '%' || a.path || '%')";
25
26#[cfg(feature = "server")]
28pub(crate) const AVATAR_REF_CLAUSE: &str =
29 "(EXISTS (SELECT 1 FROM users u WHERE u.avatar_url = '/uploads/' || a.path) \
30 OR EXISTS (SELECT 1 FROM friend_links f WHERE f.avatar_url = '/uploads/' || a.path))";
31
32#[cfg(feature = "server")]
34pub(crate) const ASSET_REF_COUNT_EXPR: &str =
35 "((SELECT COUNT(*) FROM asset_refs r WHERE r.asset_id = a.id) + \
36 (SELECT COUNT(*) FROM comments c WHERE c.deleted_at IS NULL \
37 AND c.content_html LIKE '%' || a.path || '%') + \
38 (SELECT COUNT(*) FROM users u WHERE u.avatar_url = '/uploads/' || a.path) + \
39 (SELECT COUNT(*) FROM friend_links f WHERE f.avatar_url = '/uploads/' || a.path))";
40
41pub mod delete;
43pub mod list;
45pub mod rebuild;
47pub mod types;
49
50pub use delete::{batch_delete_assets, delete_asset, purge_orphan_assets, update_asset_alt};
51pub use list::list_assets;
52pub use rebuild::rebuild_assets_index;
53pub use types::{
54 AssetListResponse, AssetOpResponse, BatchDeleteAssetsResponse, PurgeOrphansResponse,
55 RebuildAssetsResponse,
56};
57
58#[cfg(all(test, feature = "server"))]
59mod tests {
60 use super::ASSET_REF_CLAUSE;
61
62 #[test]
63 fn asset_reference_clause_protects_profile_avatar() {
64 assert!(
65 ASSET_REF_CLAUSE.contains("users u")
66 && ASSET_REF_CLAUSE.contains("u.avatar_url = '/uploads/' || a.path"),
67 "素材引用判定必须包含用户头像路径"
68 );
69 }
70}