diff --git a/api/src/controllers/composedb.js b/api/src/controllers/composedb.js new file mode 100644 index 00000000..4572a6ca --- /dev/null +++ b/api/src/controllers/composedb.js @@ -0,0 +1,32 @@ +import { ComposeDBService } from "../services/composedb.js"; + +export const createNode = async (req, res, next) => { + try { + const composeDbService = new ComposeDBService().setSession(req.session);; + const node = await composeDbService.createNode(req.params.modelId, req.body); + res.status(201).json(node); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +export const updateNode = async (req, res, next) => { + try { + const composeDbService = new ComposeDBService().setSession(req.session);; + const node = await composeDbService.updateNode(req.params.modelId, req.params.nodeId, req.body); + res.status(201).json(node); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; + +export const getNodeById = async (req, res, next) => { + try { + const composeDbService = new ComposeDBService(); + const node = await composeDbService.getNodeById(req.params.modelId, req.params.nodeId); + + res.status(200).json(node); + } catch (error) { + res.status(500).json({ error: error.message }); + } +} diff --git a/api/src/packages/api.js b/api/src/packages/api.js index 8f1194f8..3db7ae1f 100644 --- a/api/src/packages/api.js +++ b/api/src/packages/api.js @@ -46,6 +46,9 @@ import * as litProtocol from "../controllers/lit-protocol.js"; import * as fileController from "../controllers/file.js"; import * as web2Controller from "../controllers/web2.js"; + +import * as composeDbController from "../controllers/composedb.js"; + import * as zapierController from "../controllers/zapier.js"; import * as siteController from "../controllers/site.js"; @@ -401,6 +404,24 @@ app.get( web2Controller.crawlMetadata, ); + +app.get( + "/composedb/:modelId/:nodeId", + composeDbController.getNodeById, +); + +app.post( + "/composedb/:modelId", + authCheckMiddleware, + composeDbController.createNode, +); + +app.patch( + "/composedb/:modelId/:nodeId", + authCheckMiddleware, + composeDbController.updateNode, +); + //Todo refactor later. app.post("/zapier/index_link", zapierController.indexLink); app.get("/zapier/auth", zapierController.authenticate); diff --git a/api/src/services/composedb.js b/api/src/services/composedb.js new file mode 100644 index 00000000..93fe4798 --- /dev/null +++ b/api/src/services/composedb.js @@ -0,0 +1,142 @@ +import {ComposeClient} from "@composedb/client"; + +import {definition} from "../types/merged-runtime.js"; +import { webPageFragment, teamFragment } from "../types/fragments.js"; + +const fragments = { + [definition.models.WebPage.id]: { fragment: webPageFragment, name: "WebPage" }, + [definition.models.Team.id]: { fragment: teamFragment, name: "Team" } +}; + +export class ComposeDBService { + constructor() { + this.client = new ComposeClient({ + ceramic: process.env.CERAMIC_HOST, + definition: definition, + }); + this.did = null; + } + + setSession(session) { + if(session && session.did.authenticated) { + this.did = session.did + } + return this; + } + + async createNode(modelId, params) { + + const modelFragment = fragments[modelId]; + + if (!this.did) { + throw new Error("DID not set. Use setDID() to set the did."); + } + + try { + const content = { + ...params, + }; + this.client.setDID(this.did); + const {data, errors} = await this.client.executeQuery(` + mutation CreateNode($input: Create${modelFragment.name}Input!) { + create${modelFragment.name}(input: $input) { + document { + ${modelFragment.fragment} + } + } + }`, {input: { content }}); + + // Handle GraphQL errors + if (errors) { + throw new Error(`Error creating ${modelFragment.name}: ${JSON.stringify(errors)}`); + } + + // Validate the data response + if (!data || !data[`create${modelFragment.name}`] || !data[`create${modelFragment.name}`].document) { + throw new Error('Invalid response data'); + } + + // Return the created webpage document + return data[`create${modelFragment.name}`].document; + + } catch (error) { + // Log the error and rethrow it for external handling + console.error('Exception occurred in createWebPage:', error); + throw error; + } + } + + async updateNode(modelId, id, params) { + + const modelFragment = fragments[modelId]; + + if (!this.did) { + throw new Error("DID not set. Use setDID() to set the did."); + } + + try { + const content = { + ...params, + }; + this.client.setDID(this.did); + const {data, errors} = await this.client.executeQuery(` + mutation Update${modelFragment.name}($input: Update${modelFragment.name}Input!) { + update${modelFragment.name}(input: $input) { + document { + ${modelFragment.fragment} + } + } + }`, {input: {id, content}}); + + // Handle GraphQL errors + if (errors) { + throw new Error(`Error updating ${modelFragment.name}: ${JSON.stringify(errors)}`); + } + + // Validate the data response + if (!data || !data[`update${modelFragment.name}`] || !data[`update${modelFragment.name}`].document) { + throw new Error('Invalid response data'); + } + + // Return the updated node document + return data[`update${modelFragment.name}`].document; + + } catch (error) { + // Log the error and rethrow it for external handling + console.error(`Exception occurred in update${modelFragment.name}:`, error); + throw error; + } + } + + async getNodeById(modelId, id) { + + const modelFragment = fragments[modelId]; + console.log(fragments, modelId) + try { + const {data, errors} = await this.client.executeQuery(` + { + node(id: "${id}") { + ... on ${modelFragment.name} { + ${modelFragment.fragment} + } + } + }`); + + // Handle GraphQL errors + if (errors) { + throw new Error(`Error getting ${modelFragment.name}: ${JSON.stringify(errors)}`); + } + // Validate the data response + if (!data || !data.node) { + throw new Error('Invalid response data'); + } + + return data.node; + + } catch (error) { + // Log the error and rethrow it for external handling + console.error(`Exception occurred in getNodeById:`, error); + throw error; + } + } +}