Merge pull request #139 from fantasticit/fix/13x

fix paste html, notify user who is mentioned
This commit is contained in:
fantasticit
2022-07-29 22:59:29 +08:00
committed by GitHub
7 changed files with 85 additions and 8 deletions
+13 -1
View File
@@ -1,4 +1,5 @@
import type { IPagination, IUser } from '@think/domains';
import { IAuth, IUser, OrganizationApiDefinition } from '@think/domains';
import Router from 'next/router';
import { HttpClient } from './http-client';
@@ -9,3 +10,14 @@ export const register = (data: Partial<IUser>): Promise<IUser> => {
export const getUsers = (): Promise<IUser[]> => {
return HttpClient.get('/user');
};
export const getMentionUser = (): Promise<{ data: Array<{ auth: IAuth; user: IUser }>; total: number }> => {
const { organizationId } = Router.query;
return HttpClient.request({
method: OrganizationApiDefinition.getMembers.method,
url: OrganizationApiDefinition.getMembers.client(organizationId as string),
params: {
pageSize: 10000,
},
});
};
@@ -1,14 +1,14 @@
import BulitInMention from '@tiptap/extension-mention';
import { ReactRenderer } from '@tiptap/react';
import { getUsers } from 'services/user';
import { getMentionUser } from 'services/user';
import tippy from 'tippy.js';
import { MentionList } from 'tiptap/core/wrappers/mention-list';
import { getDatasetAttribute } from 'tiptap/prose-utils';
const suggestion = {
items: async ({ query }) => {
const res = await getUsers();
const data = res.map((item) => item.name);
const res = await getMentionUser();
const data = (res.data || []).map((item) => item.user.name);
return data.filter((item) => item.toLowerCase().startsWith(query.toLowerCase()));
},
@@ -25,7 +25,6 @@ interface IPasteOptions {
/**
* 将 markdown 转换为 prosemirror 节点
* FIXME: prosemirror 节点的类型是什么?
*/
markdownToProsemirror: (arg: { schema: Schema; content: string; needTitle: boolean }) => Node;
@@ -111,8 +110,8 @@ export const Paste = Extension.create<IPasteOptions>({
return true;
}
// 新增:office 套件内容处理
if (html?.includes('urn:schemas-microsoft-com:office')) {
// FIXME:各家 office 套件标准不一样,是否需要做成用户自行选择粘贴 html 或者 图片?
if (html?.length) {
const doc = htmlToProsemirror({
schema: editor.schema,
html,
@@ -46,6 +46,7 @@ export const CollaborationEditor = forwardRef((props: ICollaborationEditorProps,
targetId: documentId,
userId: user && user.id,
docType: type,
editable,
},
maxAttempts: 1,
onAwarenessUpdate: throttle(({ states }) => {
@@ -67,7 +68,7 @@ export const CollaborationEditor = forwardRef((props: ICollaborationEditorProps,
setStatus(status);
},
} as any);
}, [documentId, user, type, onAwarenessUpdate, toggleLoading]);
}, [documentId, user, type, editable, onAwarenessUpdate, toggleLoading]);
useImperativeHandle(
ref,
@@ -10,6 +10,25 @@ import { DocumentStatus, IUser } from '@think/domains';
import * as lodash from 'lodash';
import * as Y from 'yjs';
export const findMentions = (content) => {
const queue = [content];
const res = [];
while (queue.length) {
const node = queue.shift();
if (node.type === 'mention') {
res.push(node.attrs.id);
}
if (node.content && node.content.length) {
queue.push(...node.content);
}
}
return res;
};
@Injectable()
export class CollaborationService {
server: typeof Server;
@@ -244,6 +263,7 @@ export class CollaborationService {
const targetId = requestParameters.get('targetId');
const docType = requestParameters.get('docType');
const userId = requestParameters.get('userId');
const editable = requestParameters.get('editable');
if (docType === 'document') {
const data = await this.documentService.findById(targetId);
@@ -252,6 +272,14 @@ export class CollaborationService {
title: '未命名文档',
});
}
if (editable) {
const content = data.content;
const json = JSON.parse(content).default;
const mentionUsers = findMentions(json);
this.documentService.notifyMentionUsers(targetId, mentionUsers);
}
return;
}
@@ -727,4 +727,33 @@ export class DocumentService {
return data;
}
/**
* 通知文档中 @ 的用户
* @param documentId
* @param mentionUsers
* @returns
*/
public async notifyMentionUsers(documentId, mentionUsers) {
const doc = await this.documentRepo.findOne(documentId);
if (!doc) return;
await Promise.all(
mentionUsers
.map(async (userName) => {
const user = await this.userService.findOne({ name: userName });
if (!user) return null;
return await this.messageService.notify(user.id, {
title: `文档「${doc.title}」提及了您`,
message: `文档「${doc.title}」提及了您,快去看看吧!`,
url: buildMessageURL('toDocument')({
organizationId: doc.organizationId,
wikiId: doc.wikiId,
documentId: doc.id,
}),
});
})
.filter(Boolean)
);
}
}
@@ -19,6 +19,14 @@ export class MessageService {
*/
async notify(userId: IUser['id'], msg) {
const data = { userId, ...msg };
const mayBeNotified = await this.messageRepo.findOne(data);
if (mayBeNotified) {
if (!mayBeNotified.read) {
return;
}
}
const res = await this.messageRepo.create(data);
const ret = await this.messageRepo.save(res);
return ret;