Skip to content

Commit

Permalink
Feat/modify private image retrieval (#740)
Browse files Browse the repository at this point in the history
* feat: add util method to format media info

* fix: use new method to retrieve media info

* chore: remove unused imports

* chore: modify arguments

* Fix: don't export interface

* fix: separate out media directory data retrieval from getMediaFileInfo

* Fix: handle errors when retrieving images

* Chore: move types to types/media

* Refactor: move url retrieval into separate method

* chore: update types and make isPrivate optional

* Test/image retrieval tests (#741)

* feat: add media fixtures

* chore: remove private image tests and fix tests

* feat: add tests for new media util method

* Fix: screaming snake case

* Fix: remove irrelevant test

* chore: swap to jest-mock-axios

* Update src/utils/__tests__/media-utils.spec.ts

Co-authored-by: seaerchin <[email protected]>

* Update src/utils/__tests__/media-utils.spec.ts

Co-authored-by: seaerchin <[email protected]>

* Chore: remove isMediaFileOutput

* test: add new nested media test

---------

Co-authored-by: seaerchin <[email protected]>

---------

Co-authored-by: seaerchin <[email protected]>
  • Loading branch information
alexanderleegs and seaerchin committed May 18, 2023
1 parent e883f73 commit c1363db
Show file tree
Hide file tree
Showing 9 changed files with 376 additions and 133 deletions.
82 changes: 82 additions & 0 deletions src/fixtures/media.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { MediaType, MediaFile } from "@root/types"

export const MEDIA_FILE_NAME = "test file"
export const MEDIA_SITE_NAME = "site"
export const MEDIA_DIRECTORY_NAME = "dir"
export const MEDIA_SUBDIRECTORY_NAME = "sub dir"
export const MEDIA_FILE_SHA = "sha"

export const MEDIA_DIR: MediaFile = {
name: "directory",
type: "dir",
sha: MEDIA_FILE_SHA,
path: `${MEDIA_DIRECTORY_NAME}/directory`,
}

const BASE_MEDIA_FILE: MediaFile = {
name: MEDIA_FILE_NAME,
type: "file",
sha: MEDIA_FILE_SHA,
path: `${MEDIA_DIRECTORY_NAME}/${MEDIA_FILE_NAME}`,
}

export const NESTED_MEDIA_FILE: MediaFile = {
...BASE_MEDIA_FILE,
path: `${MEDIA_DIRECTORY_NAME}/${MEDIA_SUBDIRECTORY_NAME}/${MEDIA_FILE_NAME}`,
}

export const SVG_FILE = {
...BASE_MEDIA_FILE,
name: `${MEDIA_FILE_NAME}.svg`,
path: `${MEDIA_DIRECTORY_NAME}/${MEDIA_FILE_NAME}.svg`,
}

const BASE_INPUT = {
siteName: MEDIA_SITE_NAME,
directoryName: MEDIA_DIRECTORY_NAME,
}

export const DIR_INPUT = {
...BASE_INPUT,
file: MEDIA_DIR,
mediaType: "images" as MediaType,
isPrivate: false,
}

export const IMAGE_FILE_PUBLIC_INPUT = {
...BASE_INPUT,
file: BASE_MEDIA_FILE,
mediaType: "images" as MediaType,
isPrivate: false,
}

export const NESTED_IMAGE_FILE_PUBLIC_INPUT = {
...IMAGE_FILE_PUBLIC_INPUT,
file: NESTED_MEDIA_FILE,
directoryName: `${MEDIA_DIRECTORY_NAME}/${MEDIA_SUBDIRECTORY_NAME}`,
}

export const SVG_FILE_PUBLIC_INPUT = {
...IMAGE_FILE_PUBLIC_INPUT,
file: SVG_FILE,
}

export const IMAGE_FILE_PRIVATE_INPUT = {
...IMAGE_FILE_PUBLIC_INPUT,
isPrivate: true,
}

export const SVG_FILE_PRIVATE_INPUT = {
...SVG_FILE_PUBLIC_INPUT,
isPrivate: true,
}

export const PDF_FILE_PUBLIC_INPUT = {
...IMAGE_FILE_PUBLIC_INPUT,
mediaType: "files" as MediaType,
}

export const PDF_FILE_PRIVATE_INPUT = {
...PDF_FILE_PUBLIC_INPUT,
isPrivate: true,
}
65 changes: 28 additions & 37 deletions src/services/directoryServices/MediaDirectoryService.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
const { config } = require("@config/config")

const { BadRequestError } = require("@errors/BadRequestError")

const GITHUB_ORG_NAME = config.get("github.orgName")
const { isMediaPathValid } = require("@validators/validators")

const PLACEHOLDER_FILE_NAME = ".keep"
const { getMediaFileInfo } = require("@root/utils/media-utils")

const { isMediaPathValid } = require("@validators/validators")
const PLACEHOLDER_FILE_NAME = ".keep"

class MediaDirectoryService {
constructor({ baseDirectoryService, gitHubService }) {
Expand Down Expand Up @@ -40,39 +38,32 @@ class MediaDirectoryService {
const { private: isPrivate } = await this.gitHubService.getRepoInfo(
sessionData
)
const files = await this.listWithDefault(sessionData, { directoryName })

const resp = []
for (const curr of files) {
if (curr.type === "dir") {
resp.push({
name: curr.name,
type: "dir",
})
}
if (curr.type !== "file" || curr.name === PLACEHOLDER_FILE_NAME) continue
const fileData = {
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${curr.path
.split("/")
.map((v) => encodeURIComponent(v))
.join("/")}${curr.path.endsWith(".svg") ? "?sanitize=true" : ""}`,
name: curr.name,
sha: curr.sha,
mediaPath: `${directoryName}/${curr.name}`,
type: curr.type,
}
if (mediaType === "images" && isPrivate) {
// Generate blob url
const imageExt = curr.name.slice(curr.name.lastIndexOf(".") + 1)
const contentType = `image/${imageExt === "svg" ? "svg+xml" : imageExt}`
const { content } = await this.gitHubService.readMedia(sessionData, {
fileSha: curr.sha,
const files = (
await this.listWithDefault(sessionData, { directoryName })
).filter(
(file) =>
(file.type === "file" || file.type === "dir") &&
file.name !== PLACEHOLDER_FILE_NAME
)

const resp = await Promise.all(
files.map((curr) => {
if (curr.type === "dir") {
return {
name: curr.name,
type: "dir",
}
}
return getMediaFileInfo({
file: curr,
siteName,
directoryName,
mediaType,
isPrivate,
})
const blobURL = `data:${contentType};base64,${content}`
fileData.mediaUrl = blobURL
}
resp.push(fileData)
}
})
)

return resp
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,46 +129,6 @@ describe("Media Directory Service", () => {
directoryName: imageDirectoryName,
})
})
mockGitHubService.getRepoInfo.mockResolvedValueOnce({
private: true,
})
mockBaseDirectoryService.list.mockResolvedValueOnce(readImgDirResp)
mockGitHubService.readMedia.mockResolvedValueOnce({
content: mockContent1,
})
mockGitHubService.readMedia.mockResolvedValueOnce({
content: mockContent2,
})
it("ListFiles for an image directory in a private repo returns all images properly formatted", async () => {
const expectedResp = [
{
mediaUrl: `data:image/png;base64,${mockContent1}`,
name: testImg1.name,
sha: testImg1.sha,
mediaPath: `${imageDirectoryName}/${testImg1.name}`,
},
{
mediaUrl: `data:image/svg+xml;base64,${mockContent2}`,
name: testImg2.name,
sha: testImg2.sha,
mediaPath: `${imageDirectoryName}/${testImg2.name}`,
},
{
name: dir.name,
type: dir.type,
},
]
await expect(
service.listFiles(sessionData, {
mediaType: "images",
directoryName: imageDirectoryName,
})
).resolves.toMatchObject(expectedResp)
expect(mockGitHubService.getRepoInfo).toHaveBeenCalledWith(sessionData)
expect(mockBaseDirectoryService.list).toHaveBeenCalledWith(sessionData, {
directoryName: imageDirectoryName,
})
})
mockGitHubService.getRepoInfo.mockResolvedValueOnce({
private: false,
})
Expand Down
35 changes: 9 additions & 26 deletions src/services/fileServices/MdPageServices/MediaFileService.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
const { config } = require("@config/config")

const logger = require("@logger/logger")

const { BadRequestError } = require("@errors/BadRequestError")
const { MediaTypeError } = require("@errors/MediaTypeError")

const GITHUB_ORG_NAME = config.get("github.orgName")

const {
validateAndSanitizeFileUpload,
ALLOWED_FILE_EXTENSIONS,
Expand All @@ -16,6 +12,7 @@ const {
const { isMediaPathValid } = require("@validators/validators")

const { getFileExt } = require("@root/utils/files")
const { getMediaFileInfo } = require("@root/utils/media-utils")

class MediaFileService {
constructor({ gitHubService }) {
Expand Down Expand Up @@ -66,31 +63,17 @@ class MediaFileService {
const targetFile = directoryData.find(
(fileOrDir) => fileOrDir.name === fileName
)
const { sha } = targetFile
const { private: isPrivate } = await this.gitHubService.getRepoInfo(
sessionData
)
const fileData = {
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${directoryName
.split("/")
.map((v) => encodeURIComponent(v))
.join("/")}/${fileName}${
fileName.endsWith(".svg") ? "?sanitize=true" : ""
}`,
name: fileName,
sha,
mediaPath: `${directoryName}/${fileName}`,
}
if (mediaType === "images" && isPrivate) {
// Generate blob url
const imageExt = fileName.slice(fileName.lastIndexOf(".") + 1)
const contentType = `image/${imageExt === "svg" ? "svg+xml" : imageExt}`
const { content } = await this.gitHubService.readMedia(sessionData, {
fileSha: sha,
})
const blobURL = `data:${contentType};base64,${content}`
fileData.mediaUrl = blobURL
}
const fileData = await getMediaFileInfo({
file: targetFile,
siteName,
directoryName,
mediaType,
isPrivate,
})

return fileData
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ describe("Media File Service", () => {
const siteName = "test-site"
const accessToken = "test-token"
const imageName = "test image.png"
const imageEncodedName = encodeURIComponent(imageName)
const fileName = "test file.pdf"
const fileEncodedName = encodeURIComponent(fileName)
const directoryName = "images/subfolder"
const mockContent = "schema, test"
const mockSanitizedContent = "sanitized-test"
Expand Down Expand Up @@ -90,20 +92,24 @@ describe("Media File Service", () => {
const imageDirResp = [
{
name: imageName,
path: `${directoryName}/${imageName}`,
sha,
},
{
name: "image2.png",
path: `${directoryName}/image2.png`,
sha: "image2sha",
},
]
const fileDirResp = [
{
name: fileName,
path: `${directoryName}/${fileName}`,
sha,
},
{
name: "file2.pdf",
path: `${directoryName}/file2.pdf`,
sha: "file2sha",
},
]
Expand All @@ -116,7 +122,7 @@ describe("Media File Service", () => {
})
it("Reading image files in public repos works correctly", async () => {
const expectedResp = {
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${directoryName}/${imageName}`,
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${directoryName}/${imageEncodedName}`,
name: imageName,
sha,
}
Expand All @@ -139,6 +145,7 @@ describe("Media File Service", () => {
...imageDirResp,
{
sha,
path: `${directoryName}/${svgName}`,
name: svgName,
},
])
Expand Down Expand Up @@ -166,34 +173,6 @@ describe("Media File Service", () => {
)
expect(mockGithubService.getRepoInfo).toHaveBeenCalledWith(sessionData)
})
mockGithubService.readDirectory.mockResolvedValueOnce(imageDirResp)
mockGithubService.getRepoInfo.mockResolvedValueOnce({
private: true,
})
it("Reading image files in private repos works correctly", async () => {
const expectedResp = {
mediaUrl: `data:image/png;base64,${mockContent}`,
name: imageName,
sha,
}
await expect(
service.read(sessionData, {
fileName: imageName,
directoryName,
mediaType: "images",
})
).resolves.toMatchObject(expectedResp)
expect(mockGithubService.readDirectory).toHaveBeenCalledWith(
sessionData,
{
directoryName,
}
)
expect(mockGithubService.getRepoInfo).toHaveBeenCalledWith(sessionData)
expect(mockGithubService.readMedia).toHaveBeenCalledWith(sessionData, {
fileSha: sha,
})
})
mockGithubService.readDirectory.mockResolvedValueOnce(fileDirResp)
mockGithubService.getRepoInfo.mockResolvedValueOnce({
private: false,
Expand All @@ -203,7 +182,7 @@ describe("Media File Service", () => {
})
it("Reading files in public repos works correctly", async () => {
const expectedResp = {
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${directoryName}/${fileName}`,
mediaUrl: `https://raw.githubusercontent.com/${GITHUB_ORG_NAME}/${siteName}/staging/${directoryName}/${fileEncodedName}`,
name: fileName,
sha,
}
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./axios"
export * from "./error"
export * from "./media"
export * from "./request"
export * from "./amplify"
25 changes: 25 additions & 0 deletions src/types/media.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export type ItemType = "dir" | "file"
export type MediaType = "images" | "files"

export interface MediaFile {
name: string
type: ItemType
sha: string
path: string
}

export interface MediaFileInput {
file: MediaFile
siteName: string
directoryName: string
mediaType: MediaType
isPrivate?: boolean
}

export interface MediaFileOutput {
name: string
sha: string
mediaUrl: string
mediaPath: string
type: ItemType
}
Loading

0 comments on commit c1363db

Please sign in to comment.