diff --git a/src/api/rest/v1/auth/scopes.ts b/src/api/rest/v1/auth/scopes.ts index a3ad82fc..da380e1a 100644 --- a/src/api/rest/v1/auth/scopes.ts +++ b/src/api/rest/v1/auth/scopes.ts @@ -284,6 +284,15 @@ const SCOPES: Record = { type: ScopeType.API, description: "Perform a keyword search across all user data", userNote: `Perform a keyword search across all accessible data` + }, + + /** + * Connection Scopes + */ + "api:connections-profiles": { + type: ScopeType.API, + description: "Access profiles of third party accounts (ie: Google, Telegram)", + userNote: `Access profiles of third party accounts (ie: Google, Telegram)` } } diff --git a/src/api/rest/v1/connections/controller.ts b/src/api/rest/v1/connections/controller.ts index ba801b4d..76c507e9 100644 --- a/src/api/rest/v1/connections/controller.ts +++ b/src/api/rest/v1/connections/controller.ts @@ -258,7 +258,7 @@ export default class Controller { } } - public static async disconnect(req: UniqueRequest, res: Response, next: any) { + public static async disconnect(req: UniqueRequest, res: Response) { try { const connectionId = req.params.connectionId const networkInstance = req.veridaNetworkConnection @@ -283,7 +283,37 @@ export default class Controller { } } - public static async logs(req: UniqueRequest, res: Response, next: any) { + public static async profiles(req: UniqueRequest, res: Response) { + try { + const query = req.query + const providerId = query.providerId ? query.providerId.toString() : undefined + const accountId = query.accountId ? query.accountId.toString() : undefined + + const networkInstance = req.veridaNetworkConnection + const syncManager = new SyncManager(networkInstance.context) + const connections = await syncManager.getProviders(providerId, accountId) + + const result: Record = {} + for (const connection of connections) { + const uniqueId = `${connection.getProviderId()}:${connection.getAccountId()}` + result[uniqueId] = connection.getProfile() + } + + // @todo: catch and send errors + return res.send({ + profiles: result, + success: true + }) + } catch (error) { + console.log(error) + res.status(500).send({ + success: false, + error: error.message + }); + } + } + + public static async logs(req: UniqueRequest, res: Response) { try { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); diff --git a/src/api/rest/v1/connections/routes.ts b/src/api/rest/v1/connections/routes.ts index 4d73091a..dfc0b83c 100644 --- a/src/api/rest/v1/connections/routes.ts +++ b/src/api/rest/v1/connections/routes.ts @@ -1,6 +1,7 @@ import express from 'express' import Controller from './controller' import auth from "../../../../middleware/auth"; +import CONFIG from "../../../../config" const router = express.Router() @@ -9,5 +10,9 @@ router.post('/sync', auth(), Controller.sync) router.post('/:connectionId/sync', auth(), Controller.syncConnection) router.put('/:connectionId', auth(), Controller.update) router.delete('/:connectionId', auth(), Controller.disconnect) +router.get('/profiles', auth({ + scopes: ["api:connections-profiles"], + credits: CONFIG.verida.billing.defaultCredits +}), Controller.profiles) export default router \ No newline at end of file diff --git a/src/api/rest/v1/db/controller.ts b/src/api/rest/v1/db/controller.ts index 75856d68..614d8f6e 100644 --- a/src/api/rest/v1/db/controller.ts +++ b/src/api/rest/v1/db/controller.ts @@ -133,6 +133,45 @@ export class DbController { } } + public async count(req: Request, res: Response) { + try { + const dbName = req.params.database + const { context } = req.veridaNetworkConnection + const permissions = Utils.buildPermissions(req) + + const db = await context.openDatabase(dbName, { + // @ts-ignore + permissions + }) + + const selector = req.body.query + const limit = 1000 + const fields = ['_id'] + + const loops = 0 + let count = 0 + while (true) { + const result = await db.getMany(selector, { + fields, + limit, + skip: loops * limit + }) + + if (result.length < limit) { + count = loops*limit + result.length + break + } + } + + res.json({ + count + }) + } catch (error: any) { + console.log(error) + res.status(500).send(error.message); + } + } + public async query(req: Request, res: Response) { try { const dbName = req.params.database diff --git a/src/api/rest/v1/db/routes.ts b/src/api/rest/v1/db/routes.ts index de5fd77c..fe493e2a 100644 --- a/src/api/rest/v1/db/routes.ts +++ b/src/api/rest/v1/db/routes.ts @@ -11,6 +11,12 @@ router.get("/get/:database/:recordId", auth({ credits: CONFIG.verida.billing.defaultCredits }), controller.getById) +router.post("/count/:database", auth({ + scopes: ["api:db-query"], + dbScope: "r", + credits: 0 +}), controller.count) + router.post("/query/:database", auth({ scopes: ["api:db-query"], dbScope: "r", diff --git a/src/api/rest/v1/ds/controller.ts b/src/api/rest/v1/ds/controller.ts index 7eb76b77..a2ff11f3 100644 --- a/src/api/rest/v1/ds/controller.ts +++ b/src/api/rest/v1/ds/controller.ts @@ -132,6 +132,51 @@ export class DsController { } } + public async count(req: Request, res: Response) { + try { + const schemaName = Utils.getSchemaFromParams(req.params.schema) + const { context } = req.veridaNetworkConnection + const permissions = Utils.buildPermissions(req) + + const ds = await context.openDatastore(schemaName, { + // @ts-ignore + permissions + }) + + const selector = req.body.query + const limit = 1000 + const fields = ['_id'] + + const loops = 0 + let count = 0 + while (true) { + const result = await ds.getMany(selector, { + fields, + limit, + skip: loops * limit + }) + + if (result.length < limit) { + count = loops*limit + result.length + break + } + } + + res.json({ + count + }) + } catch (error: any) { + let message = error.message + if (error.message.match('invalid encoding')) { + message = 'Invalid encoding (check permissions header)' + } + + res.status(500).send({ + error: message + }); + } + } + public async query(req: Request, res: Response) { try { const schemaName = Utils.getSchemaFromParams(req.params.schema) diff --git a/src/api/rest/v1/ds/routes.ts b/src/api/rest/v1/ds/routes.ts index d8a74528..be79235d 100644 --- a/src/api/rest/v1/ds/routes.ts +++ b/src/api/rest/v1/ds/routes.ts @@ -11,6 +11,12 @@ router.get("/get/:schema/:recordId", auth({ credits: CONFIG.verida.billing.defaultCredits }), controller.getById) +router.post("/count/:schema", auth({ + scopes: ["api:ds-query"], + dsScope: "r", + credits: 0, +}), controller.count) + router.post("/query/:schema", auth({ scopes: ["api:ds-query"], dsScope: "r",