Skip to content

Commit

Permalink
Merge pull request #9 from paywteam/feature/sharing
Browse files Browse the repository at this point in the history
Complete implementation of the feature: sharing
  • Loading branch information
ihooni authored Nov 15, 2019
2 parents efb7c42 + ae8b547 commit 5edd086
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 2 deletions.
19 changes: 17 additions & 2 deletions src/app/http/controllers/GlueBoardController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface IndexResponseBody {
name: string
color: string
}
sharing: boolean
}>
}

Expand All @@ -22,6 +23,7 @@ interface GetResponseBody {
name: string
color: string
}
sharing: boolean
}

export default class GlueBoardController {
Expand Down Expand Up @@ -51,7 +53,8 @@ export default class GlueBoardController {
for (const glueBoard of glueBoards) {
responseBody.glueBoards.push({
id: glueBoard.id,
category: glueBoard.category
category: glueBoard.category,
sharing: glueBoard.sharing
})
}

Expand Down Expand Up @@ -143,7 +146,8 @@ export default class GlueBoardController {
category: {
name: glueBoard.category.name,
color: glueBoard.category.color
}
},
sharing: glueBoard.sharing
}

return res.status(200).json(responseBody)
Expand Down Expand Up @@ -198,6 +202,12 @@ export default class GlueBoardController {
},
errorMessage: '`color` must be a hex color.'
},
sharing: {
optional: true,
in: 'body',
isBoolean: true,
errorMessage: '`sharing` must be a boolean.'
},
position: {
optional: true,
in: 'body',
Expand Down Expand Up @@ -237,6 +247,11 @@ export default class GlueBoardController {
glueBoard.category.color = req.body.color
}

// update sharing option
if (req.body.sharing !== undefined) {
glueBoard.sharing = req.body.sharing
}

await glueBoard.save()

// update relative position in the GlueBoard list
Expand Down
86 changes: 86 additions & 0 deletions src/app/http/controllers/SharingController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Response, SimpleHandler } from '@/http/RequestHandler'
import { GlueBoardDoc } from '@@/migrate/schemas/glue-board'
import GlueBoard from '@@/migrate/models/glue-board'
import { FragmentDoc } from '@@/migrate/schemas/fragment'

interface GetHashResponseBody {
hash: string
}

interface GetResponseBody {
category: {
name: string
color: string
}
fragments: Array<{
url: string
selector: string
xPos: number
yPos: number
scale: number
}>
}

export default class SharingController {
/**
* Get the url hash of the shared GlueBoard
*/
public static getHash(): SimpleHandler {
return (req, res): Response => {
const glueBoard = res.locals.glueBoard as GlueBoardDoc

// if sharing option is off, reject this request.
if (glueBoard.sharing === false) {
return res.status(403).json({
err: {
msg: 'Sharing option for this GlueBoard is off.'
}
})
}

const responseBody: GetHashResponseBody = {
hash: glueBoard.id
}

return res.status(200).json(responseBody)
}
}

/**
* Access to the shared GlueBoard
*/
public static get(): SimpleHandler {
return async (req, res): Promise<Response> => {
const glueBoard = (await GlueBoard.findById(res.locals.glueBoard._id, {
category: 1,
fragments: 1
})
.lean()
.populate({
path: 'fragments',
select: '-_id -id'
})) as GlueBoardDoc

const responseBody: GetResponseBody = {
category: {
name: glueBoard.category.name,
color: glueBoard.category.color
},
fragments: []
}

// compose response body
for (const fragment of glueBoard.fragments as FragmentDoc[]) {
responseBody.fragments.push({
url: fragment.url,
selector: fragment.selector,
xPos: fragment.xPos,
yPos: fragment.yPos,
scale: fragment.scale
})
}

return res.status(200).json(responseBody)
}
}
}
47 changes: 47 additions & 0 deletions src/app/http/middleware/CheckSharing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Response, NextHandler } from '@/http/RequestHandler'
import GlueBoard from '@@/migrate/models/glue-board'
import { GlueBoardDoc } from '@@/migrate/schemas/glue-board'
import { checkSchema, ValidationChain } from 'express-validator'

export default class CheckSharing {
public static validate(): ValidationChain[] {
return checkSchema({
hash: {
exists: true,
in: 'params',
isString: true,
trim: true,
errorMessage: '`hash` must be a string.'
}
})
}

public static handler(): NextHandler {
return async (req, res, next): Promise<Response | void> => {
const glueBoardID = req.params.hash
const glueBoard = (await GlueBoard.findOne({
id: glueBoardID
})) as GlueBoardDoc

if (!glueBoard) {
return res.status(404).json({
err: {
msg: 'Glueboard not found.'
}
})
}

if (!glueBoard.sharing) {
return res.status(403).json({
err: {
msg: 'Unshared GlueBoard.'
}
})
}

res.locals.glueBoard = glueBoard

return next()
}
}
}
28 changes: 28 additions & 0 deletions src/routes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,42 @@ import express from 'express'
import oauth2Router from '@@/routes/oauth2'
import meRouter from '@@/routes/me'
import mirroringRouter from '@@/routes/mirroring'
import RequestValidationError from '@/http/middleware/RequestValidationError'
import CheckSharing from '@/http/middleware/CheckSharing'
import SharingController from '@/http/controllers/SharingController'
import Handle405Error from '@/http/middleware/Handle405Error'

const mainRouter = express.Router()

/**
* Middleware
*/

mainRouter.use(
'/sharing/:hash',
CheckSharing.validate(),
RequestValidationError.handler(),
CheckSharing.handler()
)

/**
* Sub router
*/

mainRouter.use('/oauth2', oauth2Router)
mainRouter.use('/me', meRouter)
mainRouter.use('/mirroring', mirroringRouter)

/**
* Controller
*/

/**
* GET: access to the shared GlueBoard
*/
mainRouter
.route('/sharing/:hash')
.get(SharingController.get())
.all(Handle405Error.handler())

export default mainRouter
9 changes: 9 additions & 0 deletions src/routes/me.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import GlueBoardController from '@/http/controllers/GlueBoardController'
import CheckGlueBoard from '@/http/middleware/CheckGlueBoard'
import FragmentController from '@/http/controllers/FragmentController'
import CheckFragment from '@/http/middleware/CheckFragment'
import SharingController from '@/http/controllers/SharingController'

const meRouter = express.Router({ mergeParams: true })

Expand Down Expand Up @@ -109,4 +110,12 @@ meRouter
.delete(FragmentController.delete())
.all(Handle405Error.handler())

/**
* GET: get the url hash of shared GlueBoard
*/
meRouter
.route('/glueboards/:glueboard/sharing')
.get(SharingController.getHash())
.all(Handle405Error.handler())

export default meRouter

0 comments on commit 5edd086

Please sign in to comment.