8
8
* - sendInvite
9
9
* - createMember
10
10
* - verifyMember
11
+ *
12
+ * These are the following locations referenced by legacy clients:
13
+ *
14
+ * - the client always uploads all videos—invite videos or new user videos—to a
15
+ * bucket only logged in users can see ("auth-restricted"), addressed by a
16
+ * client-generated videoToken.
17
+ * - member video locations are always expected to be in the public video
18
+ * bucket, at {memberId}/invite.mp4. These can be joint invite videos
19
+ * including the user, or a video of themselves introducing themselves.
20
+ * - When an existing member verifies a new member, they either create a new
21
+ * auth-restricted video verifying the member, or if they are the inviter,
22
+ * they use their own previous (auth-restricted) invite video to make sure
23
+ * it looks right.
24
+ * - Then, that video gets copied to the verifier's list of verification
25
+ * videos, at {memberId}/{videoToken}/video.mp4.
26
+ * - all these videos are expected to have thumbnails at <url>.thumb.jpg
11
27
*/
12
28
import * as Storage from "@google-cloud/storage" ;
13
29
import { storage as adminStorage } from "firebase-admin" ;
@@ -31,7 +47,17 @@ export type BucketStorage = adminStorage.Storage | Storage.Storage;
31
47
// methods, see the section below, where functions are prepended by LEGACY_ or
32
48
// LEGACY_COMPAT titles.
33
49
34
- const VIDEOS_DIRNAME = "videosById" ;
50
+ const VIDEOS_DIRNAME = "videosByReferenceId" ;
51
+
52
+ /**
53
+ * Get reference to the storage bucket for public videos.
54
+ */
55
+ export function getPublicVideoBucketRef (
56
+ config : Config ,
57
+ storage : BucketStorage
58
+ ) {
59
+ return ( storage as Storage . Storage ) . bucket ( config . publicVideoBucket ) ;
60
+ }
35
61
36
62
/**
37
63
* Get the public url for a file stored in Google Cloud Storage
@@ -106,7 +132,7 @@ export async function moveVideo(
106
132
if ( ! ( await sourceVideoRefs . video . exists ( ) ) [ 0 ] ) {
107
133
throw new HttpApiError (
108
134
httpStatus . BAD_REQUEST ,
109
- "Private video does not exist at expected location. Cannot move." ,
135
+ "Auth-restricted video does not exist at expected location. Cannot move." ,
110
136
{ }
111
137
) ;
112
138
}
@@ -130,9 +156,9 @@ export async function moveVideo(
130
156
// ----------------------------
131
157
132
158
/**
133
- * Legacy compatibility method to copy private invite videos to new non-legacy
134
- * locations, and return a new-style video reference pointing to the new public,
135
- * referenceId-addressed video location.
159
+ * Legacy compatibility method to copy auth-restricted invite videos to new,
160
+ * public non-legacy locations, and return a new-style video reference pointing
161
+ * to the new public, referenceId-addressed video location.
136
162
*/
137
163
export async function LEGACY_createVideoReferenceForInviteVideo (
138
164
config : Config ,
@@ -163,11 +189,11 @@ export async function LEGACY_createVideoReferenceForInviteVideo(
163
189
164
190
// we assume this is a legacy request. Copy the legacy video to the new
165
191
// video reference location
166
- await LEGACY_COMPAT_movePrivateInviteVideoToNewPublicVideoReferencesBucket ( {
192
+ await LEGACY_COMPAT_moveAuthRestrictedVideoToNewPublicVideoReferencesBucket ( {
167
193
config,
168
194
storage,
169
195
newVideoReferenceId,
170
- privateVideoToken : videoData . videoToken ,
196
+ authRestrictedVideoToken : videoData . videoToken ,
171
197
removeOriginal : false
172
198
} ) ;
173
199
@@ -209,7 +235,7 @@ function LEGACY_getPublicInviteVideoThumbnailRefForMember(
209
235
) ;
210
236
}
211
237
212
- export function getPublicInviteVideoUrlForMember (
238
+ export function LEGACY_getPublicInviteVideoUrlForMember (
213
239
config : Config ,
214
240
memberId : string
215
241
) : string {
@@ -218,66 +244,62 @@ export function getPublicInviteVideoUrlForMember(
218
244
} /${ memberId } /invite.mp4`;
219
245
}
220
246
221
- export function getPublicVideoBucketRef (
222
- config : Config ,
223
- storage : BucketStorage
224
- ) {
225
- return ( storage as Storage . Storage ) . bucket ( config . publicVideoBucket ) ;
226
- }
227
-
228
247
/**
229
- * Legacy compatibility method that moves a video from the legacy private invite
230
- * video bucket to the new, global public vidoeReference bucket. Necessary when
231
- * old clients that store videos in the legacy locations send an invite, so that
232
- * new clients that expect it from the videoReference bucket will be able to
233
- * access it.
248
+ * Legacy compatibility method that moves a video from the legacy
249
+ * auth-restricted invite video bucket to the new, global public vidoeReference
250
+ * bucket. Necessary when old clients that store videos in the legacy locations
251
+ * send an invite, so that new clients that expect it from the videoReference
252
+ * bucket will be able to access it.
234
253
*
235
- * Invite videos used to be stored in a private bucket, addressed by a "video
236
- * token" selected by the client app, which in turn was saved as the
254
+ * Invite videos used to be stored in a auth-restricted bucket, addressed by a
255
+ * "video token" selected by the client app, which in turn was saved as the
237
256
* inviteToken. Now, we will generate a separate videoReferenceId, copy the
238
- * private video to that location, and refer to that new public video in a
239
- * videoReference object on the new invite operation.
257
+ * auth-restricted video to that location, and refer to that new public video in
258
+ * a videoReference object on the new invite operation.
240
259
*/
241
- export async function LEGACY_COMPAT_movePrivateInviteVideoToNewPublicVideoReferencesBucket ( {
260
+ export async function LEGACY_COMPAT_moveAuthRestrictedVideoToNewPublicVideoReferencesBucket ( {
242
261
config,
243
262
storage,
244
263
newVideoReferenceId,
245
- privateVideoToken ,
264
+ authRestrictedVideoToken ,
246
265
removeOriginal
247
266
} : {
248
267
config : Config ;
249
268
storage : BucketStorage ;
250
269
newVideoReferenceId : string ;
251
- privateVideoToken : string ;
270
+ authRestrictedVideoToken : string ;
252
271
removeOriginal : boolean ;
253
272
} ) : Promise < void > {
254
273
const targetVideoRefs = getPublicVideoRef (
255
274
config ,
256
275
storage ,
257
276
newVideoReferenceId
258
277
) ;
259
- const privateVideoRefs = {
278
+ const authRestrictedVideoRefs = {
260
279
video : ( storage as Storage . Storage )
261
280
. bucket ( config . privateVideoBucket )
262
- . file ( `private-video/${ privateVideoToken } /video.mp4` ) ,
281
+ . file ( `private-video/${ authRestrictedVideoToken } /video.mp4` ) ,
263
282
264
283
thumbnail : ( storage as Storage . Storage )
265
284
. bucket ( config . privateVideoBucket )
266
- . file ( `private-video/${ privateVideoToken } /thumbnail.jpg` )
285
+ . file ( `private-video/${ authRestrictedVideoToken } /thumbnail.jpg` )
267
286
} ;
268
287
269
- return moveVideo ( targetVideoRefs , privateVideoRefs , removeOriginal ) ;
288
+ return moveVideo ( targetVideoRefs , authRestrictedVideoRefs , removeOriginal ) ;
270
289
}
271
290
272
291
/**
273
- * Legacy method that moves a video from the legacy private invite video bucket
274
- * to the legacy per-member public identity video bucket. This ensures old
275
- * clients will still be able to access videos where they expect to find them .
292
+ * Legacy method that moves a video from the legacy auth-restricted invite video
293
+ * bucket to the public video bucket, at a legacy per-member location. Only one
294
+ * such video can exist .
276
295
*
277
296
* Expects the video to be at /private-video/<videoToken>/video.mp4.
278
297
* Video is moved to /<publicBucket>/<memberUid>/invite.mp4.
298
+ *
299
+ * NOTE: the name of the file is invite, even if the user wasn't invited and
300
+ * just joined by uploading a video of themselves
279
301
*/
280
- export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo (
302
+ export async function LEGACY_moveAuthRestrictedVideoToPublicIdentityVideo (
281
303
config : Config ,
282
304
storage : BucketStorage ,
283
305
memberUid : string ,
@@ -293,7 +315,7 @@ export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo(
293
315
)
294
316
} ;
295
317
296
- const privateVideoRefs = {
318
+ const authRestrictedVideoRefs = {
297
319
video : ( storage as Storage . Storage )
298
320
. bucket ( config . privateVideoBucket )
299
321
. file ( `private-video/${ videoToken } /video.mp4` ) ,
@@ -303,7 +325,7 @@ export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo(
303
325
. file ( `private-video/${ videoToken } /thumbnail.jpg` )
304
326
} ;
305
327
306
- await moveVideo ( publicVideoRefs , privateVideoRefs , removeOriginal ) ;
328
+ await moveVideo ( publicVideoRefs , authRestrictedVideoRefs , removeOriginal ) ;
307
329
}
308
330
309
331
/**
@@ -317,3 +339,69 @@ export function LEGACY_getPublicIdentityVideoUrlForMemberAndToken(
317
339
) : string {
318
340
return getPublicUrlForPath ( config , `${ memberUid } /${ videoToken } /video.mp4` ) ;
319
341
}
342
+
343
+ /**
344
+ * Legacy method that moves a auth-restricted invite video to the public bucket,
345
+ * into the specified member's combined invite/verification video folder. Many
346
+ * of these can exist.
347
+ *
348
+ * Video is moved to /<publicBucket>/<memberUid>/<videoToken>/video.mp4.
349
+ */
350
+ export async function LEGACY_moveAuthRestrictedVideoToPublicMemberInviteVideoFolder (
351
+ config : Config ,
352
+ storage : BucketStorage ,
353
+ memberUid : string ,
354
+ videoToken : string ,
355
+ removeOriginal : boolean
356
+ ) {
357
+ const newVideoPath = `${ memberUid } /${ videoToken } /video.mp4` ;
358
+ const publicVideoBucket = ( storage as Storage . Storage ) . bucket (
359
+ config . publicVideoBucket
360
+ ) ;
361
+ const publicVideoRef = publicVideoBucket . file ( newVideoPath ) ;
362
+ const publicThumbnailRef = publicVideoBucket . file (
363
+ `${ newVideoPath } .thumb.jpg`
364
+ ) ;
365
+
366
+ if ( ( await publicVideoRef . exists ( ) ) [ 0 ] ) {
367
+ throw new HttpApiError (
368
+ httpStatus . BAD_REQUEST ,
369
+ "Video already exists at intended storage destination. Cannot overwrite." ,
370
+ { }
371
+ ) ;
372
+ }
373
+
374
+ const authRestrictedVideoPath = `private-video/${ videoToken } ` ;
375
+ const authRestrictedVideoBucket = ( storage as Storage . Storage ) . bucket (
376
+ config . privateVideoBucket
377
+ ) ;
378
+ const authRestrictedVideoRef = authRestrictedVideoBucket . file (
379
+ `${ authRestrictedVideoPath } /video.mp4`
380
+ ) ;
381
+ const authRestrictedVideoThumbnailRef = ( storage as Storage . Storage )
382
+ . bucket ( config . privateVideoBucket )
383
+ . file ( `${ authRestrictedVideoPath } /thumbnail.jpg` ) ;
384
+
385
+ if ( ! ( await authRestrictedVideoRef . exists ( ) ) [ 0 ] ) {
386
+ throw new HttpApiError (
387
+ httpStatus . BAD_REQUEST ,
388
+ "Private video does not exist at expected location. Cannot move." ,
389
+ { }
390
+ ) ;
391
+ }
392
+
393
+ await ( removeOriginal
394
+ ? authRestrictedVideoRef . move ( publicVideoRef )
395
+ : authRestrictedVideoRef . copy ( publicVideoRef ) ) ;
396
+
397
+ // Until the iOS app gets updated and starts generating thumbnails, we
398
+ // cannot throw an error on the thumbnail not existing.
399
+ // TODO: Throw an error on non-existent thumbnail once the iOS app gets updated.
400
+ if ( ( await authRestrictedVideoThumbnailRef . exists ( ) ) [ 0 ] ) {
401
+ await ( removeOriginal
402
+ ? authRestrictedVideoThumbnailRef . move ( publicThumbnailRef )
403
+ : authRestrictedVideoThumbnailRef . copy ( publicThumbnailRef ) ) ;
404
+ }
405
+
406
+ return publicVideoRef ;
407
+ }
0 commit comments