Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release 3.0.0-alpha.3 #28

Merged
merged 7 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule ".release"]
path = .release
url = [email protected]:msimerson/.release.git
1 change: 1 addition & 0 deletions .release
Submodule .release added at 8959a9
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# CHANGES

### Unreleased

### 3.0.0-alpha.3

- routes/permission: added GET, POST, DELETE
- permission.get: default search with deleted=0
- session.put: added
- session: store user/group info in cookie (saves DB trips)
- mysql(insert, select, update, delete): return just the query
- lib/group.get: convert booleans
- lib/user.get: convert booleans


[3.0.0-alpha.3]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.3
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ or

`npm run develop (development)`

will start up the HTTP service on the port specified in `conf.d/http.yml`. The default URL for the service is [http://localhost:3000](http://localhost:3000) and the API methods have documentation at [http://localhost:3000/documentation](http://localhost:3000/documentation).
will start up the HTTP service on the port specified in `conf.d/http.yml`. The default URL for the service is [http://localhost:3000](http://localhost:3000) and the API methods have documentation at [http://localhost:3000/documentation#/](http://localhost:3000/documentation#/).


## Using the API service
Expand Down
3 changes: 1 addition & 2 deletions conf.d/http.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

default:
host: localhost
port: 3000
cookie:
# https://hapi.dev/module/cookie/api/?v=12.0.1
name: sid-nictool
password: af1b926a5e21f535c4f5b6c42941c4cf
ttl: 3600000 # 1 hour
ttl: 3600000 # 1 hour
# domain:
path: /
clearInvalid: true
Expand Down
2 changes: 1 addition & 1 deletion conf.d/mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ default:
# settings below this line override default settings
production:
host: mysql
password: "********"
password: '********'

# used for CI testing (GitHub Actions workflows)
test:
Expand Down
61 changes: 29 additions & 32 deletions lib/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Mysql from './mysql.js'
import { mapToDbColumn } from './util.js'

const groupDbMap = { id: 'nt_group_id', parent_gid: 'parent_group_id' }
const boolFields = ['deleted']

class Group {
constructor() {
Expand All @@ -11,65 +12,61 @@ class Group {
async create(args) {
if (args.id) {
const g = await this.get({ id: args.id })
if (g.length) return g[0].id
if (g.length === 1) return g[0].id
}

return await Mysql.insert(
`INSERT INTO nt_group`,
mapToDbColumn(args, groupDbMap),
return await Mysql.execute(
...Mysql.insert(`nt_group`, mapToDbColumn(args, groupDbMap)),
)
}

async get(args) {
return await Mysql.select(
`SELECT nt_group_id AS id
const rows = await Mysql.execute(
...Mysql.select(
`SELECT nt_group_id AS id
, parent_group_id AS parent_gid
, name
FROM nt_group WHERE`,
mapToDbColumn(args, groupDbMap),
)
}

async getAdmin(args) {
return await Mysql.select(
`SELECT nt_group_id AS id
, name
, parent_group_id AS parent_gid
, deleted
FROM nt_group WHERE`,
mapToDbColumn(args, groupDbMap),
, deleted
FROM nt_group`,
mapToDbColumn(args, groupDbMap),
),
)
for (const r of rows) {
for (const b of boolFields) {
r[b] = r[b] === 1
}
}
return rows
}

async put(args) {
if (!args.id) return false
const id = args.id
delete args.id
// Mysql.debug(1)
const r = await Mysql.update(
`UPDATE nt_group SET`,
`WHERE nt_group_id=${id}`,
mapToDbColumn(args, groupDbMap),
const r = await Mysql.execute(
...Mysql.update(
`nt_group`,
`nt_group_id=${id}`,
mapToDbColumn(args, groupDbMap),
),
)
// console.log(r)
return r.changedRows === 1
}

async delete(args, val) {
const g = await this.getAdmin(args)
if (g.length !== 1) return false
async delete(args) {
await Mysql.execute(`UPDATE nt_group SET deleted=? WHERE nt_group_id=?`, [
val ?? 1,
g[0].id,
args.deleted ?? 1,
args.id,
])
return true
}

async destroy(args) {
const g = await this.getAdmin(args)
if (g.length === 1) {
await Mysql.execute(`DELETE FROM nt_group WHERE nt_group_id=?`, [g[0].id])
}
return await Mysql.execute(
...Mysql.delete(`nt_group`, { nt_group_id: args.id }),
)
}
}

Expand Down
13 changes: 8 additions & 5 deletions lib/group.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('group', function () {
id: testCase.id,
name: testCase.name,
parent_gid: 0,
deleted: false,
})
})

Expand All @@ -29,6 +30,7 @@ describe('group', function () {
id: testCase.id,
name: testCase.name,
parent_gid: 0,
deleted: false,
})
})

Expand All @@ -39,17 +41,18 @@ describe('group', function () {
id: testCase.id,
name: 'example.net',
parent_gid: 0,
deleted: false,
},
])
assert.ok(await Group.put({ id: testCase.id, name: testCase.name }))
})

it('deletes a group', async () => {
assert.ok(await Group.delete({ id: testCase.id }))
let g = await Group.getAdmin({ id: testCase.id })
assert.equal(g[0].deleted, 1)
await Group.delete({ id: testCase.id }, 0) // restore
g = await Group.getAdmin({ id: testCase.id })
assert.equal(g[0].deleted, 0)
let g = await Group.get({ id: testCase.id, deleted: 1 })
assert.equal(g[0]?.deleted, true)
await Group.delete({ id: testCase.id, deleted: 0 }) // restore
g = await Group.get({ id: testCase.id })
assert.equal(g[0].deleted, false)
})
})
44 changes: 16 additions & 28 deletions lib/mysql.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,26 @@ class Mysql {
return rows
}

