Skip to content

Commit

Permalink
Merge pull request #174 from isomerpages/develop
Browse files Browse the repository at this point in the history
Merge to prod 12 May
  • Loading branch information
alexanderleegs authored May 12, 2021
2 parents a36562b + af42723 commit bce27dc
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 56 deletions.
35 changes: 26 additions & 9 deletions classes/ImageFile.js → classes/MediaFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ const _ = require('lodash')
const validateStatus = require('../utils/axios-utils')

// Import error
const { NotFoundError } = require('../errors/NotFoundError')
const { NotFoundError } = require('../errors/NotFoundError')
const { ConflictError, inputNameConflictErrorMsg } = require('../errors/ConflictError')

// Constants
const GITHUB_ORG_NAME = 'isomerpages'

class ImageFile {
class MediaFile {
constructor(accessToken, siteName) {
this.accessToken = accessToken
this.siteName = siteName
Expand All @@ -17,14 +18,19 @@ class ImageFile {
this.fileType = null
}

setFileTypeToImage() {
this.fileType = new ImageType()
setFileTypeToImage(directory) {
this.fileType = new ImageType(directory)
this.baseEndpoint = `https://api.github.com/repos/${GITHUB_ORG_NAME}/${this.siteName}/contents/${this.fileType.getFolderName()}`
// Endpoint to retrieve files greater than 1MB
this.baseBlobEndpoint = `https://api.github.com/repos/${GITHUB_ORG_NAME}/${this.siteName}/git/blobs`
}


setFileTypeToDocument(directory) {
this.fileType = new DocumentType(directory)
this.baseEndpoint = `https://api.github.com/repos/${GITHUB_ORG_NAME}/${this.siteName}/contents/${this.fileType.getFolderName()}`
// Endpoint to retrieve files greater than 1MB
this.baseBlobEndpoint = `https://api.github.com/repos/${GITHUB_ORG_NAME}/${this.siteName}/git/blobs`
}

async list() {
try {
Expand Down Expand Up @@ -77,7 +83,9 @@ class ImageFile {

return { sha: resp.data.content.sha }
} catch (err) {
throw err
const status = err.response.status
if (status === 422 || status === 409) throw new ConflictError(inputNameConflictErrorMsg(fileName))
throw err.response
}
}

Expand Down Expand Up @@ -161,11 +169,20 @@ class ImageFile {
}

class ImageType {
constructor() {
this.folderName = 'images'
constructor(directory) {
this.folderName = directory ? directory : 'images'
}
getFolderName() {
return this.folderName
}
}

class DocumentType {
constructor(directory) {
this.folderName = directory ? directory : 'files'
}
getFolderName() {
return this.folderName
}
}
module.exports = { ImageFile }
module.exports = { MediaFile }
87 changes: 87 additions & 0 deletions classes/MediaSubfolder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const _ = require('lodash')

const { File, ImageType, DocumentType } = require('./File.js')
const { getTree, sendTree } = require('../utils/utils.js')

class MediaSubfolder {
constructor(accessToken, siteName, fileType) {
this.accessToken = accessToken
this.siteName = siteName
switch (fileType) {
case 'images':
this.fileType = new ImageType()
this.mediaFolderName = fileType
break
case 'documents':
this.fileType = new DocumentType()
this.mediaFolderName = 'files'
break
default:
throw new Error("Invalid media type!")
}
}

async create(subfolderPath) {
try {
const IsomerFile = new File(this.accessToken, this.siteName)
IsomerFile.setFileType(this.fileType)
await IsomerFile.create(`${subfolderPath}/.keep`, '')
} catch (err) {
throw err
}
}

async delete(subfolderPath, currentCommitSha, treeSha) {
try {
const commitMessage = `Delete ${this.mediaFolderName} subfolder ${subfolderPath}`
const gitTree = await getTree(this.siteName, this.accessToken, treeSha, true)
const directoryName = `${this.mediaFolderName}/${subfolderPath}`
const newGitTree = []
gitTree.forEach(item => {
if (item.path.includes(directoryName)) {
return
} else if (item.type === 'tree' && item.path.includes(this.mediaFolderName)) {
// We don't include any trees in the media folder - we reconstruct them by adding all their individual files instead
return
} else {
newGitTree.push(item)
}
})
await sendTree(newGitTree, currentCommitSha, this.siteName, this.accessToken, commitMessage)
} catch (err) {
throw err
}
}

async rename(oldSubfolderPath, newSubfolderPath, currentCommitSha, treeSha) {
try {
const commitMessage = `Rename ${this.mediaFolderName} subfolder from ${oldSubfolderPath} to ${newSubfolderPath}`

const gitTree = await getTree(this.siteName, this.accessToken, treeSha, true);
const oldDirectoryName = `${this.mediaFolderName}/${oldSubfolderPath}`
const newDirectoryName = `${this.mediaFolderName}/${newSubfolderPath}`
const newGitTree = []
gitTree.forEach(item => {
if (item.path === oldDirectoryName) {
newGitTree.push({
...item,
path: newDirectoryName
})
} else if (item.path.includes(oldDirectoryName)) {
// We don't want to include these because they use the old path, they are included with the renamed tree
return
} else if (item.type === 'tree' && item.path.includes(this.mediaFolderName)) {
// We don't include any other trees - we reconstruct them by adding all their individual files instead
return
} else {
newGitTree.push(item)
}
})
await sendTree(newGitTree, currentCommitSha, this.siteName, this.accessToken, commitMessage);
} catch (err) {
throw err
}
}
}

module.exports = { MediaSubfolder }
21 changes: 20 additions & 1 deletion middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,24 @@ const verifyJwt = (req, res, next) => {
return next('router')
}

// Extracts access_token if any, else set access_token to null
const whoamiAuth = (req, res, next) => {
let access_token
try {
const { isomercms } = req.cookies
access_token = jwtUtils.verifyToken(isomercms).access_token
} catch (err) {
access_token = undefined
} finally {
req.accessToken = access_token
return next('router')
}
}

// Login and logout
auth.get('/v1/auth', noVerify)
auth.get('/v1/auth/logout', noVerify)
auth.get('/v1/auth/whoami', verifyJwt)
auth.get('/v1/auth/whoami', whoamiAuth)

// Index
auth.get('/v1', noVerify)
Expand Down Expand Up @@ -89,6 +103,11 @@ auth.post('/v1/sites/:siteName/images/:imageName', verifyJwt)
auth.delete('/v1/sites/:siteName/images/:imageName', verifyJwt)
auth.post('/v1/sites/:siteName/images/:imageName/rename/:newImageName', verifyJwt)

// Media subfolders
auth.post('/v1/sites/:siteName/media/:mediaType/:folderPath', verifyJwt)
auth.delete('/v1/sites/:siteName/media/:mediaType/:folderPath', verifyJwt)
auth.post('/v1/sites/:siteName/media/:mediaType/:oldFolderPath/rename/:newFolderPath', verifyJwt)

// Menu directory
auth.get('/v1/sites/:siteName/tree', verifyJwt)

Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"http-errors": "~1.6.3",
"js-base64": "^2.5.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.19",
"lodash": "^4.17.21",
"moment-timezone": "^0.5.31",
"morgan": "~1.9.1",
"query-string": "^6.8.3",
Expand Down
23 changes: 14 additions & 9 deletions routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,20 @@ async function whoami(req, res) {
// Make a call to github
const endpoint = 'https://api.github.com/user'

const resp = await axios.get(endpoint, {
headers: {
Authorization: `token ${accessToken}`,
"Content-Type": "application/json"
}
})

const { login: userId } = resp.data
res.status(200).json({ userId })
let userId
try {
const resp = await axios.get(endpoint, {
headers: {
Authorization: `token ${accessToken}`,
"Content-Type": "application/json"
}
})
userId = resp.data.login
} catch (err) {
userId = undefined
} finally {
res.status(200).json({ userId })
}
}

router.get('/', attachReadRouteHandlerWrapper(githubAuth));
Expand Down
7 changes: 6 additions & 1 deletion routes/directory.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ async function listDirectoryContent (req, res, next) {
const IsomerDirectory = new Directory(accessToken, siteName)
const folderType = new FolderType(decodedPath)
IsomerDirectory.setDirType(folderType)
const directoryContents = await IsomerDirectory.list()
let directoryContents = []
try {
directoryContents = await IsomerDirectory.list()
} catch (err) {
console.log(err)
}
res.status(200).json({ directoryContents })
}

Expand Down
55 changes: 41 additions & 14 deletions routes/documents.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,32 @@ const router = express.Router();

// Import classes
const { File, DocumentType } = require('../classes/File.js');
const { MediaFile } = require('../classes/MediaFile.js');
const {
attachReadRouteHandlerWrapper,
attachWriteRouteHandlerWrapper
} = require('../middleware/routeHandler')

const extractDirectoryAndFileName = (documentName) => {
let documentDirectory, documentFileName

// documentName contains the file path excluding the media folder, e.g. subfolder1/subfolder2/file.pdf
const pathArr = documentName.split('/')
if (pathArr.length === 1) {
// documentName only contains the file name
documentDirectory = 'files'
documentFileName = documentName
} else if (pathArr.length > 1) {
// We discard the name of the file for the directory
documentDirectory = `files/${pathArr.slice(0, -1)}`
documentFileName = pathArr[pathArr.length - 1]
}
return {
documentDirectory,
documentFileName,
}
}

// List documents
async function listDocuments (req, res, next) {
const { accessToken } = req
Expand All @@ -26,15 +47,14 @@ async function createNewDocument (req, res, next) {
const { accessToken } = req

const { siteName } = req.params
const { documentName, content } = req.body
const { documentName, documentDirectory, content } = req.body

// TO-DO:
// Validate fileName and content

const IsomerFile = new File(accessToken, siteName)
const documentType = new DocumentType()
IsomerFile.setFileType(documentType)
const { sha } = await IsomerFile.create(documentName, content)
const IsomerDocumentFile = new MediaFile(accessToken, siteName)
IsomerDocumentFile.setFileTypeToDocument(documentDirectory)
const { sha } = await IsomerDocumentFile.create(documentName, content)

res.status(200).json({ documentName, content, sha })
}
Expand All @@ -44,10 +64,12 @@ async function readDocument (req, res, next) {
const { accessToken } = req
const { siteName, documentName } = req.params

const IsomerFile = new File(accessToken, siteName)
const documentType = new DocumentType()
IsomerFile.setFileType(documentType)
const { sha, content } = await IsomerFile.read(documentName)
// get document directory
const { documentDirectory, documentFileName } = extractDirectoryAndFileName(documentName)

const IsomerDocumentFile = new MediaFile(accessToken, siteName)
IsomerDocumentFile.setFileTypeToDocument(documentDirectory)
const { sha, content } = await IsomerDocumentFile.read(documentFileName)

// TO-DO:
// Validate content
Expand Down Expand Up @@ -98,11 +120,16 @@ async function renameDocument (req, res, next) {
// TO-DO:
// Validate documentName and content

const IsomerFile = new File(accessToken, siteName)
const documentType = new DocumentType()
IsomerFile.setFileType(documentType)
const { sha: newSha } = await IsomerFile.create(newDocumentName, content)
await IsomerFile.delete(documentName, sha)
const { documentDirectory: oldDocumentDirectory, documentFileName: oldDocumentFileName } = extractDirectoryAndFileName(documentName)
const { documentDirectory: newDocumentDirectory, documentFileName: newDocumentFileName } = extractDirectoryAndFileName(newDocumentName)

const newIsomerDocumentFile = new MediaFile(accessToken, siteName)
newIsomerDocumentFile.setFileTypeToDocument(newDocumentDirectory)
const { sha: newSha } = await newIsomerDocumentFile.create(newDocumentFileName, content)

const oldIsomerDocumentFile = new MediaFile(accessToken, siteName)
oldIsomerDocumentFile.setFileTypeToDocument(oldDocumentDirectory)
await oldIsomerDocumentFile.delete(oldDocumentFileName, sha)

res.status(200).json({ documentName: newDocumentName, content, sha: newSha })
}
Expand Down
Loading

0 comments on commit bce27dc

Please sign in to comment.