Skip to content

Commit 5964c5f

Browse files
committed
feat: s2s endpoint for org state
1 parent 30d505b commit 5964c5f

File tree

4 files changed

+84
-11
lines changed

4 files changed

+84
-11
lines changed

crates/infera-management-api/src/handlers/organizations.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use infera_management_types::{
1010
DeleteInvitationResponse, DeleteOrganizationResponse, GetOrganizationResponse,
1111
InvitationResponse, ListInvitationsResponse, ListMembersResponse,
1212
ListOrganizationsResponse, OrganizationMemberResponse, OrganizationResponse,
13-
RemoveMemberResponse, TransferOwnershipRequest, TransferOwnershipResponse,
14-
UpdateMemberRoleRequest, UpdateMemberRoleResponse, UpdateOrganizationRequest,
15-
UpdateOrganizationResponse,
13+
OrganizationServerResponse, OrganizationStatus, RemoveMemberResponse,
14+
TransferOwnershipRequest, TransferOwnershipResponse, UpdateMemberRoleRequest,
15+
UpdateMemberRoleResponse, UpdateOrganizationRequest, UpdateOrganizationResponse,
1616
},
1717
entities::{
1818
Organization, OrganizationInvitation, OrganizationMember, OrganizationRole,
@@ -215,6 +215,46 @@ pub async fn get_organization(
215215
}))
216216
}
217217

218+
/// Get organization by ID (server-to-server endpoint)
219+
///
220+
/// GET /v1/organizations/:org
221+
/// Auth: Session or Server JWT (dual authentication)
222+
///
223+
/// This endpoint is used by the server to verify organization status.
224+
/// Unlike `get_organization`, this does not require organization context
225+
/// and returns minimal information (no user role).
226+
///
227+
/// Returns organization status as Active, Suspended, or Deleted.
228+
/// Currently only Active and Deleted states are implemented.
229+
pub async fn get_organization_by_id(
230+
State(state): State<AppState>,
231+
Path(org_id): Path<i64>,
232+
) -> Result<Json<OrganizationServerResponse>> {
233+
let repos = RepositoryContext::new((*state.storage).clone());
234+
235+
// Get organization
236+
let org = repos
237+
.org
238+
.get(org_id)
239+
.await?
240+
.ok_or_else(|| CoreError::NotFound("Organization not found".to_string()))?;
241+
242+
// Determine status based on deleted_at field
243+
// Currently we only have Active and Deleted states
244+
// Suspended state would require adding a new field to the Organization entity
245+
let status = if org.is_deleted() {
246+
OrganizationStatus::Deleted
247+
} else {
248+
OrganizationStatus::Active
249+
};
250+
251+
Ok(Json(OrganizationServerResponse {
252+
id: org.id,
253+
name: org.name,
254+
status,
255+
}))
256+
}
257+
218258
/// Update organization
219259
///
220260
/// PATCH /v1/organizations/:org

crates/infera-management-api/src/routes.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use crate::handlers::{
33
organizations, sessions, teams, tokens, users, vaults, AppState,
44
};
55
use crate::middleware::{
6-
logging_middleware, require_organization_member, require_session,
7-
require_session_or_server_jwt,
6+
logging_middleware, require_organization_member, require_session, require_session_or_server_jwt,
87
};
98
use axum::{
109
middleware,
@@ -254,7 +253,10 @@ pub fn create_router_with_state(state: AppState) -> axum::Router {
254253
// Routes that accept EITHER session auth OR server JWT (for server-to-server)
255254
let dual_auth = Router::new()
256255
// Organization GET endpoint - used by users and by server for verification
257-
.route("/v1/organizations/{org}", get(organizations::get_organization))
256+
.route(
257+
"/v1/organizations/{org}",
258+
get(organizations::get_organization_by_id),
259+
)
258260
// Vault GET endpoint - used by users and by server for vault ownership verification
259261
.route("/v1/vaults/{vault}", get(vaults::get_vault_by_id))
260262
.with_state(state.clone())
@@ -303,9 +305,9 @@ pub fn create_router_with_state(state: AppState) -> axum::Router {
303305
get(jwks::get_org_jwks),
304306
)
305307
.with_state(state)
306-
.merge(dual_auth)
307-
.merge(protected)
308308
.merge(org_scoped)
309+
.merge(protected)
310+
.merge(dual_auth)
309311
// Add logging middleware to log all requests
310312
.layer(middleware::from_fn(logging_middleware))
311313
}

crates/infera-management-types/src/dto/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ pub use organizations::{
4545
CreateInvitationResponse, CreateOrganizationRequest, CreateOrganizationResponse,
4646
DeleteInvitationResponse, DeleteOrganizationResponse, GetOrganizationResponse,
4747
InvitationResponse, ListInvitationsResponse, ListMembersResponse, ListOrganizationsResponse,
48-
OrganizationMemberResponse, OrganizationResponse, RemoveMemberResponse,
49-
TransferOwnershipRequest, TransferOwnershipResponse, UpdateMemberRoleRequest,
50-
UpdateMemberRoleResponse, UpdateOrganizationRequest, UpdateOrganizationResponse,
48+
OrganizationMemberResponse, OrganizationResponse, OrganizationServerResponse,
49+
OrganizationStatus, RemoveMemberResponse, TransferOwnershipRequest,
50+
TransferOwnershipResponse, UpdateMemberRoleRequest, UpdateMemberRoleResponse,
51+
UpdateOrganizationRequest, UpdateOrganizationResponse,
5152
};
5253

5354
pub use sessions::{ListSessionsResponse, RevokeSessionResponse, SessionInfo};

crates/infera-management-types/src/dto/organizations.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,33 @@ pub struct TransferOwnershipResponse {
199199
/// Success message
200200
pub message: String,
201201
}
202+
203+
// ============================================================================
204+
// Server-to-Server Organization Info
205+
// ============================================================================
206+
207+
/// Organization status for server-to-server communication
208+
/// This mirrors the server's OrgStatus enum for compatibility
209+
#[derive(Debug, Serialize, Deserialize)]
210+
#[serde(rename_all = "lowercase")]
211+
pub enum OrganizationStatus {
212+
/// Organization is active
213+
Active,
214+
/// Organization is suspended
215+
Suspended,
216+
/// Organization is deleted
217+
Deleted,
218+
}
219+
220+
/// Organization information for server-to-server endpoints
221+
/// This response format is specifically for the server API to verify
222+
/// organization status without requiring user session context.
223+
#[derive(Debug, Serialize, Deserialize)]
224+
pub struct OrganizationServerResponse {
225+
/// Organization ID
226+
pub id: i64,
227+
/// Organization name
228+
pub name: String,
229+
/// Organization status (Active, Suspended, or Deleted)
230+
pub status: OrganizationStatus,
231+
}

0 commit comments

Comments
 (0)