Merged PR 484: NotificationHubsの通知フォーマット
## 概要 [Task2820: NotificationHubsの通知フォーマット](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2820) - NotificationHubsで通知を行う処理を修正 - 通知内容を変更 - デスクトップ側でレンダリングを行うため、こちらからは必要なデータを送信する - 通知処理を読んでいる箇所を修正 - タスクキャンセル - チェックアウト候補変更 - 音声ファイルアップロード完了(タスク作成) ## レビューポイント - taskService内で通知をする箇所が複数あったのでプライベートメソッドとして切り出したが、fileServiceの通知処理もまとめたほうが良いか。 - まとめる場合は、どこに切り出すか。 - sendNotify(今回作成したプライベートメソッド)に、TasksRepositoryServiceやUserGroupsRepositoryServiceを引数に追加して共通関数としてCommonのどこかに配置する? - notificationhub.service.tsのnotifyメソッドの中で通知内容のための情報取得~通知内容作成まで全部行うようにする? ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
36401d0542
commit
ad49a19f04
107
dictation_server/package-lock.json
generated
107
dictation_server/package-lock.json
generated
@ -11,7 +11,7 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^3.1.3",
|
||||
"@azure/keyvault-secrets": "^4.6.0",
|
||||
"@azure/notification-hubs": "^1.0.2",
|
||||
"@azure/notification-hubs": "^1.0.3",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.5",
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
@ -341,6 +341,22 @@
|
||||
"openapi-types": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure-rest/core-client": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-1.1.4.tgz",
|
||||
"integrity": "sha512-RUIQOA8T0WcbNlddr8hjl2MuC5GVRqmMwPXqBVsgvdKesLy+eg3y/6nf3qe2fvcJMI1gF6VtgU5U4hRaR4w4ag==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.5.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/abort-controller": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
|
||||
@ -353,15 +369,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-auth": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.4.0.tgz",
|
||||
"integrity": "sha512-HFrcTgmuSuukRf/EdPmqBrc5l6Q5Uu+2TbuhaKbgaCpP2TfAeiNaQPAadxO+CYBRHGUzIDteMAjFspFLDLnKVQ==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz",
|
||||
"integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-util": "^1.1.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-client": {
|
||||
@ -443,11 +460,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.1.tgz",
|
||||
"integrity": "sha512-JHQy/bA3NOz2WuzOi5zEk6n/TJdAropupxUT521JIJvW7EXV2YN2SFYZrf/2RHeD28QAClGdynYadZsbmP+nyQ==",
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz",
|
||||
"integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
@ -467,23 +485,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-rest-pipeline": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.10.2.tgz",
|
||||
"integrity": "sha512-e3WzAsRKLor5EgK2bQqR1OY5D7VBqzORHtlqtygZZQGCYOIBsynqrZBa8MFD1Ue9r8TPtofOLditalnlQHS45Q==",
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.12.2.tgz",
|
||||
"integrity": "sha512-wLLJQdL4v1yoqYtEtjKNjf8pJ/G/BqVomAWxcKOR1KbZJyCEnCv04yks7Y1NhJ3JzxbDs307W67uX0JzklFdCg==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.4.0",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.0.0",
|
||||
"@azure/core-util": "^1.3.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"form-data": "^4.0.0",
|
||||
"http-proxy-agent": "^5.0.0",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"tslib": "^2.2.0",
|
||||
"uuid": "^8.3.0"
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-tracing": {
|
||||
@ -498,23 +515,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-util": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz",
|
||||
"integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.6.1.tgz",
|
||||
"integrity": "sha512-h5taHeySlsV9qxuK64KZxy4iln1BtMYlNt5jbuEFN3UFSAd1EwKg/Gjl5a6tZ/W8t6li3xPnutOx7zbDyXnPmQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-xml": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.3.3.tgz",
|
||||
"integrity": "sha512-Go/xGz7nGqVINsD9O7gOfe8uiR1S+IFcw9WTUPJHSzoFT6F5ZWjXIIlSikLZm77TtmxzXGnQYjjiZIoIZ4x14A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.3.4.tgz",
|
||||
"integrity": "sha512-B1xI79Ur/u+KR69fGTcsMNj8KDjBSqAy0Ys6Byy4Qm1CqoUy7gCT5A7Pej0EBWRskuH6bpCwrAnosfmQEalkcg==",
|
||||
"dependencies": {
|
||||
"fast-xml-parser": "^4.0.8",
|
||||
"fast-xml-parser": "^4.2.4",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -628,25 +645,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/notification-hubs": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.2.tgz",
|
||||
"integrity": "sha512-INtgq8uFQpncwbKm4It8M0GkKIePNDNybhuXs4cQPf5H0i9CbfFEt2c6LtT1AdEzbWfUhjsmU5y0p3YDmecwwg==",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.3.tgz",
|
||||
"integrity": "sha512-IWzIO2nKwM+9CWgnTsMyZhXxR7q3n3/aXpJiqUn1U3xHXTtHVE+joZ/AL9fCZTEBVB1PQvbrjp8VZvwEptqJ/Q==",
|
||||
"dependencies": {
|
||||
"@azure-rest/core-client": "^1.1.4",
|
||||
"@azure/abort-controller": "^1.1.0",
|
||||
"@azure/core-client": "^1.6.1",
|
||||
"@azure/core-lro": "^2.4.0",
|
||||
"@azure/core-paging": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.8.1",
|
||||
"@azure/core-auth": "^1.5.0",
|
||||
"@azure/core-lro": "^2.5.4",
|
||||
"@azure/core-paging": "^1.5.0",
|
||||
"@azure/core-rest-pipeline": "^1.12.2",
|
||||
"@azure/core-tracing": "^1.0.1",
|
||||
"@azure/core-util": "^1.3.0",
|
||||
"@azure/core-xml": "^1.3.1",
|
||||
"@azure/logger": "^1.0.3",
|
||||
"tslib": "^2.4.0"
|
||||
"@azure/core-util": "^1.6.1",
|
||||
"@azure/core-xml": "^1.3.4",
|
||||
"@azure/logger": "^1.0.4",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/notification-hubs/node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/@azure/storage-blob": {
|
||||
"version": "12.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.14.0.tgz",
|
||||
@ -5899,17 +5922,17 @@
|
||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.6.tgz",
|
||||
"integrity": "sha512-Xo1qV++h/Y3Ng8dphjahnYe+rGHaaNdsYOBWL9Y9GCPKpNKilJtilvWkLcI9f9X2DoKTLsZsGYAls5+JL5jfLA==",
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz",
|
||||
"integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/naturalintelligence"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@azure/identity": "^3.1.3",
|
||||
"@azure/keyvault-secrets": "^4.6.0",
|
||||
"@azure/notification-hubs": "^1.0.2",
|
||||
"@azure/notification-hubs": "^1.0.3",
|
||||
"@azure/storage-blob": "^12.14.0",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.5",
|
||||
"@nestjs/axios": "^0.1.0",
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
/*
|
||||
通知メッセージコード作成方針
|
||||
M+6桁(数字)で構成する。
|
||||
- 1~2桁目の値は種類(正常系、以上系...)
|
||||
- 3~4桁目の値は関連機能(タスク、ユーザー、ファイル...)
|
||||
- 5~6桁目の値は任意の重複しない値
|
||||
ex)
|
||||
E00XXXX : 正常系メッセージ
|
||||
E01XXXX : 以上系メッセージ
|
||||
EXX00XX : 全般
|
||||
EXX01XX : タスク関連
|
||||
*/
|
||||
export const NotifyMessageCodes = ['M000101'] as const;
|
||||
@ -1,7 +0,0 @@
|
||||
import { notifyMessages } from './message';
|
||||
import { NotifyMessageCodeType } from './types/types';
|
||||
|
||||
export const makeNotifyMessage = (code: NotifyMessageCodeType): string => {
|
||||
const msg = notifyMessages[code];
|
||||
return msg;
|
||||
};
|
||||
@ -1,6 +0,0 @@
|
||||
import { NotifyMessages } from './types/types';
|
||||
|
||||
// エラーコードとメッセージ対応表
|
||||
export const notifyMessages: NotifyMessages = {
|
||||
M000101: 'You are assigned to Typist.',
|
||||
};
|
||||
@ -1,7 +1,6 @@
|
||||
import { NotifyMessageCodes } from '../code';
|
||||
|
||||
export type NotifyMessageCodeType = (typeof NotifyMessageCodes)[number];
|
||||
|
||||
export type NotifyMessages = {
|
||||
[P in NotifyMessageCodeType]: string;
|
||||
export type NotificationBody = {
|
||||
filename: string;
|
||||
authorId: string;
|
||||
priority: string;
|
||||
uploadedAt: string;
|
||||
};
|
||||
|
||||
@ -32,7 +32,6 @@ import {
|
||||
import { createWorktype } from '../accounts/test/utility';
|
||||
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { getCheckoutPermissions, getTask } from '../tasks/test/utility';
|
||||
import { DateWithZeroTime } from '../licenses/types/types';
|
||||
import { LICENSE_ALLOCATED_STATUS, LICENSE_TYPE } from '../../constants';
|
||||
@ -371,7 +370,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -467,7 +471,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -585,7 +594,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -702,7 +716,12 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'XXXXXXXXXX',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
@ -716,7 +735,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_group_id).toEqual(userGroupId);
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
it('ワークフローが見つからない場合、タスク作成時に、自動ルーティングを行うことができない', async () => {
|
||||
if (!source) fail();
|
||||
|
||||
@ -30,7 +30,6 @@ import {
|
||||
} from '../../repositories/accounts/errors/types';
|
||||
import { Task } from '../../repositories/tasks/entity/task.entity';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import {
|
||||
LicenseExpiredError,
|
||||
@ -237,11 +236,12 @@ export class FilesService {
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
);
|
||||
await this.notificationhubService.notify(context, tags, {
|
||||
authorId: authorId,
|
||||
filename: fileName.replace('.zip', ''),
|
||||
priority: priority === '00' ? 'Normal' : 'High',
|
||||
uploadedAt: uploadedDate,
|
||||
});
|
||||
|
||||
// 追加したタスクのJOBナンバーを返却
|
||||
return { jobNumber: task.job_number };
|
||||
|
||||
@ -35,7 +35,6 @@ import {
|
||||
} from '../workflows/test/utility';
|
||||
import { createTemplateFile } from '../templates/test/utility';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { Roles } from '../../common/types/role';
|
||||
|
||||
describe('TasksService', () => {
|
||||
@ -835,6 +834,9 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, typistUserId_1);
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
const NotificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
@ -850,6 +852,18 @@ describe('changeCheckoutPermission', () => {
|
||||
user_id: typistUserId_2,
|
||||
user_group_id: null,
|
||||
});
|
||||
const resultTask = await getTask(source, taskId);
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId_2}`],
|
||||
{
|
||||
authorId: 'MY_AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('タスクのチェックアウト権限を変更できる。(グループ指定)', async () => {
|
||||
@ -903,6 +917,9 @@ describe('changeCheckoutPermission', () => {
|
||||
await createCheckoutPermissions(source, taskId, typistUserId_1);
|
||||
await createCheckoutPermissions(source, taskId, undefined, userGroupId_1);
|
||||
const service = module.get<TasksService>(TasksService);
|
||||
const NotificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
await service.changeCheckoutPermission(
|
||||
makeContext('trackingId'),
|
||||
1,
|
||||
@ -918,6 +935,19 @@ describe('changeCheckoutPermission', () => {
|
||||
user_id: null,
|
||||
user_group_id: userGroupId_2,
|
||||
});
|
||||
|
||||
const resultTask = await getTask(source, taskId);
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId_2}`],
|
||||
{
|
||||
authorId: 'MY_AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('タスクのチェックアウト権限を変更できる。(チェックアウト権限を外す)', async () => {
|
||||
@ -2655,9 +2685,14 @@ describe('cancel', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${typistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
it('API実行者のRoleがAdminの場合、自身が文字起こし実行中のタスクをキャンセルし、そのタスクの自動ルーティングを行う(API実行者のAuthorIDと音声ファイルに紐づくWorkType)', async () => {
|
||||
if (!source) fail();
|
||||
@ -2760,7 +2795,12 @@ describe('cancel', () => {
|
||||
expect(NotificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId'),
|
||||
[`user_${autoRoutingTypistUserId}`],
|
||||
makeNotifyMessage('M000101'),
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'x',
|
||||
priority: 'High',
|
||||
uploadedAt: resultTask?.file?.uploaded_at.toISOString(),
|
||||
},
|
||||
);
|
||||
});
|
||||
it('API実行者のRoleがTypistの場合、自身が文字起こし実行中のタスクをキャンセルするが、一致するワークフローがない場合は自動ルーティングを行うことができない', async () => {
|
||||
|
||||
@ -31,7 +31,6 @@ import { Roles } from '../../common/types/role';
|
||||
import { InvalidRoleError } from './errors/types';
|
||||
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { makeNotifyMessage } from '../../common/notify/makeNotifyMessage';
|
||||
import { Context } from '../../common/log';
|
||||
import { User } from '../../repositories/users/entity/user.entity';
|
||||
|
||||
@ -444,31 +443,13 @@ export class TasksService {
|
||||
user.author_id ?? undefined,
|
||||
);
|
||||
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
typistGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([...typistIds, ...groupMembers.map((x) => x.user_id)]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
// 通知を送信する
|
||||
await this.sendNotify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
typistIds,
|
||||
typistGroupIds,
|
||||
audioFileId,
|
||||
user.account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
// 処理の本筋はタスクキャンセルのため自動ルーティングに失敗してもエラーにしない
|
||||
@ -600,35 +581,13 @@ export class TasksService {
|
||||
.flatMap((assignee) =>
|
||||
assignee.typistUserId ? [assignee.typistUserId] : [],
|
||||
);
|
||||
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
assigneesGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([
|
||||
...assigneesUserIds,
|
||||
...groupMembers.map((x) => x.user_id),
|
||||
]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(
|
||||
// 通知を送信する
|
||||
await this.sendNotify(
|
||||
context,
|
||||
tags,
|
||||
makeNotifyMessage('M000101'),
|
||||
assigneesUserIds,
|
||||
assigneesGroupIds,
|
||||
audioFileId,
|
||||
account_id,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
@ -662,4 +621,51 @@ export class TasksService {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 通知を送信するプライベートメソッド
|
||||
private async sendNotify(
|
||||
context: Context,
|
||||
typistUserIds: number[],
|
||||
typistGroupIds: number[],
|
||||
audioFileId: number,
|
||||
accountId: number,
|
||||
): Promise<void> {
|
||||
const groupMembers =
|
||||
await this.userGroupsRepositoryService.getGroupMembersFromGroupIds(
|
||||
typistGroupIds,
|
||||
);
|
||||
|
||||
// 重複のない割り当て候補ユーザーID一覧を取得する
|
||||
const distinctUserIds = [
|
||||
...new Set([...typistUserIds, ...groupMembers.map((x) => x.user_id)]),
|
||||
];
|
||||
|
||||
// 割り当てられたユーザーがいない場合は通知不要
|
||||
if (distinctUserIds.length === 0) {
|
||||
this.logger.log('No user assigned.');
|
||||
return;
|
||||
}
|
||||
|
||||
// タグを生成
|
||||
const tags = distinctUserIds.map((x) => `user_${x}`);
|
||||
this.logger.log(`tags: ${tags}`);
|
||||
|
||||
// 通知内容に含む音声ファイル情報を取得
|
||||
const { file } = await this.taskRepository.getTaskAndAudioFile(
|
||||
audioFileId,
|
||||
accountId,
|
||||
[TASK_STATUS.UPLOADED],
|
||||
);
|
||||
if (!file) {
|
||||
throw new Error('audio file not found');
|
||||
}
|
||||
|
||||
// タグ対象に通知送信
|
||||
await this.notificationhubService.notify(context, tags, {
|
||||
authorId: file.author_id,
|
||||
filename: file.file_name.replace('.zip', ''),
|
||||
priority: file.priority === '00' ? 'Normal' : 'High',
|
||||
uploadedAt: file.uploaded_at.toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,6 +207,9 @@ export const getTask = async (
|
||||
task_id: number,
|
||||
): Promise<Task | null> => {
|
||||
const task = await datasource.getRepository(Task).findOne({
|
||||
relations: {
|
||||
file: true,
|
||||
},
|
||||
where: {
|
||||
id: task_id,
|
||||
},
|
||||
|
||||
@ -5,13 +5,15 @@ import {
|
||||
createAppleNotificationBody,
|
||||
createAppleNotification,
|
||||
createTagExpression,
|
||||
createWindowsToastNotification,
|
||||
createWindowsInstallation,
|
||||
createAppleInstallation,
|
||||
createWindowsRawNotification,
|
||||
} from '@azure/notification-hubs';
|
||||
import { TAG_MAX_COUNT } from '../../constants';
|
||||
import { PNS } from '../../constants';
|
||||
import { Context } from '../../common/log';
|
||||
import { NotificationBody } from '../../common/notify/types/types';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationhubService {
|
||||
private readonly logger = new Logger(NotificationhubService.name);
|
||||
@ -76,17 +78,22 @@ export class NotificationhubService {
|
||||
|
||||
/**
|
||||
* 指定したタグのユーザーに通知を送信する
|
||||
* @param context
|
||||
* @param tags
|
||||
* @param message
|
||||
* @param bodyContent
|
||||
* @returns notify
|
||||
*/
|
||||
async notify(
|
||||
context: Context,
|
||||
tags: string[],
|
||||
message: string,
|
||||
bodyContent: NotificationBody,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`[IN] [${context.trackingId}] ${this.notify.name} | params: { tags: ${tags}, message: ${message} }`,
|
||||
`[IN] [${context.trackingId}] ${
|
||||
this.notify.name
|
||||
} | params: { tags: ${tags}, bodyContent: ${JSON.stringify(
|
||||
bodyContent,
|
||||
)} }`,
|
||||
);
|
||||
|
||||
try {
|
||||
@ -99,8 +106,15 @@ export class NotificationhubService {
|
||||
|
||||
// Windows
|
||||
try {
|
||||
const body = `<toast><visual><binding template="ToastText01"><text id="1">${message}</text></binding></visual></toast>`;
|
||||
const notification = createWindowsToastNotification({ body });
|
||||
const body = {
|
||||
wns: {
|
||||
alert: '',
|
||||
},
|
||||
newDictation: bodyContent,
|
||||
};
|
||||
const notification = createWindowsRawNotification({
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
const result = await this.client.sendNotification(notification, {
|
||||
tagExpression,
|
||||
});
|
||||
@ -110,7 +124,12 @@ export class NotificationhubService {
|
||||
}
|
||||
// Apple
|
||||
try {
|
||||
const body = createAppleNotificationBody({ aps: { alert: message } });
|
||||
const body = createAppleNotificationBody({
|
||||
aps: {
|
||||
alert: '',
|
||||
},
|
||||
newDictation: bodyContent,
|
||||
});
|
||||
const notification = createAppleNotification({ body });
|
||||
const result = await this.client.sendNotification(notification, {
|
||||
tagExpression,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user