@sync-in/server
Version:
The secure, open-source platform for file storage, sharing, collaboration, and sync
763 lines (762 loc) • 43.2 kB
JavaScript
/*
* 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