Skip to content

Commit 75fa96c

Browse files
Merge branch 'develop' into feature-be-#279
2 parents 36b0d5d + 0668dcc commit 75fa96c

File tree

15 files changed

+538
-149
lines changed

15 files changed

+538
-149
lines changed

apps/backend/src/workspace/workspace.service.ts

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Injectable } from '@nestjs/common';
1+
import { Injectable, Logger } from '@nestjs/common';
22
import { UserRepository } from '../user/user.repository';
33
import { WorkspaceRepository } from './workspace.repository';
44
import { RoleRepository } from '../role/role.repository';
@@ -11,14 +11,33 @@ import { NotWorkspaceOwnerException } from '../exception/workspace-auth.exceptio
1111
import { TokenService } from '../auth/token/token.service';
1212
import { ForbiddenAccessException } from '../exception/access.exception';
1313

14+
enum MainWorkspace {
15+
OWNER_SNOWFLAKEID = 'admin',
16+
OWNER_PROVIDER_ID = 'adminProviderId',
17+
OWNER_PROVIDER = 'adminProvider',
18+
OWNER_EMAIL = '[email protected]',
19+
WORKSPACE_SNOWFLAKEID = 'main',
20+
WORKSPACE_TITLE = 'main workspace',
21+
WORKSPACE_DESCRIPTION = '모든 유저가 접근 가능한 메인 workspace',
22+
WORKSPACE_VISIBILITY = 'public',
23+
}
24+
1425
@Injectable()
1526
export class WorkspaceService {
27+
private readonly logger = new Logger(WorkspaceService.name); // 클래스 이름을 context로 설정
28+
1629
constructor(
1730
private readonly workspaceRepository: WorkspaceRepository,
1831
private readonly userRepository: UserRepository,
1932
private readonly roleRepository: RoleRepository,
2033
private readonly tokenService: TokenService,
21-
) {}
34+
) {
35+
console.log('환경 : ', process.env.NODE_ENV);
36+
if (process.env.NODE_ENV !== 'test') {
37+
this.initializeMainWorkspace();
38+
}
39+
}
40+
2241

2342
async createWorkspace(
2443
userId: number,
@@ -186,4 +205,62 @@ export class WorkspaceService {
186205
// 권한이 없으면 예외 발생
187206
throw new ForbiddenAccessException();
188207
}
208+
209+
// 가장 처음에 모두가 접속할 수 있는 main workspace를 생성한다.
210+
async initializeMainWorkspace() {
211+
let findOwner = await this.userRepository.findOneBy({
212+
snowflakeId: MainWorkspace.OWNER_SNOWFLAKEID,
213+
});
214+
215+
// 존재하지 않을 때만 생성한다.
216+
if (!findOwner) {
217+
// main workspace owner를 생성한다.
218+
const owner = await this.userRepository.save({
219+
snowflakeId: MainWorkspace.OWNER_SNOWFLAKEID,
220+
providerId: MainWorkspace.OWNER_PROVIDER_ID,
221+
provider: MainWorkspace.OWNER_PROVIDER,
222+
email: MainWorkspace.OWNER_EMAIL,
223+
});
224+
225+
findOwner = owner;
226+
}
227+
this.logger.log('main workspace owner가 존재합니다.');
228+
229+
// main workspace를 찾는다.
230+
let findWorkspace = await this.workspaceRepository.findOneBy({
231+
snowflakeId: MainWorkspace.WORKSPACE_SNOWFLAKEID,
232+
});
233+
234+
// owner는 존재하지만 워크스페이스가 없으면 생성한다.
235+
if (!findWorkspace) {
236+
findWorkspace = await this.workspaceRepository.save({
237+
snowflakeId: MainWorkspace.WORKSPACE_SNOWFLAKEID,
238+
owner: findOwner,
239+
title: MainWorkspace.WORKSPACE_TITLE,
240+
description: MainWorkspace.WORKSPACE_DESCRIPTION,
241+
visibility: MainWorkspace.WORKSPACE_VISIBILITY,
242+
});
243+
this.logger.log('main workspace를 생성했습니다.');
244+
}
245+
this.logger.log('main workspace가 존재합니다.');
246+
247+
// owner의 role을 찾는다.
248+
const role = await this.roleRepository.findOne({
249+
where: {
250+
workspaceId: findWorkspace.id,
251+
userId: findOwner.id,
252+
},
253+
});
254+
255+
// owner의 role이 없으면 생성한다.
256+
if (!role) {
257+
await this.roleRepository.save({
258+
workspaceId: findWorkspace.id,
259+
userId: findOwner.id,
260+
workspace: findWorkspace,
261+
user: findOwner,
262+
role: 'owner',
263+
});
264+
}
265+
}
189266
}

