UNPKG

@sync-in/server

Version:

The secure, open-source platform for file storage, sharing, collaboration, and sync

763 lines (762 loc) 43.2 kB
/* * Copyright (C) 2012-2025 Johan Legrand <johan.legrand@sync-in.com> * This file is part of Sync-in | The open source file sync and share solution * See the LICENSE file for licensing details */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "SpacesQueries", { enumerable: true, get: function() { return SpacesQueries; } }); const _common = require("@nestjs/common"); const _drizzleorm = require("drizzle-orm"); const _mysqlcore = require("drizzle-orm/mysql-core"); const _constants = require("../../../common/constants"); const _shared = require("../../../common/shared"); const _cachedecorator = require("../../../infrastructure/cache/cache.decorator"); const _cacheservice = require("../../../infrastructure/cache/services/cache.service"); const _constants1 = require("../../../infrastructure/database/constants"); const _databaseinterface = require("../../../infrastructure/database/interfaces/database.interface"); const _utils = require("../../../infrastructure/database/utils"); const _commentsschema = require("../../comments/schemas/comments.schema"); const _filesschema = require("../../files/schemas/files.schema"); const _filesqueriesservice = require("../../files/services/files-queries.service"); const _linksschema = require("../../links/schemas/links.schema"); const _sharesschema = require("../../shares/schemas/shares.schema"); const _sharesqueriesservice = require("../../shares/services/shares-queries.service"); const _syncclientsschema = require("../../sync/schemas/sync-clients.schema"); const _syncpathsschema = require("../../sync/schemas/sync-paths.schema"); const _group = require("../../users/constants/group"); const _member = require("../../users/constants/member"); const _user = require("../../users/constants/user"); const _groupsschema = require("../../users/schemas/groups.schema"); const _usersgroupsschema = require("../../users/schemas/users-groups.schema"); const _usersschema = require("../../users/schemas/users.schema"); const _spaces = require("../constants/spaces"); const _spacepropsmodel = require("../models/space-props.model"); const _spacesmembersschema = require("../schemas/spaces-members.schema"); const _spacesrootsschema = require("../schemas/spaces-roots.schema"); const _spacesschema = require("../schemas/spaces.schema"); function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } function _ts_metadata(k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); } function _ts_param(paramIndex, decorator) { return function(target, key) { decorator(target, key, paramIndex); }; } let SpacesQueries = class SpacesQueries { spaceExistsForAlias(alias) { return this.db.query.spaces.findFirst({ columns: { id: true }, where: (0, _drizzleorm.eq)(_spacesschema.spaces.alias, alias) }); } spaceRootExistsForAlias(spaceId, rootAlias) { return this.db.query.spacesRoots.findFirst({ columns: { id: true }, where: (0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, spaceId), (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.alias, rootAlias)) }); } selectSpaces(fields = [ 'id', 'alias', 'name' ], where) { const select = (0, _utils.convertToSelect)(_spacesschema.spaces, fields); return this.db.select(select).from(_spacesschema.spaces).where((0, _drizzleorm.and)(...where)); } async userIsSpaceManager(userId, spaceId, shareId) { /* Check if user is a space manager */ const q = this.db.select({ userId: _spacesmembersschema.spacesMembers.userId, spaceId: _spacesmembersschema.spacesMembers.spaceId, ...shareId && { shareId: _sharesschema.shares.id } }).from(_spacesmembersschema.spacesMembers); if (shareId) { q.innerJoin(_sharesschema.shares, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_sharesschema.shares.id, shareId), (0, _drizzleorm.eq)(_sharesschema.shares.spaceId, spaceId))); } const [r] = await q.where((0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, spaceId), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.userId, userId), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.role, _spaces.SPACE_ROLE.IS_MANAGER))).limit(1); return r && r.userId === userId && r.spaceId === spaceId && (shareId ? r.shareId === shareId : true); } async getSpaceAsManager(userId, spaceId) { /* User must be the manager of the space */ // todo: make a condition if current user is an admin if (!this.spaceQuery) { const otherMembers = (0, _mysqlcore.alias)(_spacesmembersschema.spacesMembers, 'otherMembers'); const rootOwner = (0, _mysqlcore.alias)(_usersschema.users, 'rootOwner'); // fileOwner: avoid providing file path information for roots not owned by the current user const fileOwner = (0, _mysqlcore.alias)(_filesschema.files, 'fileOwner'); const linkUsers = (0, _mysqlcore.alias)(_usersschema.users, 'linkUsers'); this.spaceQuery = this.db.select({ id: _spacesschema.spaces.id, name: _spacesschema.spaces.name, alias: _spacesschema.spaces.alias, description: _spacesschema.spaces.description, enabled: _spacesschema.spaces.enabled, storageUsage: _spacesschema.spaces.storageUsage, storageQuota: _spacesschema.spaces.storageQuota, createdAt: _spacesschema.spaces.createdAt, modifiedAt: _spacesschema.spaces.modifiedAt, disabledAt: _spacesschema.spaces.disabledAt, roots: (0, _utils.concatDistinctObjectsInArray)(_spacesrootsschema.spacesRoots.id, { id: _spacesrootsschema.spacesRoots.id, name: _spacesrootsschema.spacesRoots.name, alias: _spacesrootsschema.spacesRoots.alias, externalPath: _spacesrootsschema.spacesRoots.externalPath, permissions: _spacesrootsschema.spacesRoots.permissions, createdAt: (0, _utils.dateTimeUTC)(_spacesrootsschema.spacesRoots.createdAt), owner: { id: rootOwner.id, login: rootOwner.login, fullName: (0, _usersschema.userFullNameSQL)(rootOwner), email: rootOwner.email }, // fileOwner: (hide if not owner), files: allow fields file: { id: fileOwner.id, path: (0, _filesschema.filePathSQL)(fileOwner), mime: _filesschema.files.mime } }), users: (0, _utils.concatDistinctObjectsInArray)(_usersschema.users.id, { id: _usersschema.users.id, login: _usersschema.users.login, name: (0, _usersschema.userFullNameSQL)(_usersschema.users), type: (0, _drizzleorm.sql)`IF (${_usersschema.users.role} = ${_user.USER_ROLE.GUEST}, ${_member.MEMBER_TYPE.GUEST}, ${_member.MEMBER_TYPE.USER})`, spaceRole: otherMembers.role, description: _usersschema.users.email, permissions: otherMembers.permissions, createdAt: (0, _utils.dateTimeUTC)(otherMembers.createdAt) }), groups: (0, _utils.concatDistinctObjectsInArray)(_groupsschema.groups.id, { id: _groupsschema.groups.id, name: _groupsschema.groups.name, type: (0, _drizzleorm.sql)`IF (${_groupsschema.groups.type} = ${_group.GROUP_TYPE.PERSONAL}, ${_member.MEMBER_TYPE.PGROUP}, ${_member.MEMBER_TYPE.GROUP})`, spaceRole: (0, _drizzleorm.sql)`${_spaces.SPACE_ROLE.IS_MEMBER}`, description: _groupsschema.groups.description, permissions: otherMembers.permissions, createdAt: (0, _utils.dateTimeUTC)(otherMembers.createdAt) }), links: (0, _utils.concatDistinctObjectsInArray)(linkUsers.id, { id: linkUsers.id, linkId: _linksschema.links.id, name: _linksschema.links.name, type: _drizzleorm.sql.raw(`'${_member.MEMBER_TYPE.USER}'`), spaceRole: (0, _drizzleorm.sql)`${_spaces.SPACE_ROLE.IS_MEMBER}`, description: _linksschema.links.email, permissions: otherMembers.permissions, createdAt: (0, _utils.dateTimeUTC)(otherMembers.createdAt) }) }).from(_spacesmembersschema.spacesMembers).innerJoin(_spacesschema.spaces, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesschema.spaces.id, _spacesmembersschema.spacesMembers.spaceId), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, _drizzleorm.sql.placeholder('spaceId')), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.userId, _drizzleorm.sql.placeholder('userId')), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.role, _spaces.SPACE_ROLE.IS_MANAGER))).innerJoin(otherMembers, (0, _drizzleorm.eq)(otherMembers.spaceId, _spacesschema.spaces.id)).leftJoin(_usersschema.users, (0, _drizzleorm.and)((0, _drizzleorm.isNull)(otherMembers.linkId), (0, _drizzleorm.eq)(otherMembers.userId, _usersschema.users.id))).leftJoin(linkUsers, (0, _drizzleorm.and)((0, _drizzleorm.isNotNull)(otherMembers.linkId), (0, _drizzleorm.eq)(linkUsers.id, otherMembers.userId))).leftJoin(_linksschema.links, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_linksschema.links.userId, linkUsers.id), (0, _drizzleorm.eq)(_linksschema.links.id, otherMembers.linkId))).leftJoin(_groupsschema.groups, (0, _drizzleorm.eq)(otherMembers.groupId, _groupsschema.groups.id)).leftJoin(_spacesrootsschema.spacesRoots, (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, _spacesschema.spaces.id)).leftJoin(_filesschema.files, (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.fileId, _filesschema.files.id)).leftJoin(rootOwner, (0, _drizzleorm.eq)(rootOwner.id, _filesschema.files.ownerId)).leftJoin(fileOwner, (0, _drizzleorm.and)((0, _drizzleorm.eq)(fileOwner.id, _filesschema.files.id), (0, _drizzleorm.eq)(fileOwner.ownerId, _drizzleorm.sql.placeholder('userId')))).groupBy(_spacesschema.spaces.id).limit(1).prepare(); } const [space] = await this.spaceQuery.execute({ userId, spaceId }); if (!space) { return null; } // merge members space.members = [ ...(0, _shared.popFromObject)('users', space), ...(0, _shared.popFromObject)('groups', space), ...(0, _shared.popFromObject)('links', space) ]; return new _spacepropsmodel.SpaceProps(space, userId); } async createSpace(space) { return (0, _utils.dbGetInsertedId)(await this.db.insert(_spacesschema.spaces).values(space)); } async deleteSpace(spaceId, deleteNow = false) { let r; if (deleteNow) { r = await this.db.delete(_spacesschema.spaces).where((0, _drizzleorm.eq)(_spacesschema.spaces.id, spaceId)); } else { r = await this.db.update(_spacesschema.spaces).set({ enabled: false, disabledAt: new Date() }).where((0, _drizzleorm.eq)(_spacesschema.spaces.id, spaceId)); } return (0, _utils.dbCheckAffectedRows)(r, 1); } async updateSpace(id, set) { try { (0, _utils.dbCheckAffectedRows)(await this.db.update(_spacesschema.spaces).set(set).where((0, _drizzleorm.eq)(_spacesschema.spaces.id, id)), 1); this.logger.debug(`${this.updateSpace.name} - space (${id}) was updated : ${JSON.stringify(set)}`); return true; } catch (e) { this.logger.error(`${this.updateSpace.name} - space (${id}) was not updated : ${JSON.stringify(set)} : ${e}`); return false; } } async spaceRootFiles(userId, spaceId, options) { if (!this.spaceRootFilesQuery) { const select = { id: _filesschema.files.id, path: (0, _filesschema.filePathSQL)(_filesschema.files), isDir: _filesschema.files.isDir, inTrash: _filesschema.files.inTrash, size: _filesschema.files.size, ctime: _filesschema.files.ctime, mtime: _filesschema.files.mtime, mime: _filesschema.files.mime, root: { id: _spacesrootsschema.spacesRoots.id, alias: _spacesrootsschema.spacesRoots.alias, name: _spacesrootsschema.spacesRoots.name, externalPath: _spacesrootsschema.spacesRoots.externalPath, permissions: _spacesrootsschema.spacesRoots.permissions, owner: { login: _usersschema.users.login, email: _usersschema.users.email, fullName: (0, _usersschema.userFullNameSQL)(_usersschema.users) } }, shares: (0, _drizzleorm.sql)`IF (${_drizzleorm.sql.placeholder('withShares')}, ${(0, _utils.concatDistinctObjectsInArray)(_sharesschema.shares.id, { id: _sharesschema.shares.id, alias: _sharesschema.shares.alias, name: _sharesschema.shares.name, type: _sharesschema.shares.type })}, '[]')`.mapWith(JSON.parse), syncs: (0, _drizzleorm.sql)`IF (${_drizzleorm.sql.placeholder('withSyncs')}, ${(0, _utils.concatDistinctObjectsInArray)(_syncpathsschema.syncPaths.id, { id: _syncpathsschema.syncPaths.id, clientId: _syncclientsschema.syncClients.id, clientName: (0, _drizzleorm.sql)`JSON_VALUE(${_syncclientsschema.syncClients.info}, '$.node')` })}, '[]')`.mapWith(JSON.parse), hasComments: (0, _drizzleorm.sql)`IF (${_drizzleorm.sql.placeholder('withHasComments')}, ${(0, _commentsschema.fileHasCommentsSubquerySQL)(_filesschema.files.id)}, 0)`.mapWith(Boolean) }; this.spaceRootFilesQuery = this.db.select(select).from(_spacesrootsschema.spacesRoots).leftJoin(_filesschema.files, (0, _drizzleorm.eq)(_filesschema.files.id, _spacesrootsschema.spacesRoots.fileId)).leftJoin(_usersschema.users, (0, _drizzleorm.eq)(_usersschema.users.id, _filesschema.files.ownerId)).leftJoin(_sharesschema.shares, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_drizzleorm.sql.placeholder('withShares'), _drizzleorm.sql.raw('1')), (0, _drizzleorm.eq)(_sharesschema.shares.ownerId, _drizzleorm.sql.placeholder('userId')), (0, _drizzleorm.isNull)(_sharesschema.shares.fileId), (0, _drizzleorm.isNull)(_sharesschema.shares.parentId), (0, _drizzleorm.eq)(_sharesschema.shares.spaceRootId, _spacesrootsschema.spacesRoots.id))).leftJoin(_syncclientsschema.syncClients, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_drizzleorm.sql.placeholder('withSyncs'), _drizzleorm.sql.raw('1')), (0, _drizzleorm.eq)(_syncclientsschema.syncClients.ownerId, _drizzleorm.sql.placeholder('userId')))).leftJoin(_syncpathsschema.syncPaths, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_drizzleorm.sql.placeholder('withSyncs'), _drizzleorm.sql.raw('1')), (0, _drizzleorm.eq)(_syncpathsschema.syncPaths.clientId, _syncclientsschema.syncClients.id), (0, _drizzleorm.eq)(_syncpathsschema.syncPaths.spaceId, _drizzleorm.sql.placeholder('spaceId')), (0, _drizzleorm.eq)(_syncpathsschema.syncPaths.spaceRootId, _spacesrootsschema.spacesRoots.id), (0, _drizzleorm.isNull)(_syncpathsschema.syncPaths.fileId))).where((0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, _drizzleorm.sql.placeholder('spaceId'))).groupBy(_filesschema.files.id, _spacesrootsschema.spacesRoots.id).prepare(); } return this.spaceRootFilesQuery.execute({ userId, spaceId, withHasComments: +!!options.withHasComments, withShares: +!!options.withShares, withSyncs: +!!options.withSyncs }); } async getSpaceRoots(spaceId, userId) { const where = [ (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, spaceId) ]; if (userId) { where.push((0, _drizzleorm.eq)(_filesschema.files.ownerId, userId)); } return await this.db.select({ id: _spacesrootsschema.spacesRoots.id, alias: _spacesrootsschema.spacesRoots.alias, name: _spacesrootsschema.spacesRoots.name, permissions: _spacesrootsschema.spacesRoots.permissions, createdAt: _spacesrootsschema.spacesRoots.createdAt, ...!userId && { owner: { id: _filesschema.files.ownerId } }, file: { id: _filesschema.files.id, path: (0, _filesschema.filePathSQL)(_filesschema.files), mime: _filesschema.files.mime } }).from(_spacesrootsschema.spacesRoots).leftJoin(_filesschema.files, (0, _drizzleorm.eq)(_filesschema.files.id, _spacesrootsschema.spacesRoots.fileId)).where((0, _drizzleorm.and)(...where)); } async getSpaceMemberIds(spaceId) { const members = { userIds: [], groupIds: [] }; for (const m of (await this.db.select({ userId: _spacesmembersschema.spacesMembers.userId, groupId: _spacesmembersschema.spacesMembers.groupId }).from(_spacesmembersschema.spacesMembers).where((0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, spaceId)))){ if (m.userId) { members.userIds.push(m.userId); } else { members.groupIds.push(m.groupId); } } return members; } async updateMembers(spaceId, add, update, remove) { // store status const status = { [_constants.ACTION.ADD]: { userIds: [], groupIds: [] }, [_constants.ACTION.UPDATE]: { userIds: [], groupIds: [] }, [_constants.ACTION.DELETE]: { userIds: [], groupIds: [] } }; // add for (const m of add){ try { (0, _utils.dbCheckAffectedRows)(await this.db.insert(_spacesmembersschema.spacesMembers).values({ spaceId: spaceId, ...m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? { userId: m.id } : { groupId: m.id }, role: m.spaceRole, permissions: m.permissions }), 1); status[_constants.ACTION.ADD][`${m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? 'userIds' : 'groupIds'}`].push(m.id); this.logger.debug(`${this.updateMembers.name} - ${m.type} (${m.id}) added to the space (${spaceId})`); } catch (e) { this.logger.error(`${this.updateMembers.name} - ${m.type} (${m.id}) was not added to the space ${spaceId} -> : ${e}`); } } // update for (const props of update){ const m = (0, _shared.popFromObject)('object', props); const spaceRole = (0, _shared.popFromObject)('spaceRole', props); if (Number.isInteger(spaceRole)) { props.role = spaceRole; } try { (0, _utils.dbCheckAffectedRows)(await this.db.update(_spacesmembersschema.spacesMembers).set(props).where((0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, spaceId), (0, _drizzleorm.eq)(m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? _spacesmembersschema.spacesMembers.userId : _spacesmembersschema.spacesMembers.groupId, m.id))).limit(1), 1); status[_constants.ACTION.UPDATE][`${m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? 'userIds' : 'groupIds'}`].push(m.id); this.logger.debug(`${this.updateMembers.name} - ${m.type} (${m.id}) was updated on space (${spaceId}) : ${JSON.stringify(props)}`); } catch (e) { this.logger.error(`${this.updateMembers.name} - ${m.type} (${m.id}) was not updated on space (${spaceId}) : ${JSON.stringify(props)} : ${e}`); } } // remove for (const m of remove){ try { (0, _utils.dbCheckAffectedRows)(await this.db.delete(_spacesmembersschema.spacesMembers).where((0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, spaceId), (0, _drizzleorm.eq)(m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? _spacesmembersschema.spacesMembers.userId : _spacesmembersschema.spacesMembers.groupId, m.id))), 1); status[_constants.ACTION.DELETE][`${m.type === _member.MEMBER_TYPE.USER || m.type === _member.MEMBER_TYPE.GUEST ? 'userIds' : 'groupIds'}`].push(m.id); this.logger.debug(`${this.updateMembers.name} - ${m.type} (${m.id}) removed from space (${spaceId})`); } catch (e) { this.logger.error(`${this.updateMembers.name} - ${m.type} (${m.id}) was not removed from space (${spaceId}) : ${e}`); } } return status; } async updateSpaceRoots(userId, spaceId, add, update, remove) { // store status const status = {}; // add for (const r of add){ if (await this.addRoot(userId, spaceId, r)) { ; (status[_constants.ACTION.ADD] ||= []).push(r); } } // update for (const props of update){ const r = (0, _shared.popFromObject)('object', props); if (await this.updateRoot(props, { id: r.id })) { ; (status[_constants.ACTION.UPDATE] ||= []).push(r); } } // delete for (const r of remove){ if (await this.removeRoot(r.id)) { ; (status[_constants.ACTION.DELETE] ||= []).push(r); } } return status; } async spaceIds(userId) { if (!this.spaceIdsQuery) { const unionAlias = this.fromUserAndGroups({ id: _spacesschema.spaces.id }); this.spaceIdsQuery = this.db.select({ id: unionAlias.id }).from(unionAlias).groupBy(unionAlias.id).prepare(); } return (await this.spaceIdsQuery.execute({ userId })).map((r)=>r.id); } async spaces(userId, withPermissions = false, fromId) { let pQuery; if (fromId) { pQuery = this.spaceFromIdWithPermissionsQuery; } else if (withPermissions) { pQuery = this.spacesWithPermissionsQuery; } else { pQuery = this.spacesQuery; } if (!pQuery) { const selectUnion = { id: _spacesschema.spaces.id, alias: _spacesschema.spaces.alias, name: _spacesschema.spaces.name, description: _spacesschema.spaces.description, enabled: _spacesschema.spaces.enabled, createdAt: _spacesschema.spaces.createdAt, modifiedAt: _spacesschema.spaces.modifiedAt, ...withPermissions && { permissions: _spacesmembersschema.spacesMembers.permissions, role: _spacesmembersschema.spacesMembers.role } }; const unionAlias = this.fromUserAndGroups(selectUnion); const select = { id: unionAlias.id, alias: unionAlias.alias, name: unionAlias.name, description: unionAlias.description, enabled: unionAlias.enabled, createdAt: unionAlias.createdAt, modifiedAt: unionAlias.modifiedAt, ...withPermissions && { permissions: (0, _spacesschema.spaceGroupConcatPermissions)(unionAlias.permissions), role: (0, _drizzleorm.max)(unionAlias.role) } }; if (fromId) { pQuery = this.db.select(select).from(unionAlias).where((0, _drizzleorm.eq)(unionAlias.id, fromId)).limit(1).prepare(); this.spaceFromIdWithPermissionsQuery = pQuery; } else { pQuery = this.db.select(select).from(unionAlias).groupBy(unionAlias.id).prepare(); if (withPermissions) { this.spacesWithPermissionsQuery = pQuery; } else { this.spacesQuery = pQuery; } } } // SpaceProps instance is required, if the user is a space manager, he must have all permissions return (await pQuery.execute({ userId })).map((s)=>new _spacepropsmodel.SpaceProps(s)); } async spacesWithDetails(userId) { if (!this.spacesWithDetailsQuery) { const selectUnion = { id: _spacesschema.spaces.id, alias: _spacesschema.spaces.alias, name: _spacesschema.spaces.name, description: _spacesschema.spaces.description, enabled: _spacesschema.spaces.enabled, permissions: _spacesmembersschema.spacesMembers.permissions, role: _spacesmembersschema.spacesMembers.role, createdAt: _spacesschema.spaces.createdAt, modifiedAt: _spacesschema.spaces.modifiedAt, disabledAt: _spacesschema.spaces.disabledAt }; const unionAlias = this.fromUserAndGroups(selectUnion); const managers = (0, _mysqlcore.alias)(_usersschema.users, 'managers'); const select = { id: unionAlias.id, alias: unionAlias.alias, name: unionAlias.name, description: unionAlias.description, enabled: unionAlias.enabled, permissions: (0, _spacesschema.spaceGroupConcatPermissions)(unionAlias.permissions), role: (0, _drizzleorm.max)(unionAlias.role), modifiedAt: unionAlias.modifiedAt, createdAt: unionAlias.createdAt, disabledAt: unionAlias.disabledAt, members: (0, _utils.concatDistinctObjectsInArray)(managers.id, { id: managers.id, login: managers.login, name: (0, _usersschema.userFullNameSQL)(managers), description: managers.email, type: _drizzleorm.sql.raw(`'${_member.MEMBER_TYPE.USER}'`), spaceRole: _spacesmembersschema.spacesMembers.role, permissions: (0, _drizzleorm.sql)`''`, createdAt: (0, _utils.dateTimeUTC)(_spacesmembersschema.spacesMembers.createdAt) }), counts: { users: (0, _drizzleorm.sql)`COUNT(DISTINCT(CASE WHEN ${_spacesmembersschema.spacesMembers.userId} IS NOT NULL AND ${_spacesmembersschema.spacesMembers.linkId} IS NULL THEN ${_spacesmembersschema.spacesMembers.userId} END))`, groups: (0, _drizzleorm.countDistinct)(_spacesmembersschema.spacesMembers.groupId), links: (0, _drizzleorm.sql)`COUNT(DISTINCT(CASE WHEN ${_spacesmembersschema.spacesMembers.linkId} IS NOT NULL THEN ${_spacesmembersschema.spacesMembers.linkId} END))`, roots: (0, _drizzleorm.countDistinct)(_filesschema.files.id), shares: (0, _drizzleorm.sql)`COUNT(DISTINCT(CASE WHEN ${_sharesschema.shares.id} IS NOT NULL THEN ${_sharesschema.shares.id} END))` } }; this.spacesWithDetailsQuery = this.db.select(select).from(unionAlias).leftJoin(_spacesmembersschema.spacesMembers, (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, unionAlias.id)).leftJoin(_usersschema.users, (0, _drizzleorm.eq)(_usersschema.users.id, _spacesmembersschema.spacesMembers.userId)).leftJoin(_groupsschema.groups, (0, _drizzleorm.eq)(_groupsschema.groups.id, _spacesmembersschema.spacesMembers.groupId)).leftJoin(managers, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.userId, managers.id), (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.role, _spaces.SPACE_ROLE.IS_MANAGER))).leftJoin(_spacesrootsschema.spacesRoots, (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, unionAlias.id)).leftJoin(_filesschema.files, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_filesschema.files.id, _spacesrootsschema.spacesRoots.fileId), (0, _drizzleorm.eq)(_filesschema.files.ownerId, _drizzleorm.sql.placeholder('userId')))).leftJoin(_sharesschema.shares, (0, _drizzleorm.and)((0, _drizzleorm.eq)(unionAlias.role, 1), (0, _drizzleorm.eq)(_sharesschema.shares.spaceId, unionAlias.id), (0, _drizzleorm.isNotNull)(_sharesschema.shares.spaceId))).groupBy(unionAlias.id).prepare(); } const r = await this.spacesWithDetailsQuery.execute({ userId }); return r.length ? r.map((s)=>new _spacepropsmodel.SpaceProps(s)) : []; } async permissions(userId, spaceAlias, rootAlias) { if (rootAlias) { return await this.spaceAndRootPermissions(userId, spaceAlias, rootAlias); } return await this.spacePermissions(userId, spaceAlias); } async addRoot(userId, spaceId, root) { const r = { name: root.name, alias: root.alias, permissions: root.permissions, spaceId: spaceId }; if (root.externalPath) { r.externalPath = root.externalPath; } else { r.fileId = await this.getOrCreateUserFile(userId, root.file); } try { (0, _utils.dbCheckAffectedRows)(await this.db.insert(_spacesrootsschema.spacesRoots).values(r), 1); this.logger.debug(`${this.addRoot.name} - *${root.alias}* (${root.id}) added`); return true; } catch (e) { this.logger.error(`${this.addRoot.name} - *${root.alias}* (${root.id}) was not added : ${JSON.stringify(root)} : ${e}`); return false; } } async updateRoot(set, filters) { const where = (0, _utils.convertToWhere)(_spacesrootsschema.spacesRoots, filters); try { (0, _utils.dbCheckAffectedRows)(await this.db.update(_spacesrootsschema.spacesRoots).set(set).where((0, _drizzleorm.and)(...where)).limit(1), 1); this.logger.debug(`${this.updateRoot.name} - ${JSON.stringify(filters)} was updated : ${JSON.stringify(set)}`); return true; } catch (e) { this.logger.error(`${this.updateRoot.name} - ${JSON.stringify(filters)} was not updated : ${JSON.stringify(set)} : ${e}`); return false; } } async getOrCreateUserFile(userId, file) { return this.filesQueries.getOrCreateUserFile(userId, file); } async getOrCreateSpaceFile(fileId, file, dbFile) { return this.filesQueries.getOrCreateSpaceFile(fileId, file, dbFile); } async clearCachePermissions(spaceAlias, rootAliases, userIds) { const uIds = userIds ?? [ '*' ]; for (const uid of uIds){ const basePattern = [ this.constructor.name, this.permissions.name, uid, spaceAlias ]; const patterns = []; if (rootAliases?.length) { // clear cache on space root rootAliases.forEach((rAlias)=>patterns.push(this.cache.genSlugKey(...basePattern, rAlias))); } else { // clear cache on spaces list patterns.push(this.cache.genSlugKey(...[ this.constructor.name, this.spaces.name, uid, '*' ])); // clear cache on spaces and roots patterns.push(this.cache.genSlugKey(...basePattern), this.cache.genSlugKey(...basePattern, '*')); } for (const p of patterns){ const keys = await this.cache.keys(p); if (keys.length) { this.logger.verbose(`${this.clearCachePermissions.name} - ${JSON.stringify(keys)}`); this.cache.mdel(keys).catch((e)=>this.logger.error(`${this.clearCachePermissions.name} - ${e}`)); } } } } async removeRoot(id) { try { (0, _utils.dbCheckAffectedRows)(await this.db.delete(_spacesrootsschema.spacesRoots).where((0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.id, id)), 1); this.logger.debug(`${this.removeRoot.name} - root (${id}) removed`); return true; } catch (e) { this.logger.error(`${this.removeRoot.name} - root (${id}) was not deleted : ${e}`); return false; } } async spacePermissions(userId, spaceAlias) { if (!this.spacePermissionsQuery) { const selectUnion = { id: _spacesschema.spaces.id, alias: _spacesschema.spaces.alias, name: _spacesschema.spaces.name, enabled: _spacesschema.spaces.enabled, permissions: _spacesmembersschema.spacesMembers.permissions, role: _spacesmembersschema.spacesMembers.role }; const filters = [ (0, _drizzleorm.eq)(_spacesschema.spaces.alias, _drizzleorm.sql.placeholder('spaceAlias')) ]; const unionAlias = this.fromUserAndGroups(selectUnion, filters); const select = { id: unionAlias.id, alias: unionAlias.alias, name: unionAlias.name, enabled: unionAlias.enabled, permissions: (0, _spacesschema.spaceGroupConcatPermissions)(unionAlias.permissions), role: (0, _drizzleorm.max)(unionAlias.role) }; this.spacePermissionsQuery = this.db.select(select).from(unionAlias).groupBy(unionAlias.id).limit(1).prepare(); } const r = await this.spacePermissionsQuery.execute({ userId, spaceAlias }); return r.length ? r.at(0) : null; } async spaceAndRootPermissions(userId, spaceAlias, rootAlias) { if (!this.spaceAndRootPermissionsQuery) { const selectUnion = { id: _spacesschema.spaces.id, alias: _spacesschema.spaces.alias, name: _spacesschema.spaces.name, enabled: _spacesschema.spaces.enabled, permissions: _spacesmembersschema.spacesMembers.permissions, role: _spacesmembersschema.spacesMembers.role, rootId: (0, _drizzleorm.sql)`${_spacesrootsschema.spacesRoots.id}`.as('rootId'), rootAlias: (0, _drizzleorm.sql)`${_spacesrootsschema.spacesRoots.alias}`.as('rootAlias'), rootName: (0, _drizzleorm.sql)`${_spacesrootsschema.spacesRoots.name}`.as('rootName'), rootPermissions: (0, _drizzleorm.sql)`${_spacesrootsschema.spacesRoots.permissions}`.as('rootPermissions'), rootOwnerId: _filesschema.files.ownerId, rootOwnerLogin: _usersschema.users.login, rootFileId: (0, _drizzleorm.sql)`${_filesschema.files.id}`.as('rootFileId'), rootFilePath: (0, _filesschema.filePathSQL)(_filesschema.files).as('rootFilePath'), rootFileInTrash: _filesschema.files.inTrash, rootExternalPath: _spacesrootsschema.spacesRoots.externalPath }; const filters = [ (0, _drizzleorm.eq)(_spacesschema.spaces.alias, _drizzleorm.sql.placeholder('spaceAlias')) ]; const fromUser = this.fromUserQuery(selectUnion, filters).$dynamic(); const fromGroups = this.fromGroupsQuery(selectUnion, filters).$dynamic(); for (const q of [ fromUser, fromGroups ]){ q.leftJoin(_spacesrootsschema.spacesRoots, (0, _drizzleorm.and)((0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.spaceId, _spacesmembersschema.spacesMembers.spaceId), (0, _drizzleorm.eq)(_spacesrootsschema.spacesRoots.alias, _drizzleorm.sql.placeholder('rootAlias')))).leftJoin(_filesschema.files, (0, _drizzleorm.eq)(_filesschema.files.id, _spacesrootsschema.spacesRoots.fileId)).leftJoin(_usersschema.users, (0, _drizzleorm.eq)(_usersschema.users.id, _filesschema.files.ownerId)); } const unionAlias = (0, _mysqlcore.union)(fromUser, fromGroups).as('union_alias'); const select = { id: unionAlias.id, alias: unionAlias.alias, name: unionAlias.name, enabled: unionAlias.enabled, permissions: (0, _spacesschema.spaceGroupConcatPermissions)(unionAlias.permissions), role: (0, _drizzleorm.sql)`MAX(${unionAlias.role})`, root: { id: unionAlias.rootId, alias: unionAlias.rootAlias, name: unionAlias.rootName, permissions: unionAlias.rootPermissions, owner: { id: unionAlias.rootOwnerId, login: unionAlias.rootOwnerLogin }, file: { id: unionAlias.rootFileId, path: unionAlias.rootFilePath, inTrash: unionAlias.rootFileInTrash }, externalPath: unionAlias.rootExternalPath } }; this.spaceAndRootPermissionsQuery = this.db.select(select).from(unionAlias).groupBy(unionAlias.id).limit(1).prepare(); } const r = await this.spaceAndRootPermissionsQuery.execute({ userId, spaceAlias, rootAlias }); return r.length ? r.at(0) : null; } fromUserAndGroups(select, filters = []) { return (0, _mysqlcore.union)(this.fromUserQuery(select, filters), this.fromGroupsQuery(select, filters)).as('union_alias'); } fromUserQuery(select, filters = []) { const where = [ (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.userId, _drizzleorm.sql.placeholder('userId')), ...filters ]; return this.db.select(select).from(_spacesmembersschema.spacesMembers).innerJoin(_spacesschema.spaces, (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, _spacesschema.spaces.id)).where((0, _drizzleorm.and)(...where)); } fromGroupsQuery(select, filters = []) { const where = [ (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.groupId, _usersgroupsschema.usersGroups.groupId), ...filters ]; return this.db.select(select).from(_spacesmembersschema.spacesMembers).innerJoin(_usersgroupsschema.usersGroups, (0, _drizzleorm.eq)(_usersgroupsschema.usersGroups.userId, _drizzleorm.sql.placeholder('userId'))).innerJoin(_spacesschema.spaces, (0, _drizzleorm.eq)(_spacesmembersschema.spacesMembers.spaceId, _spacesschema.spaces.id)).where((0, _drizzleorm.and)(...where)); } constructor(db, cache, filesQueries, sharesQueries){ this.db = db; this.cache = cache; this.filesQueries = filesQueries; this.sharesQueries = sharesQueries; this.logger = new _common.Logger(SpacesQueries.name); this.spacePermissionsQuery = null; this.spaceAndRootPermissionsQuery = null; this.spacesWithDetailsQuery = null; this.spacesQuery = null; this.spaceIdsQuery = null; this.spaceQuery = null; this.spacesWithPermissionsQuery = null; this.spaceFromIdWithPermissionsQuery = null; this.spaceRootFilesQuery = null; } }; _ts_decorate([ (0, _cachedecorator.CacheDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ Number ]), _ts_metadata("design:returntype", Promise) ], SpacesQueries.prototype, "spaceIds", null); _ts_decorate([ (0, _cachedecorator.CacheDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ Number, void 0, Number ]), _ts_metadata("design:returntype", Promise) ], SpacesQueries.prototype, "spaces", null); _ts_decorate([ (0, _cachedecorator.CacheDecorator)(), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ Number, String, String ]), _ts_metadata("design:returntype", Promise) ], SpacesQueries.prototype, "permissions", null); SpacesQueries = _ts_decorate([ (0, _common.Injectable)(), _ts_param(0, (0, _common.Inject)(_constants1.DB_TOKEN_PROVIDER)), _ts_metadata("design:type", Function), _ts_metadata("design:paramtypes", [ typeof _databaseinterface.DBSchema === "undefined" ? Object : _databaseinterface.DBSchema, typeof _cacheservice.Cache === "undefined" ? Object : _cacheservice.Cache, typeof _filesqueriesservice.FilesQueries === "undefined" ? Object : _filesqueriesservice.FilesQueries, typeof _sharesqueriesservice.SharesQueries === "undefined" ? Object : _sharesqueriesservice.SharesQueries ]) ], SpacesQueries); //# sourceMappingURL=spaces-queries.service.js.map