@@ -75,6 +75,18 @@ export function filesRoutes(ctx: RouteContext): void {
7575 . channels . all ( )
7676 . find ( ( ch ) => ! ch . is_im && ! ch . is_mpim && ch . name === channel ) ;
7777
78+ type ShareTargetRef = { key : string ; channel ?: SlackChannel ; directUserId ?: string } ;
79+
80+ const findDirectMessage = ( authUserId : string , userId : string ) => {
81+ const members = [ authUserId , userId ] . sort ( ) ;
82+ return ss ( )
83+ . channels . all ( )
84+ . find (
85+ ( ch ) =>
86+ ch . is_im && ch . members . length === members . length && [ ...ch . members ] . sort ( ) . join ( "," ) === members . join ( "," ) ,
87+ ) ;
88+ } ;
89+
7890 const findOrCreateDirectMessage = ( authUser : { login : string } , userId : string ) => {
7991 const targetUser = ss ( ) . users . findOneBy ( "user_id" , userId ) ;
8092 if ( ! targetUser || targetUser . deleted ) return undefined ;
@@ -83,12 +95,7 @@ export function filesRoutes(ctx: RouteContext): void {
8395 if ( targetUser . user_id === authUserId ) return undefined ;
8496
8597 const members = [ authUserId , targetUser . user_id ] . sort ( ) ;
86- const existing = ss ( )
87- . channels . all ( )
88- . find (
89- ( ch ) =>
90- ch . is_im && ch . members . length === members . length && [ ...ch . members ] . sort ( ) . join ( "," ) === members . join ( "," ) ,
91- ) ;
98+ const existing = findDirectMessage ( authUserId , targetUser . user_id ) ;
9299 if ( existing ) return existing ;
93100
94101 const team = ss ( ) . teams . all ( ) [ 0 ] ;
@@ -113,8 +120,21 @@ export function filesRoutes(ctx: RouteContext): void {
113120 } ) ;
114121 } ;
115122
116- const findShareTarget = ( authUser : { login : string } , channel : string ) =>
117- findChannel ( channel ) ?? ( channel . startsWith ( "U" ) ? findOrCreateDirectMessage ( authUser , channel ) : undefined ) ;
123+ const resolveShareTarget = ( authUser : { login : string } , channel : string ) : ShareTargetRef | undefined => {
124+ const existingChannel = findChannel ( channel ) ;
125+ if ( existingChannel ) return { key : existingChannel . channel_id , channel : existingChannel } ;
126+ if ( ! channel . startsWith ( "U" ) ) return undefined ;
127+
128+ const targetUser = ss ( ) . users . findOneBy ( "user_id" , channel ) ;
129+ if ( ! targetUser || targetUser . deleted ) return undefined ;
130+
131+ const authUserId = getAuthUserId ( authUser ) ;
132+ if ( targetUser . user_id === authUserId ) return undefined ;
133+
134+ const existingDirectMessage = findDirectMessage ( authUserId , targetUser . user_id ) ;
135+ if ( existingDirectMessage ) return { key : existingDirectMessage . channel_id , channel : existingDirectMessage } ;
136+ return { key : `user:${ targetUser . user_id } ` , directUserId : targetUser . user_id } ;
137+ } ;
118138
119139 app . post ( "/api/files.getUploadURLExternal" , async ( c ) => {
120140 const authUser = c . get ( "authUser" ) ;
@@ -179,16 +199,6 @@ export function filesRoutes(ctx: RouteContext): void {
179199 }
180200
181201 const authUserId = getAuthUserId ( authUser ) ;
182- const rawChannelIds = parseDestinationChannels ( body . channel_id , body . channels ) ;
183- const targets : SlackChannel [ ] = [ ] ;
184- for ( const channelId of rawChannelIds ) {
185- const channel = findShareTarget ( authUser , channelId ) ;
186- if ( ! channel ) return slackError ( c , "channel_not_found" ) ;
187- if ( channel . is_archived ) return slackError ( c , "is_archived" ) ;
188- if ( ! canReadConversation ( channel , getAuthSlackUser ( authUser ) , authUserId ) ) return slackError ( c , "not_in_channel" ) ;
189- targets . push ( channel ) ;
190- }
191-
192202 const initialComment = typeof body . initial_comment === "string" ? body . initial_comment : "" ;
193203 const threadTs = typeof body . thread_ts === "string" ? body . thread_ts : undefined ;
194204 const blocks = parseBlocks ( body . blocks ) ;
@@ -203,6 +213,29 @@ export function filesRoutes(ctx: RouteContext): void {
203213 requestedSessions . push ( session ) ;
204214 }
205215
216+ const rawChannelIds = parseDestinationChannels ( body . channel_id , body . channels ) ;
217+ const targetRefs : ShareTargetRef [ ] = [ ] ;
218+ const targetKeys = new Set < string > ( ) ;
219+ for ( const channelId of rawChannelIds ) {
220+ const target = resolveShareTarget ( authUser , channelId ) ;
221+ if ( ! target ) return slackError ( c , "channel_not_found" ) ;
222+ if ( target . channel ?. is_archived ) return slackError ( c , "is_archived" ) ;
223+ if ( target . channel && ! canReadConversation ( target . channel , getAuthSlackUser ( authUser ) , authUserId ) ) {
224+ return slackError ( c , "not_in_channel" ) ;
225+ }
226+ if ( ! targetKeys . has ( target . key ) ) {
227+ targetKeys . add ( target . key ) ;
228+ targetRefs . push ( target ) ;
229+ }
230+ }
231+
232+ const targets : SlackChannel [ ] = [ ] ;
233+ for ( const target of targetRefs ) {
234+ const channel = target . channel ?? findOrCreateDirectMessage ( authUser , target . directUserId ?? "" ) ;
235+ if ( ! channel ) return slackError ( c , "channel_not_found" ) ;
236+ targets . push ( channel ) ;
237+ }
238+
206239 const completedFiles : SlackFile [ ] = [ ] ;
207240 for ( let index = 0 ; index < requestedFiles . length ; index ++ ) {
208241 const requestedFile = requestedFiles [ index ] ;
0 commit comments