apps/backend/src/yjs/yjs.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ export class YjsService
4444
private readonly pageService: PageService,
4545
private readonly edgeService: EdgeService,
4646
private readonly redisService: RedisService,
47-
) {}
47+
) {
48+
49+
}
4850

4951
@WebSocketServer()
5052
server: Server;
@@ -153,6 +155,9 @@ export class YjsService
153155
for (const [key, change] of event.changes.keys) {
154156
if (change.action === 'update') {
155157
const node: any = nodesMap.get(key);
158+
if (node.type !== 'note') {
159+
continue;
160+
}
156161
const { title, id } = node.data; // TODO: 이모지 추가
157162
const { x, y } = node.position;
158163
const isHolding = node.isHolding;

apps/frontend/src/features/canvas/model/calculateHandles.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,61 @@
1-
import { Position, Node } from "@xyflow/react";
1+
import { Position, Node, XYPosition } from "@xyflow/react";
22

3-
export const getHandlePosition = (node: Node, handleId: Position) => {
3+
const getAbsolutePosition = (node: Node, nodes: Node[]): XYPosition => {
4+
if (!node.parentId) {
5+
return node.position;
6+
}
7+
8+
const parentNode = nodes.find((n) => n.id === node.parentId);
9+
if (!parentNode) {
10+
return node.position;
11+
}
12+
13+
const parentPosition: XYPosition = getAbsolutePosition(parentNode, nodes);
14+
return {
15+
x: parentPosition.x + node.position.x,
16+
y: parentPosition.y + node.position.y,
17+
};
18+
};
19+
20+
export const getHandlePosition = (
21+
node: Node,
22+
handleId: Position,
23+
nodes: Node[],
24+
) => {
425
const nodeElement = document.querySelector(`[data-id="${node.id}"]`);
526
const nodeRect = nodeElement!.getBoundingClientRect();
627
const nodeWidth = nodeRect.width;
728
const nodeHeight = nodeRect.height;
829

30+
const absolutePosition = getAbsolutePosition(node, nodes);
31+
932
const positions = {
1033
[Position.Left]: {
11-
x: node.position.x,
12-
y: node.position.y + nodeHeight / 2,
34+
x: absolutePosition.x,
35+
y: absolutePosition.y + nodeHeight / 2,
1336
},
1437
[Position.Right]: {
15-
x: node.position.x + nodeWidth,
16-
y: node.position.y + nodeHeight / 2,
38+
x: absolutePosition.x + nodeWidth,
39+
y: absolutePosition.y + nodeHeight / 2,
1740
},
1841
[Position.Top]: {
19-
x: node.position.x + nodeWidth / 2,
20-
y: node.position.y,
42+
x: absolutePosition.x + nodeWidth / 2,
43+
y: absolutePosition.y,
2144
},
2245
[Position.Bottom]: {
23-
x: node.position.x + nodeWidth / 2,
24-
y: node.position.y + nodeHeight,
46+
x: absolutePosition.x + nodeWidth / 2,
47+
y: absolutePosition.y + nodeHeight,
2548
},
2649
};
2750

2851
return positions[handleId];
2952
};
3053

31-
export const calculateBestHandles = (sourceNode: Node, targetNode: Node) => {
54+
export const calculateBestHandles = (
55+
sourceNode: Node,
56+
targetNode: Node,
57+
nodes: Node[],
58+
) => {
3259
const handlePositions = [
3360
Position.Left,
3461
Position.Right,
@@ -42,9 +69,9 @@ export const calculateBestHandles = (sourceNode: Node, targetNode: Node) => {
4269
};
4370

4471
handlePositions.forEach((sourceHandle) => {
45-
const sourcePosition = getHandlePosition(sourceNode, sourceHandle);
72+
const sourcePosition = getHandlePosition(sourceNode, sourceHandle, nodes);
4673
handlePositions.forEach((targetHandle) => {
47-
const targetPosition = getHandlePosition(targetNode, targetHandle);
74+
const targetPosition = getHandlePosition(targetNode, targetHandle, nodes);
4875
const distance = Math.hypot(
4976
sourcePosition.x - targetPosition.x,
5077
sourcePosition.y - targetPosition.y,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { type Node } from "@xyflow/react";
2+
3+
export const getRelativePosition = (node: Node, parentNode: Node) => ({
4+
x: node.position.x - parentNode.position.x,
5+
y: node.position.y - parentNode.position.y,
6+
});
7+
8+
export const getAbsolutePosition = (node: Node, parentNode: Node) => ({
9+
x: parentNode.position.x + node.position.x,
10+
y: parentNode.position.y + node.position.y,
11+
});

0 commit comments

Comments
 (0)