feat: add room by name endpoint for non-authenticated access

- Add GET /rooms/name/{room_name} backend endpoint
- Endpoint supports non-authenticated access for public rooms
- Returns RoomDetails with webhook fields hidden for non-owners
- Update useRoomGetByName hook to use new direct endpoint
- Remove authentication requirement from frontend hook
- Regenerate API client types

Fixes: Non-authenticated users can now access room lobbies
This commit is contained in:
2025-09-10 19:04:09 -06:00
parent e483e2a97f
commit 304f3dca3a
3 changed files with 2888 additions and 2843 deletions

View File

@@ -155,6 +155,30 @@ async def rooms_get(
return room return room
@router.get("/rooms/name/{room_name}", response_model=RoomDetails)
async def rooms_get_by_name(
room_name: str,
user: Annotated[Optional[auth.UserInfo], Depends(auth.current_user_optional)],
):
user_id = user["sub"] if user else None
room = await rooms_controller.get_by_name(room_name)
if not room:
raise HTTPException(status_code=404, detail="Room not found")
# Convert to RoomDetails format (add webhook fields if user is owner)
room_dict = room.__dict__.copy()
if user_id == room.user_id:
# User is owner, include webhook details if available
room_dict["webhook_url"] = getattr(room, "webhook_url", None)
room_dict["webhook_secret"] = getattr(room, "webhook_secret", None)
else:
# Non-owner, hide webhook details
room_dict["webhook_url"] = None
room_dict["webhook_secret"] = None
return RoomDetails(**room_dict)
@router.post("/rooms", response_model=Room) @router.post("/rooms", response_model=Room)
async def rooms_create( async def rooms_create(
room: CreateRoom, room: CreateRoom,

View File

@@ -642,19 +642,16 @@ export function useRoomsCreateMeeting() {
// Calendar integration hooks // Calendar integration hooks
export function useRoomGetByName(roomName: string | null) { export function useRoomGetByName(roomName: string | null) {
const { isAuthenticated } = useAuthReady();
return $api.useQuery( return $api.useQuery(
"get", "get",
"/v1/rooms", "/v1/rooms/name/{room_name}",
{ {
params: { params: {
query: { page: 1 }, // We'll need to filter by room name on the client side path: { room_name: roomName || "" },
}, },
}, },
{ {
enabled: !!roomName && isAuthenticated, enabled: !!roomName,
select: (data) => data.items?.find((room) => room.name === roomName),
}, },
); );
} }

View File

@@ -98,6 +98,23 @@ export interface paths {
patch: operations["v1_rooms_update"]; patch: operations["v1_rooms_update"];
trace?: never; trace?: never;
}; };
"/v1/rooms/name/{room_name}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Rooms Get By Name */
get: operations["v1_rooms_get_by_name"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/v1/rooms/{room_name}/meeting": { "/v1/rooms/{room_name}/meeting": {
parameters: { parameters: {
query?: never; query?: never;
@@ -656,11 +673,9 @@ export interface components {
*/ */
end_time: string; end_time: string;
/** Attendees */ /** Attendees */
attendees?: attendees?: {
| {
[key: string]: unknown; [key: string]: unknown;
}[] }[] | null;
| null;
/** Location */ /** Location */
location?: string | null; location?: string | null;
/** /**
@@ -756,13 +771,7 @@ export interface components {
* Status * Status
* @enum {string} * @enum {string}
*/ */
status: status: "idle" | "uploaded" | "recording" | "processing" | "error" | "ended";
| "idle"
| "uploaded"
| "recording"
| "processing"
| "error"
| "ended";
/** Locked */ /** Locked */
locked: boolean; locked: boolean;
/** Duration */ /** Duration */
@@ -810,13 +819,7 @@ export interface components {
* Status * Status
* @enum {string} * @enum {string}
*/ */
status: status: "idle" | "uploaded" | "recording" | "processing" | "error" | "ended";
| "idle"
| "uploaded"
| "recording"
| "processing"
| "error"
| "ended";
/** Locked */ /** Locked */
locked: boolean; locked: boolean;
/** Duration */ /** Duration */
@@ -1031,11 +1034,7 @@ export interface components {
* @default automatic-2nd-participant * @default automatic-2nd-participant
* @enum {string} * @enum {string}
*/ */
recording_trigger: recording_trigger: "none" | "prompt" | "automatic" | "automatic-2nd-participant";
| "none"
| "prompt"
| "automatic"
| "automatic-2nd-participant";
/** /**
* Num Clients * Num Clients
* @default 0 * @default 0
@@ -1247,13 +1246,7 @@ export interface components {
* Status * Status
* @enum {string} * @enum {string}
*/ */
status: status: "idle" | "uploaded" | "recording" | "processing" | "error" | "ended";
| "idle"
| "uploaded"
| "recording"
| "processing"
| "error"
| "ended";
/** Rank */ /** Rank */
rank: number; rank: number;
/** /**
@@ -1727,6 +1720,37 @@ export interface operations {
}; };
}; };
}; };
v1_rooms_get_by_name: {
parameters: {
query?: never;
header?: never;
path: {
room_name: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["RoomDetails"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
v1_rooms_create_meeting: { v1_rooms_create_meeting: {
parameters: { parameters: {
query?: never; query?: never;