wip(backend): More work on backend/tests
This commit is contained in:
parent
2297b61d20
commit
b9bb96d837
22 changed files with 905 additions and 101 deletions
|
@ -7,7 +7,6 @@
|
||||||
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
||||||
"homepage": "https://freesewing.org/",
|
"homepage": "https://freesewing.org/",
|
||||||
"repository": "github:freesewing/freesewing",
|
"repository": "github:freesewing/freesewing",
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/freesewing/freesewing/issues"
|
"url": "https://github.com/freesewing/freesewing/issues"
|
||||||
},
|
},
|
||||||
|
@ -30,10 +29,13 @@
|
||||||
"crypto": "^1.0.1",
|
"crypto": "^1.0.1",
|
||||||
"express": "4.18.2",
|
"express": "4.18.2",
|
||||||
"mustache": "^4.2.0",
|
"mustache": "^4.2.0",
|
||||||
|
"passport": "^0.6.0",
|
||||||
"passport-http": "^0.3.0",
|
"passport-http": "^0.3.0",
|
||||||
|
"passport-jwt": "^4.0.0",
|
||||||
"pino": "^8.7.0"
|
"pino": "^8.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"chai-http": "^4.3.0",
|
||||||
"mocha": "^10.1.0",
|
"mocha": "^10.1.0",
|
||||||
"mocha-steps": "^1.3.0",
|
"mocha-steps": "^1.3.0",
|
||||||
"prisma": "4.5.0"
|
"prisma": "4.5.0"
|
||||||
|
|
|
@ -73,9 +73,12 @@ model Pattern {
|
||||||
data String
|
data String
|
||||||
design String
|
design String
|
||||||
img String?
|
img String?
|
||||||
|
name String @default("")
|
||||||
|
notes String
|
||||||
person Person? @relation(fields: [personId], references: [id])
|
person Person? @relation(fields: [personId], references: [id])
|
||||||
personId Int?
|
personId Int?
|
||||||
notes String
|
public Boolean @default(false)
|
||||||
|
settings String
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
userId Int
|
userId Int
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
Binary file not shown.
|
@ -4,7 +4,7 @@ import { log } from '../utils/log.mjs'
|
||||||
import { ApikeyModel } from '../models/apikey.mjs'
|
import { ApikeyModel } from '../models/apikey.mjs'
|
||||||
import { UserModel } from '../models/user.mjs'
|
import { UserModel } from '../models/user.mjs'
|
||||||
|
|
||||||
export function ApikeyController() {}
|
export function ApikeysController() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create API key
|
* Create API key
|
||||||
|
@ -12,7 +12,7 @@ export function ApikeyController() {}
|
||||||
* This is the endpoint that handles creation of API keys/tokens
|
* This is the endpoint that handles creation of API keys/tokens
|
||||||
* See: https://freesewing.dev/reference/backend/api/apikey
|
* See: https://freesewing.dev/reference/backend/api/apikey
|
||||||
*/
|
*/
|
||||||
ApikeyController.prototype.create = async (req, res, tools) => {
|
ApikeysController.prototype.create = async (req, res, tools) => {
|
||||||
const Apikey = new ApikeyModel(tools)
|
const Apikey = new ApikeyModel(tools)
|
||||||
await Apikey.create(req)
|
await Apikey.create(req)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ ApikeyController.prototype.create = async (req, res, tools) => {
|
||||||
* This is the endpoint that handles creation of API keys/tokens
|
* This is the endpoint that handles creation of API keys/tokens
|
||||||
* See: https://freesewing.dev/reference/backend/api/apikey
|
* See: https://freesewing.dev/reference/backend/api/apikey
|
||||||
*/
|
*/
|
||||||
ApikeyController.prototype.read = async (req, res, tools) => {
|
ApikeysController.prototype.read = async (req, res, tools) => {
|
||||||
const Apikey = new ApikeyModel(tools)
|
const Apikey = new ApikeyModel(tools)
|
||||||
await Apikey.guardedRead(req)
|
await Apikey.guardedRead(req)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ ApikeyController.prototype.read = async (req, res, tools) => {
|
||||||
* request
|
* request
|
||||||
* See: https://freesewing.dev/reference/backend/api/apikey
|
* See: https://freesewing.dev/reference/backend/api/apikey
|
||||||
*/
|
*/
|
||||||
ApikeyController.prototype.whoami = async (req, res, tools) => {
|
ApikeysController.prototype.whoami = async (req, res, tools) => {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
const Apikey = new ApikeyModel(tools)
|
const Apikey = new ApikeyModel(tools)
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ ApikeyController.prototype.whoami = async (req, res, tools) => {
|
||||||
* This is the endpoint that handles removal of API keys/tokens
|
* This is the endpoint that handles removal of API keys/tokens
|
||||||
* See: https://freesewing.dev/reference/backend/api/apikey
|
* See: https://freesewing.dev/reference/backend/api/apikey
|
||||||
*/
|
*/
|
||||||
ApikeyController.prototype.delete = async (req, res, tools) => {
|
ApikeysController.prototype.delete = async (req, res, tools) => {
|
||||||
const Apikey = new ApikeyModel(tools)
|
const Apikey = new ApikeyModel(tools)
|
||||||
await Apikey.guardedDelete(req)
|
await Apikey.guardedDelete(req)
|
||||||
|
|
58
sites/backend/src/controllers/patterns.mjs
Normal file
58
sites/backend/src/controllers/patterns.mjs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import { PatternModel } from '../models/pattern.mjs'
|
||||||
|
|
||||||
|
export function PatternsController() {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a pattern
|
||||||
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
|
*/
|
||||||
|
PatternsController.prototype.create = async (req, res, tools) => {
|
||||||
|
const Pattern = new PatternModel(tools)
|
||||||
|
await Pattern.guardedCreate(req)
|
||||||
|
|
||||||
|
return Pattern.sendResponse(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a pattern
|
||||||
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
|
*/
|
||||||
|
PatternsController.prototype.read = async (req, res, tools) => {
|
||||||
|
const Pattern = new PatternModel(tools)
|
||||||
|
await Pattern.guardedRead(req)
|
||||||
|
|
||||||
|
return Pattern.sendResponse(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update a pattern
|
||||||
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
|
*/
|
||||||
|
PatternsController.prototype.update = async (req, res, tools) => {
|
||||||
|
const Pattern = new PatternModel(tools)
|
||||||
|
await Pattern.guardedUpdate(req)
|
||||||
|
|
||||||
|
return Pattern.sendResponse(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove a pattern
|
||||||
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
|
*/
|
||||||
|
PatternsController.prototype.delete = async (req, res, tools) => {
|
||||||
|
const Pattern = new PatternModel(tools)
|
||||||
|
await Pattern.guardedDelete(req)
|
||||||
|
|
||||||
|
return Pattern.sendResponse(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clone a pattern
|
||||||
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
|
*/
|
||||||
|
PatternsController.prototype.clone = async (req, res, tools) => {
|
||||||
|
const Pattern = new PatternModel(tools)
|
||||||
|
await Pattern.guardedClone(req)
|
||||||
|
|
||||||
|
return Pattern.sendResponse(res)
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
import { PersonModel } from '../models/person.mjs'
|
import { PersonModel } from '../models/person.mjs'
|
||||||
|
|
||||||
export function PersonController() {}
|
export function PeopleController() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a person for the authenticated user
|
* Create a person for the authenticated user
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
PersonController.prototype.create = async (req, res, tools) => {
|
PeopleController.prototype.create = async (req, res, tools) => {
|
||||||
const Person = new PersonModel(tools)
|
const Person = new PersonModel(tools)
|
||||||
await Person.guardedCreate(req)
|
await Person.guardedCreate(req)
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ PersonController.prototype.create = async (req, res, tools) => {
|
||||||
* Read a person
|
* Read a person
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
PersonController.prototype.read = async (req, res, tools) => {
|
PeopleController.prototype.read = async (req, res, tools) => {
|
||||||
const Person = new PersonModel(tools)
|
const Person = new PersonModel(tools)
|
||||||
await Person.guardedRead(req)
|
await Person.guardedRead(req)
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ PersonController.prototype.read = async (req, res, tools) => {
|
||||||
* Update a person
|
* Update a person
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
PersonController.prototype.update = async (req, res, tools) => {
|
PeopleController.prototype.update = async (req, res, tools) => {
|
||||||
const Person = new PersonModel(tools)
|
const Person = new PersonModel(tools)
|
||||||
await Person.guardedUpdate(req)
|
await Person.guardedUpdate(req)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ PersonController.prototype.update = async (req, res, tools) => {
|
||||||
* Remove a person
|
* Remove a person
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
PersonController.prototype.delete = async (req, res, tools) => {
|
PeopleController.prototype.delete = async (req, res, tools) => {
|
||||||
const Person = new PersonModel(tools)
|
const Person = new PersonModel(tools)
|
||||||
await Person.guardedDelete(req)
|
await Person.guardedDelete(req)
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ PersonController.prototype.delete = async (req, res, tools) => {
|
||||||
* Clone a person
|
* Clone a person
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
PersonController.prototype.clone = async (req, res, tools) => {
|
PeopleController.prototype.clone = async (req, res, tools) => {
|
||||||
const Person = new PersonModel(tools)
|
const Person = new PersonModel(tools)
|
||||||
await Person.guardedClone(req)
|
await Person.guardedClone(req)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { UserModel } from '../models/user.mjs'
|
import { UserModel } from '../models/user.mjs'
|
||||||
|
|
||||||
export function UserController() {}
|
export function UsersController() {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signup
|
* Signup
|
||||||
|
@ -8,7 +8,7 @@ export function UserController() {}
|
||||||
* This is the endpoint that handles account signups
|
* This is the endpoint that handles account signups
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
UserController.prototype.signup = async (req, res, tools) => {
|
UsersController.prototype.signup = async (req, res, tools) => {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
await User.guardedCreate(req)
|
await User.guardedCreate(req)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ UserController.prototype.signup = async (req, res, tools) => {
|
||||||
* This is the endpoint that fully unlocks the account if the user gives their consent
|
* This is the endpoint that fully unlocks the account if the user gives their consent
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
UserController.prototype.confirm = async (req, res, tools) => {
|
UsersController.prototype.confirm = async (req, res, tools) => {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
await User.confirm(req)
|
await User.confirm(req)
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ UserController.prototype.confirm = async (req, res, tools) => {
|
||||||
* This is the endpoint that provides traditional username/password login
|
* This is the endpoint that provides traditional username/password login
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
UserController.prototype.login = async function (req, res, tools) {
|
UsersController.prototype.login = async function (req, res, tools) {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
await User.passwordLogin(req)
|
await User.passwordLogin(req)
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ UserController.prototype.login = async function (req, res, tools) {
|
||||||
*
|
*
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
UserController.prototype.whoami = async (req, res, tools) => {
|
UsersController.prototype.whoami = async (req, res, tools) => {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
await User.guardedRead({ id: req.user.uid }, req)
|
await User.guardedRead({ id: req.user.uid }, req)
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ UserController.prototype.whoami = async (req, res, tools) => {
|
||||||
*
|
*
|
||||||
* See: https://freesewing.dev/reference/backend/api
|
* See: https://freesewing.dev/reference/backend/api
|
||||||
*/
|
*/
|
||||||
UserController.prototype.update = async (req, res, tools) => {
|
UsersController.prototype.update = async (req, res, tools) => {
|
||||||
const User = new UserModel(tools)
|
const User = new UserModel(tools)
|
||||||
await User.guardedRead({ id: req.user.uid }, req)
|
await User.guardedRead({ id: req.user.uid }, req)
|
||||||
await User.guardedUpdate(req)
|
await User.guardedUpdate(req)
|
317
sites/backend/src/models/pattern.mjs
Normal file
317
sites/backend/src/models/pattern.mjs
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
import { log } from '../utils/log.mjs'
|
||||||
|
import { setPatternAvatar } from '../utils/sanity.mjs'
|
||||||
|
|
||||||
|
export function PatternModel(tools) {
|
||||||
|
this.config = tools.config
|
||||||
|
this.prisma = tools.prisma
|
||||||
|
this.decrypt = tools.decrypt
|
||||||
|
this.encrypt = tools.encrypt
|
||||||
|
this.encryptedFields = ['data', 'img', 'name', 'notes', 'settings']
|
||||||
|
this.clear = {} // For holding decrypted data
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
data String
|
||||||
|
design String
|
||||||
|
img String?
|
||||||
|
person Person? @relation(fields: [personId], references: [id])
|
||||||
|
personId Int?
|
||||||
|
name String @default("")
|
||||||
|
notes String
|
||||||
|
public
|
||||||
|
settings String
|
||||||
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
userId Int
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
*/
|
||||||
|
|
||||||
|
PatternModel.prototype.guardedCreate = async function ({ body, user }) {
|
||||||
|
if (user.level < 3) return this.setResponse(403, 'insufficientAccessLevel')
|
||||||
|
if (Object.keys(body) < 2) return this.setResponse(400, 'postBodyMissing')
|
||||||
|
if (!body.person) return this.setResponse(400, 'personMissing')
|
||||||
|
if (typeof body.person !== 'number') return this.setResponse(400, 'personNotNumeric')
|
||||||
|
if (typeof body.settings !== 'object') return this.setResponse(400, 'settingsNotAnObject')
|
||||||
|
if (body.data && typeof body.data !== 'object') return this.setResponse(400, 'dataNotAnObject')
|
||||||
|
if (!body.design && !body.data?.design) return this.setResponse(400, 'designMissing')
|
||||||
|
if (typeof body.design !== 'string') return this.setResponse(400, 'designNotStringy')
|
||||||
|
|
||||||
|
// Prepare data
|
||||||
|
const data = {
|
||||||
|
design: body.design,
|
||||||
|
personId: body.person,
|
||||||
|
settings: body.settings,
|
||||||
|
}
|
||||||
|
// Data (will be encrypted, so always set _some_ value)
|
||||||
|
if (typeof body.data === 'object') data.data = body.data
|
||||||
|
else data.data = {}
|
||||||
|
// Name (will be encrypted, so always set _some_ value)
|
||||||
|
if (typeof body.name === 'string' && body.name.length > 0) data.name = body.name
|
||||||
|
else data.name = '--'
|
||||||
|
// Notes (will be encrypted, so always set _some_ value)
|
||||||
|
if (typeof body.notes === 'string' && body.notes.length > 0) data.notes = body.notes
|
||||||
|
else data.notes = '--'
|
||||||
|
// Public
|
||||||
|
if (body.public === true) data.public = true
|
||||||
|
data.userId = user.uid
|
||||||
|
// Set this one initially as we need the ID to create a custom img via Sanity
|
||||||
|
data.img = this.config.avatars.pattern
|
||||||
|
|
||||||
|
// Create record
|
||||||
|
await this.unguardedCreate(data)
|
||||||
|
|
||||||
|
// Update img? (now that we have the ID)
|
||||||
|
const img =
|
||||||
|
this.config.use.sanity &&
|
||||||
|
typeof body.img === 'string' &&
|
||||||
|
(!body.unittest || (body.unittest && this.config.use.tests?.sanity))
|
||||||
|
? await setPatternAvatar(this.record.id, body.img)
|
||||||
|
: false
|
||||||
|
|
||||||
|
if (img) await this.unguardedUpdate(this.cloak({ img: img.url }))
|
||||||
|
else await this.read({ id: this.record.id })
|
||||||
|
|
||||||
|
return this.setResponse(201, 'created', { pattern: this.asPattern() })
|
||||||
|
}
|
||||||
|
|
||||||
|
PatternModel.prototype.unguardedCreate = async function (data) {
|
||||||
|
try {
|
||||||
|
this.record = await this.prisma.pattern.create({ data: this.cloak(data) })
|
||||||
|
} catch (err) {
|
||||||
|
log.warn(err, 'Could not create pattern')
|
||||||
|
return this.setResponse(500, 'createPatternFailed')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads a pattern from the database based on the where clause you pass it
|
||||||
|
*
|
||||||
|
* Stores result in this.record
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.read = async function (where) {
|
||||||
|
try {
|
||||||
|
this.record = await this.prisma.pattern.findUnique({ where })
|
||||||
|
} catch (err) {
|
||||||
|
log.warn({ err, where }, 'Could not read pattern')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reveal()
|
||||||
|
|
||||||
|
return this.setExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loads a pattern from the database based on the where clause you pass it
|
||||||
|
* In addition prepares it for returning the pattern data
|
||||||
|
*
|
||||||
|
* Stores result in this.record
|
||||||
|
*/
|
||||||
|
PatternModel.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({ id: parseInt(params.id) })
|
||||||
|
if (this.record.userId !== user.uid && user.level < 5) {
|
||||||
|
return this.setResponse(403, 'insufficientAccessLevel')
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.setResponse(200, false, {
|
||||||
|
result: 'success',
|
||||||
|
pattern: this.asPattern(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clones a pattern
|
||||||
|
* In addition prepares it for returning the pattern data
|
||||||
|
*
|
||||||
|
* Stores result in this.record
|
||||||
|
*/
|
||||||
|
PatternModel.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 pattern
|
||||||
|
const data = this.asPattern()
|
||||||
|
delete data.id
|
||||||
|
data.name += ` (cloned from #${this.record.id})`
|
||||||
|
data.notes += ` (Note: This pattern was cloned from pattern #${this.record.id})`
|
||||||
|
await this.unguardedCreate(data)
|
||||||
|
|
||||||
|
// Update unencrypted data
|
||||||
|
this.reveal()
|
||||||
|
|
||||||
|
return this.setResponse(200, false, {
|
||||||
|
result: 'success',
|
||||||
|
pattern: this.asPattern(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method to decrypt at-rest data
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.reveal = async function () {
|
||||||
|
this.clear = {}
|
||||||
|
if (this.record) {
|
||||||
|
for (const field of this.encryptedFields) {
|
||||||
|
this.clear[field] = this.decrypt(this.record[field])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method to encrypt at-rest data
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.cloak = function (data) {
|
||||||
|
for (const field of this.encryptedFields) {
|
||||||
|
if (typeof data[field] !== 'undefined') {
|
||||||
|
data[field] = this.encrypt(data[field])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks this.record and sets a boolean to indicate whether
|
||||||
|
* the pattern exists or not
|
||||||
|
*
|
||||||
|
* Stores result in this.exists
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.setExists = function () {
|
||||||
|
this.exists = this.record ? true : false
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the pattern data - Used when we create the data ourselves
|
||||||
|
* so we know it's safe
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.unguardedUpdate = async function (data) {
|
||||||
|
try {
|
||||||
|
this.record = await this.prisma.pattern.update({
|
||||||
|
where: { id: this.record.id },
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
log.warn(err, 'Could not update pattern record')
|
||||||
|
process.exit()
|
||||||
|
return this.setResponse(500, 'updatePatternFailed')
|
||||||
|
}
|
||||||
|
await this.reveal()
|
||||||
|
|
||||||
|
return this.setResponse(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Updates the pattern data - Used when we pass through user-provided data
|
||||||
|
* so we can't be certain it's safe
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.guardedUpdate = async function ({ params, body, 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 && user.level < 8) {
|
||||||
|
return this.setResponse(403, 'insufficientAccessLevel')
|
||||||
|
}
|
||||||
|
const data = {}
|
||||||
|
// Name
|
||||||
|
if (typeof body.name === 'string') data.name = body.name
|
||||||
|
// Notes
|
||||||
|
if (typeof body.notes === 'string') data.notes = body.notes
|
||||||
|
// Public
|
||||||
|
if (body.public === true || body.public === false) data.public = body.public
|
||||||
|
// Data
|
||||||
|
if (typeof body.data === 'object') data.data = body.data
|
||||||
|
// Settings
|
||||||
|
if (typeof body.settings === 'object') data.settings = body.settings
|
||||||
|
// Image (img)
|
||||||
|
if (typeof body.img === 'string') {
|
||||||
|
const img = await setPatternAvatar(params.id, body.img)
|
||||||
|
data.img = img.url
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now update the record
|
||||||
|
await this.unguardedUpdate(this.cloak(data))
|
||||||
|
|
||||||
|
return this.setResponse(200, false, { pattern: this.asPattern() })
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes the pattern - No questions asked
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.unguardedDelete = async function () {
|
||||||
|
await this.prisma.pattern.delete({ here: { id: this.record.id } })
|
||||||
|
this.record = null
|
||||||
|
this.clear = null
|
||||||
|
|
||||||
|
return this.setExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes the pattern - Checks permissions
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.guardedDelete = async function ({ params, body, 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 && user.level < 8) {
|
||||||
|
return this.setResponse(403, 'insufficientAccessLevel')
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.unguardedDelete()
|
||||||
|
|
||||||
|
return this.setResponse(204, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns record data
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.asPattern = function () {
|
||||||
|
return {
|
||||||
|
...this.record,
|
||||||
|
...this.clear,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method to set the response code, result, and body
|
||||||
|
*
|
||||||
|
* Will be used by this.sendResponse()
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.setResponse = function (status = 200, error = false, data = {}) {
|
||||||
|
this.response = {
|
||||||
|
status,
|
||||||
|
body: {
|
||||||
|
result: 'success',
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (status > 201) {
|
||||||
|
this.response.body.error = error
|
||||||
|
this.response.body.result = 'error'
|
||||||
|
this.error = true
|
||||||
|
} else this.error = false
|
||||||
|
|
||||||
|
return this.setExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper method to send response
|
||||||
|
*/
|
||||||
|
PatternModel.prototype.sendResponse = async function (res) {
|
||||||
|
return res.status(this.response.status).send(this.response.body)
|
||||||
|
}
|
|
@ -19,7 +19,12 @@ PersonModel.prototype.guardedCreate = async function ({ body, user }) {
|
||||||
|
|
||||||
// Prepare data
|
// Prepare data
|
||||||
const data = { name: body.name }
|
const data = { name: body.name }
|
||||||
|
// Name (will be encrypted, so always set _some_ value)
|
||||||
|
if (typeof body.name === 'string') data.name = body.name
|
||||||
|
else data.name = '--'
|
||||||
|
// Notes (will be encrypted, so always set _some_ value)
|
||||||
if (body.notes || typeof body.notes === 'string') data.notes = body.notes
|
if (body.notes || typeof body.notes === 'string') data.notes = body.notes
|
||||||
|
else data.notes = '--'
|
||||||
if (body.public === true) data.public = true
|
if (body.public === true) data.public = true
|
||||||
if (body.measies) data.measies = this.sanitizeMeasurements(body.measies)
|
if (body.measies) data.measies = this.sanitizeMeasurements(body.measies)
|
||||||
data.imperial = body.imperial === true ? true : false
|
data.imperial = body.imperial === true ? true : false
|
||||||
|
|
|
@ -223,9 +223,9 @@ UserModel.prototype.guardedCreate = async function ({ body }) {
|
||||||
* Login based on username + password
|
* Login based on username + password
|
||||||
*/
|
*/
|
||||||
UserModel.prototype.passwordLogin = async function (req) {
|
UserModel.prototype.passwordLogin = async function (req) {
|
||||||
if (Object.keys(req.body) < 1) return this.setReponse(400, 'postBodyMissing')
|
if (Object.keys(req.body) < 1) return this.setResponse(400, 'postBodyMissing')
|
||||||
if (!req.body.username) return this.setReponse(400, 'usernameMissing')
|
if (!req.body.username) return this.setResponse(400, 'usernameMissing')
|
||||||
if (!req.body.password) return this.setReponse(400, 'passwordMissing')
|
if (!req.body.password) return this.setResponse(400, 'passwordMissing')
|
||||||
|
|
||||||
await this.find(req.body)
|
await this.find(req.body)
|
||||||
if (!this.exists) {
|
if (!this.exists) {
|
||||||
|
@ -255,7 +255,7 @@ UserModel.prototype.passwordLogin = async function (req) {
|
||||||
* Confirms a user account
|
* Confirms a user account
|
||||||
*/
|
*/
|
||||||
UserModel.prototype.confirm = async function ({ body, params }) {
|
UserModel.prototype.confirm = async function ({ body, params }) {
|
||||||
if (!params.id) return this.setReponse(404, 'missingConfirmationId')
|
if (!params.id) return this.setResponse(404, 'missingConfirmationId')
|
||||||
if (Object.keys(body) < 1) return this.setResponse(400, 'postBodyMissing')
|
if (Object.keys(body) < 1) return this.setResponse(400, 'postBodyMissing')
|
||||||
if (!body.consent || typeof body.consent !== 'number' || body.consent < 1)
|
if (!body.consent || typeof body.consent !== 'number' || body.consent < 1)
|
||||||
return this.setResponse(400, 'consentRequired')
|
return this.setResponse(400, 'consentRequired')
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { ApikeyController } from '../controllers/apikey.mjs'
|
|
||||||
|
|
||||||
const Apikey = new ApikeyController()
|
|
||||||
const jwt = ['jwt', { session: false }]
|
|
||||||
const bsc = ['basic', { session: false }]
|
|
||||||
|
|
||||||
export function apikeyRoutes(tools) {
|
|
||||||
const { app, passport } = tools
|
|
||||||
|
|
||||||
// Create Apikey
|
|
||||||
app.post('/apikey/jwt', passport.authenticate(...jwt), (req, res) =>
|
|
||||||
Apikey.create(req, res, tools)
|
|
||||||
)
|
|
||||||
app.post('/apikey/key', passport.authenticate(...bsc), (req, res) =>
|
|
||||||
Apikey.create(req, res, tools)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read Apikey
|
|
||||||
app.get('/apikey/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
|
||||||
Apikey.read(req, res, tools)
|
|
||||||
)
|
|
||||||
app.get('/apikey/:id/key', passport.authenticate(...bsc), (req, res) =>
|
|
||||||
Apikey.read(req, res, tools)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read current Apikey
|
|
||||||
app.get('/whoami/key', passport.authenticate(...bsc), (req, res) =>
|
|
||||||
Apikey.whoami(req, res, tools)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Remove Apikey
|
|
||||||
app.delete('/apikey/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
|
||||||
Apikey.delete(req, res, tools)
|
|
||||||
)
|
|
||||||
app.delete('/apikey/:id/key', passport.authenticate(...bsc), (req, res) =>
|
|
||||||
Apikey.delete(req, res, tools)
|
|
||||||
)
|
|
||||||
}
|
|
38
sites/backend/src/routes/apikeys.mjs
Normal file
38
sites/backend/src/routes/apikeys.mjs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { ApikeysController } from '../controllers/apikeys.mjs'
|
||||||
|
|
||||||
|
const Apikeys = new ApikeysController()
|
||||||
|
const jwt = ['jwt', { session: false }]
|
||||||
|
const bsc = ['basic', { session: false }]
|
||||||
|
|
||||||
|
export function apikeysRoutes(tools) {
|
||||||
|
const { app, passport } = tools
|
||||||
|
|
||||||
|
// Create Apikey
|
||||||
|
app.post('/apikeys/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Apikeys.create(req, res, tools)
|
||||||
|
)
|
||||||
|
app.post('/apikeys/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Apikeys.create(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read Apikey
|
||||||
|
app.get('/apikeys/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Apikeys.read(req, res, tools)
|
||||||
|
)
|
||||||
|
app.get('/apikeys/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Apikeys.read(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read current Apikey
|
||||||
|
app.get('/whoami/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Apikeys.whoami(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Remove Apikey
|
||||||
|
app.delete('/apikeys/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Apikeys.delete(req, res, tools)
|
||||||
|
)
|
||||||
|
app.delete('/apikeys/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Apikeys.delete(req, res, tools)
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
import { apikeyRoutes } from './apikey.mjs'
|
import { apikeysRoutes } from './apikeys.mjs'
|
||||||
import { userRoutes } from './user.mjs'
|
import { usersRoutes } from './users.mjs'
|
||||||
import { personRoutes } from './person.mjs'
|
import { peopleRoutes } from './people.mjs'
|
||||||
|
import { patternsRoutes } from './patterns.mjs'
|
||||||
|
|
||||||
export const routes = {
|
export const routes = {
|
||||||
apikeyRoutes,
|
apikeysRoutes,
|
||||||
userRoutes,
|
usersRoutes,
|
||||||
personRoutes,
|
peopleRoutes,
|
||||||
|
patternsRoutes,
|
||||||
}
|
}
|
||||||
|
|
49
sites/backend/src/routes/patterns.mjs
Normal file
49
sites/backend/src/routes/patterns.mjs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { PatternsController } from '../controllers/patterns.mjs'
|
||||||
|
|
||||||
|
const Patterns = new PatternsController()
|
||||||
|
const jwt = ['jwt', { session: false }]
|
||||||
|
const bsc = ['basic', { session: false }]
|
||||||
|
|
||||||
|
export function patternsRoutes(tools) {
|
||||||
|
const { app, passport } = tools
|
||||||
|
|
||||||
|
// Create pattern
|
||||||
|
app.post('/patterns/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Patterns.create(req, res, tools)
|
||||||
|
)
|
||||||
|
app.post('/patterns/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Patterns.create(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clone pattern
|
||||||
|
app.post('/patterns/:id/clone/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Patterns.clone(req, res, tools)
|
||||||
|
)
|
||||||
|
app.post('/patterns/:id/clone/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Patterns.clone(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read pattern
|
||||||
|
app.get('/patterns/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Patterns.read(req, res, tools)
|
||||||
|
)
|
||||||
|
app.get('/patterns/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Patterns.read(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update pattern
|
||||||
|
app.put('/patterns/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Patterns.update(req, res, tools)
|
||||||
|
)
|
||||||
|
app.put('/patterns/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Patterns.update(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete pattern
|
||||||
|
app.delete('/patterns/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
|
Patterns.delete(req, res, tools)
|
||||||
|
)
|
||||||
|
app.delete('/patterns/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Patterns.delete(req, res, tools)
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,49 +1,49 @@
|
||||||
import { PersonController } from '../controllers/person.mjs'
|
import { PeopleController } from '../controllers/people.mjs'
|
||||||
|
|
||||||
const Person = new PersonController()
|
const People = new PeopleController()
|
||||||
const jwt = ['jwt', { session: false }]
|
const jwt = ['jwt', { session: false }]
|
||||||
const bsc = ['basic', { session: false }]
|
const bsc = ['basic', { session: false }]
|
||||||
|
|
||||||
export function personRoutes(tools) {
|
export function peopleRoutes(tools) {
|
||||||
const { app, passport } = tools
|
const { app, passport } = tools
|
||||||
|
|
||||||
// Create person
|
// Create person
|
||||||
app.post('/people/jwt', passport.authenticate(...jwt), (req, res) =>
|
app.post('/people/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
Person.create(req, res, tools)
|
People.create(req, res, tools)
|
||||||
)
|
)
|
||||||
app.post('/people/key', passport.authenticate(...bsc), (req, res) =>
|
app.post('/people/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
Person.create(req, res, tools)
|
People.create(req, res, tools)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Clone person
|
// Clone person
|
||||||
app.post('/people/:id/clone/jwt', passport.authenticate(...jwt), (req, res) =>
|
app.post('/people/:id/clone/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
Person.clone(req, res, tools)
|
People.clone(req, res, tools)
|
||||||
)
|
)
|
||||||
app.post('/people/:id/clone/key', passport.authenticate(...bsc), (req, res) =>
|
app.post('/people/:id/clone/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
Person.clone(req, res, tools)
|
People.clone(req, res, tools)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Read person
|
// Read person
|
||||||
app.get('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
app.get('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
Person.read(req, res, tools)
|
People.read(req, res, tools)
|
||||||
)
|
)
|
||||||
app.get('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
app.get('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
Person.read(req, res, tools)
|
People.read(req, res, tools)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Update person
|
// Update person
|
||||||
app.put('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
app.put('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
Person.update(req, res, tools)
|
People.update(req, res, tools)
|
||||||
)
|
)
|
||||||
app.put('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
app.put('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
Person.update(req, res, tools)
|
People.update(req, res, tools)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Delete person
|
// Delete person
|
||||||
app.delete('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
app.delete('/people/:id/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
Person.delete(req, res, tools)
|
People.delete(req, res, tools)
|
||||||
)
|
)
|
||||||
app.delete('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
app.delete('/people/:id/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
Person.delete(req, res, tools)
|
People.delete(req, res, tools)
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,30 +1,38 @@
|
||||||
import { UserController } from '../controllers/user.mjs'
|
import { UsersController } from '../controllers/users.mjs'
|
||||||
|
|
||||||
const User = new UserController()
|
const Users = new UsersController()
|
||||||
const jwt = ['jwt', { session: false }]
|
const jwt = ['jwt', { session: false }]
|
||||||
const bsc = ['basic', { session: false }]
|
const bsc = ['basic', { session: false }]
|
||||||
|
|
||||||
export function userRoutes(tools) {
|
export function usersRoutes(tools) {
|
||||||
const { app, passport } = tools
|
const { app, passport } = tools
|
||||||
|
|
||||||
// Sign up
|
// Sign up
|
||||||
app.post('/signup', (req, res) => User.signup(req, res, tools))
|
app.post('/signup', (req, res) => Users.signup(req, res, tools))
|
||||||
|
|
||||||
// Confirm account
|
// Confirm account
|
||||||
app.post('/confirm/signup/:id', (req, res) => User.confirm(req, res, tools))
|
app.post('/confirm/signup/:id', (req, res) => Users.confirm(req, res, tools))
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
app.post('/login', (req, res) => User.login(req, res, tools))
|
app.post('/login', (req, res) => Users.login(req, res, tools))
|
||||||
|
|
||||||
// Read current jwt
|
// Read current jwt
|
||||||
|
|
||||||
app.get('/whoami/jwt', passport.authenticate(...jwt), (req, res) => User.whoami(req, res, tools))
|
app.get('/whoami/jwt', passport.authenticate(...jwt), (req, res) => Users.whoami(req, res, tools))
|
||||||
app.get('/account/jwt', passport.authenticate(...jwt), (req, res) => User.whoami(req, res, tools))
|
app.get('/account/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
app.get('/account/key', passport.authenticate(...bsc), (req, res) => User.whoami(req, res, tools))
|
Users.whoami(req, res, tools)
|
||||||
|
)
|
||||||
|
app.get('/account/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Users.whoami(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
// Update account
|
// Update account
|
||||||
app.put('/account/jwt', passport.authenticate(...jwt), (req, res) => User.update(req, res, tools))
|
app.put('/account/jwt', passport.authenticate(...jwt), (req, res) =>
|
||||||
app.put('/account/key', passport.authenticate(...bsc), (req, res) => User.update(req, res, tools))
|
Users.update(req, res, tools)
|
||||||
|
)
|
||||||
|
app.put('/account/key', passport.authenticate(...bsc), (req, res) =>
|
||||||
|
Users.update(req, res, tools)
|
||||||
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -33,6 +33,7 @@ async function getAvatar(type, id) {
|
||||||
*/
|
*/
|
||||||
export const setUserAvatar = async (id, data) => setAvatar('user', id, data)
|
export const setUserAvatar = async (id, data) => setAvatar('user', id, data)
|
||||||
export const setPersonAvatar = async (id, data) => setAvatar('person', id, data)
|
export const setPersonAvatar = async (id, data) => setAvatar('person', id, data)
|
||||||
|
export const setPatternAvatar = async (id, data) => setAvatar('pattern', id, data)
|
||||||
export async function setAvatar(type, id, data) {
|
export async function setAvatar(type, id, data) {
|
||||||
// Step 1: Upload the image as asset
|
// Step 1: Upload the image as asset
|
||||||
const [contentType, binary] = b64ToBinaryWithType(data)
|
const [contentType, binary] = b64ToBinaryWithType(data)
|
||||||
|
|
|
@ -3,7 +3,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'jwt')} Create API Key (jwt)`, (done) => {
|
step(`${store.icon('key', 'jwt')} Create API Key (jwt)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.post('/apikey/jwt')
|
.post('/apikeys/jwt')
|
||||||
.set('Authorization', 'Bearer ' + store.account.token)
|
.set('Authorization', 'Bearer ' + store.account.token)
|
||||||
.send({
|
.send({
|
||||||
name: 'Test API key',
|
name: 'Test API key',
|
||||||
|
@ -27,7 +27,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'key')} Create API Key (key)`, (done) => {
|
step(`${store.icon('key', 'key')} Create API Key (key)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.post('/apikey/key')
|
.post('/apikeys/key')
|
||||||
.auth(store.apikey1.key, store.apikey1.secret)
|
.auth(store.apikey1.key, store.apikey1.secret)
|
||||||
.send({
|
.send({
|
||||||
name: 'Test API key with key',
|
name: 'Test API key with key',
|
||||||
|
@ -67,7 +67,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'key')} Read API key (key)`, (done) => {
|
step(`${store.icon('key', 'key')} Read API key (key)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.get(`/apikey/${store.apikey1.key}/key`)
|
.get(`/apikeys/${store.apikey1.key}/key`)
|
||||||
.auth(store.apikey2.key, store.apikey2.secret)
|
.auth(store.apikey2.key, store.apikey2.secret)
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.status).to.equal(200)
|
expect(res.status).to.equal(200)
|
||||||
|
@ -83,7 +83,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'jwt')} Read API key (jwt)`, (done) => {
|
step(`${store.icon('key', 'jwt')} Read API key (jwt)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.get(`/apikey/${store.apikey2.key}/jwt`)
|
.get(`/apikeys/${store.apikey2.key}/jwt`)
|
||||||
.set('Authorization', 'Bearer ' + store.account.token)
|
.set('Authorization', 'Bearer ' + store.account.token)
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.status).to.equal(200)
|
expect(res.status).to.equal(200)
|
||||||
|
@ -99,7 +99,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'key')} Remove API key (key)`, (done) => {
|
step(`${store.icon('key', 'key')} Remove API key (key)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.delete(`/apikey/${store.apikey2.key}/key`)
|
.delete(`/apikeys/${store.apikey2.key}/key`)
|
||||||
.auth(store.apikey2.key, store.apikey2.secret)
|
.auth(store.apikey2.key, store.apikey2.secret)
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.status).to.equal(204)
|
expect(res.status).to.equal(204)
|
||||||
|
@ -110,7 +110,7 @@ export const apikeyTests = async (chai, config, expect, store) => {
|
||||||
step(`${store.icon('key', 'jwt')} Remove API key (jwt)`, (done) => {
|
step(`${store.icon('key', 'jwt')} Remove API key (jwt)`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.delete(`/apikey/${store.apikey1.key}/jwt`)
|
.delete(`/apikeys/${store.apikey1.key}/jwt`)
|
||||||
.set('Authorization', 'Bearer ' + store.account.token)
|
.set('Authorization', 'Bearer ' + store.account.token)
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
expect(res.status).to.equal(204)
|
expect(res.status).to.equal(204)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { userTests } from './user.mjs'
|
||||||
import { accountTests } from './account.mjs'
|
import { accountTests } from './account.mjs'
|
||||||
import { apikeyTests } from './apikey.mjs'
|
import { apikeyTests } from './apikey.mjs'
|
||||||
import { personTests } from './person.mjs'
|
import { personTests } from './person.mjs'
|
||||||
|
import { patternTests } from './pattern.mjs'
|
||||||
import { setup } from './shared.mjs'
|
import { setup } from './shared.mjs'
|
||||||
|
|
||||||
const runTests = async (...params) => {
|
const runTests = async (...params) => {
|
||||||
|
@ -9,6 +10,7 @@ const runTests = async (...params) => {
|
||||||
await apikeyTests(...params)
|
await apikeyTests(...params)
|
||||||
await accountTests(...params)
|
await accountTests(...params)
|
||||||
await personTests(...params)
|
await personTests(...params)
|
||||||
|
await patternTests(...params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load initial data required for tests
|
// Load initial data required for tests
|
||||||
|
|
326
sites/backend/tests/pattern.mjs
Normal file
326
sites/backend/tests/pattern.mjs
Normal file
|
@ -0,0 +1,326 @@
|
||||||
|
import { cat } from './cat.mjs'
|
||||||
|
|
||||||
|
export const patternTests = async (chai, config, expect, store) => {
|
||||||
|
store.account.patterns = {}
|
||||||
|
for (const auth of ['jwt', 'key']) {
|
||||||
|
describe(`${store.icon('pattern', auth)} Pattern tests (${auth})`, () => {
|
||||||
|
it(`${store.icon('pattern', auth)} Should create a new pattern (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.post(`/patterns/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString(
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.send({
|
||||||
|
design: 'aaron',
|
||||||
|
settings: {},
|
||||||
|
person: store.account.people.her.id,
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(201)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(typeof res.body.pattern?.id).to.equal('number')
|
||||||
|
expect(res.body.pattern.userId).to.equal(store.account.id)
|
||||||
|
expect(res.body.pattern.personId).to.equal(store.account.people.her.id)
|
||||||
|
expect(res.body.pattern.design).to.equal('aaron')
|
||||||
|
expect(res.body.pattern.public).to.equal(false)
|
||||||
|
store.account.patterns[auth] = res.body.pattern
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
}).timeout(5000)
|
||||||
|
|
||||||
|
for (const field of ['name', 'notes']) {
|
||||||
|
it(`${store.icon('pattern', auth)} Should update the ${field} field (${auth})`, (done) => {
|
||||||
|
const data = {}
|
||||||
|
const val = store.account.patterns[auth][field] + '_updated'
|
||||||
|
data[field] = val
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(
|
||||||
|
`${store.account.apikey.key}:${store.account.apikey.secret}`
|
||||||
|
).toString('base64')
|
||||||
|
)
|
||||||
|
.send(data)
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(200)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(res.body.pattern[field]).to.equal('--_updated')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it(`${store.icon('person', auth)} Should update the public field (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString(
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.send({ public: true })
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(200)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(res.body.pattern.public).to.equal(true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`${store.icon('person', auth)} Should not update the design field (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString(
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.send({ design: 'updated' })
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(200)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(res.body.pattern.design).to.equal('aaron')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`${store.icon('person', auth)} Should not update the person field (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(`${store.account.apikey.key}:${store.account.apikey.secret}`).toString(
|
||||||
|
'base64'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.send({ person: 1 })
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(200)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(res.body.pattern.personId).to.equal(store.account.people.her.id)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const field of ['data', 'settings']) {
|
||||||
|
it(`${store.icon('person', auth)} Should update the ${field} field (${auth})`, (done) => {
|
||||||
|
const data = {}
|
||||||
|
data[field] = { test: { value: 'hello' } }
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.account.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(
|
||||||
|
`${store.account.apikey.key}:${store.account.apikey.secret}`
|
||||||
|
).toString('base64')
|
||||||
|
)
|
||||||
|
.send(data)
|
||||||
|
.end((err, res) => {
|
||||||
|
expect(err === null).to.equal(true)
|
||||||
|
expect(res.status).to.equal(200)
|
||||||
|
expect(res.body.result).to.equal(`success`)
|
||||||
|
expect(res.body.pattern[field].test.value).to.equal('hello')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
it(`${store.icon('pattern', auth)} Should read a pattern (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.get(`/patterns/${store.account.patterns[auth].id}/${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(res.body.pattern.data.test.value).to.equal('hello')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`${store.icon(
|
||||||
|
'person',
|
||||||
|
auth
|
||||||
|
)} Should not allow reading another user's pattern (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.get(`/patterns/${store.account.patterns[auth].id}/${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) => {
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`${store.icon(
|
||||||
|
'person',
|
||||||
|
auth
|
||||||
|
)} Should not allow updating another user's pattern (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.put(`/patterns/${store.account.patterns[auth].id}/${auth}`)
|
||||||
|
.set(
|
||||||
|
'Authorization',
|
||||||
|
auth === 'jwt'
|
||||||
|
? 'Bearer ' + store.altaccount.token
|
||||||
|
: 'Basic ' +
|
||||||
|
new Buffer(
|
||||||
|
`${store.altaccount.apikey.key}:${store.altaccount.apikey.secret}`
|
||||||
|
).toString('base64')
|
||||||
|
)
|
||||||
|
.send({
|
||||||
|
name: 'I have been taken over',
|
||||||
|
})
|
||||||
|
.end((err, res) => {
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it(`${store.icon(
|
||||||
|
'person',
|
||||||
|
auth
|
||||||
|
)} Should not allow removing another user's pattern (${auth})`, (done) => {
|
||||||
|
chai
|
||||||
|
.request(config.api)
|
||||||
|
.delete(`/patterns/${store.account.patterns[auth].id}/${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) => {
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,12 +4,17 @@ import chai from 'chai'
|
||||||
import http from 'chai-http'
|
import http from 'chai-http'
|
||||||
import { verifyConfig } from '../src/config.mjs'
|
import { verifyConfig } from '../src/config.mjs'
|
||||||
import { randomString } from '../src/utils/crypto.mjs'
|
import { randomString } from '../src/utils/crypto.mjs'
|
||||||
|
import {
|
||||||
|
cisFemaleAdult34 as her,
|
||||||
|
cisMaleAdult42 as him,
|
||||||
|
} from '../../../packages/models/src/index.mjs'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
const config = verifyConfig(true)
|
const config = verifyConfig(true)
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
chai.use(http)
|
chai.use(http)
|
||||||
|
const people = { her, him }
|
||||||
|
|
||||||
export const setup = async () => {
|
export const setup = async () => {
|
||||||
// Initial store contents
|
// Initial store contents
|
||||||
|
@ -21,17 +26,20 @@ export const setup = async () => {
|
||||||
email: `test_${randomString()}@${config.tests.domain}`,
|
email: `test_${randomString()}@${config.tests.domain}`,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
password: randomString(),
|
password: randomString(),
|
||||||
|
people: {},
|
||||||
},
|
},
|
||||||
altaccount: {
|
altaccount: {
|
||||||
email: `test_${randomString()}@${config.tests.domain}`,
|
email: `test_${randomString()}@${config.tests.domain}`,
|
||||||
language: 'en',
|
language: 'en',
|
||||||
password: randomString(),
|
password: randomString(),
|
||||||
|
people: {},
|
||||||
},
|
},
|
||||||
icons: {
|
icons: {
|
||||||
user: '🧑 ',
|
user: '🧑 ',
|
||||||
jwt: '🎫 ',
|
jwt: '🎫 ',
|
||||||
key: '🎟️ ',
|
key: '🎟️ ',
|
||||||
person: '🧕 ',
|
person: '🧕 ',
|
||||||
|
pattern: '👕 ',
|
||||||
},
|
},
|
||||||
randomString,
|
randomString,
|
||||||
}
|
}
|
||||||
|
@ -63,12 +71,12 @@ export const setup = async () => {
|
||||||
}
|
}
|
||||||
store[acc].token = result.data.token
|
store[acc].token = result.data.token
|
||||||
store[acc].username = result.data.account.username
|
store[acc].username = result.data.account.username
|
||||||
store[acc].userid = result.data.account.id
|
store[acc].id = result.data.account.id
|
||||||
|
|
||||||
// Create API key
|
// Create API key
|
||||||
try {
|
try {
|
||||||
result = await axios.post(
|
result = await axios.post(
|
||||||
`${store.config.api}/apikey/jwt`,
|
`${store.config.api}/apikeys/jwt`,
|
||||||
{
|
{
|
||||||
name: 'Test API key',
|
name: 'Test API key',
|
||||||
level: 4,
|
level: 4,
|
||||||
|
@ -85,6 +93,29 @@ export const setup = async () => {
|
||||||
process.exit()
|
process.exit()
|
||||||
}
|
}
|
||||||
store[acc].apikey = result.data.apikey
|
store[acc].apikey = result.data.apikey
|
||||||
|
|
||||||
|
// Create people key
|
||||||
|
for (const name in people) {
|
||||||
|
try {
|
||||||
|
result = await axios.post(
|
||||||
|
`${store.config.api}/people/jwt`,
|
||||||
|
{
|
||||||
|
name: `This is ${name} name`,
|
||||||
|
name: `These are ${name} notes`,
|
||||||
|
measies: people[name],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${store[acc].token}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Failed at API key creation request', err)
|
||||||
|
process.exit()
|
||||||
|
}
|
||||||
|
store[acc].people[name] = result.data.person
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { chai, config, expect, store }
|
return { chai, config, expect, store }
|
||||||
|
|
|
@ -184,12 +184,12 @@ export const userTests = async (chai, config, expect, store) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
step(`${store.icon('user')} Should login with userid and password`, (done) => {
|
step(`${store.icon('user')} Should login with id and password`, (done) => {
|
||||||
chai
|
chai
|
||||||
.request(config.api)
|
.request(config.api)
|
||||||
.post('/login')
|
.post('/login')
|
||||||
.send({
|
.send({
|
||||||
username: store.account.userid,
|
username: store.account.id,
|
||||||
password: store.account.password,
|
password: store.account.password,
|
||||||
})
|
})
|
||||||
.end((err, res) => {
|
.end((err, res) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue