Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/#295 db에 문서가 저장되지 않는 문제 수정 #297

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion server/src/workspace/schemas/workspace.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export class Workspace {
@Prop({ type: [Page], default: [] })
pageList: Page[];

@Prop({ type: Map, default: new Map() })
@Prop({ type: Object, default: {} })
authUser: Map<string, string>;

@Prop({ default: Date.now })
Expand Down
7 changes: 3 additions & 4 deletions server/src/workspace/workspace.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,13 @@ export class WorkspaceGateway implements OnGatewayInit, OnGatewayConnection, OnG
const workspaces = await this.workSpaceService.getUserWorkspaces(userId);
const userInfo = await this.authService.getProfile(userId);
let NewWorkspaceId = "";

if (userId === "guest") {
client.join("guest");
NewWorkspaceId = "guest";
} else if (workspaces.length === 0) {
const workspace = await this.workSpaceService.createWorkspace(
userId,
`${userInfo.name}의 Workspace`,
`${userInfo === null ? "guest" : userInfo.name}의 Workspace`,
);
client.join(workspace.id);
NewWorkspaceId = workspace.id;
Expand Down Expand Up @@ -176,7 +175,7 @@ export class WorkspaceGateway implements OnGatewayInit, OnGatewayConnection, OnG
};
});

this.logger.log(`Sending workspace list to client ${client.id}`);
this.logger.log(`Sending workspace list to client(user.id): ${client.data.userId}`);
client.emit("workspace/list", workspaceList);
this.SocketStoreBroadcastWorkspaceConnections();
}, 100);
Expand Down Expand Up @@ -454,6 +453,7 @@ export class WorkspaceGateway implements OnGatewayInit, OnGatewayConnection, OnG
page: newPage.serialize(),
} as RemotePageCreateOperation;
client.emit("create/page", operation);

this.emitOperation(client.id, workspaceId, "create/page", operation, batch);
} catch (error) {
this.logger.error(
Expand Down Expand Up @@ -658,7 +658,6 @@ export class WorkspaceGateway implements OnGatewayInit, OnGatewayConnection, OnG
`Block Update 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`,
JSON.stringify(data),
);
console.log(data);
const { workspaceId } = client.data;
const currentPage = await this.workSpaceService.getPage(workspaceId, data.pageId);
if (!currentPage) {
Expand Down
75 changes: 47 additions & 28 deletions server/src/workspace/workspace.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,28 @@ export class WorkSpaceService implements OnModuleInit {
// room의 연결된 클라이언트 수 확인
const room = this.server.sockets.adapter.rooms.get(roomId);
const clientCount = room ? room.size : 0;

// 연결된 클라이언트가 없으면 DB에 저장하고 메모리에서 제거
if (clientCount === 0) {
const serializedWorkspace = workspace.serialize();
const serializedData = workspace.serialize();
// 스키마에 맞게 데이터 변환
const workspaceData = {
id: roomId,
name: workspace.name,
pageList: serializedData.pageList,
authUser: serializedData.authUser,
updatedAt: new Date(),
};
bulkOps.push({
updateOne: {
filter: { id: roomId },
update: { $set: { ...serializedWorkspace } },
update: { $set: workspaceData },
upsert: true,
},
});

this.workspaces.delete(roomId);
this.logger.log(`Workspace ${roomId} will be saved to DB and removed from memory`);
}
}

// DB에 저장할 작업이 있으면 한 번에 실행
if (bulkOps.length > 0) {
await this.workspaceModel.bulkWrite(bulkOps, { ordered: false });
Expand All @@ -97,6 +102,9 @@ export class WorkSpaceService implements OnModuleInit {
// DB에서 찾기
const workspaceJSON = await this.workspaceModel.findOne({ id: workspaceId });

if (!workspaceJSON) {
throw new Error(`workspaceJson ${workspaceId} not found`);
}
const workspace = new CRDTWorkSpace();

if (workspaceJSON) {
Expand Down Expand Up @@ -172,10 +180,11 @@ export class WorkSpaceService implements OnModuleInit {
if (!workspaceData) {
throw new Error(`Workspace with id ${workspaceId} not found`);
}

// authUser Map에서 모든 유저 ID를 배열로 변환하여 반환
// authUser는 Map<string, string> 형태로 userId와 role을 저장하고 있음
return Array.from(workspaceData.authUser.keys());
// return Array.from(workspaceData.authUser.keys());
const members = await this.userModel.find({ workspaces: workspaceId }).select("id");
return members.map((member) => member.id);
} catch (error) {
this.logger.error(`Failed to get workspace members: ${error.message}`);
throw error;
Expand All @@ -185,9 +194,9 @@ export class WorkSpaceService implements OnModuleInit {
async createWorkspace(userId: string, name: string): Promise<Workspace> {
const newWorkspace = await this.workspaceModel.create({
name,
authUser: new Map([[userId, "owner"]]), // 올바른 형태
authUser: { [userId]: "owner" },
});

// newWorkspace.authUser[userId]
// 유저 정보 업데이트
await this.userModel.updateOne({ id: userId }, { $push: { workspaces: newWorkspace.id } });

Expand Down Expand Up @@ -237,22 +246,28 @@ export class WorkSpaceService implements OnModuleInit {
const workspaces = await this.workspaceModel.find({
id: { $in: user.workspaces },
});

const workspaceList = workspaces.map((workspace) => {
const room = this.getServer().sockets.adapter.rooms.get(workspace.id);
return {
id: workspace.id,
name: workspace.name,
role: workspace.authUser.get(userId) || "editor",
memberCount: workspace.authUser.size,
activeUsers: room ? room.size : 0,
};
});

const workspaceList = await Promise.all(
workspaces.map(async (workspace) => {
const room = this.getServer().sockets.adapter.rooms.get(workspace.id);
const role = workspace.authUser[userId] || "editor";

// users 컬렉션에서 멤버 수 조회
const memberCount = await this.userModel.countDocuments({
workspaces: workspace.id,
});

return {
id: workspace.id,
name: workspace.name,
role,
memberCount,
activeUsers: room?.size || 0,
};
}),
);
return workspaceList;
}

// 워크스페이스에 유저 초대
async inviteUserToWorkspace(
ownerId: string,
workspaceId: string,
Expand All @@ -264,18 +279,22 @@ export class WorkSpaceService implements OnModuleInit {
throw new Error(`Workspace with id ${workspaceId} not found`);
}

// 권한 확인
if (!workspace.authUser.has(ownerId) || workspace.authUser.get(ownerId) !== "owner") {
// 권한 확인 - 객체의 속성 접근 방식으로 변경
if (!(ownerId in workspace.authUser) || workspace.authUser[ownerId] !== "owner") {
throw new Error(`User ${ownerId} does not have permission to invite users to this workspace`);
}

// 워크스페이스에 유저 추가
if (!workspace.authUser.has(invitedUserId)) {
workspace.authUser.set(invitedUserId, "editor");
// 워크스페이스에 유저 추가 - 객체 속성 할당 방식으로 변경
if (!(invitedUserId in workspace.authUser)) {
// 일반 객체 업데이트
workspace.authUser[invitedUserId] = "editor";
await workspace.save();

// 유저 정보 업데이트
await this.userModel.updateOne({ id: invitedUserId }, { $push: { workspaces: workspaceId } });
await this.userModel.updateOne(
{ id: invitedUserId },
{ $addToSet: { workspaces: workspaceId } },
);
}
}
}
Loading