async insert(query, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

query += `(${Object.keys(params).join(',')}) VALUES(${Object.keys(params).map(() => '?')})`

if (skipExecute) return query
return await this.execute(query, Object.values(params))
insert(table, params = {}) {
return [
`INSERT INTO ${table} (${Object.keys(params).join(',')}) VALUES(${Object.keys(params).map(() => '?')})`,
Object.values(params),
]
}

async select(query, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

const [queryWhere, paramsArray] = this.whereConditions(query, params)

if (skipExecute) return queryWhere
return await this.execute(queryWhere, paramsArray)
select(query, params = {}) {
return this.whereConditions(query, params)
}

async update(query, where, params = {}) {
const skipExecute = params.skipExecute ?? false
delete params.skipExecute

query += ` ${Object.keys(params).join('=?,')}=? ${where}`
update(table, where, params = {}) {
return [
`UPDATE ${table} SET ${Object.keys(params).join('=?,')}=? WHERE ${where}`,
Object.values(params),
]
}

if (skipExecute) return { q: query, p: Object.values(params) }
return await this.execute(query, Object.values(params))
delete(table, params) {
return this.whereConditions(`DELETE FROM ${table}`, params)
}

whereConditions(query, params) {
Expand All @@ -82,6 +74,7 @@ class Mysql {
// Object to WHERE conditions
let first = true
for (const p in params) {
if (first) newQuery += ' WHERE'
if (!first) newQuery += ' AND'
newQuery += ` ${p}=?`
paramsArray.push(params[p])
Expand All @@ -91,11 +84,6 @@ class Mysql {
return [newQuery, paramsArray]
}

async delete(query, params) {
const [queryWhere, paramsArray] = this.whereConditions(query, params)
return await this.execute(queryWhere, paramsArray)
}

async disconnect(dbh) {
const d = dbh || this.dbh
if (_debug) console.log(`MySQL connection id ${d.connection.connectionId}`)
Expand Down
103 changes: 63 additions & 40 deletions lib/mysql.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,57 +20,80 @@ describe('mysql', () => {
})
}

it('SQL: formats SELECT queries', async () => {
const r = await Mysql.select(`SELECT * FROM nt_user WHERE`, {
last_name: 'Test',
skipExecute: true,
})
assert.equal(r, `SELECT * FROM nt_user WHERE last_name=?`)
it('formats SELECT queries', () => {
assert.deepEqual(
Mysql.select(`SELECT * FROM nt_user`, {
last_name: 'Test',
}),
[`SELECT * FROM nt_user WHERE last_name=?`, ['Test']],
)
})

it('SQL: formats INSERT queries', async () => {
const r = await Mysql.select(`INSERT INTO nt_user SET`, {
it('formats INSERT query', () => {
const r = Mysql.insert(`nt_user`, {
first_name: 'uNite',
last_name: 'Test',
skipExecute: true,
})
assert.equal(r, `INSERT INTO nt_user SET first_name=? AND last_name=?`)
assert.deepEqual(r, [
`INSERT INTO nt_user (first_name,last_name) VALUES(?,?)`,
['uNite', 'Test'],
])
})

it('SQL: formats UPDATE queries, 1', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ first_name: 'uNite', skipExecute: true },
)
assert.equal(q, `UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`)
assert.deepEqual(p, ['uNite'])
describe('update', () => {
it('formats with one value', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
first_name: 'uNite',
})
assert.deepEqual(r, [
`UPDATE nt_user SET first_name=? WHERE nt_user_id=4096`,
['uNite'],
])
})

it('formats with two values', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
last_name: 'Teste',
is_admin: 1,
})
assert.deepEqual(r, [
`UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`,
['Teste', 1],
])
})

it('formats with three values', () => {
const r = Mysql.update(`nt_user`, `nt_user_id=4096`, {
first_name: 'Unit',
last_name: 'Test',
is_admin: 0,
})
assert.deepEqual(r, [
`UPDATE nt_user SET first_name=?,last_name=?,is_admin=? WHERE nt_user_id=4096`,
['Unit', 'Test', 0],
])
})
})

it('SQL: formats UPDATE queries, 2', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ last_name: 'Teste', is_admin: 1, skipExecute: true },
)
assert.equal(
q,
`UPDATE nt_user SET last_name=?,is_admin=? WHERE nt_user_id=4096`,
)
assert.deepEqual(p, ['Teste', 1])
describe('delete', () => {
it('no params', () => {
assert.deepEqual(Mysql.delete(`nt_user`, {}), [`DELETE FROM nt_user`, []])
})

it('with params', () => {
assert.deepEqual(Mysql.delete(`nt_user`, { last_name: 'Test' }), [
`DELETE FROM nt_user WHERE last_name=?`,
['Test'],
])
})
})

it('SQL: formats UPDATE queries, 3', async () => {
const { q, p } = await Mysql.update(
`UPDATE nt_user SET`,
`WHERE nt_user_id=4096`,
{ first_name: 'Unit', last_name: 'Test', is_admin: 0, skipExecute: true },
)
assert.equal(
q,
`UPDATE nt_user SET first_name=?,last_name=?,is_admin=? WHERE nt_user_id=4096`,
)
assert.deepEqual(p, ['Unit', 'Test', 0])
it('executes formatted queries', async () => {
const [query, argsArray] = Mysql.select(`SELECT * FROM nt_options`)
const r = await Mysql.execute(query, argsArray)
assert.deepEqual(r[0].option_id, 1)

// await Mysql.execute(...Mysql.select(`SELECT * FROM nt_options`))
})

it('disconnects', async () => {
Expand Down
Loading
Loading