-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactored video cloud function and wrote test for delete video
- Loading branch information
Showing
5 changed files
with
189 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { VideoMetadata, VideoService } from './VideoService'; | ||
|
||
import { GetSignedUrlConfig } from '@google-cloud/storage'; | ||
import { Storage } from '@google-cloud/storage'; | ||
import { initializeApp } from "firebase-admin/app"; | ||
import { CollectionReference, Firestore, getFirestore } from "firebase-admin/firestore"; | ||
|
||
const UPLOADED_VIDEO_BUCKET_NAME = 'uploaded-video-bucket'; | ||
const TRANSCODED_VIDEO_BUCKET_NAME = "transcoded-videos-bucket" | ||
initializeApp(); | ||
export class FirebaseVideoService implements VideoService { | ||
private storage: Storage | ||
private firestore: Firestore | ||
private videoCollection: CollectionReference | ||
|
||
|
||
constructor() { | ||
// Creates a client, loading the service account key. | ||
this.storage = new Storage({ keyFilename: 'key.json' }); | ||
this.firestore = getFirestore() | ||
this.videoCollection = this.firestore.collection("Video") | ||
} | ||
|
||
async generateSignedUrlForUpload(videoFileName: string, contentType: string): Promise<string> { | ||
const options: GetSignedUrlConfig = { | ||
version: 'v4', | ||
action: "write", | ||
expires: Date.now() + 15 * 60 * 1000, // 15 minutes | ||
contentType: contentType, | ||
}; | ||
|
||
// Get a v4 signed URL for uploading file | ||
const url = await this.storage | ||
.bucket(UPLOADED_VIDEO_BUCKET_NAME) | ||
.file(videoFileName) | ||
.getSignedUrl(options); | ||
|
||
|
||
return url.toString() | ||
} | ||
|
||
async saveVideoMetadata(videoFileName: string, videoMetadata: VideoMetadata): Promise<void> { | ||
await this.videoCollection.doc(videoFileName).set(videoMetadata, { merge: true }) | ||
} | ||
|
||
|
||
async deleteVideoMetadata(videoId: string): Promise<void> { | ||
let docReference = this.videoCollection.doc(videoId) | ||
let doc = await docReference.get() | ||
if (!doc.exists) { | ||
return | ||
} | ||
await docReference.delete() | ||
} | ||
|
||
async deleteVideoFile(videoFileName: string): Promise<void> { | ||
let transcodedVideoBucket = this.storage.bucket(TRANSCODED_VIDEO_BUCKET_NAME) | ||
let file = transcodedVideoBucket.file(videoFileName) | ||
if (await file.exists()) { | ||
await file.delete() | ||
} | ||
} | ||
|
||
async getVideoMetatadata(videoId: string) { | ||
let docReference = this.videoCollection.doc(videoId) | ||
let doc = await docReference.get() | ||
if (!doc.exists) { | ||
return | ||
} | ||
let data = doc.data()! | ||
return data | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Timestamp } from "firebase-admin/firestore"; | ||
|
||
export type VideoMetadata = { | ||
userId: string | ||
videoName: string, | ||
description: string, | ||
timestamp: Timestamp, | ||
contentType: string, | ||
status: string | ||
}; | ||
|
||
export interface VideoService { | ||
/** | ||
* Delete video metadata in the db. | ||
* @param videoId videoId of the video to delete | ||
* @returns void | ||
*/ | ||
deleteVideoMetadata(videoId: string): Promise<void>; | ||
|
||
/** | ||
* Deletes the stored video file | ||
* @param videoFileName videoId of the video file to delete | ||
* @returns void | ||
*/ | ||
deleteVideoFile(videoFileName: string): Promise<void>; | ||
|
||
/** | ||
* Retrieve video metadata from db | ||
* @param videoId videoId of the video to retrieve metadata for | ||
* @returns video metadata as an object | ||
*/ | ||
getVideoMetatadata(videoId: string): Promise<any> | ||
|
||
/** | ||
* Save video metadata to storage. | ||
* @param videoFileName video file name | ||
* @param videoMetadata object containing video metadata | ||
*/ | ||
saveVideoMetadata(videoFileName: string, videoMetadata: VideoMetadata): Promise<void> | ||
|
||
/** | ||
* Create a signed url for uploading video file to storage bucket | ||
* @param videoFileName video file name to create signed url for | ||
* @param contentType content type of video file | ||
* @returns signed url as a string | ||
*/ | ||
generateSignedUrlForUpload(videoFileName: string, contentType: string): Promise<string> | ||
|
||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import * as sinon from 'sinon'; | ||
import * as mocha from "mocha" | ||
import * as ServiceImpl from '../service/FirebaseVideoService'; | ||
import { VideoMetadata } from '../service/VideoService'; | ||
import { Timestamp } from 'firebase-admin/firestore'; | ||
|
||
const videoServiceStub = sinon.createStubInstance(ServiceImpl.FirebaseVideoService) | ||
|
||
sinon.stub(ServiceImpl, "FirebaseVideoService").callsFake((args) => { | ||
return videoServiceStub | ||
}) | ||
|
||
const cloudFunctions = require('../index'); | ||
describe("Delete video function", function () { | ||
|
||
beforeEach(() => { | ||
const fakeResolutionToVideoId = new Map() | ||
fakeResolutionToVideoId.set("360", "www.test.com") | ||
const fakeVideoData = { | ||
userId: "user", | ||
videoName: "Cool video", | ||
description: "This is a cool video", | ||
timestamp: Timestamp.now(), | ||
contentType: "application/mp3", | ||
status: "Processed", | ||
resolutionToVideoId: fakeResolutionToVideoId | ||
} | ||
|
||
videoServiceStub.getVideoMetatadata.withArgs("ABC").returns(Promise.resolve(fakeVideoData)) | ||
}); | ||
|
||
afterEach(() => { | ||
sinon.resetHistory() | ||
}); | ||
|
||
|
||
it("deletes video metadata and video file", async function () { | ||
const VIDEO_ID = "ABC" | ||
await cloudFunctions.deleteVideo(VIDEO_ID) | ||
assert(videoServiceStub.deleteVideoMetadata.called) | ||
assert(videoServiceStub.deleteVideoFile.calledOnce) | ||
assert(videoServiceStub.deleteVideoFile.calledWith("360_" + VIDEO_ID), "called with wrong arg") | ||
}); | ||
|
||
}) | ||
|
||
function assert(condition: boolean, message = "Assertion failed") { | ||
if (!condition) { | ||
throw new Error(message); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.