directus

Форк
0
/
activity.ts 
120 строк · 4.1 Кб
1
import { Action } from '@directus/constants';
2
import { useEnv } from '@directus/env';
3
import { ErrorCode, isDirectusError } from '@directus/errors';
4
import type { Accountability, Item, PrimaryKey } from '@directus/types';
5
import { uniq } from 'lodash-es';
6
import { useLogger } from '../logger.js';
7
import type { AbstractServiceOptions, MutationOptions } from '../types/index.js';
8
import { getPermissions } from '../utils/get-permissions.js';
9
import { isValidUuid } from '../utils/is-valid-uuid.js';
10
import { Url } from '../utils/url.js';
11
import { userName } from '../utils/user-name.js';
12
import { AuthorizationService } from './authorization.js';
13
import { ItemsService } from './items.js';
14
import { NotificationsService } from './notifications.js';
15
import { UsersService } from './users.js';
16

17
const env = useEnv();
18
const logger = useLogger();
19

20
export class ActivityService extends ItemsService {
21
	notificationsService: NotificationsService;
22
	usersService: UsersService;
23

24
	constructor(options: AbstractServiceOptions) {
25
		super('directus_activity', options);
26
		this.notificationsService = new NotificationsService({ schema: this.schema });
27
		this.usersService = new UsersService({ schema: this.schema });
28
	}
29

30
	override async createOne(data: Partial<Item>, opts?: MutationOptions): Promise<PrimaryKey> {
31
		if (data['action'] === Action.COMMENT && typeof data['comment'] === 'string') {
32
			const usersRegExp = new RegExp(/@[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/gi);
33

34
			const mentions = uniq(data['comment'].match(usersRegExp) ?? []);
35

36
			const sender = await this.usersService.readOne(this.accountability!.user!, {
37
				fields: ['id', 'first_name', 'last_name', 'email'],
38
			});
39

40
			for (const mention of mentions) {
41
				const userID = mention.substring(1);
42

43
				const user = await this.usersService.readOne(userID, {
44
					fields: ['id', 'first_name', 'last_name', 'email', 'role.id', 'role.admin_access', 'role.app_access'],
45
				});
46

47
				const accountability: Accountability = {
48
					user: userID,
49
					role: user['role']?.id ?? null,
50
					admin: user['role']?.admin_access ?? null,
51
					app: user['role']?.app_access ?? null,
52
				};
53

54
				accountability.permissions = await getPermissions(accountability, this.schema);
55

56
				const authorizationService = new AuthorizationService({ schema: this.schema, accountability });
57
				const usersService = new UsersService({ schema: this.schema, accountability });
58

59
				try {
60
					await authorizationService.checkAccess('read', data['collection'], data['item']);
61

62
					const templateData = await usersService.readByQuery({
63
						fields: ['id', 'first_name', 'last_name', 'email'],
64
						filter: { id: { _in: mentions.map((mention) => mention.substring(1)) } },
65
					});
66

67
					const userPreviews = templateData.reduce(
68
						(acc, user) => {
69
							acc[user['id']] = `<em>${userName(user)}</em>`;
70
							return acc;
71
						},
72
						{} as Record<string, string>,
73
					);
74

75
					let comment = data['comment'];
76

77
					for (const mention of mentions) {
78
						const uuid = mention.substring(1);
79
						// We only match on UUIDs in the first place. This is just an extra sanity check.
80
						if (isValidUuid(uuid) === false) continue;
81
						comment = comment.replace(new RegExp(mention, 'gm'), userPreviews[uuid] ?? '@Unknown User');
82
					}
83

84
					comment = `> ${comment.replace(/\n+/gm, '\n> ')}`;
85

86
					const href = new Url(env['PUBLIC_URL'] as string)
87
						.addPath('admin', 'content', data['collection'], data['item'])
88
						.toString();
89

90
					const message = `
91
Hello ${userName(user)},
92

93
${userName(sender)} has mentioned you in a comment:
94

95
${comment}
96

97
<a href="${href}">Click here to view.</a>
98
`;
99

100
					await this.notificationsService.createOne({
101
						recipient: userID,
102
						sender: sender['id'],
103
						subject: `You were mentioned in ${data['collection']}`,
104
						message,
105
						collection: data['collection'],
106
						item: data['item'],
107
					});
108
				} catch (err: any) {
109
					if (isDirectusError(err, ErrorCode.Forbidden)) {
110
						logger.warn(`User ${userID} doesn't have proper permissions to receive notification for this item.`);
111
					} else {
112
						throw err;
113
					}
114
				}
115
			}
116
		}
117

118
		return super.createOne(data, opts);
119
	}
120
}
121

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.