diff --git a/packages/backend/src/definitions/SimpleEntity.js b/packages/backend/src/definitions/SimpleEntity.js new file mode 100644 index 00000000..cdc64ad2 --- /dev/null +++ b/packages/backend/src/definitions/SimpleEntity.js @@ -0,0 +1,24 @@ +const { Context } = require("../util/context"); + +module.exports = function SimpleEntity ({ name, methods, fetchers }) { + const create = function (values) { + const entity = { values }; + Object.assign(entity, methods); + for ( const fetcher_name in fetchers ) { + entity['fetch_' + fetcher_name] = async function () { + if ( this.values.hasOwnProperty(fetcher_name) ) { + return this.values[fetcher_name]; + } + const value = await fetchers[fetcher_name].call(this); + this.values[fetcher_name] = value; + return value; + } + } + entity.context = values.context ?? Context.get(); + entity.services = entity.context.get('services'); + return entity; + }; + + create.name = name; + return create; +}; diff --git a/packages/backend/src/entities/Group.js b/packages/backend/src/entities/Group.js new file mode 100644 index 00000000..7f8a96fa --- /dev/null +++ b/packages/backend/src/entities/Group.js @@ -0,0 +1,23 @@ +const SimpleEntity = require("../definitions/SimpleEntity"); + +module.exports = SimpleEntity({ + name: 'group', + fetchers: { + async members () { + const svc_group = this.services.get('group'); + const members = await svc_group.list_members({ uid: this.values.uid }); + return members; + } + }, + methods: { + async get_client_value () { + await this.fetch_members(); + const group = { + uid: this.values.uid, + metadata: this.values.metadata, + members: this.values.members, + }; + return group; + } + } +}); diff --git a/packages/backend/src/services/PermissionAPIService.js b/packages/backend/src/services/PermissionAPIService.js index b0b76383..7404f882 100644 --- a/packages/backend/src/services/PermissionAPIService.js +++ b/packages/backend/src/services/PermissionAPIService.js @@ -165,6 +165,30 @@ class PermissionAPIService extends BaseService { res.json({}); } }).attach(router); + + Endpoint({ + route: '/list', + methods: ['GET'], + mw: [configurable_auth()], + handler: async (req, res) => { + const svc_group = this.services.get('group'); + + // TODO: validate string and uuid for request + + const owned_groups = await svc_group.list_groups_with_owner( + { owner_user_id: req.user.id }); + + const in_groups = await svc_group.list_groups_with_member( + { user_id: req.user.id }); + + res.json({ + owned_groups: await Promise.all(owned_groups.map( + g => g.get_client_value())), + in_groups: await Promise.all(in_groups.map( + g => g.get_client_value())), + }); + } + }).attach(router); } } diff --git a/packages/backend/src/services/auth/GroupService.js b/packages/backend/src/services/auth/GroupService.js index 71204882..2f39bd07 100644 --- a/packages/backend/src/services/auth/GroupService.js +++ b/packages/backend/src/services/auth/GroupService.js @@ -1,3 +1,4 @@ +const Group = require("../../entities/Group"); const BaseService = require("../BaseService"); const { DB_WRITE } = require("../database/consts"); @@ -44,6 +45,54 @@ class GroupService extends BaseService { return uid; } + + async list_groups_with_owner ({ owner_user_id }) { + const groups = await this.db.read( + 'SELECT * FROM `group` WHERE owner_user_id=?', + [owner_user_id], + ); + for ( const group of groups ) { + group.extra = this.db.case({ + mysql: () => group.extra, + otherwise: () => JSON.parse(group.extra), + })(); + group.metadata = this.db.case({ + mysql: () => group.metadata, + otherwise: () => JSON.parse(group.metadata), + })(); + } + return groups.map(g => Group(g)); + } + + async list_groups_with_member ({ user_id }) { + const groups = await this.db.read( + 'SELECT * FROM `group` WHERE id IN (' + + 'SELECT group_id FROM `jct_user_group` WHERE user_id=?)', + [user_id], + ); + for ( const group of groups ) { + group.extra = this.db.case({ + mysql: () => group.extra, + otherwise: () => JSON.parse(group.extra), + })(); + group.metadata = this.db.case({ + mysql: () => group.metadata, + otherwise: () => JSON.parse(group.metadata), + })(); + } + return groups.map(g => Group(g)); + } + + async list_members ({ uid }) { + const users = await this.db.read( + 'SELECT u.username FROM user u ' + + 'JOIN (SELECT user_id FROM `jct_user_group` WHERE group_id = ' + + '(SELECT id FROM `group` WHERE uid=?)) ug ' + + 'ON u.id = ug.user_id', + [uid], + ); + return users.map(u => u.username); + } async add_users ({ uid, users }) { const question_marks =