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 v3.0.0-alpha.4 #29

Merged
merged 12 commits into from
Mar 6, 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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

### Unreleased


### [3.0.0-alpha.4] - 2024-03-05

- feat(lib/nameserver): added, with tests
- feat(routes/nameserver): added, with tests

### 3.0.0-alpha.3

- routes/permission: added GET, POST, DELETE
Expand All @@ -14,3 +20,4 @@


[3.0.0-alpha.3]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.3
[3.0.0-alpha.4]: https://github.com/NicTool/api/releases/tag/3.0.0-alpha.4
143 changes: 143 additions & 0 deletions lib/nameserver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import Mysql from './mysql.js'
import { mapToDbColumn } from './util.js'

const nsDbMap = { id: 'nt_nameserver_id', gid: 'nt_group_id' }
const boolFields = ['deleted', 'export_serials']

class Nameserver {
constructor() {
this.mysql = Mysql
}

async create(args) {
if (args.id) {
const g = await this.get({ id: args.id })
if (g.length === 1) return g[0].id
}

if (args.export.type) {
args = JSON.parse(JSON.stringify(args))
const rows = await Mysql.execute(
...Mysql.select('SELECT id FROM nt_nameserver_export_type', {
name: args.export.type,
}),
)
args.export_type_id = rows[0].id
delete args.export.type
}

return await Mysql.execute(
...Mysql.insert(
`nt_nameserver`,
mapToDbColumn(objectToDb(args), nsDbMap),
),
)
}

async get(args) {
if (args.name !== undefined) {
args['ns.name'] = args.name
delete args.name
}
const rows = await Mysql.execute(
...Mysql.select(
`SELECT ns.nt_nameserver_id AS id
, ns.nt_group_id AS gid
, ns.name
, ns.ttl
, ns.description
, ns.address
, ns.address6
, ns.remote_login
, ns.logdir
, ns.datadir
, ns.export_interval
, ns.export_serials
, ns.export_status
, ns.deleted
, t.name AS export_type
FROM nt_nameserver ns
JOIN nt_nameserver_export_type t ON ns.export_type_id=t.id`,
mapToDbColumn(args, nsDbMap),
),
)
for (const r of rows) {
for (const b of boolFields) {
r[b] = r[b] === 1
}
}
return dbToObject(rows)
}

async put(args) {
if (!args.id) return false
const id = args.id
delete args.id
// Mysql.debug(1)
const r = await Mysql.execute(
...Mysql.update(
`nt_nameserver`,
`nt_nameserver_id=${id}`,
mapToDbColumn(args, nsDbMap),
),
)
// console.log(r)
return r.changedRows === 1
}

async delete(args) {
await Mysql.execute(
`UPDATE nt_nameserver SET deleted=? WHERE nt_nameserver_id=?`,
[args.deleted ?? 1, args.id],
)
return true
}

async destroy(args) {
return await Mysql.execute(
...Mysql.delete(`nt_nameserver`, { nt_nameserver_id: args.id }),
)
}
}

export default new Nameserver()

function dbToObject(rows) {
for (const row of rows) {
for (const f of [
'description',
'address6',
'remote_login',
'datadir',
'logdir',
'export_status',
]) {
if ([undefined, null].includes(row[f])) row[f] = ''
}
for (const f of ['export']) {
for (const p of ['type', 'interval', 'serials', 'status']) {
if (row[`${f}_${p}`] !== undefined) {
if (row[f] === undefined) row[f] = {}
row[f][p] = row[`${f}_${p}`]
delete row[`${f}_${p}`]
}
}
}
}
return rows
}

function objectToDb(row) {
row = JSON.parse(JSON.stringify(row)) // don't mutate the original

for (const f of ['export']) {
for (const p of ['interval', 'serials', 'status']) {
if (row[f] === undefined) continue
if (row[f][p] === undefined) continue
row[`${f}_${p}`] = row[f][p]
delete row[f][p]
}
delete row[f]
}
return row
}
46 changes: 46 additions & 0 deletions lib/nameserver.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import assert from 'node:assert/strict'
import { describe, it, after, before } from 'node:test'

import Nameserver from './nameserver.js'

import testCase from './test/nameserver.json' with { type: 'json' }

before(async () => {
await Nameserver.destroy({ id: testCase.id })
await Nameserver.create(testCase)
})

after(async () => {
await Nameserver.destroy({ id: testCase.id })
Nameserver.mysql.disconnect()
})

describe('nameserver', function () {
it('gets nameserver by id', async () => {
const g = await Nameserver.get({ id: testCase.id })
assert.deepEqual(g[0], testCase)
})

it('gets nameserver by name', async () => {
const g = await Nameserver.get({ name: testCase.name })
assert.deepEqual(g[0], testCase)
})

it('changes a nameserver', async () => {
assert.ok(
await Nameserver.put({ id: testCase.id, name: 'b.ns.example.com.' }),
)
const ns = await Nameserver.get({ id: testCase.id })
assert.deepEqual(ns[0].name, 'b.ns.example.com.')
assert.ok(await Nameserver.put({ id: testCase.id, name: testCase.name }))
})

it('deletes a nameserver', async () => {
assert.ok(await Nameserver.delete({ id: testCase.id }))
let g = await Nameserver.get({ id: testCase.id, deleted: 1 })
assert.equal(g[0]?.deleted, true)
await Nameserver.delete({ id: testCase.id, deleted: 0 }) // restore
g = await Nameserver.get({ id: testCase.id })
assert.equal(g[0].deleted, false)
})
})
19 changes: 19 additions & 0 deletions lib/test/nameserver.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"id": 4096,
"gid": 4096,
"name": "a.ns.example.com.",
"description": "",
"address": "1.2.3.4",
"address6": "2001:DB8::1",
"remote_login": "nsd",
"logdir": "/foo",
"datadir": "/bar",
"export": {
"interval": 0,
"serials": true,
"status": "last run:03-05 15:25<br>last cp :09-20 12:59",
"type": "NSD"
},
"ttl": 3600,
"deleted": false
}
11 changes: 5 additions & 6 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,15 @@ const meta = {
}

