Skip to content
Draft
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
8 changes: 7 additions & 1 deletion acs-configdb/bin/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Service, Version } from "../lib/constants.js";

import { Auth } from "../lib/auth.js";
import { BootstrapUUIDs } from "../lib/constants.js";
import { RDF } from "../lib/rdf.js";
import Model from "../lib/model.js";
import MQTTCli from "../lib/mqttcli.js";
import { CDBNotify } from "../lib/notify.js";
Expand All @@ -32,6 +33,11 @@ const model = await new Model({
const auth = new Auth({ fplus });
const mqtt = MQTTCli.fromEnv(fplus, env);

const rdf = await new RDF({
auth, model,
debug: fplus.debug,
}).init();

const api = await new WebAPI({
ping: {
version: Version,
Expand All @@ -51,7 +57,7 @@ const api = await new WebAPI({
max_age: env.CACHE_MAX_AGE,
body_limit: env.BODY_LIMIT,

routes: routes({ auth, model, fplus, mqtt }),
routes: routes({ auth, rdf, model, fplus, mqtt }),
}).init();

const notify = new CDBNotify({
Expand Down
6 changes: 1 addition & 5 deletions acs-configdb/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ const AppUuid = {
Registration: "cb40bed5-49ad-4443-a7f5-08c75009da8f",
General_Info: "64a8bfa9-7772-45c4-9d1a-9e6290690957",
};
const Class = {
Rank: "1f2ee062-6782-48c8-926b-904f56bd18b1",
Individual: "33343846-8c14-4cb0-8027-989071a20724",
};

let Token = null;

Expand Down Expand Up @@ -236,7 +232,7 @@ function ObjMenu (props) {
}

function MenuButton (props) {
const { title, items } = props;
const { items } = props;
const id = useId();

const buttons = items.map(item => {
Expand Down
48 changes: 48 additions & 0 deletions acs-configdb/lib/api-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class APIv2 {

this.routes = express.Router();
this.model = opts.model;
this.rdf = opts.rdf;

this.setup_routes();
}
Expand Down Expand Up @@ -86,6 +87,11 @@ export class APIv2 {
.patch(this.config_patch.bind(this));

api.get("/save", this.dump_save.bind(this));

api.get("/qpf", this.qpf_query.bind(this));
api.route("/sparql")
.get(this.sparql_query.bind(this))
.post(this.sparql_query.bind(this));
}

async app_get(req, res) {
Expand Down Expand Up @@ -357,4 +363,46 @@ export class APIv2 {
const dump = await this.model.dump_save();
res.status(200).json(dump);
}

async qpf_query (req, res) {
const {s, p, o} = req.query;

const base = `${req.protocol}://${req.host}${req.baseUrl}`;

const ttl = await this.rdf.qpf_query({
auth: req.auth,
template: `${base}${req.path}{?s,p,o}`,
fragment: `${base}${req.url}`,
query: [s, p, o],
});

res.type("text/turtle");
res.send(ttl);
}

async sparql_query (req, res) {
const spec = req.is("application/x-www-form-urlencoded")
? req.body : {...req.query};
if (req.is("application/sparql-query"))
spec.query = req.body;

this.log("SPARQL query: %o", spec);

if (spec["default-graph-uri"] || spec["named-graph-uri"])
/* The SPARQL spec says to use 400 here. I don't think this
* is right and it should be 403 or some such. */
return res.status(400).end();

const types = this.rdf.sparql_types;
const type = req.accepts(types);
if (!type)
return res.status(406).end();

const [st, data] = await this.rdf.sparql_query(spec.query, req.auth, type);
res.status(st);
if (st != 200)
return res.end();
res.type(type);
data.pipe(res);
}
}
36 changes: 33 additions & 3 deletions acs-configdb/lib/model.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/*
* if (!ok) return [];
*
* if (memb.uuid) {
* const klasses = await this.model.
*
* Copyright (c) University of Sheffield AMRC 2025.
*/

Expand Down Expand Up @@ -61,9 +66,9 @@ function _q_uuids (...args) {
return _q_set(...args).then(rs => rs.map(r => r.uuid));
}

function _q_exists (...args) {
return _q_set(...args).then(rs => rs.length != 0);
}
//function _q_exists (...args) {
// return _q_set(...args).then(rs => rs.length != 0);
//}

export default class Model extends EventEmitter {
constructor(opts) {
Expand Down Expand Up @@ -127,6 +132,14 @@ export default class Model extends EventEmitter {
`, [uuid]);
}

_obj_lookup (query, id, table) {
return _q_uuids(query, `
select distinct k.uuid
from ${table} r join object k on k.id = r.class
where r.id = $1
`, [id]);
}

_app_id (query, app) { return this._obj_id(query, app); }
_class_id (query, klass) { return this._obj_id(query, klass); }

Expand All @@ -139,6 +152,15 @@ export default class Model extends EventEmitter {
return dbr.rows[0]?.id;
}

async relation_lookup (table) {
return this.db.query(`
select o.uuid obj, c.uuid class
from ${table} r
join object o on o.id = r.id
join object c on c.id = r.class
`).then(dbr => dbr.rows.map(r => [r.obj, r.class]));
}

object_list() {
return _q_uuids(this.db.query.bind(this.db),
`select o.uuid from object o`);
Expand All @@ -153,6 +175,14 @@ export default class Model extends EventEmitter {
`);
}

object_lookup (obj, table) {
return this.db.txn({}, async query => {
const id = await this._obj_id(query, obj);
if (id == null) return;
return this._obj_lookup(query, id, table);
});
}

/* XXX This is the correct place to set the owner of the new object
* but I don't have access to that information yet. */
async _object_create_uuid (query, uuid, klass) {
Expand Down
2 changes: 1 addition & 1 deletion acs-configdb/lib/notify.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class ConfigWatch {
}

config_search (filter) {
const { model, app } = this;
const { app } = this;

const search = rxx.rx(
this.updates,
Expand Down
Loading