@@ -2,13 +2,20 @@ import { db } from "@cap/database";
22import { sendEmail } from "@cap/database/emails/config" ;
33import { FirstShareableLink } from "@cap/database/emails/first-shareable-link" ;
44import { nanoId } from "@cap/database/helpers" ;
5- import { s3Buckets , videos , videoUploads } from "@cap/database/schema" ;
5+ import {
6+ organizationMembers ,
7+ organizations ,
8+ s3Buckets ,
9+ users ,
10+ videos ,
11+ videoUploads ,
12+ } from "@cap/database/schema" ;
613import { buildEnv , NODE_ENV , serverEnv } from "@cap/env" ;
714import { userIsPro } from "@cap/utils" ;
815import { S3Buckets } from "@cap/web-backend" ;
916import { Video } from "@cap/web-domain" ;
1017import { zValidator } from "@hono/zod-validator" ;
11- import { and , count , eq , gt , gte , lt , lte } from "drizzle-orm" ;
18+ import { and , count , eq , gt , gte , lt , lte , or } from "drizzle-orm" ;
1219import { Effect , Option } from "effect" ;
1320import { Hono } from "hono" ;
1421import { z } from "zod" ;
@@ -34,6 +41,7 @@ app.get(
3441 width : stringOrNumberOptional ,
3542 height : stringOrNumberOptional ,
3643 fps : stringOrNumberOptional ,
44+ orgId : z . string ( ) . optional ( ) ,
3745 } ) ,
3846 ) ,
3947 async ( c ) => {
@@ -47,6 +55,7 @@ app.get(
4755 width,
4856 height,
4957 fps,
58+ orgId,
5059 } = c . req . valid ( "query" ) ;
5160 const user = c . get ( "user" ) ;
5261
@@ -71,8 +80,6 @@ app.get(
7180 . from ( s3Buckets )
7281 . where ( eq ( s3Buckets . ownerId , user . id ) ) ;
7382
74- console . log ( "User bucket:" , customBucket ? "found" : "not found" ) ;
75-
7683 const date = new Date ( ) ;
7784 const formattedDate = `${ date . getDate ( ) } ${ date . toLocaleString (
7885 "default" ,
@@ -95,6 +102,58 @@ app.get(
95102 } ) ;
96103 }
97104
105+ const userOrganizations = await db ( )
106+ . select ( {
107+ id : organizations . id ,
108+ name : organizations . name ,
109+ } )
110+ . from ( organizations )
111+ . leftJoin (
112+ organizationMembers ,
113+ eq ( organizations . id , organizationMembers . organizationId ) ,
114+ )
115+ . where (
116+ or (
117+ // User owns the organization
118+ eq ( organizations . ownerId , user . id ) ,
119+ // User is a member of the organization
120+ eq ( organizationMembers . userId , user . id ) ,
121+ ) ,
122+ )
123+ // Remove duplicates if user is both owner and member
124+ . groupBy ( organizations . id , organizations . name )
125+ . orderBy ( organizations . createdAt ) ;
126+ const userOrgIds = userOrganizations . map ( ( org ) => org . id ) ;
127+
128+ let videoOrgId : string ;
129+ if ( orgId ) {
130+ // Hard error if the user requested org is non-existent or they don't have access.
131+ if ( ! userOrgIds . includes ( orgId ) )
132+ return c . json ( { error : "forbidden_org" } , { status : 403 } ) ;
133+ videoOrgId = orgId ;
134+ } else if ( user . defaultOrgId ) {
135+ // User's defaultOrgId is no longer valid, switch to first available org
136+ if ( ! userOrgIds . includes ( user . defaultOrgId ) ) {
137+ if ( ! userOrganizations [ 0 ] )
138+ return c . json ( { error : "no_valid_org" } , { status : 403 } ) ;
139+
140+ videoOrgId = userOrganizations [ 0 ] . id ;
141+
142+ // Update user's defaultOrgId to the new valid org
143+ await db ( )
144+ . update ( users )
145+ . set ( {
146+ defaultOrgId : videoOrgId ,
147+ } )
148+ . where ( eq ( users . id , user . id ) ) ;
149+ } else videoOrgId = user . defaultOrgId ;
150+ } else {
151+ // No orgId provided and no defaultOrgId, use first available org
152+ if ( ! userOrganizations [ 0 ] )
153+ return c . json ( { error : "no_valid_org" } , { status : 403 } ) ;
154+ videoOrgId = userOrganizations [ 0 ] . id ;
155+ }
156+
98157 const idToUse = Video . VideoId . make ( nanoId ( ) ) ;
99158
100159 const videoName =
@@ -107,6 +166,7 @@ app.get(
107166 id : idToUse ,
108167 name : videoName ,
109168 ownerId : user . id ,
169+ orgId : videoOrgId ,
110170 source :
111171 recordingMode === "hls"
112172 ? { type : "local" as const }
0 commit comments