diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..53e71ae --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: msimerson diff --git a/.release b/.release index 74f584c..704e50c 160000 --- a/.release +++ b/.release @@ -1 +1 @@ -Subproject commit 74f584cf23f63960f4fccefe08436e1261e34241 +Subproject commit 704e50ce14387d29293bd208d0a6ff290b49d66e diff --git a/CHANGELOG.md b/CHANGELOG.md index 155b3f1..9122a57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - feat(lib/zone): added, with tests, fixes #22 - feat(lib/zone_record): added, with tests, fixes #23 +- feat: default get sets deleted=false + - group, nameserver, permission, user, zone ### [3.0.0-alpha.4] - 2024-03-05 diff --git a/lib/group.js b/lib/group.js index 8e3f376..957656a 100644 --- a/lib/group.js +++ b/lib/group.js @@ -21,6 +21,9 @@ class Group { } async get(args) { + args = JSON.parse(JSON.stringify(args)) + if (args.deleted === undefined) args.deleted = false + const rows = await Mysql.execute( ...Mysql.select( `SELECT nt_group_id AS id @@ -31,10 +34,11 @@ class Group { mapToDbColumn(args, groupDbMap), ), ) - for (const r of rows) { + for (const row of rows) { for (const b of boolFields) { - r[b] = r[b] === 1 + row[b] = row[b] === 1 } + if (args.deleted === false) delete row.deleted } return rows } diff --git a/lib/group.test.js b/lib/group.test.js index 7ec9da1..0c2bed3 100644 --- a/lib/group.test.js +++ b/lib/group.test.js @@ -20,7 +20,6 @@ describe('group', function () { id: testCase.id, name: testCase.name, parent_gid: 0, - deleted: false, }) }) @@ -30,7 +29,6 @@ describe('group', function () { id: testCase.id, name: testCase.name, parent_gid: 0, - deleted: false, }) }) @@ -41,7 +39,6 @@ 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 })) @@ -53,6 +50,6 @@ describe('group', function () { 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) + assert.equal(g[0].deleted, undefined) }) }) diff --git a/lib/mysql.js b/lib/mysql.js index b55f35c..8754bd7 100644 --- a/lib/mysql.js +++ b/lib/mysql.js @@ -38,6 +38,10 @@ class Mysql { } if (/^(REPLACE|INSERT) INTO/.test(query)) return rows.insertId + if (/^UPDATE /.test(query)) { + console.log(rows) + console.log(fields) + } return rows } diff --git a/lib/nameserver.js b/lib/nameserver.js index 2aa28c8..d515ffd 100644 --- a/lib/nameserver.js +++ b/lib/nameserver.js @@ -35,6 +35,9 @@ class Nameserver { } async get(args) { + args = JSON.parse(JSON.stringify(args)) + if (args.deleted === undefined) args.deleted = false + if (args.name !== undefined) { args['ns.name'] = args.name delete args.name @@ -61,10 +64,11 @@ class Nameserver { mapToDbColumn(args, nsDbMap), ), ) - for (const r of rows) { + for (const row of rows) { for (const b of boolFields) { - r[b] = r[b] === 1 + row[b] = row[b] === 1 } + if (args.deleted === false) delete row.deleted } return dbToObject(rows) } diff --git a/lib/nameserver.test.js b/lib/nameserver.test.js index 7684348..619b5eb 100644 --- a/lib/nameserver.test.js +++ b/lib/nameserver.test.js @@ -41,6 +41,6 @@ describe('nameserver', function () { 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) + assert.equal(g[0].deleted, undefined) }) }) diff --git a/lib/permission.js b/lib/permission.js index e868640..b4feda5 100644 --- a/lib/permission.js +++ b/lib/permission.js @@ -26,6 +26,9 @@ class Permission { } async get(args) { + args = JSON.parse(JSON.stringify(args)) + if (args.deleted === undefined) args.deleted = false + const query = `SELECT p.nt_perm_id AS id , p.nt_user_id AS uid , p.nt_group_id AS gid @@ -35,7 +38,6 @@ class Permission { , p.deleted FROM nt_perm p` // Mysql.debug(1) - if (args.deleted === undefined) args.deleted = false const rows = await Mysql.execute( ...Mysql.select(query, mapToDbColumn(args, permDbMap)), @@ -46,7 +48,9 @@ class Permission { `permissions.get found ${rows.length} rows for uid ${args.uid}`, ) } - return dbToObject(rows[0]) + const row = dbToObject(rows[0]) + if (args.deleted === false) delete row.deleted + return row } async getGroup(args) { @@ -59,11 +63,13 @@ class Permission { , p.deleted FROM nt_perm p INNER JOIN nt_user u ON p.nt_group_id = u.nt_group_id - WHERE p.deleted=0 + WHERE p.deleted=${args.deleted === true ? 1 : 0} AND u.deleted=0 AND u.nt_user_id=?` const rows = await Mysql.execute(...Mysql.select(query, [args.uid])) - return dbToObject(rows[0]) + const row = dbToObject(rows[0]) + if ([false, undefined].includes(args.deleted)) delete row.deleted + return row } async put(args) { @@ -185,60 +191,61 @@ JSON object format: const boolFields = ['self_write', 'inherit', 'deleted'] function dbToObject(row) { - const newRow = JSON.parse(JSON.stringify(row)) + row = JSON.parse(JSON.stringify(row)) for (const f of ['group', 'nameserver', 'zone', 'zonerecord', 'user']) { for (const p of ['create', 'write', 'delete', 'delegate']) { - if (newRow[`${f}_${p}`] !== undefined) { - if (newRow[f] === undefined) newRow[f] = {} - newRow[f][p] = newRow[`${f}_${p}`] === 1 - delete newRow[`${f}_${p}`] + if (row[`${f}_${p}`] !== undefined) { + if (row[f] === undefined) row[f] = {} + row[f][p] = row[`${f}_${p}`] === 1 + delete row[`${f}_${p}`] } } } for (const b of boolFields) { - newRow[b] = newRow[b] === 1 + row[b] = row[b] === 1 } - if (newRow.uid !== undefined) { - newRow.user.id = newRow.uid - delete newRow.uid + + if (row.uid !== undefined) { + row.user.id = row.uid + delete row.uid } - if (newRow.gid !== undefined) { - newRow.group.id = newRow.gid - delete newRow.gid + if (row.gid !== undefined) { + row.group.id = row.gid + delete row.gid } - newRow.nameserver.usable = [] - if (![undefined, ''].includes(newRow.usable_ns)) { - newRow.nameserver.usable = newRow.usable_ns.split(',') + row.nameserver.usable = [] + if (![undefined, ''].includes(row.usable_ns)) { + row.nameserver.usable = row.usable_ns.split(',') } - delete newRow.usable_ns - return newRow + delete row.usable_ns + return row } function objectToDb(row) { - const newRow = JSON.parse(JSON.stringify(row)) - if (newRow?.user?.id !== undefined) { - newRow.uid = newRow.user.id - delete newRow.user.id + row = JSON.parse(JSON.stringify(row)) + if (row?.user?.id !== undefined) { + row.uid = row.user.id + delete row.user.id } - if (newRow?.group?.id !== undefined) { - newRow.gid = newRow.group.id - delete newRow.group.id + if (row?.group?.id !== undefined) { + row.gid = row.group.id + delete row.group.id } - if (newRow?.nameserver?.usable !== undefined) { - newRow.usable_ns = newRow.nameserver.usable.join(',') - delete newRow.nameserver.usable + if (row?.nameserver?.usable !== undefined) { + row.usable_ns = row.nameserver.usable.join(',') + delete row.nameserver.usable } for (const f of ['group', 'nameserver', 'zone', 'zonerecord', 'user']) { for (const p of ['create', 'write', 'delete', 'delegate']) { - if (newRow[f] === undefined) continue - if (newRow[f][p] === undefined) continue - newRow[`${f}_${p}`] = newRow[f][p] === true ? 1 : 0 - delete newRow[f][p] + if (row[f] === undefined) continue + if (row[f][p] === undefined) continue + row[`${f}_${p}`] = row[f][p] === true ? 1 : 0 + delete row[f][p] } - delete newRow[f] + delete row[f] } for (const b of boolFields) { - newRow[b] = newRow[b] === true ? 1 : 0 + row[b] = row[b] === true ? 1 : 0 } - return newRow + return row } diff --git a/lib/permission.test.js b/lib/permission.test.js index aaf2984..2d7725e 100644 --- a/lib/permission.test.js +++ b/lib/permission.test.js @@ -66,7 +66,7 @@ describe('permission', function () { assert.equal(p?.deleted, true) await Permission.delete({ id: permTestCase.id, deleted: 0 }) // restore p = await Permission.get({ id: permTestCase.id }) - assert.equal(p.deleted, false) + assert.equal(p.deleted, undefined) }) it('destroys a permission', async () => { diff --git a/lib/test/group.json b/lib/test/group.json index 1c31eaa..b0eb8bc 100644 --- a/lib/test/group.json +++ b/lib/test/group.json @@ -1,6 +1,5 @@ { "id": 4096, "parent_gid": 0, - "name": "example.com", - "deleted": false + "name": "example.com" } diff --git a/lib/test/nameserver.json b/lib/test/nameserver.json index 6888ab9..39e76ab 100644 --- a/lib/test/nameserver.json +++ b/lib/test/nameserver.json @@ -14,6 +14,5 @@ "status": "last run:03-05 15:25
last cp :09-20 12:59", "type": "NSD" }, - "ttl": 3600, - "deleted": false + "ttl": 3600 } diff --git a/lib/test/permission.json b/lib/test/permission.json index 21b10b3..dc09a85 100644 --- a/lib/test/permission.json +++ b/lib/test/permission.json @@ -3,7 +3,6 @@ "inherit": true, "name": "Test Permission", "self_write": false, - "deleted": false, "group": { "id": 4096, "create": false, "write": false, "delete": false }, "nameserver": { "usable": [], diff --git a/lib/test/user.json b/lib/test/user.json index bbc9fac..60532b9 100644 --- a/lib/test/user.json +++ b/lib/test/user.json @@ -6,6 +6,5 @@ "password": "Wh@tA-Decent#P6ssw0rd", "first_name": "Unit", "last_name": "Test", - "is_admin": false, - "deleted": false + "is_admin": false } diff --git a/lib/test/zone.json b/lib/test/zone.json index c6bdc17..3f18ca0 100644 --- a/lib/test/zone.json +++ b/lib/test/zone.json @@ -11,6 +11,5 @@ "minimum": 4, "ttl": 3600, "location": "", - "last_publish": null, - "deleted": false + "last_publish": null } diff --git a/lib/test/zone_record.json b/lib/test/zone_record.json index d102022..a5be936 100644 --- a/lib/test/zone_record.json +++ b/lib/test/zone_record.json @@ -5,4 +5,4 @@ "ttl": 86400, "type": "A", "address": "1.1.1.1" -} \ No newline at end of file +} diff --git a/lib/user.js b/lib/user.js index fe10ee4..d6fa590 100644 --- a/lib/user.js +++ b/lib/user.js @@ -66,6 +66,8 @@ class User { const u = await this.get({ id: args.id, gid: args.gid }) if (u.length === 1) return u[0].id + args = JSON.parse(JSON.stringify(args)) + if (args.password) { if (!args.pass_salt) args.pass_salt = this.generateSalt() args.password = await this.hashAuthPbkdf2(args.password, args.pass_salt) @@ -78,7 +80,9 @@ class User { } async get(args) { + args = JSON.parse(JSON.stringify(args)) if (args.deleted === undefined) args.deleted = false + const rows = await Mysql.execute( ...Mysql.select( `SELECT email @@ -97,6 +101,7 @@ class User { for (const b of boolFields) { r[b] = r[b] === 1 } + if (args.deleted === false) delete r.deleted } return rows } diff --git a/lib/user.test.js b/lib/user.test.js index 152706a..63337d7 100644 --- a/lib/user.test.js +++ b/lib/user.test.js @@ -61,7 +61,7 @@ describe('user', function () { assert.equal(u[0].deleted, true) await User.delete({ id: testCase.id, deleted: 0 }) // restore u = await User.get({ id: testCase.id }) - assert.equal(u[0].deleted, false) + assert.equal(u[0].deleted, undefined) }) }) diff --git a/lib/zone.js b/lib/zone.js index 4f89668..2f385fd 100644 --- a/lib/zone.js +++ b/lib/zone.js @@ -21,6 +21,9 @@ class Zone { } async get(args) { + args = JSON.parse(JSON.stringify(args)) + if (args.deleted === undefined) args.deleted = false + const rows = await Mysql.execute( ...Mysql.select( `SELECT nt_zone_id AS id @@ -42,13 +45,14 @@ class Zone { mapToDbColumn(args, zoneDbMap), ), ) - for (const r of rows) { + for (const row of rows) { for (const b of boolFields) { - r[b] = r[b] === 1 + row[b] = row[b] === 1 } for (const f of ['description', 'location']) { - if ([null].includes(r[f])) r[f] = '' + if ([null].includes(row[f])) row[f] = '' } + if (args.deleted === false) delete row.deleted } return rows diff --git a/lib/zone.test.js b/lib/zone.test.js index 05bab3e..01185de 100644 --- a/lib/zone.test.js +++ b/lib/zone.test.js @@ -37,12 +37,22 @@ describe('zone', function () { assert.ok(await Zone.put({ id: testCase.id, mailaddr: testCase.mailaddr })) }) - it('deletes a zone', async () => { - assert.ok(await Zone.delete({ id: testCase.id })) - let g = await Zone.get({ id: testCase.id, deleted: 1 }) - assert.equal(g[0]?.deleted, true) - await Zone.delete({ id: testCase.id, deleted: 0 }) // restore - g = await Zone.get({ id: testCase.id }) - assert.equal(g[0].deleted, false) + describe('deletes a zone', async () => { + it('can delete a zone', async () => { + assert.ok(await Zone.delete({ id: testCase.id })) + }) + it('default get does not find deleted zone', async () => { + let z = await Zone.get({ id: testCase.id }) + assert.equal(z.length, 0) + }) + it('can get the deleted zone', async () => { + let z = await Zone.get({ id: testCase.id, deleted: 1 }) + assert.equal(z[0]?.deleted, true) + }) + it('can restore the zone', async () => { + await Zone.delete({ id: testCase.id, deleted: 0 }) + let z = await Zone.get({ id: testCase.id }) + assert.equal(z.length, 1) + }) }) }) diff --git a/lib/zone_record.js b/lib/zone_record.js index f975b68..a84b28e 100644 --- a/lib/zone_record.js +++ b/lib/zone_record.js @@ -1,3 +1,5 @@ +import { typeMap } from '@nictool/dns-resource-record' + import Mysql from './mysql.js' import { mapToDbColumn } from './util.js' @@ -15,7 +17,9 @@ class ZoneRecord { if (g.length === 1) return g[0].id } - // const type = await Mysql.execute(...Mysql.select(`SELECT `)) + args = JSON.parse(JSON.stringify(args)) + args.type_id = typeMap[args.type] + delete args.type return await Mysql.execute( ...Mysql.insert(`nt_zone_record`, mapToDbColumn(args, zrDbMap)), @@ -23,6 +27,9 @@ class ZoneRecord { } async get(args) { + args = JSON.parse(JSON.stringify(args)) + if (args.deleted === undefined) args.deleted = false + const rows = await Mysql.execute( ...Mysql.select( `SELECT nt_zone_record_id AS id @@ -42,13 +49,24 @@ class ZoneRecord { mapToDbColumn(args, zrDbMap), ), ) - for (const r of rows) { + + for (const row of rows) { for (const b of boolFields) { - r[b] = r[b] === 1 + row[b] = row[b] === 1 } - for (const f of ['description', 'other', 'location']) { - if ([null].includes(r[f])) r[f] = '' + for (const f of [ + 'description', + 'other', + 'location', + 'weight', + 'priority', + 'timestamp', + ]) { + if (null === row[f]) delete row[f] } + row.type = typeMap[row.type_id] + delete row.type_id + if (args.deleted === false) delete row.deleted } return rows @@ -69,11 +87,11 @@ class ZoneRecord { } async delete(args) { - await Mysql.execute(`UPDATE nt_zone_record SET deleted=? WHERE nt_zone_record_id=?`, [ - args.deleted ?? 1, - args.id, - ]) - return true + return await Mysql.execute( + ...Mysql.update(`nt_zone_record`, `nt_zone_record_id=${args.id}`, { + deleted: args.deleted ?? 1, + }), + ) } async destroy(args) { diff --git a/lib/zone_record.test.js b/lib/zone_record.test.js index 3c61620..b73cbba 100644 --- a/lib/zone_record.test.js +++ b/lib/zone_record.test.js @@ -16,33 +16,43 @@ after(async () => { }) describe('zone_record', function () { - it('gets zone_record by id', async () => { - const g = await ZoneRecord.get({ id: testCase.id }) - delete g[0].last_modified - assert.deepEqual(g[0], testCase) + it('GET by id', async () => { + const zrs = await ZoneRecord.get({ id: testCase.id }) + delete zrs[0].last_modified + assert.deepEqual(zrs[0], testCase) }) - it('gets zone_record by name', async () => { - const g = await ZoneRecord.get({ zone_record: testCase.zone_record }) - delete g[0].last_modified - assert.deepEqual(g[0], testCase) + it('GET by name', async () => { + const zrs = await ZoneRecord.get({ zone_record: testCase.zone_record }) + delete zrs[0].last_modified + assert.deepEqual(zrs[0], testCase) }) - it('changes a zone_record', async () => { + it('PUT makes changes', async () => { + assert.ok(await ZoneRecord.put({ id: testCase.id, address: '2.2.2.2' })) + const zrs = await ZoneRecord.get({ id: testCase.id }) + assert.deepEqual(zrs[0].address, '2.2.2.2') assert.ok( - await ZoneRecord.put({ id: testCase.id, address: '2.2.2.2' }), + await ZoneRecord.put({ id: testCase.id, address: testCase.address }), ) - const ns = await ZoneRecord.get({ id: testCase.id }) - assert.deepEqual(ns[0].address, '2.2.2.2') - assert.ok(await ZoneRecord.put({ id: testCase.id, address: testCase.address })) }) - it('deletes a zone_record', async () => { - assert.ok(await ZoneRecord.delete({ id: testCase.id })) - let g = await ZoneRecord.get({ id: testCase.id, deleted: 1 }) - assert.equal(g[0]?.deleted, true) - await ZoneRecord.delete({ id: testCase.id, deleted: 0 }) // restore - g = await ZoneRecord.get({ id: testCase.id }) - assert.equal(g[0].deleted, false) + describe('DELETE', async () => { + it('deletes a zr', async () => { + assert.ok(await ZoneRecord.delete({ id: testCase.id })) + }) + it('deleted zr is not found', async () => { + let zrs = await ZoneRecord.get({ id: testCase.id }) + assert.equal(zrs.length, 0) + }) + it('deleted zr can be retrieved', async () => { + let zrs = await ZoneRecord.get({ id: testCase.id, deleted: true }) + assert.equal(zrs[0]?.deleted, true) + }) + it('deleted record can be restored', async () => { + await ZoneRecord.delete({ id: testCase.id, deleted: false }) // restore + let zrs = await ZoneRecord.get({ id: testCase.id }) + assert.equal(zrs[0].deleted, undefined) + }) }) }) diff --git a/package.json b/package.json index 8371411..59d48dd 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@hapi/hoek": "^11.0.4", "@hapi/inert": "^7.1.0", "@hapi/vision": "^7.0.3", - "@nictool/dns-resource-record": "^1.1.7", + "@nictool/dns-resource-record": "^1.2.0", "@nictool/validate": "^0.8.0", "hapi-swagger": "^17.2.1", "mysql2": "^3.9.2",