mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
feat: enhance comments (#1980)
* feat: non-inline comments support * enhance comments * fix types
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../integrations/audit/audit.service';
|
||||
import { WsService } from '../../ws/ws.service';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('comments')
|
||||
@@ -41,6 +42,7 @@ export class CommentController {
|
||||
private readonly pageRepo: PageRepo,
|
||||
private readonly spaceAbility: SpaceAbilityFactory,
|
||||
private readonly pageAccessService: PageAccessService,
|
||||
private readonly wsService: WsService,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
@@ -119,7 +121,10 @@ export class CommentController {
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('update')
|
||||
async update(@Body() dto: UpdateCommentDto, @AuthUser() user: User) {
|
||||
const comment = await this.commentRepo.findById(dto.commentId);
|
||||
const comment = await this.commentRepo.findById(dto.commentId, {
|
||||
includeCreator: true,
|
||||
includeResolvedBy: true,
|
||||
});
|
||||
if (!comment) {
|
||||
throw new NotFoundException('Comment not found');
|
||||
}
|
||||
@@ -170,6 +175,12 @@ export class CommentController {
|
||||
await this.commentRepo.deleteComment(comment.id);
|
||||
}
|
||||
|
||||
this.wsService.emitCommentEvent(comment.spaceId, comment.pageId, {
|
||||
operation: 'commentDeleted',
|
||||
pageId: comment.pageId,
|
||||
commentId: comment.id,
|
||||
});
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.COMMENT_DELETED,
|
||||
resourceType: AuditResource.COMMENT,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { CursorPaginationResult } from '@docmost/db/pagination/cursor-pagination
|
||||
import { QueueJob, QueueName } from '../../integrations/queue/constants';
|
||||
import { extractUserMentionIdsFromJson } from '../../common/helpers/prosemirror/utils';
|
||||
import { ICommentNotificationJob } from '../../integrations/queue/constants/queue.interface';
|
||||
import { WsService } from '../../ws/ws.service';
|
||||
|
||||
@Injectable()
|
||||
export class CommentService {
|
||||
@@ -25,6 +26,7 @@ export class CommentService {
|
||||
constructor(
|
||||
private commentRepo: CommentRepo,
|
||||
private pageRepo: PageRepo,
|
||||
private wsService: WsService,
|
||||
@InjectQueue(QueueName.GENERAL_QUEUE)
|
||||
private generalQueue: Queue,
|
||||
@InjectQueue(QueueName.NOTIFICATION_QUEUE)
|
||||
@@ -63,7 +65,7 @@ export class CommentService {
|
||||
}
|
||||
}
|
||||
|
||||
const comment = await this.commentRepo.insertComment({
|
||||
const inserted = await this.commentRepo.insertComment({
|
||||
pageId: page.id,
|
||||
content: commentContent,
|
||||
selection: createCommentDto?.selection?.substring(0, 250) ?? null,
|
||||
@@ -74,6 +76,11 @@ export class CommentService {
|
||||
spaceId: page.spaceId,
|
||||
});
|
||||
|
||||
const comment = await this.commentRepo.findById(inserted.id, {
|
||||
includeCreator: true,
|
||||
includeResolvedBy: true,
|
||||
});
|
||||
|
||||
this.generalQueue
|
||||
.add(QueueJob.ADD_PAGE_WATCHERS, {
|
||||
userIds: [userId],
|
||||
@@ -99,6 +106,12 @@ export class CommentService {
|
||||
createCommentDto.parentCommentId,
|
||||
);
|
||||
|
||||
this.wsService.emitCommentEvent(page.spaceId, page.id, {
|
||||
operation: 'commentCreated',
|
||||
pageId: page.id,
|
||||
comment,
|
||||
});
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
@@ -154,6 +167,12 @@ export class CommentService {
|
||||
comment.editedAt = editedAt;
|
||||
comment.updatedAt = editedAt;
|
||||
|
||||
this.wsService.emitCommentEvent(comment.spaceId, comment.pageId, {
|
||||
operation: 'commentUpdated',
|
||||
pageId: comment.pageId,
|
||||
comment,
|
||||
});
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule apps/server/src/ee updated: 7ef5900616...0b3a6f4af0
@@ -45,7 +45,7 @@ export class WsService {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.broadcastToAuthorizedUsers(client, room, pageId, data);
|
||||
await this.broadcastToAuthorizedUsers(room, client.data.userId, pageId, data);
|
||||
}
|
||||
|
||||
async invalidateSpaceRestrictionCache(spaceId: string): Promise<void> {
|
||||
@@ -54,6 +54,29 @@ export class WsService {
|
||||
);
|
||||
}
|
||||
|
||||
async emitCommentEvent(
|
||||
spaceId: string,
|
||||
pageId: string,
|
||||
data: any,
|
||||
): Promise<void> {
|
||||
const room = getSpaceRoomName(spaceId);
|
||||
|
||||
const hasRestrictions = await this.spaceHasRestrictions(spaceId);
|
||||
if (!hasRestrictions) {
|
||||
this.server.to(room).emit('message', data);
|
||||
return;
|
||||
}
|
||||
|
||||
const isRestricted =
|
||||
await this.pagePermissionRepo.hasRestrictedAncestor(pageId);
|
||||
if (!isRestricted) {
|
||||
this.server.to(room).emit('message', data);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.broadcastToAuthorizedUsers(room, null, pageId, data);
|
||||
}
|
||||
|
||||
async emitToUsers(userIds: string[], data: any): Promise<void> {
|
||||
if (userIds.length === 0) return;
|
||||
const rooms = userIds.map((id) => getUserRoomName(id));
|
||||
@@ -82,14 +105,16 @@ export class WsService {
|
||||
}
|
||||
|
||||
private async broadcastToAuthorizedUsers(
|
||||
sender: Socket,
|
||||
room: string,
|
||||
excludeUserId: string | null,
|
||||
pageId: string,
|
||||
data: any,
|
||||
): Promise<void> {
|
||||
const sockets = await this.server.in(room).fetchSockets();
|
||||
|
||||
const otherSockets = sockets.filter((s) => s.id !== sender.id);
|
||||
const otherSockets = excludeUserId
|
||||
? sockets.filter((s) => s.data.userId !== excludeUserId)
|
||||
: sockets;
|
||||
if (otherSockets.length === 0) return;
|
||||
|
||||
const userSocketMap = new Map<string, typeof otherSockets>();
|
||||
|
||||
Reference in New Issue
Block a user