1
0
Fork 0

wip(backend): Cloning of people

This commit is contained in:
joostdecock 2022-11-14 18:26:20 +01:00
parent e37548fcf7
commit d0b8572f46
6 changed files with 127 additions and 30 deletions

View file

@ -8,7 +8,7 @@ export function PersonController() {}
*/
PersonController.prototype.create = async (req, res, tools) => {
const Person = new PersonModel(tools)
await Person.create(req)
await Person.guardedCreate(req)
return Person.sendResponse(res)
}
@ -19,7 +19,7 @@ PersonController.prototype.create = async (req, res, tools) => {
*/
PersonController.prototype.read = async (req, res, tools) => {
const Person = new PersonModel(tools)
await Person.readForReturn({ id: parseInt(req.params.id) }, req.user)
await Person.guardedRead(req)
return Person.sendResponse(res)
}
@ -50,9 +50,9 @@ PersonController.prototype.delete = async (req, res, tools) => {
* Clone a person
* See: https://freesewing.dev/reference/backend/api
*/
//PersonController.prototype.clone = async (req, res, tools) => {
// const Person = new PersonModel(tools)
// await Person.unsafeUpdate(req)
//
// return Person.sendResponse(res)
//}
PersonController.prototype.clone = async (req, res, tools) => {
const Person = new PersonModel(tools)
await Person.guardedClone(req)
return Person.sendResponse(res)
}

View file

@ -10,7 +10,7 @@ export function UserController() {}
*/
UserController.prototype.signup = async (req, res, tools) => {
const User = new UserModel(tools)
await User.create(req)
await User.guardedCreate(req)
return User.sendResponse(res)
}
@ -48,7 +48,7 @@ UserController.prototype.login = async function (req, res, tools) {
*/
UserController.prototype.whoami = async (req, res, tools) => {
const User = new UserModel(tools)
await User.readForReturn({ id: req.user.uid })
await User.guardedRead({ id: req.user.uid })
return User.sendResponse(res)
}

View file

@ -12,7 +12,7 @@ export function PersonModel(tools) {
return this
}
PersonModel.prototype.create = async function ({ body, user }) {
PersonModel.prototype.guardedCreate = async function ({ body, user }) {
if (user.level < 3) return this.setResponse(403, 'insufficientAccessLevel')
if (Object.keys(body) < 1) return this.setResponse(400, 'postBodyMissing')
if (!body.name || typeof body.name !== 'string') return this.setResponse(400, 'nameMissing')
@ -28,12 +28,7 @@ PersonModel.prototype.create = async function ({ body, user }) {
data.img = this.config.avatars.person
// Create record
try {
this.record = await this.prisma.person.create({ data: this.cloak(data) })
} catch (err) {
log.warn(err, 'Could not create person')
return this.setResponse(500, 'createPersonFailed')
}
await this.unguardedCreate(data)
// Update img? (now that we have the ID)
const img =
@ -49,6 +44,17 @@ PersonModel.prototype.create = async function ({ body, user }) {
return this.setResponse(201, 'created', { person: this.asPerson() })
}
PersonModel.prototype.unguardedCreate = async function (data) {
try {
this.record = await this.prisma.person.create({ data: this.cloak(data) })
} catch (err) {
log.warn(err, 'Could not create person')
return this.setResponse(500, 'createPersonFailed')
}
return this
}
/*
* Loads a person from the database based on the where clause you pass it
*
@ -72,11 +78,11 @@ PersonModel.prototype.read = async function (where) {
*
* Stores result in this.record
*/
PersonModel.prototype.readForReturn = async function (where, user) {
PersonModel.prototype.guardedRead = async function ({ params, user }) {
if (user.level < 1) return this.setResponse(403, 'insufficientAccessLevel')
if (user.iss && user.status < 1) return this.setResponse(403, 'accountStatusLacking')
await this.read(where)
await this.read({ id: parseInt(params.id) })
if (this.record.userId !== user.uid && user.level < 5) {
return this.setResponse(403, 'insufficientAccessLevel')
}
@ -87,6 +93,37 @@ PersonModel.prototype.readForReturn = async function (where, user) {
})
}
/*
* Clones a person
* In addition prepares it for returning the person data
*
* Stores result in this.record
*/
PersonModel.prototype.guardedClone = async function ({ params, user }) {
if (user.level < 3) return this.setResponse(403, 'insufficientAccessLevel')
if (user.iss && user.status < 1) return this.setResponse(403, 'accountStatusLacking')
await this.read({ id: parseInt(params.id) })
if (this.record.userId !== user.uid && !this.record.public && user.level < 5) {
return this.setResponse(403, 'insufficientAccessLevel')
}
// Clone person
const data = this.asPerson()
delete data.id
data.name += ` (cloned from #${this.record.id})`
data.notes += ` (Note: This person was cloned from person #${this.record.id})`
await this.unguardedCreate(data)
// Update unencrypted data
this.reveal()
return this.setResponse(200, false, {
result: 'success',
person: this.asPerson(),
})
}
/*
* Helper method to decrypt at-rest data
*/

View file

@ -67,7 +67,7 @@ UserModel.prototype.cloak = function (data) {
*
* Stores result in this.record
*/
UserModel.prototype.readForReturn = async function (where) {
UserModel.prototype.guardedRead = async function (where) {
await this.read(where)
return this.setResponse(200, false, {
@ -136,7 +136,7 @@ UserModel.prototype.setExists = function () {
/*
* Creates a user+confirmation and sends out signup email
*/
UserModel.prototype.create = async function ({ body }) {
UserModel.prototype.guardedCreate = async function ({ body }) {
if (Object.keys(body) < 1) return this.setResponse(400, 'postBodyMissing')
if (!body.email) return this.setResponse(400, 'emailMissing')
if (!body.language) return this.setResponse(400, 'languageMissing')

View file

@ -15,6 +15,14 @@ export function personRoutes(tools) {
Person.create(req, res, tools)
)
// Clone person
app.post('/people/:id/clone/jwt', passport.authenticate(...jwt), (req, res) =>
Person.clone(req, res, tools)
)
app.post('/people/:id/clone/key', passport.authenticate(...bsc), (req, res) =>
Person.clone(req, res, tools)
)
// Read person
app.get('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
Person.read(req, res, tools)
@ -31,14 +39,6 @@ export function personRoutes(tools) {
Person.update(req, res, tools)
)
// Clone person
app.put('/people/:id/clone/jwt', passport.authenticate(...jwt), (req, res) =>
Person.clone(req, res, tools)
)
app.put('/people/:id/clone/key', passport.authenticate(...bsc), (req, res) =>
Person.clone(req, res, tools)
)
// Delete person
app.delete('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
Person.delete(req, res, tools)

View file

@ -95,7 +95,7 @@ export const personTests = async (chai, config, expect, store) => {
for (const field of ['imperial', 'public']) {
it(`${store.icon('person', auth)} Should update the ${field} field (${auth})`, (done) => {
const data = {}
const val = false
const val = !store.person[auth][field]
data[field] = val
chai
.request(config.api)
@ -115,6 +115,7 @@ export const personTests = async (chai, config, expect, store) => {
expect(res.status).to.equal(200)
expect(res.body.result).to.equal(`success`)
expect(res.body.person[field]).to.equal(val)
store.person[auth][field] = val
done()
})
})
@ -310,6 +311,65 @@ export const personTests = async (chai, config, expect, store) => {
})
})
//it(`${store.icon(
// 'person',
// auth
//)} Should clone a person (${auth})`, (done) => {
// chai
// .request(config.api)
// .post(`/people/${store.person[auth].id}/clone/${auth}`)
// .set(
// 'Authorization',
// auth === 'jwt'
// ? 'Bearer ' + store.account.token
// : 'Basic ' +
// new Buffer(
// `${store.account.apikey.key}:${store.account.apikey.secret}`
// ).toString('base64')
// )
// .end((err, res) => {
// expect(err === null).to.equal(true)
// expect(res.status).to.equal(200)
// expect(res.body.result).to.equal(`success`)
// expect(typeof res.body.error).to.equal(`undefined`)
// expect(typeof res.body.person.id).to.equal(`number`)
// done()
// })
//})
it(`${store.icon(
'person',
auth
)} Should (not) clone a public person across accounts (${auth})`, (done) => {
chai
.request(config.api)
.post(`/people/${store.person[auth].id}/clone/${auth}`)
.set(
'Authorization',
auth === 'jwt'
? 'Bearer ' + store.altaccount.token
: 'Basic ' +
new Buffer(
`${store.altaccount.apikey.key}:${store.altaccount.apikey.secret}`
).toString('base64')
)
.end((err, res) => {
if (store.person[auth].public) {
expect(err === null).to.equal(true)
expect(res.status).to.equal(200)
expect(res.body.result).to.equal(`success`)
expect(typeof res.body.error).to.equal(`undefined`)
expect(typeof res.body.person.id).to.equal(`number`)
} else {
expect(err === null).to.equal(true)
expect(res.status).to.equal(403)
expect(res.body.result).to.equal(`error`)
expect(res.body.error).to.equal(`insufficientAccessLevel`)
}
done()
})
})
// TODO:
// - Clone person
// - Clone person accross accounts of they are public