mirror of
https://github.com/colanode/colanode.git
synced 2025-12-29 00:25:03 +01:00
Move id and contants in core package and use lodash-es package
This commit is contained in:
@@ -29,6 +29,8 @@
|
||||
"tsup": "^8.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@colanode/core": "workspace:*",
|
||||
"@colanode/crdt": "workspace:*",
|
||||
"@aws-sdk/client-s3": "^3.675.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.675.0",
|
||||
"axios": "^1.7.7",
|
||||
@@ -46,7 +48,6 @@
|
||||
"postgres": "^3.4.4",
|
||||
"redis": "^4.7.0",
|
||||
"sharp": "^0.33.5",
|
||||
"ulid": "^2.3.0",
|
||||
"ws": "^8.18.0",
|
||||
"yjs": "^13.6.20"
|
||||
}
|
||||
|
||||
@@ -1,28 +1,4 @@
|
||||
export const NodeTypes = {
|
||||
User: 'user',
|
||||
Space: 'space',
|
||||
Page: 'page',
|
||||
Channel: 'channel',
|
||||
Chat: 'chat',
|
||||
Message: 'message',
|
||||
Database: 'database',
|
||||
DatabaseReplica: 'database_replica',
|
||||
Record: 'record',
|
||||
Folder: 'folder',
|
||||
TableView: 'table_view',
|
||||
BoardView: 'board_view',
|
||||
CalendarView: 'calendar_view',
|
||||
Field: 'field',
|
||||
SelectOption: 'select_option',
|
||||
File: 'file',
|
||||
};
|
||||
|
||||
export const NodeRoles = {
|
||||
Admin: 'admin',
|
||||
Editor: 'editor',
|
||||
Collaborator: 'collaborator',
|
||||
Viewer: 'viewer',
|
||||
};
|
||||
import { NodeRoles } from '@colanode/core';
|
||||
|
||||
export const hasAdminAccess = (role: string): boolean => {
|
||||
return role === NodeRoles.Admin;
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { monotonicFactory } from 'ulid';
|
||||
|
||||
const ulid = monotonicFactory();
|
||||
|
||||
export enum IdType {
|
||||
Account = 'ac',
|
||||
Workspace = 'wc',
|
||||
User = 'us',
|
||||
Version = 've',
|
||||
Mutation = 'mu',
|
||||
Space = 'sp',
|
||||
Page = 'pg',
|
||||
Channel = 'ch',
|
||||
Chat = 'ct',
|
||||
Node = 'nd',
|
||||
Message = 'ms',
|
||||
Subscriber = 'sb',
|
||||
Paragraph = 'pa',
|
||||
Heading1 = 'h1',
|
||||
Heading2 = 'h2',
|
||||
Heading3 = 'h3',
|
||||
Blockquote = 'bq',
|
||||
CodeBlock = 'cb',
|
||||
ListItem = 'li',
|
||||
OrderedList = 'ol',
|
||||
BulletList = 'bl',
|
||||
TaskList = 'tl',
|
||||
TaskItem = 'ti',
|
||||
HorizontalRule = 'hr',
|
||||
Database = 'db',
|
||||
DatabaseReplica = 'dr',
|
||||
Record = 'rc',
|
||||
Folder = 'fl',
|
||||
TableView = 'tv',
|
||||
BoardView = 'bv',
|
||||
CalendarView = 'cv',
|
||||
Field = 'fi',
|
||||
SelectOption = 'so',
|
||||
ViewFilter = 'vf',
|
||||
ViewSort = 'vs',
|
||||
Query = 'qu',
|
||||
Device = 'dv',
|
||||
Change = 'cd',
|
||||
Avatar = 'av',
|
||||
}
|
||||
|
||||
export const generateId = (type: IdType): string => {
|
||||
return ulid().toLowerCase() + type;
|
||||
};
|
||||
|
||||
export const isIdOfType = (id: string, type: IdType): boolean => {
|
||||
return id.endsWith(type);
|
||||
};
|
||||
|
||||
export const getIdType = (id: string): IdType => {
|
||||
return id.substring(id.length - 2) as IdType;
|
||||
};
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
WorkspaceStatus,
|
||||
WorkspaceUserStatus,
|
||||
} from '@/types/workspaces';
|
||||
import { generateId, IdType } from '@/lib/id';
|
||||
import { generateId, IdType, NodeRoles } from '@colanode/core';
|
||||
import * as Y from 'yjs';
|
||||
import { fromUint8Array } from 'js-base64';
|
||||
import { NodeCreatedEvent } from '@/types/events';
|
||||
import { enqueueEvent } from '@/queues/events';
|
||||
import { NodeRoles } from './constants';
|
||||
import {} from './constants';
|
||||
|
||||
export const createDefaultWorkspace = async (account: SelectAccount) => {
|
||||
const createdAt = new Date();
|
||||
@@ -64,7 +64,7 @@ export const createDefaultWorkspace = async (account: SelectAccount) => {
|
||||
|
||||
const buildUserNodeCreate = (
|
||||
workspaceId: string,
|
||||
account: SelectAccount,
|
||||
account: SelectAccount
|
||||
): CreateNode => {
|
||||
const id = generateId(IdType.User);
|
||||
const versionId = generateId(IdType.Version);
|
||||
@@ -99,7 +99,7 @@ const buildUserNodeCreate = (
|
||||
|
||||
const buildSpaceNodeCreate = (
|
||||
workspaceId: string,
|
||||
userId: string,
|
||||
userId: string
|
||||
): CreateNode => {
|
||||
const id = generateId(IdType.Space);
|
||||
const versionId = generateId(IdType.Version);
|
||||
@@ -115,7 +115,7 @@ const buildSpaceNodeCreate = (
|
||||
|
||||
attributesMap.set('collaborators', new Y.Map());
|
||||
const collaboratorsMap = attributesMap.get(
|
||||
'collaborators',
|
||||
'collaborators'
|
||||
) as Y.Map<string>;
|
||||
|
||||
collaboratorsMap.set(userId, NodeRoles.Admin);
|
||||
@@ -139,7 +139,7 @@ const buildSpaceNodeCreate = (
|
||||
const buildPageNodeCreate = (
|
||||
workspaceId: string,
|
||||
spaceId: string,
|
||||
userId: string,
|
||||
userId: string
|
||||
): CreateNode => {
|
||||
const id = generateId(IdType.Page);
|
||||
const versionId = generateId(IdType.Version);
|
||||
@@ -172,7 +172,7 @@ const buildPageNodeCreate = (
|
||||
const buildChannelNodeCreate = (
|
||||
workspaceId: string,
|
||||
spaceId: string,
|
||||
userId: string,
|
||||
userId: string
|
||||
): CreateNode => {
|
||||
const id = generateId(IdType.Channel);
|
||||
const versionId = generateId(IdType.Version);
|
||||
|
||||
@@ -3,8 +3,7 @@ import { redisConfig } from '@/data/redis';
|
||||
import { CreateUserNode } from '@/data/schema';
|
||||
import { filesStorage } from '@/data/storage';
|
||||
import { BUCKET_NAMES } from '@/data/storage';
|
||||
import { NodeTypes } from '@/lib/constants';
|
||||
import { generateId, IdType } from '@/lib/id';
|
||||
import { generateId, IdType, NodeTypes } from '@colanode/core';
|
||||
import { fetchNodeCollaborators, fetchWorkspaceUsers } from '@/lib/nodes';
|
||||
import { synapse } from '@/services/synapse';
|
||||
import {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '@/types/accounts';
|
||||
import axios from 'axios';
|
||||
import { ApiError, NeuronRequest, NeuronResponse } from '@/types/api';
|
||||
import { generateId, IdType } from '@/lib/id';
|
||||
import { generateId, IdType } from '@colanode/core';
|
||||
import { database } from '@/data/database';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { WorkspaceOutput, WorkspaceRole } from '@/types/workspaces';
|
||||
@@ -229,7 +229,7 @@ accountsRouter.delete(
|
||||
});
|
||||
|
||||
return res.status(200).end();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
accountsRouter.put(
|
||||
@@ -285,7 +285,7 @@ accountsRouter.put(
|
||||
database
|
||||
.selectFrom('workspace_users')
|
||||
.select('id')
|
||||
.where('account_id', '=', req.account.id),
|
||||
.where('account_id', '=', req.account.id)
|
||||
)
|
||||
.execute();
|
||||
|
||||
@@ -301,7 +301,7 @@ accountsRouter.put(
|
||||
updated_at: new Date(),
|
||||
})
|
||||
.where('id', '=', req.account.id)
|
||||
.compile(),
|
||||
.compile()
|
||||
);
|
||||
|
||||
for (const user of users) {
|
||||
@@ -345,7 +345,7 @@ accountsRouter.put(
|
||||
server_updated_at: updatedAt,
|
||||
})
|
||||
.where('id', '=', user.id)
|
||||
.compile(),
|
||||
.compile()
|
||||
);
|
||||
|
||||
const event: NodeUpdatedEvent = {
|
||||
@@ -380,11 +380,11 @@ accountsRouter.put(
|
||||
};
|
||||
|
||||
return res.status(200).json(output);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const buildLoginOutput = async (
|
||||
account: SelectAccount,
|
||||
account: SelectAccount
|
||||
): Promise<LoginOutput> => {
|
||||
let workspaceUsers = await database
|
||||
.selectFrom('workspace_users')
|
||||
@@ -420,7 +420,7 @@ const buildLoginOutput = async (
|
||||
|
||||
for (const workspaceUser of workspaceUsers) {
|
||||
const workspace = workspaces.find(
|
||||
(w) => w.id === workspaceUser.workspace_id,
|
||||
(w) => w.id === workspaceUser.workspace_id
|
||||
);
|
||||
|
||||
if (!workspace) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { avatarStorage, BUCKET_NAMES } from '@/data/storage';
|
||||
import { generateId, IdType } from '@/lib/id';
|
||||
import { generateId, IdType } from '@colanode/core';
|
||||
import { PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
||||
import { Router } from 'express';
|
||||
import multer from 'multer';
|
||||
@@ -16,7 +16,7 @@ const upload = multer({
|
||||
fileFilter: (req, file, cb) => {
|
||||
const filetypes = /jpeg|jpg|png|webp/;
|
||||
const extname = filetypes.test(
|
||||
path.extname(file.originalname).toLowerCase(),
|
||||
path.extname(file.originalname).toLowerCase()
|
||||
);
|
||||
const mimetype = filetypes.test(file.mimetype);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
WorkspaceStatus,
|
||||
} from '@/types/workspaces';
|
||||
import { ApiError, NeuronRequest, NeuronResponse } from '@/types/api';
|
||||
import { generateId, IdType } from '@/lib/id';
|
||||
import { generateId, IdType } from '@colanode/core';
|
||||
import { database } from '@/data/database';
|
||||
import { Router } from 'express';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
SynapseNodeChangeMessage,
|
||||
SynapseUserNodeChangeMessage,
|
||||
} from '@/types/synapse';
|
||||
import { getIdType, IdType } from '@/lib/id';
|
||||
import { getIdType, IdType } from '@colanode/core';
|
||||
import { MessageInput } from '@/types/messages';
|
||||
|
||||
interface SynapseConnection {
|
||||
@@ -91,20 +91,20 @@ class SynapseService {
|
||||
const subscriber = redis.duplicate();
|
||||
await subscriber.connect();
|
||||
await subscriber.subscribe(CHANNEL_NAMES.SYNAPSE, (message) =>
|
||||
this.handleSynapseMessage(message.toString()),
|
||||
this.handleSynapseMessage(message.toString())
|
||||
);
|
||||
}
|
||||
|
||||
private sendSocketMessage(
|
||||
connection: SynapseConnection,
|
||||
message: MessageInput,
|
||||
message: MessageInput
|
||||
) {
|
||||
connection.socket.send(JSON.stringify(message));
|
||||
}
|
||||
|
||||
private async handleSocketMessage(
|
||||
connection: SynapseConnection,
|
||||
message: MessageInput,
|
||||
message: MessageInput
|
||||
) {
|
||||
if (message.type === 'local_node_sync') {
|
||||
await database
|
||||
@@ -123,7 +123,7 @@ class SynapseService {
|
||||
workspace_id: message.workspaceId,
|
||||
node_version_id: message.versionId,
|
||||
node_synced_at: new Date(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.execute();
|
||||
} else if (message.type === 'local_user_node_sync') {
|
||||
@@ -143,7 +143,7 @@ class SynapseService {
|
||||
workspace_id: message.workspaceId,
|
||||
user_node_version_id: message.versionId,
|
||||
user_node_synced_at: new Date(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.execute();
|
||||
} else if (message.type === 'local_node_delete') {
|
||||
@@ -154,7 +154,7 @@ class SynapseService {
|
||||
.execute();
|
||||
|
||||
const userId = connection.workspaceUsers.find(
|
||||
(wu) => wu.workspaceId === message.workspaceId,
|
||||
(wu) => wu.workspaceId === message.workspaceId
|
||||
)?.userId;
|
||||
|
||||
if (userId) {
|
||||
@@ -167,7 +167,7 @@ class SynapseService {
|
||||
database
|
||||
.selectFrom('workspace_users')
|
||||
.select('account_id')
|
||||
.where('id', '=', userId),
|
||||
.where('id', '=', userId)
|
||||
)
|
||||
.execute();
|
||||
|
||||
@@ -231,7 +231,7 @@ class SynapseService {
|
||||
.selectFrom('user_nodes')
|
||||
.selectAll()
|
||||
.where((eb) =>
|
||||
eb.and([eb('user_id', 'in', userIds), eb('node_id', '=', data.nodeId)]),
|
||||
eb.and([eb('user_id', 'in', userIds), eb('node_id', '=', data.nodeId)])
|
||||
)
|
||||
.execute();
|
||||
|
||||
@@ -317,7 +317,7 @@ class SynapseService {
|
||||
}
|
||||
|
||||
private async handleUserNodeUpdateMessage(
|
||||
data: SynapseUserNodeChangeMessage,
|
||||
data: SynapseUserNodeChangeMessage
|
||||
) {
|
||||
const userDevices = this.getWorkspaceUserDevices(data.workspaceId);
|
||||
if (!userDevices.has(data.userId)) {
|
||||
@@ -369,7 +369,7 @@ class SynapseService {
|
||||
|
||||
private async sendPendingChanges(connection: SynapseConnection) {
|
||||
const userIds = connection.workspaceUsers.map(
|
||||
(workspaceUser) => workspaceUser.userId,
|
||||
(workspaceUser) => workspaceUser.userId
|
||||
);
|
||||
|
||||
console.log('sendPendingChanges', userIds);
|
||||
@@ -384,7 +384,7 @@ class SynapseService {
|
||||
.leftJoin('device_nodes as nds', (join) =>
|
||||
join
|
||||
.onRef('nds.node_id', '=', 'nus.node_id')
|
||||
.on('nds.device_id', '=', connection.deviceId),
|
||||
.on('nds.device_id', '=', connection.deviceId)
|
||||
)
|
||||
.select([
|
||||
'n.id',
|
||||
@@ -420,7 +420,7 @@ class SynapseService {
|
||||
eb('nds.user_node_version_id', 'is', null),
|
||||
eb('nds.user_node_version_id', '!=', eb.ref('nus.version_id')),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
)
|
||||
.orderBy('n.id', 'asc')
|
||||
.limit(100)
|
||||
@@ -509,7 +509,7 @@ class SynapseService {
|
||||
}
|
||||
|
||||
private async fetchWorkspaceUsers(
|
||||
connection: SynapseConnection,
|
||||
connection: SynapseConnection
|
||||
): Promise<void> {
|
||||
const workspaceUsers = await database
|
||||
.selectFrom('workspace_users')
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasAdminAccess, hasEditorAccess } from '@/lib/constants';
|
||||
import { fetchNodeRole } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
export class BoardViewValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const role = await fetchNodeRole(attributes.parentId, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attributes.collaborators) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isEqual(node.attributes.collaborators, attributes.collaborators)) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasAdminAccess, hasEditorAccess } from '@/lib/constants';
|
||||
import { fetchNodeRole } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
export class CalendarViewValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parentId = attributes.parentId;
|
||||
const role = await fetchNodeRole(parentId, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attributes.collaborators) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isEqual(node.attributes.collaborators, attributes.collaborators)) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasAdminAccess, hasEditorAccess } from '@/lib/constants';
|
||||
import { fetchNodeRole } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
|
||||
export class FieldValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes,
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const role = await fetchNodeRole(attributes.parentId, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes,
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasEditorAccess, NodeTypes } from '@/lib/constants';
|
||||
import { hasEditorAccess } from '@/lib/constants';
|
||||
import { NodeTypes } from '@colanode/core';
|
||||
import { extractNodeRole, fetchNodeAncestors } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
@@ -7,7 +8,7 @@ import { Validator } from '@/types/validators';
|
||||
export class FileValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
@@ -19,7 +20,7 @@ export class FileValidator implements Validator {
|
||||
}
|
||||
|
||||
const parent = ancestors.find(
|
||||
(ancestor) => ancestor.id === attributes.parentId,
|
||||
(ancestor) => ancestor.id === attributes.parentId
|
||||
);
|
||||
|
||||
if (!parent) {
|
||||
@@ -41,7 +42,7 @@ export class FileValidator implements Validator {
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
@@ -53,7 +54,7 @@ export class FileValidator implements Validator {
|
||||
}
|
||||
|
||||
const parent = ancestors.find(
|
||||
(ancestor) => ancestor.id === attributes.parentId,
|
||||
(ancestor) => ancestor.id === attributes.parentId
|
||||
);
|
||||
|
||||
if (!parent) {
|
||||
@@ -74,7 +75,7 @@ export class FileValidator implements Validator {
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
node: ServerNode
|
||||
): Promise<boolean> {
|
||||
if (!node.parentId) {
|
||||
return false;
|
||||
|
||||
@@ -1,35 +1,25 @@
|
||||
import { NodeTypes } from '@/lib/constants';
|
||||
import { NodeTypes } from '@colanode/core';
|
||||
import { Validator } from '@/types/validators';
|
||||
import { BoardViewValidator } from '@/validators/board-view-validator';
|
||||
import { CalendarViewValidator } from '@/validators/calendar-view-validator';
|
||||
import { ChannelValidator } from '@/validators/channel-validator';
|
||||
import { ChatValidator } from '@/validators/chat-validator';
|
||||
import { DatabaseValidator } from '@/validators/database-validator';
|
||||
import { FieldValidator } from '@/validators/field-validator';
|
||||
import { FileValidator } from '@/validators/file-validator';
|
||||
import { FolderValidator } from '@/validators/folder-validator';
|
||||
import { MessageValidator } from '@/validators/message-validator';
|
||||
import { PageValidator } from '@/validators/page-validator';
|
||||
import { RecordValidator } from '@/validators/record-validator';
|
||||
import { SelectOptionValidator } from '@/validators/select-option-validator';
|
||||
import { SpaceValidator } from '@/validators/space-validator';
|
||||
import { TableViewValidator } from '@/validators/table-view-validator';
|
||||
|
||||
const validators: Record<string, Validator> = {
|
||||
[NodeTypes.BoardView]: new BoardViewValidator(),
|
||||
[NodeTypes.CalendarView]: new CalendarViewValidator(),
|
||||
[NodeTypes.Channel]: new ChannelValidator(),
|
||||
[NodeTypes.Chat]: new ChatValidator(),
|
||||
[NodeTypes.Database]: new DatabaseValidator(),
|
||||
[NodeTypes.Field]: new FieldValidator(),
|
||||
[NodeTypes.File]: new FileValidator(),
|
||||
[NodeTypes.Folder]: new FolderValidator(),
|
||||
[NodeTypes.Message]: new MessageValidator(),
|
||||
[NodeTypes.Page]: new PageValidator(),
|
||||
[NodeTypes.Record]: new RecordValidator(),
|
||||
[NodeTypes.SelectOption]: new SelectOptionValidator(),
|
||||
[NodeTypes.Space]: new SpaceValidator(),
|
||||
[NodeTypes.TableView]: new TableViewValidator(),
|
||||
};
|
||||
|
||||
export const getValidator = (type: string): Validator | undefined => {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasAdminAccess, hasEditorAccess } from '@/lib/constants';
|
||||
import { fetchNodeRole } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
export class SelectOptionValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const parentId = attributes.parentId;
|
||||
const role = await fetchNodeRole(parentId, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attributes.collaborators) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isEqual(node.attributes.collaborators, attributes.collaborators)) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { SelectWorkspaceUser } from '@/data/schema';
|
||||
import { hasAdminAccess, hasEditorAccess } from '@/lib/constants';
|
||||
import { fetchNodeRole } from '@/lib/nodes';
|
||||
import { ServerNode, ServerNodeAttributes } from '@/types/nodes';
|
||||
import { Validator } from '@/types/validators';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
export class TableViewValidator implements Validator {
|
||||
async canCreate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
if (!attributes.parentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const role = await fetchNodeRole(attributes.parentId, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attributes.collaborators) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canUpdate(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode,
|
||||
attributes: ServerNodeAttributes
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isEqual(node.attributes.collaborators, attributes.collaborators)) {
|
||||
return hasAdminAccess(role);
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
|
||||
async canDelete(
|
||||
workspaceUser: SelectWorkspaceUser,
|
||||
node: ServerNode
|
||||
): Promise<boolean> {
|
||||
const role = await fetchNodeRole(node.id, workspaceUser.id);
|
||||
if (!role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasEditorAccess(role);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/core"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/crdt"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user