Skip to content

Commit 84f3780

Browse files
committed
rename legacy video methods again and better comment what's going on in the legacy case
1 parent f7a7925 commit 84f3780

File tree

3 files changed

+149
-111
lines changed

3 files changed

+149
-111
lines changed

packages/server/src/helpers/legacyVideoMethods.ts

Lines changed: 125 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@
88
* - sendInvite
99
* - createMember
1010
* - 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
1127
*/
1228
import * as Storage from "@google-cloud/storage";
1329
import { storage as adminStorage } from "firebase-admin";
@@ -31,7 +47,17 @@ export type BucketStorage = adminStorage.Storage | Storage.Storage;
3147
// methods, see the section below, where functions are prepended by LEGACY_ or
3248
// LEGACY_COMPAT titles.
3349

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+
}
3561

3662
/**
3763
* Get the public url for a file stored in Google Cloud Storage
@@ -106,7 +132,7 @@ export async function moveVideo(
106132
if (!(await sourceVideoRefs.video.exists())[0]) {
107133
throw new HttpApiError(
108134
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.",
110136
{}
111137
);
112138
}
@@ -130,9 +156,9 @@ export async function moveVideo(
130156
// ----------------------------
131157

132158
/**
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.
136162
*/
137163
export async function LEGACY_createVideoReferenceForInviteVideo(
138164
config: Config,
@@ -163,11 +189,11 @@ export async function LEGACY_createVideoReferenceForInviteVideo(
163189

164190
// we assume this is a legacy request. Copy the legacy video to the new
165191
// video reference location
166-
await LEGACY_COMPAT_movePrivateInviteVideoToNewPublicVideoReferencesBucket({
192+
await LEGACY_COMPAT_moveAuthRestrictedVideoToNewPublicVideoReferencesBucket({
167193
config,
168194
storage,
169195
newVideoReferenceId,
170-
privateVideoToken: videoData.videoToken,
196+
authRestrictedVideoToken: videoData.videoToken,
171197
removeOriginal: false
172198
});
173199

@@ -209,7 +235,7 @@ function LEGACY_getPublicInviteVideoThumbnailRefForMember(
209235
);
210236
}
211237

212-
export function getPublicInviteVideoUrlForMember(
238+
export function LEGACY_getPublicInviteVideoUrlForMember(
213239
config: Config,
214240
memberId: string
215241
): string {
@@ -218,66 +244,62 @@ export function getPublicInviteVideoUrlForMember(
218244
}/${memberId}/invite.mp4`;
219245
}
220246

221-
export function getPublicVideoBucketRef(
222-
config: Config,
223-
storage: BucketStorage
224-
) {
225-
return (storage as Storage.Storage).bucket(config.publicVideoBucket);
226-
}
227-
228247
/**
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.
234253
*
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
237256
* 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.
240259
*/
241-
export async function LEGACY_COMPAT_movePrivateInviteVideoToNewPublicVideoReferencesBucket({
260+
export async function LEGACY_COMPAT_moveAuthRestrictedVideoToNewPublicVideoReferencesBucket({
242261
config,
243262
storage,
244263
newVideoReferenceId,
245-
privateVideoToken,
264+
authRestrictedVideoToken,
246265
removeOriginal
247266
}: {
248267
config: Config;
249268
storage: BucketStorage;
250269
newVideoReferenceId: string;
251-
privateVideoToken: string;
270+
authRestrictedVideoToken: string;
252271
removeOriginal: boolean;
253272
}): Promise<void> {
254273
const targetVideoRefs = getPublicVideoRef(
255274
config,
256275
storage,
257276
newVideoReferenceId
258277
);
259-
const privateVideoRefs = {
278+
const authRestrictedVideoRefs = {
260279
video: (storage as Storage.Storage)
261280
.bucket(config.privateVideoBucket)
262-
.file(`private-video/${privateVideoToken}/video.mp4`),
281+
.file(`private-video/${authRestrictedVideoToken}/video.mp4`),
263282

264283
thumbnail: (storage as Storage.Storage)
265284
.bucket(config.privateVideoBucket)
266-
.file(`private-video/${privateVideoToken}/thumbnail.jpg`)
285+
.file(`private-video/${authRestrictedVideoToken}/thumbnail.jpg`)
267286
};
268287

269-
return moveVideo(targetVideoRefs, privateVideoRefs, removeOriginal);
288+
return moveVideo(targetVideoRefs, authRestrictedVideoRefs, removeOriginal);
270289
}
271290

272291
/**
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.
276295
*
277296
* Expects the video to be at /private-video/<videoToken>/video.mp4.
278297
* 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
279301
*/
280-
export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo(
302+
export async function LEGACY_moveAuthRestrictedVideoToPublicIdentityVideo(
281303
config: Config,
282304
storage: BucketStorage,
283305
memberUid: string,
@@ -293,7 +315,7 @@ export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo(
293315
)
294316
};
295317

296-
const privateVideoRefs = {
318+
const authRestrictedVideoRefs = {
297319
video: (storage as Storage.Storage)
298320
.bucket(config.privateVideoBucket)
299321
.file(`private-video/${videoToken}/video.mp4`),
@@ -303,7 +325,7 @@ export async function LEGACY_movePrivateInviteVideoToPublicInviteVideo(
303325
.file(`private-video/${videoToken}/thumbnail.jpg`)
304326
};
305327

306-
await moveVideo(publicVideoRefs, privateVideoRefs, removeOriginal);
328+
await moveVideo(publicVideoRefs, authRestrictedVideoRefs, removeOriginal);
307329
}
308330

309331
/**
@@ -317,3 +339,69 @@ export function LEGACY_getPublicIdentityVideoUrlForMemberAndToken(
317339
): string {
318340
return getPublicUrlForPath(config, `${memberUid}/${videoToken}/video.mp4`);
319341
}
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+
}

packages/server/src/routes/members/createMember.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import { sendPushNotification } from "../../helpers/sendPushNotification";
2020
import { validateAbilityToCreateOperation } from "../../helpers/abilities";
2121
import {
2222
BucketStorage,
23-
getPublicInviteVideoUrlForMember,
24-
LEGACY_movePrivateInviteVideoToPublicInviteVideo
23+
LEGACY_getPublicInviteVideoUrlForMember,
24+
LEGACY_moveAuthRestrictedVideoToPublicIdentityVideo
2525
} from "../../helpers/legacyVideoMethods";
2626

2727
interface SgClient {
@@ -136,7 +136,10 @@ async function _createInvitedMember(
136136
email_address_is_verified: false,
137137
request_invite_from_member_id: requestInviteFromMemberId,
138138
invite_confirmed: false,
139-
identity_video_url: getPublicInviteVideoUrlForMember(config, loggedInUid),
139+
identity_video_url: LEGACY_getPublicInviteVideoUrlForMember(
140+
config,
141+
loggedInUid
142+
),
140143
created_at: firestore.FieldValue.serverTimestamp()
141144
};
142145

@@ -149,13 +152,18 @@ async function _createInvitedMember(
149152
);
150153
transaction.create(membersCollection.doc(loggedInUid), newMember);
151154

152-
LEGACY_movePrivateInviteVideoToPublicInviteVideo(
155+
LEGACY_moveAuthRestrictedVideoToPublicIdentityVideo(
153156
config,
154157
storage,
155158
loggedInUid,
156159
videoToken,
157-
// If the videoToken == the videoToken of the identity video, then we want to leave
158-
// the private video in place so that the verifier can confirm it.
160+
// If the videoToken == the videoToken of the identity video, it's a joint
161+
// video and the new member elected to use that video as their identity
162+
// video (they didn't record a new one). So, leave the auth-restricted
163+
// invite video in place so that the inviter can confirm it when they verify
164+
// the new member.
165+
// otherwise, we can just move it because the verifier will have to make a
166+
// new verification video anyway.
159167
videoToken !== inviteVideoToken
160168
);
161169

@@ -192,7 +200,10 @@ async function _createUninvitedMember(
192200
email_address: emailAddress || null,
193201
email_address_is_verified: false,
194202
invite_confirmed: false,
195-
identity_video_url: getPublicInviteVideoUrlForMember(config, loggedInUid),
203+
identity_video_url: LEGACY_getPublicInviteVideoUrlForMember(
204+
config,
205+
loggedInUid
206+
),
196207
created_at: firestore.FieldValue.serverTimestamp()
197208
};
198209

@@ -201,7 +212,7 @@ async function _createUninvitedMember(
201212
const newMemberRef = membersCollection.doc(loggedInUid);
202213
transaction.create(newMemberRef, newMember);
203214

204-
LEGACY_movePrivateInviteVideoToPublicInviteVideo(
215+
LEGACY_moveAuthRestrictedVideoToPublicIdentityVideo(
205216
config,
206217
storage,
207218
loggedInUid,

0 commit comments

Comments
 (0)