function mapToDbColumn(args, maps) {
// create an instance, so we don't mangle the original args
const newArgs = JSON.parse(JSON.stringify(args))
args = JSON.parse(JSON.stringify(args)) // don't mutate the original

for (const [key, val] of Object.entries(maps)) {
if (newArgs[key] !== undefined) {
newArgs[val] = newArgs[key]
delete newArgs[key]
if (args[key] !== undefined) {
args[val] = args[key]
delete args[key]
}
}
return newArgs
return args
}

export { setEnv, meta, mapToDbColumn }
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nictool/api",
"version": "3.0.0-alpha.3",
"version": "3.0.0-alpha.4",
"description": "NicTool API",
"main": "index.js",
"type": "module",
Expand Down Expand Up @@ -43,7 +43,7 @@
"@hapi/hoek": "^11.0.4",
"@hapi/inert": "^7.1.0",
"@hapi/vision": "^7.0.3",
"@nictool/validate": "^0.7.4",
"@nictool/validate": "^0.8.0",
"hapi-swagger": "^17.2.1",
"mysql2": "^3.9.2",
"qs": "^6.11.2",
Expand Down
20 changes: 11 additions & 9 deletions routes/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ function GroupRoutes(server) {
method: 'GET',
path: '/group/{id}',
options: {
validate: {
query: validate.group.GET_req,
},
response: {
schema: validate.group.GET,
schema: validate.group.GET_res,
},
tags: ['api'],
},
Expand Down Expand Up @@ -50,15 +53,12 @@ function GroupRoutes(server) {
payload: validate.group.POST,
},
response: {
schema: validate.group.GET,
schema: validate.group.GET_res,
},
tags: ['api'],
},
handler: async (request, h) => {
const gid = await Group.create(request.payload)
if (!gid) {
console.log(`POST /group oops`) // TODO
}

const groups = await Group.get({ id: gid })

Expand All @@ -77,13 +77,16 @@ function GroupRoutes(server) {
method: 'DELETE',
path: '/group/{id}',
options: {
validate: {
query: validate.group.DELETE,
},
response: {
schema: validate.group.GET,
schema: validate.group.GET_res,
},
tags: ['api'],
},
handler: async (request, h) => {
const groups = await Group.get(request.params)
const groups = await Group.get({ id: parseInt(request.params.id, 10) })
/* c8 ignore next 10 */
if (groups.length !== 1) {
return h
Expand All @@ -96,8 +99,7 @@ function GroupRoutes(server) {
.code(204)
}

const action = request.query.destroy === 'true' ? 'destroy' : 'delete'
await Group[action]({ id: groups[0].id })
await Group.delete({ id: groups[0].id })
delete groups[0].gid

return h
Expand Down
26 changes: 7 additions & 19 deletions routes/group.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import groupCase from './test/group.json' with { type: 'json' }
import userCase from './test/user.json' with { type: 'json' }

let server
const case2Id = 4094

before(async () => {
server = await init()
Expand All @@ -17,7 +18,8 @@ before(async () => {
})

after(async () => {
await server.stop()
await Group.destroy({ id: case2Id })
server.stop()
})

describe('group routes', () => {
Expand Down Expand Up @@ -45,11 +47,9 @@ describe('group routes', () => {
},
})
// console.log(res.result)
assert.equal(res.statusCode, 200)
assert.ok([200, 204].includes(res.statusCode))
})

const case2Id = 4094

it('POST /group', async () => {
const testCase = JSON.parse(JSON.stringify(groupCase))
testCase.id = case2Id // make it unique
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('group routes', () => {
},
})
// console.log(res.result)
assert.equal(res.statusCode, 200)
assert.ok([200, 204].includes(res.statusCode))
})

it(`DELETE /group/${case2Id}`, async () => {
Expand Down Expand Up @@ -108,25 +108,13 @@ describe('group routes', () => {
it(`GET /group/${case2Id} (deleted)`, async () => {
const res = await server.inject({
method: 'GET',
url: `/group/${case2Id}?deleted=1`,
url: `/group/${case2Id}?deleted=true`,
headers: {
Cookie: sessionCookie,
},
})
// console.log(res.result)
assert.equal(res.statusCode, 200)
})

it(`DELETE /group/${case2Id}`, async () => {
const res = await server.inject({
method: 'DELETE',
url: `/group/${case2Id}?destroy=true`,
headers: {
Cookie: sessionCookie,
},
})
// console.log(res.result)
assert.equal(res.statusCode, 200)
assert.ok([200, 204].includes(res.statusCode))
})

it('DELETE /session', async () => {
Expand Down
Loading
Loading