linkrs_server/permission/
error.rs1use std::error::Error;
11
12use linkrs_core::error::codes::{ErrorCode, PublicError, ToPublicError};
13
14type BoxedError = Box<dyn Error + Send + Sync>;
16
17pub type PermissionResult<T> = Result<T, PermissionError>;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum PermissionErrorKind {
23 InsufficientPermission,
24 NoRoleInSpace,
25 PermissionDenied,
26 RoleNotFound,
27 UserNotFound,
28 GrantRoleFailed,
29 RevokeRoleFailed,
30 OnlyGodCanManageSpaces,
31 OnlyGodCanManageUsers,
32 SpaceIdRequired,
33 SchemaSpaceIdRequired,
34 SchemaWriteSpaceIdRequired,
35 SchemaWritePermissionDenied,
36 DataReadSpaceIdRequired,
37 DataWriteSpaceIdRequired,
38 GuestCannotWriteData,
39 CannotReadUserInfo,
40 RoleOperationSpaceIdRequired,
41 RoleOperationTargetRoleRequired,
42 OnlyAdminOrGodCanManageRoles,
43 CannotGrantRole,
44 CannotModifyOwnRole,
45 ChangePasswordTargetUserRequired,
46 CanOnlyChangeOwnPassword,
47}
48
49impl PermissionErrorKind {
50 pub fn as_str(&self) -> &'static str {
51 match self {
52 PermissionErrorKind::InsufficientPermission => "insufficient_permission",
53 PermissionErrorKind::NoRoleInSpace => "no_role_in_space",
54 PermissionErrorKind::PermissionDenied => "permission_denied",
55 PermissionErrorKind::RoleNotFound => "role_not_found",
56 PermissionErrorKind::UserNotFound => "user_not_found",
57 PermissionErrorKind::GrantRoleFailed => "grant_role_failed",
58 PermissionErrorKind::RevokeRoleFailed => "revoke_role_failed",
59 PermissionErrorKind::OnlyGodCanManageSpaces => "only_god_can_manage_spaces",
60 PermissionErrorKind::OnlyGodCanManageUsers => "only_god_can_manage_users",
61 PermissionErrorKind::SpaceIdRequired => "space_id_required",
62 PermissionErrorKind::SchemaSpaceIdRequired => "schema_space_id_required",
63 PermissionErrorKind::SchemaWriteSpaceIdRequired => "schema_write_space_id_required",
64 PermissionErrorKind::SchemaWritePermissionDenied => "schema_write_permission_denied",
65 PermissionErrorKind::DataReadSpaceIdRequired => "data_read_space_id_required",
66 PermissionErrorKind::DataWriteSpaceIdRequired => "data_write_space_id_required",
67 PermissionErrorKind::GuestCannotWriteData => "guest_cannot_write_data",
68 PermissionErrorKind::CannotReadUserInfo => "cannot_read_user_info",
69 PermissionErrorKind::RoleOperationSpaceIdRequired => "role_operation_space_id_required",
70 PermissionErrorKind::RoleOperationTargetRoleRequired => {
71 "role_operation_target_role_required"
72 }
73 PermissionErrorKind::OnlyAdminOrGodCanManageRoles => {
74 "only_admin_or_god_can_manage_roles"
75 }
76 PermissionErrorKind::CannotGrantRole => "cannot_grant_role",
77 PermissionErrorKind::CannotModifyOwnRole => "cannot_modify_own_role",
78 PermissionErrorKind::ChangePasswordTargetUserRequired => {
79 "change_password_target_user_required"
80 }
81 PermissionErrorKind::CanOnlyChangeOwnPassword => "can_only_change_own_password",
82 }
83 }
84}
85
86#[derive(Debug)]
93pub struct PermissionError {
94 kind: PermissionErrorKind,
95 message: String,
96 source: Option<BoxedError>,
97}
98
99impl PermissionError {
100 pub fn new(kind: PermissionErrorKind, message: impl Into<String>) -> Self {
101 Self {
102 kind,
103 message: message.into(),
104 source: None,
105 }
106 }
107
108 pub fn with_source(mut self, source: BoxedError) -> Self {
109 self.source = Some(source);
110 self
111 }
112
113 pub fn kind(&self) -> PermissionErrorKind {
114 self.kind
115 }
116
117 pub fn message(&self) -> &str {
118 &self.message
119 }
120
121 pub fn insufficient_permission() -> Self {
123 Self::new(
124 PermissionErrorKind::InsufficientPermission,
125 "Insufficient permission",
126 )
127 }
128
129 pub fn no_role_in_space(user: impl Into<String>, space_id: i64) -> Self {
130 Self::new(
131 PermissionErrorKind::NoRoleInSpace,
132 format!("User {} has no role in space {}", user.into(), space_id),
133 )
134 }
135
136 pub fn permission_denied(permission: impl Into<String>, user: impl Into<String>) -> Self {
137 Self::new(
138 PermissionErrorKind::PermissionDenied,
139 format!(
140 "Permission denied: {} for user {}",
141 permission.into(),
142 user.into()
143 ),
144 )
145 }
146
147 pub fn role_not_found(role: impl Into<String>) -> Self {
148 Self::new(
149 PermissionErrorKind::RoleNotFound,
150 format!("Role not found: {}", role.into()),
151 )
152 }
153
154 pub fn user_not_found(user: impl Into<String>) -> Self {
155 Self::new(
156 PermissionErrorKind::UserNotFound,
157 format!("User not found: {}", user.into()),
158 )
159 }
160
161 pub fn grant_role_failed(message: impl Into<String>) -> Self {
162 Self::new(PermissionErrorKind::GrantRoleFailed, message)
163 }
164
165 pub fn revoke_role_failed(message: impl Into<String>) -> Self {
166 Self::new(PermissionErrorKind::RevokeRoleFailed, message)
167 }
168
169 pub fn only_god_can_manage_spaces() -> Self {
170 Self::new(
171 PermissionErrorKind::OnlyGodCanManageSpaces,
172 "Permission denied: only Admin or God can create/delete spaces",
173 )
174 }
175
176 pub fn only_god_can_manage_users() -> Self {
177 Self::new(
178 PermissionErrorKind::OnlyGodCanManageUsers,
179 "Permission denied: only Admin or God can manage users",
180 )
181 }
182
183 pub fn space_id_required() -> Self {
184 Self::new(
185 PermissionErrorKind::SpaceIdRequired,
186 "Space ID required for read Space operation",
187 )
188 }
189
190 pub fn schema_space_id_required() -> Self {
191 Self::new(
192 PermissionErrorKind::SchemaSpaceIdRequired,
193 "Space ID required for read Schema operation",
194 )
195 }
196
197 pub fn schema_write_space_id_required() -> Self {
198 Self::new(
199 PermissionErrorKind::SchemaWriteSpaceIdRequired,
200 "Space ID required for write Schema operation",
201 )
202 }
203
204 pub fn schema_write_permission_denied(space_id: i64, user: impl Into<String>) -> Self {
205 Self::new(
206 PermissionErrorKind::SchemaWritePermissionDenied,
207 format!(
208 "Schema write permission denied: user {} has insufficient privileges in space {}",
209 user.into(),
210 space_id
211 ),
212 )
213 }
214
215 pub fn data_read_space_id_required() -> Self {
216 Self::new(
217 PermissionErrorKind::DataReadSpaceIdRequired,
218 "Space ID required for read data operation",
219 )
220 }
221
222 pub fn data_write_space_id_required() -> Self {
223 Self::new(
224 PermissionErrorKind::DataWriteSpaceIdRequired,
225 "Space ID required for write data operation",
226 )
227 }
228
229 pub fn guest_cannot_write_data() -> Self {
230 Self::new(
231 PermissionErrorKind::GuestCannotWriteData,
232 "Guest role has no permission to write data",
233 )
234 }
235
236 pub fn cannot_read_user_info() -> Self {
237 Self::new(
238 PermissionErrorKind::CannotReadUserInfo,
239 "No permission to read user information",
240 )
241 }
242
243 pub fn role_operation_space_id_required() -> Self {
244 Self::new(
245 PermissionErrorKind::RoleOperationSpaceIdRequired,
246 "Space ID required for role operation",
247 )
248 }
249
250 pub fn role_operation_target_role_required() -> Self {
251 Self::new(
252 PermissionErrorKind::RoleOperationTargetRoleRequired,
253 "Target role required for role operation",
254 )
255 }
256
257 pub fn only_admin_or_god_can_manage_roles() -> Self {
258 Self::new(
259 PermissionErrorKind::OnlyAdminOrGodCanManageRoles,
260 "Permission denied: only Admin or God can manage roles",
261 )
262 }
263
264 pub fn cannot_grant_role(role: impl Into<String>) -> Self {
265 Self::new(
266 PermissionErrorKind::CannotGrantRole,
267 format!("Permission denied: cannot grant role {}", role.into()),
268 )
269 }
270
271 pub fn cannot_modify_own_role() -> Self {
272 Self::new(
273 PermissionErrorKind::CannotModifyOwnRole,
274 "Cannot modify own role",
275 )
276 }
277
278 pub fn change_password_target_user_required() -> Self {
279 Self::new(
280 PermissionErrorKind::ChangePasswordTargetUserRequired,
281 "Target user required for change password operation",
282 )
283 }
284
285 pub fn can_only_change_own_password() -> Self {
286 Self::new(
287 PermissionErrorKind::CanOnlyChangeOwnPassword,
288 "Can only change own password",
289 )
290 }
291}
292
293impl std::fmt::Display for PermissionError {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295 write!(f, "[{}] {}", self.kind.as_str(), self.message)?;
296 if let Some(ref source) = self.source {
297 write!(f, "\n Caused by: {}", source)?;
298 }
299 Ok(())
300 }
301}
302
303impl Clone for PermissionError {
304 fn clone(&self) -> Self {
305 Self {
306 kind: self.kind,
307 message: self.message.clone(),
308 source: None,
309 }
310 }
311}
312
313impl std::error::Error for PermissionError {
314 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
315 self.source
316 .as_ref()
317 .map(|e| e.as_ref() as &(dyn std::error::Error + 'static))
318 }
319}
320
321impl ToPublicError for PermissionError {
322 fn to_public_error(&self) -> PublicError {
323 PublicError::new(self.to_error_code(), self.to_public_message())
324 }
325
326 fn to_error_code(&self) -> ErrorCode {
327 ErrorCode::PermissionDenied
328 }
329
330 fn to_public_message(&self) -> String {
331 self.message.clone()
332 }
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn test_permission_error_size() {
341 assert!(
342 std::mem::size_of::<PermissionError>() <= 64,
343 "PermissionError should be small, got {} bytes",
344 std::mem::size_of::<PermissionError>()
345 );
346 }
347
348 #[test]
349 fn test_permission_error_creation() {
350 let err = PermissionError::role_not_found("admin");
351 assert_eq!(err.kind(), PermissionErrorKind::RoleNotFound);
352 assert!(err.message().contains("admin"));
353 }
354}