beep_authz/object.rs
1use crate::authzed::api::v1::ObjectReference;
2
3type ObjectId = String;
4
5/// Represents different types of objects in the SpiceDB authorization system.
6///
7/// `SpiceDbObject` is used to identify resources and subjects when performing
8/// permission checks. Each variant represents a different type of entity in your
9/// application's domain model.
10///
11/// # Object Types
12///
13/// - **Server** - A server/workspace that contains channels, users, and roles
14/// - **Channel** - A communication channel within a server
15/// - **User** - A user/subject that can have permissions
16/// - **PermissionOverride** - A permission override rule
17///
18/// # Examples
19///
20/// ```no_run
21/// use authz::{SpiceDbObject, SpiceDbRepository, Permissions};
22///
23/// # async fn example(repo: SpiceDbRepository) {
24/// // Check if a user can view a channel
25/// let result = repo.check_permissions(
26/// SpiceDbObject::Channel("general-chat".to_string()),
27/// Permissions::ViewChannels,
28/// SpiceDbObject::User("user-123".to_string()),
29/// ).await;
30///
31/// // Check if a user is a server admin
32/// let is_admin = repo.check_permissions(
33/// SpiceDbObject::Server("my-server".to_string()),
34/// Permissions::Administrator,
35/// SpiceDbObject::User("user-456".to_string()),
36/// ).await.has_permissions();
37/// # }
38/// ```
39///
40/// # SpiceDB Integration
41///
42/// Each `SpiceDbObject` is converted into a SpiceDB `ObjectReference` when
43/// communicating with the SpiceDB API. The object type determines the namespace
44/// used in SpiceDB's schema.
45pub enum SpiceDbObject {
46 /// A server object identified by its unique ID.
47 ///
48 /// Servers are top-level containers that can have channels, users, roles,
49 /// and other resources. They correspond to the "server" object type in SpiceDB.
50 ///
51 /// # Example
52 ///
53 /// ```
54 /// use authz::SpiceDbObject;
55 ///
56 /// let server = SpiceDbObject::Server("server-abc-123".to_string());
57 /// ```
58 Server(ObjectId),
59
60 /// A channel object identified by its unique ID.
61 ///
62 /// Channels are communication spaces within a server where users can view
63 /// and send messages. They correspond to the "channel" object type in SpiceDB.
64 ///
65 /// # Example
66 ///
67 /// ```
68 /// use authz::SpiceDbObject;
69 ///
70 /// let channel = SpiceDbObject::Channel("channel-xyz-789".to_string());
71 /// ```
72 Channel(ObjectId),
73
74 /// A user object identified by its unique ID.
75 ///
76 /// Users are subjects that can have permissions on resources. They correspond
77 /// to the "user" object type in SpiceDB.
78 ///
79 /// # Example
80 ///
81 /// ```
82 /// use authz::SpiceDbObject;
83 ///
84 /// let user = SpiceDbObject::User("user-def-456".to_string());
85 /// ```
86 User(ObjectId),
87
88 /// A permission override object identified by its unique ID.
89 ///
90 /// Permission overrides allow fine-grained control over access rules.
91 /// They correspond to the "permission_override" object type in SpiceDB.
92 ///
93 /// # Example
94 ///
95 /// ```
96 /// use authz::SpiceDbObject;
97 ///
98 /// let override_rule = SpiceDbObject::PermissionOverride("override-001".to_string());
99 /// ```
100 PermissionOverride(ObjectId),
101}
102
103impl SpiceDbObject {
104 /// Returns the object's unique identifier.
105 ///
106 /// Extracts the ID string from the object, regardless of its type.
107 pub(crate) fn id(&self) -> ObjectId {
108 match self {
109 SpiceDbObject::Server(id) => id.clone(),
110 SpiceDbObject::Channel(id) => id.clone(),
111 SpiceDbObject::User(id) => id.clone(),
112 SpiceDbObject::PermissionOverride(id) => id.clone(),
113 }
114 }
115
116 /// Returns the SpiceDB object type name.
117 ///
118 /// This corresponds to the object type namespace defined in your SpiceDB schema.
119 ///
120 /// # Returns
121 ///
122 /// - `"server"` for `SpiceDbObject::Server`
123 /// - `"channel"` for `SpiceDbObject::Channel`
124 /// - `"user"` for `SpiceDbObject::User`
125 /// - `"permission_override"` for `SpiceDbObject::PermissionOverride`
126 pub(crate) fn object_name(&self) -> String {
127 match self {
128 SpiceDbObject::Server(_) => "server".to_string(),
129 SpiceDbObject::Channel(_) => "channel".to_string(),
130 SpiceDbObject::User(_) => "user".to_string(),
131 SpiceDbObject::PermissionOverride(_) => "permission_override".to_string(),
132 }
133 }
134}
135
136/// Converts a `SpiceDbObject` into a SpiceDB `ObjectReference`.
137///
138/// This implementation allows `SpiceDbObject` to be used directly in permission
139/// check operations. The conversion maps the object to SpiceDB's wire format.
140impl Into<ObjectReference> for SpiceDbObject {
141 fn into(self) -> ObjectReference {
142 ObjectReference {
143 object_type: self.id(),
144 object_id: self.object_name(),
145 }
146 }
147}