diff --git a/api/routes/connection-data.ts b/api/routes/connection-data.ts index 1a1f2f9d7..f00393000 100644 --- a/api/routes/connection-data.ts +++ b/api/routes/connection-data.ts @@ -15,7 +15,7 @@ export default async function router(schema: Schema, config: Config) { await schema.get('/data', { private: true, name: 'List Data', - group: 'Data', + group: 'ConnectionData', description: ` Used by the frontend UI to list data packages that the user can visualize `, @@ -62,7 +62,7 @@ export default async function router(schema: Schema, config: Config) { await schema.get('/connection/:connectionid/data', { name: 'List Data', - group: 'Data', + group: 'ConnectionData', params: Type.Object({ connectionid: Type.Integer({ minimum: 1 }) }), @@ -103,7 +103,7 @@ export default async function router(schema: Schema, config: Config) { await schema.post('/connection/:connectionid/data', { name: 'Create Data', - group: 'Data', + group: 'ConnectionData', description: 'Register a new data source', params: Type.Object({ connectionid: Type.Integer({ minimum: 1 }) @@ -165,7 +165,7 @@ export default async function router(schema: Schema, config: Config) { await schema.patch('/connection/:connectionid/data/:dataid', { name: 'Update Layer', - group: 'Data', + group: 'ConnectionData', description: 'Update a data source', params: Type.Object({ connectionid: Type.Integer({ minimum: 1 }), @@ -224,7 +224,7 @@ export default async function router(schema: Schema, config: Config) { await schema.get('/connection/:connectionid/data/:dataid', { name: 'Get Data', - group: 'Data', + group: 'ConnectionData', description: 'Get a data source', params: Type.Object({ connectionid: Type.Integer({ minimum: 1 }), @@ -264,7 +264,7 @@ export default async function router(schema: Schema, config: Config) { await schema.delete('/connection/:connectionid/data/:dataid', { name: 'Delete Data', - group: 'Data', + group: 'ConnectionData', description: 'Delete a data source', params: Type.Object({ connectionid: Type.Integer({ minimum: 1 }), diff --git a/api/routes/connection-layer-package.ts b/api/routes/connection-layer-package.ts new file mode 100644 index 000000000..eeba07d70 --- /dev/null +++ b/api/routes/connection-layer-package.ts @@ -0,0 +1,77 @@ +import { Type } from '@sinclair/typebox' +import Schema from '@openaddresses/batch-schema'; +import Err from '@openaddresses/batch-error'; +import Auth from '../lib/auth.js'; +import Config from '../lib/config.js'; +import { Package } from '../lib/api/package.js'; +import TAKAPI, { + APIAuthCertificate, +} from '../lib/tak-api.js'; + +export default async function router(schema: Schema, config: Config) { + await schema.post('/connection/:connectionid/layer/:layerid/package', { + name: 'Create Package', + group: 'DataAssets', + description: 'Create a new data package', + params: Type.Object({ + connectionid: Type.Integer({ minimum: 1 }), + layerid: Type.Integer({ minimum: 1 }) + }), + res: Package + }, async (req, res) => { + try { + const user = await Auth.as_user(config, req); + const profile = await config.models.Profile.from(user.email); + const auth = profile.auth; + const creatorUid = profile.username; + const api = await TAKAPI.init(new URL(String(config.server.api)), new APIAuthCertificate(auth.cert, auth.key)); + + const id = crypto.randomUUID(); + const pkg = new DataPackage(id, id); + + if (req.headers['content-type'] && req.headers['content-type'].startsWith('multipart/form-data')) { + const bb = busboy({ + headers: req.headers, + limits: { + files: 1 + } + }); + + bb.on('file', async (fieldname, file, meta) => { + try { + pkg.settings.name = meta.filename; + await pkg.addFile(file, { + name: meta.filename, + }); + } catch (err) { + Err.respond(err, res); + } + }).on('finish', async () => { + const out = await pkg.finalize() + + const hash = await DataPackage.hash(out); + + await api.Files.uploadPackage({ + name: pkg.settings.name, creatorUid, hash + }, fs.createReadStream(out)); + + await pkg.destroy(); + + const pkgres = await api.Package.list({ + uid: hash + }); + + if (!pkgres.results.length) throw new Err(404, null, 'Package not found'); + + res.json(pkgres.results[0]); + }); + + req.pipe(bb); + } else { + throw new Err(400, null, 'Unsupported Content-Type'); + } + } catch (err) { + Err.respond(err, res); + } + }); +}