@neutron.co.id/pendidikan-operation 1.26.19 → 1.26.21-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/actions/jadwal/action.createManySession.cjs +2 -1
- package/build/actions/jadwal/action.createManySession.d.ts +1 -0
- package/build/actions/jadwal/action.createManySession.mjs +2 -1
- package/build/actions/tanya/action.acceptQuestion.cjs +50 -0
- package/build/actions/tanya/action.acceptQuestion.d.ts +6 -0
- package/build/actions/tanya/action.acceptQuestion.mjs +51 -1
- package/build/actions/tanya/action.hasUnderstand.cjs +49 -0
- package/build/actions/tanya/action.hasUnderstand.d.ts +5 -0
- package/build/actions/tanya/action.hasUnderstand.mjs +50 -1
- package/build/actions/tanya/action.notUnderstand.cjs +50 -0
- package/build/actions/tanya/action.notUnderstand.d.ts +5 -0
- package/build/actions/tanya/action.notUnderstand.mjs +51 -1
- package/build/actions/tanya/action.reminderQuestions.cjs +162 -0
- package/build/actions/tanya/action.reminderQuestions.d.ts +13 -0
- package/build/actions/tanya/action.reminderQuestions.mjs +160 -0
- package/build/actions/tanya/action.sendAnswer.cjs +49 -0
- package/build/actions/tanya/action.sendAnswer.d.ts +6 -0
- package/build/actions/tanya/action.sendAnswer.mjs +50 -1
- package/build/actions/tanya/action.sendQuestion.cjs +50 -0
- package/build/actions/tanya/action.sendQuestion.d.ts +5 -1
- package/build/actions/tanya/action.sendQuestion.mjs +51 -1
- package/build/actions/tanya/index.d.ts +1 -0
- package/build/index.cjs +3 -0
- package/build/index.d.ts +1 -0
- package/build/index.mjs +3 -1
- package/package.json +12 -11
|
@@ -50,7 +50,8 @@ const createManySession = operation.Action.define({
|
|
|
50
50
|
subjectIds: input.subjectIds,
|
|
51
51
|
teacherIds: input.teacherRepeaterIds,
|
|
52
52
|
classSessionPurposeId: input.classSessionPurposeId,
|
|
53
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
54
|
+
createdBy: input.createdBy
|
|
54
55
|
});
|
|
55
56
|
intervalCount += input.interval;
|
|
56
57
|
}
|
|
@@ -48,7 +48,8 @@ const createManySession = Action.define({
|
|
|
48
48
|
subjectIds: input.subjectIds,
|
|
49
49
|
teacherIds: input.teacherRepeaterIds,
|
|
50
50
|
classSessionPurposeId: input.classSessionPurposeId,
|
|
51
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
51
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
52
|
+
createdBy: input.createdBy
|
|
52
53
|
});
|
|
53
54
|
intervalCount += input.interval;
|
|
54
55
|
}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const core = require('@neon.id/core');
|
|
4
4
|
const operation = require('@neon.id/operation');
|
|
5
|
+
const query = require('@neon.id/query');
|
|
5
6
|
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
6
8
|
|
|
7
9
|
const acceptQuestion = operation.Action.define({
|
|
8
10
|
key: "acceptQuestion",
|
|
@@ -13,7 +15,9 @@ const acceptQuestion = operation.Action.define({
|
|
|
13
15
|
utils.guard(stream, "streamRequired");
|
|
14
16
|
utils.guard(input, "inputRequired");
|
|
15
17
|
const dbs = stream.core.dbs;
|
|
18
|
+
const config = stream?.context?.config;
|
|
16
19
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
20
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
17
21
|
const teacherId = input.teacherId;
|
|
18
22
|
const teacherIds = [];
|
|
19
23
|
if (!teacherIds.includes(teacherId)) {
|
|
@@ -29,6 +33,52 @@ const acceptQuestion = operation.Action.define({
|
|
|
29
33
|
teacherIds
|
|
30
34
|
}
|
|
31
35
|
);
|
|
36
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
37
|
+
model: "neu:akademik:student",
|
|
38
|
+
query: query.Query.define({
|
|
39
|
+
fields: {
|
|
40
|
+
id: 1,
|
|
41
|
+
user: {
|
|
42
|
+
id: 1,
|
|
43
|
+
name: 1,
|
|
44
|
+
email: 1,
|
|
45
|
+
phone: 1
|
|
46
|
+
},
|
|
47
|
+
userId: 1
|
|
48
|
+
},
|
|
49
|
+
filter: {
|
|
50
|
+
_id: input.studentId
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
}, stream);
|
|
54
|
+
const students = studentResult.payload.data || [];
|
|
55
|
+
for (const student of students) {
|
|
56
|
+
const identifier = await dbIdentitas.findOne({ userId: student.userId });
|
|
57
|
+
await ofetch.ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
61
|
+
"Content-Type": "application/json"
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
name: "question-accepted",
|
|
65
|
+
to: {
|
|
66
|
+
subscriberId: student.userId || identifier?.userId,
|
|
67
|
+
email: identifier?.email || student.user?.email,
|
|
68
|
+
firstName: student.user?.name || identifier?.profile?.given_name,
|
|
69
|
+
lastName: student.user?.name || identifier?.profile?.family_name
|
|
70
|
+
},
|
|
71
|
+
payload: {
|
|
72
|
+
questionId: input.questionId,
|
|
73
|
+
code: input.code,
|
|
74
|
+
studentName: input.studentName,
|
|
75
|
+
subject: input.subjectName,
|
|
76
|
+
date: utils.DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
77
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
}
|
|
32
82
|
return core.Result.ok({
|
|
33
83
|
state: "acceptQuestion",
|
|
34
84
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -2,6 +2,12 @@ import { Action } from '@neon.id/operation';
|
|
|
2
2
|
export interface AcceptQuestionInput {
|
|
3
3
|
questionId: string;
|
|
4
4
|
teacherId: string;
|
|
5
|
+
askedAt: any;
|
|
6
|
+
studentId: string;
|
|
7
|
+
studentName: string;
|
|
8
|
+
code: string;
|
|
9
|
+
subjectName: string;
|
|
10
|
+
branchIds: string[];
|
|
5
11
|
}
|
|
6
12
|
export interface AcceptQuestionOutput {
|
|
7
13
|
code: number;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Result } from '@neon.id/core';
|
|
2
2
|
import { Action } from '@neon.id/operation';
|
|
3
|
-
import {
|
|
3
|
+
import { Query } from '@neon.id/query';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
4
6
|
|
|
5
7
|
const acceptQuestion = Action.define({
|
|
6
8
|
key: "acceptQuestion",
|
|
@@ -11,7 +13,9 @@ const acceptQuestion = Action.define({
|
|
|
11
13
|
guard(stream, "streamRequired");
|
|
12
14
|
guard(input, "inputRequired");
|
|
13
15
|
const dbs = stream.core.dbs;
|
|
16
|
+
const config = stream?.context?.config;
|
|
14
17
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
18
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
15
19
|
const teacherId = input.teacherId;
|
|
16
20
|
const teacherIds = [];
|
|
17
21
|
if (!teacherIds.includes(teacherId)) {
|
|
@@ -27,6 +31,52 @@ const acceptQuestion = Action.define({
|
|
|
27
31
|
teacherIds
|
|
28
32
|
}
|
|
29
33
|
);
|
|
34
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
35
|
+
model: "neu:akademik:student",
|
|
36
|
+
query: Query.define({
|
|
37
|
+
fields: {
|
|
38
|
+
id: 1,
|
|
39
|
+
user: {
|
|
40
|
+
id: 1,
|
|
41
|
+
name: 1,
|
|
42
|
+
email: 1,
|
|
43
|
+
phone: 1
|
|
44
|
+
},
|
|
45
|
+
userId: 1
|
|
46
|
+
},
|
|
47
|
+
filter: {
|
|
48
|
+
_id: input.studentId
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}, stream);
|
|
52
|
+
const students = studentResult.payload.data || [];
|
|
53
|
+
for (const student of students) {
|
|
54
|
+
const identifier = await dbIdentitas.findOne({ userId: student.userId });
|
|
55
|
+
await ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: {
|
|
58
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
59
|
+
"Content-Type": "application/json"
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
name: "question-accepted",
|
|
63
|
+
to: {
|
|
64
|
+
subscriberId: student.userId || identifier?.userId,
|
|
65
|
+
email: identifier?.email || student.user?.email,
|
|
66
|
+
firstName: student.user?.name || identifier?.profile?.given_name,
|
|
67
|
+
lastName: student.user?.name || identifier?.profile?.family_name
|
|
68
|
+
},
|
|
69
|
+
payload: {
|
|
70
|
+
questionId: input.questionId,
|
|
71
|
+
code: input.code,
|
|
72
|
+
studentName: input.studentName,
|
|
73
|
+
subject: input.subjectName,
|
|
74
|
+
date: DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
75
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
30
80
|
return Result.ok({
|
|
31
81
|
state: "acceptQuestion",
|
|
32
82
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -4,6 +4,7 @@ const core = require('@neon.id/core');
|
|
|
4
4
|
const operation = require('@neon.id/operation');
|
|
5
5
|
const query = require('@neon.id/query');
|
|
6
6
|
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
7
8
|
|
|
8
9
|
const hasUnderstand = operation.Action.define({
|
|
9
10
|
key: "hasUnderstand",
|
|
@@ -13,8 +14,10 @@ const hasUnderstand = operation.Action.define({
|
|
|
13
14
|
execute: async (input, stream) => {
|
|
14
15
|
utils.guard(stream, "streamRequired");
|
|
15
16
|
utils.guard(input, "inputRequired");
|
|
17
|
+
const config = stream?.context?.config;
|
|
16
18
|
const dbs = stream.core.dbs;
|
|
17
19
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
20
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
18
21
|
const resultQuestion = await stream.actions.data.getOne.execute(
|
|
19
22
|
{
|
|
20
23
|
model: "neu:tanya:question",
|
|
@@ -43,6 +46,52 @@ const hasUnderstand = operation.Action.define({
|
|
|
43
46
|
durationTotal
|
|
44
47
|
}
|
|
45
48
|
);
|
|
49
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
50
|
+
model: "neu:akademik:teacher",
|
|
51
|
+
query: query.Query.define({
|
|
52
|
+
fields: {
|
|
53
|
+
id: 1,
|
|
54
|
+
user: {
|
|
55
|
+
id: 1,
|
|
56
|
+
name: 1,
|
|
57
|
+
email: 1,
|
|
58
|
+
phone: 1
|
|
59
|
+
},
|
|
60
|
+
userId: 1
|
|
61
|
+
},
|
|
62
|
+
filter: {
|
|
63
|
+
branchIds: { $in: input.branchIds },
|
|
64
|
+
subjectIds: { $in: [input.subjectId] }
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}, stream);
|
|
68
|
+
const teachers = teachersResult.payload.data || [];
|
|
69
|
+
for (const teacher of teachers) {
|
|
70
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
71
|
+
await ofetch.ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: {
|
|
74
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
75
|
+
"Content-Type": "application/json"
|
|
76
|
+
},
|
|
77
|
+
body: JSON.stringify({
|
|
78
|
+
name: "question-has-understand",
|
|
79
|
+
to: {
|
|
80
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
81
|
+
email: teacher.user.email || identifier.email,
|
|
82
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
83
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
84
|
+
},
|
|
85
|
+
payload: {
|
|
86
|
+
questionId: input.questionId,
|
|
87
|
+
code: input.code,
|
|
88
|
+
studentName: input.studentName,
|
|
89
|
+
date: utils.DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
90
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
}
|
|
46
95
|
return core.Result.ok({
|
|
47
96
|
state: "hasUnderstand",
|
|
48
97
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Action } from '@neon.id/operation';
|
|
2
2
|
export interface HasUnderstandInput {
|
|
3
3
|
questionId: string;
|
|
4
|
+
askedAt: any;
|
|
5
|
+
studentName: string;
|
|
6
|
+
code: string;
|
|
7
|
+
subjectId: string;
|
|
8
|
+
branchIds: string[];
|
|
4
9
|
}
|
|
5
10
|
export interface HasUnderstandOutput {
|
|
6
11
|
code: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Result } from '@neon.id/core';
|
|
2
2
|
import { Action } from '@neon.id/operation';
|
|
3
3
|
import { Query } from '@neon.id/query';
|
|
4
|
-
import { guard } from '@neon.id/utils';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
5
6
|
|
|
6
7
|
const hasUnderstand = Action.define({
|
|
7
8
|
key: "hasUnderstand",
|
|
@@ -11,8 +12,10 @@ const hasUnderstand = Action.define({
|
|
|
11
12
|
execute: async (input, stream) => {
|
|
12
13
|
guard(stream, "streamRequired");
|
|
13
14
|
guard(input, "inputRequired");
|
|
15
|
+
const config = stream?.context?.config;
|
|
14
16
|
const dbs = stream.core.dbs;
|
|
15
17
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
18
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
16
19
|
const resultQuestion = await stream.actions.data.getOne.execute(
|
|
17
20
|
{
|
|
18
21
|
model: "neu:tanya:question",
|
|
@@ -41,6 +44,52 @@ const hasUnderstand = Action.define({
|
|
|
41
44
|
durationTotal
|
|
42
45
|
}
|
|
43
46
|
);
|
|
47
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
48
|
+
model: "neu:akademik:teacher",
|
|
49
|
+
query: Query.define({
|
|
50
|
+
fields: {
|
|
51
|
+
id: 1,
|
|
52
|
+
user: {
|
|
53
|
+
id: 1,
|
|
54
|
+
name: 1,
|
|
55
|
+
email: 1,
|
|
56
|
+
phone: 1
|
|
57
|
+
},
|
|
58
|
+
userId: 1
|
|
59
|
+
},
|
|
60
|
+
filter: {
|
|
61
|
+
branchIds: { $in: input.branchIds },
|
|
62
|
+
subjectIds: { $in: [input.subjectId] }
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
}, stream);
|
|
66
|
+
const teachers = teachersResult.payload.data || [];
|
|
67
|
+
for (const teacher of teachers) {
|
|
68
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
69
|
+
await ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: {
|
|
72
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
73
|
+
"Content-Type": "application/json"
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
name: "question-has-understand",
|
|
77
|
+
to: {
|
|
78
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
79
|
+
email: teacher.user.email || identifier.email,
|
|
80
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
81
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
82
|
+
},
|
|
83
|
+
payload: {
|
|
84
|
+
questionId: input.questionId,
|
|
85
|
+
code: input.code,
|
|
86
|
+
studentName: input.studentName,
|
|
87
|
+
date: DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
88
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
}
|
|
44
93
|
return Result.ok({
|
|
45
94
|
state: "hasUnderstand",
|
|
46
95
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const core = require('@neon.id/core');
|
|
4
4
|
const operation = require('@neon.id/operation');
|
|
5
|
+
const query = require('@neon.id/query');
|
|
5
6
|
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
6
8
|
|
|
7
9
|
const notUnderstand = operation.Action.define({
|
|
8
10
|
key: "notUnderstand",
|
|
@@ -12,8 +14,10 @@ const notUnderstand = operation.Action.define({
|
|
|
12
14
|
execute: async (input, stream) => {
|
|
13
15
|
utils.guard(stream, "streamRequired");
|
|
14
16
|
utils.guard(input, "inputRequired");
|
|
17
|
+
const config = stream?.context?.config;
|
|
15
18
|
const dbs = stream.core.dbs;
|
|
16
19
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
20
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
17
21
|
await dbQuestion.updateOne(
|
|
18
22
|
{
|
|
19
23
|
_id: input.questionId
|
|
@@ -22,6 +26,52 @@ const notUnderstand = operation.Action.define({
|
|
|
22
26
|
status: "notUnderstand"
|
|
23
27
|
}
|
|
24
28
|
);
|
|
29
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
30
|
+
model: "neu:akademik:teacher",
|
|
31
|
+
query: query.Query.define({
|
|
32
|
+
fields: {
|
|
33
|
+
id: 1,
|
|
34
|
+
user: {
|
|
35
|
+
id: 1,
|
|
36
|
+
name: 1,
|
|
37
|
+
email: 1,
|
|
38
|
+
phone: 1
|
|
39
|
+
},
|
|
40
|
+
userId: 1
|
|
41
|
+
},
|
|
42
|
+
filter: {
|
|
43
|
+
branchIds: { $in: input.branchIds },
|
|
44
|
+
subjectIds: { $in: [input.subjectId] }
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}, stream);
|
|
48
|
+
const teachers = teachersResult.payload.data || [];
|
|
49
|
+
for (const teacher of teachers) {
|
|
50
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
51
|
+
await ofetch.ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: {
|
|
54
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
55
|
+
"Content-Type": "application/json"
|
|
56
|
+
},
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
name: "question-not-understand",
|
|
59
|
+
to: {
|
|
60
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
61
|
+
email: teacher.user.email || identifier.email,
|
|
62
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
63
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
64
|
+
},
|
|
65
|
+
payload: {
|
|
66
|
+
questionId: input.questionId,
|
|
67
|
+
code: input.code,
|
|
68
|
+
studentName: input.studentName,
|
|
69
|
+
date: utils.DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
70
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
25
75
|
return core.Result.ok({
|
|
26
76
|
state: "notUnderstand",
|
|
27
77
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Action } from '@neon.id/operation';
|
|
2
2
|
export interface NotUnderstandInput {
|
|
3
3
|
questionId: string;
|
|
4
|
+
askedAt: any;
|
|
5
|
+
studentName: string;
|
|
6
|
+
code: string;
|
|
7
|
+
subjectId: string;
|
|
8
|
+
branchIds: string[];
|
|
4
9
|
}
|
|
5
10
|
export interface NotUnderstandOutput {
|
|
6
11
|
code: number;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Result } from '@neon.id/core';
|
|
2
2
|
import { Action } from '@neon.id/operation';
|
|
3
|
-
import {
|
|
3
|
+
import { Query } from '@neon.id/query';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
4
6
|
|
|
5
7
|
const notUnderstand = Action.define({
|
|
6
8
|
key: "notUnderstand",
|
|
@@ -10,8 +12,10 @@ const notUnderstand = Action.define({
|
|
|
10
12
|
execute: async (input, stream) => {
|
|
11
13
|
guard(stream, "streamRequired");
|
|
12
14
|
guard(input, "inputRequired");
|
|
15
|
+
const config = stream?.context?.config;
|
|
13
16
|
const dbs = stream.core.dbs;
|
|
14
17
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
18
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
15
19
|
await dbQuestion.updateOne(
|
|
16
20
|
{
|
|
17
21
|
_id: input.questionId
|
|
@@ -20,6 +24,52 @@ const notUnderstand = Action.define({
|
|
|
20
24
|
status: "notUnderstand"
|
|
21
25
|
}
|
|
22
26
|
);
|
|
27
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
28
|
+
model: "neu:akademik:teacher",
|
|
29
|
+
query: Query.define({
|
|
30
|
+
fields: {
|
|
31
|
+
id: 1,
|
|
32
|
+
user: {
|
|
33
|
+
id: 1,
|
|
34
|
+
name: 1,
|
|
35
|
+
email: 1,
|
|
36
|
+
phone: 1
|
|
37
|
+
},
|
|
38
|
+
userId: 1
|
|
39
|
+
},
|
|
40
|
+
filter: {
|
|
41
|
+
branchIds: { $in: input.branchIds },
|
|
42
|
+
subjectIds: { $in: [input.subjectId] }
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
}, stream);
|
|
46
|
+
const teachers = teachersResult.payload.data || [];
|
|
47
|
+
for (const teacher of teachers) {
|
|
48
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
49
|
+
await ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: {
|
|
52
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
53
|
+
"Content-Type": "application/json"
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
name: "question-not-understand",
|
|
57
|
+
to: {
|
|
58
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
59
|
+
email: teacher.user.email || identifier.email,
|
|
60
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
61
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
62
|
+
},
|
|
63
|
+
payload: {
|
|
64
|
+
questionId: input.questionId,
|
|
65
|
+
code: input.code,
|
|
66
|
+
studentName: input.studentName,
|
|
67
|
+
date: DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
68
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
}
|
|
23
73
|
return Result.ok({
|
|
24
74
|
state: "notUnderstand",
|
|
25
75
|
message: "Pertanyaan berhasil diterima"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const core = require('@neon.id/core');
|
|
4
|
+
const operation = require('@neon.id/operation');
|
|
5
|
+
const query = require('@neon.id/query');
|
|
6
|
+
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
8
|
+
|
|
9
|
+
const reminderQuestions = operation.Action.define({
|
|
10
|
+
key: "reminderQuestions",
|
|
11
|
+
name: "Send Question Acceptance Reminders",
|
|
12
|
+
type: "command",
|
|
13
|
+
category: "domain",
|
|
14
|
+
execute: async (input, stream) => {
|
|
15
|
+
utils.guard(stream, "streamRequired");
|
|
16
|
+
console.log("input", input);
|
|
17
|
+
const dbs = stream.core.dbs;
|
|
18
|
+
const config = stream?.context?.config;
|
|
19
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
20
|
+
if (!config?.novuApi?.url || !config?.novuApi?.token) {
|
|
21
|
+
return core.Result.fail({
|
|
22
|
+
state: "ReminderQuestions",
|
|
23
|
+
message: "Novu API configuration is missing"
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (!config?.appFluffyUrl) {
|
|
27
|
+
return core.Result.fail({
|
|
28
|
+
state: "ReminderQuestions",
|
|
29
|
+
message: "Frontend URL configuration is missing"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const errors = [];
|
|
33
|
+
let processedCount = 0;
|
|
34
|
+
try {
|
|
35
|
+
const getQuestions = await stream.actions.data.getMany.execute({
|
|
36
|
+
model: "neu:tanya:question",
|
|
37
|
+
query: query.Query.define({
|
|
38
|
+
fields: {
|
|
39
|
+
id: 1,
|
|
40
|
+
code: 1,
|
|
41
|
+
askedAt: 1,
|
|
42
|
+
student: {
|
|
43
|
+
id: 1,
|
|
44
|
+
name: 1
|
|
45
|
+
},
|
|
46
|
+
teacher: {
|
|
47
|
+
id: 1,
|
|
48
|
+
name: 1,
|
|
49
|
+
user: {
|
|
50
|
+
id: 1,
|
|
51
|
+
name: 1,
|
|
52
|
+
email: 1,
|
|
53
|
+
phone: 1
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
subject: {
|
|
57
|
+
name: 1
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
filter: {
|
|
61
|
+
status: "waiting"
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
}, stream);
|
|
65
|
+
const questions = getQuestions.payload.data || [];
|
|
66
|
+
if (questions.length === 0) {
|
|
67
|
+
return core.Result.ok({
|
|
68
|
+
state: "ReminderQuestions",
|
|
69
|
+
message: "No waiting questions found"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
for (const question of questions) {
|
|
73
|
+
try {
|
|
74
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
75
|
+
model: "neu:akademik:student",
|
|
76
|
+
query: query.Query.define({
|
|
77
|
+
fields: {
|
|
78
|
+
id: 1,
|
|
79
|
+
userId: 1,
|
|
80
|
+
user: {
|
|
81
|
+
id: 1,
|
|
82
|
+
name: 1,
|
|
83
|
+
email: 1,
|
|
84
|
+
phone: 1
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
filter: {
|
|
88
|
+
_id: question.student.id
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
}, stream);
|
|
92
|
+
const students = studentResult.payload.data || [];
|
|
93
|
+
if (students.length === 0) {
|
|
94
|
+
errors.push(`Student not found for question ${question.id}`);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
for (const student of students) {
|
|
98
|
+
try {
|
|
99
|
+
const identifier = await dbIdentitas.findOne({
|
|
100
|
+
userId: student.userId
|
|
101
|
+
});
|
|
102
|
+
const email = identifier?.email || student.user?.email;
|
|
103
|
+
const firstName = student.user?.name || identifier?.profile?.given_name || "";
|
|
104
|
+
const lastName = identifier?.profile?.family_name || "";
|
|
105
|
+
if (!email) {
|
|
106
|
+
errors.push(`No email found for student ${student.id} in question ${question.id}`);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
await ofetch.ofetch(`${config.novuApi.url}/v1/events/trigger`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: {
|
|
112
|
+
"Authorization": `ApiKey ${config.novuApi.token}`,
|
|
113
|
+
"Content-Type": "application/json"
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify({
|
|
116
|
+
name: "question-reminder",
|
|
117
|
+
to: {
|
|
118
|
+
subscriberId: student.userId || identifier?.userId,
|
|
119
|
+
email,
|
|
120
|
+
firstName,
|
|
121
|
+
lastName
|
|
122
|
+
},
|
|
123
|
+
payload: {
|
|
124
|
+
totalQuestions: questions.length,
|
|
125
|
+
questionId: question.id,
|
|
126
|
+
code: question.code || "",
|
|
127
|
+
studentName: question.student.name,
|
|
128
|
+
subject: question.subject?.name,
|
|
129
|
+
timeAgo: utils.DateUtil.diff(question.askedAt, /* @__PURE__ */ new Date()),
|
|
130
|
+
date: utils.DateUtil.formatTz(question.askedAt, {
|
|
131
|
+
pattern: "yyyy-MM-dd HH:mm"
|
|
132
|
+
}),
|
|
133
|
+
url: `${config.appFluffyUrl}/tanya/${question.id}`
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
processedCount++;
|
|
138
|
+
} catch (notificationError) {
|
|
139
|
+
const errorMessage = notificationError instanceof Error ? notificationError.message : "Unknown notification error";
|
|
140
|
+
errors.push(`Failed to send notification to student ${student.id}: ${errorMessage}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch (studentError) {
|
|
144
|
+
const errorMessage = studentError instanceof Error ? studentError.message : "Unknown student lookup error";
|
|
145
|
+
errors.push(`Failed to process question ${question.id}: ${errorMessage}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return core.Result.ok({
|
|
149
|
+
state: "ReminderQuestions",
|
|
150
|
+
message: `Successfully processed ${processedCount} reminders${errors.length > 0 ? ` with ${errors.length} errors` : ""}`
|
|
151
|
+
});
|
|
152
|
+
} catch (error) {
|
|
153
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
154
|
+
return core.Result.fail({
|
|
155
|
+
state: "ReminderQuestions",
|
|
156
|
+
message: `Failed to process reminders: ${errorMessage}`
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
exports.reminderQuestions = reminderQuestions;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Action } from '@neon.id/operation';
|
|
2
|
+
export interface ReminderQuestionsInput {
|
|
3
|
+
questionId?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ReminderQuestionsOutput {
|
|
6
|
+
code: number;
|
|
7
|
+
processedCount: number;
|
|
8
|
+
errors: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface ReminderQuestionsMeta {
|
|
11
|
+
}
|
|
12
|
+
export declare const reminderQuestions: Action<"reminderQuestions", ReminderQuestionsInput, ReminderQuestionsOutput, ReminderQuestionsMeta>;
|
|
13
|
+
export type ReminderQuestionsAction = typeof reminderQuestions;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Result } from '@neon.id/core';
|
|
2
|
+
import { Action } from '@neon.id/operation';
|
|
3
|
+
import { Query } from '@neon.id/query';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
6
|
+
|
|
7
|
+
const reminderQuestions = Action.define({
|
|
8
|
+
key: "reminderQuestions",
|
|
9
|
+
name: "Send Question Acceptance Reminders",
|
|
10
|
+
type: "command",
|
|
11
|
+
category: "domain",
|
|
12
|
+
execute: async (input, stream) => {
|
|
13
|
+
guard(stream, "streamRequired");
|
|
14
|
+
console.log("input", input);
|
|
15
|
+
const dbs = stream.core.dbs;
|
|
16
|
+
const config = stream?.context?.config;
|
|
17
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
18
|
+
if (!config?.novuApi?.url || !config?.novuApi?.token) {
|
|
19
|
+
return Result.fail({
|
|
20
|
+
state: "ReminderQuestions",
|
|
21
|
+
message: "Novu API configuration is missing"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (!config?.appFluffyUrl) {
|
|
25
|
+
return Result.fail({
|
|
26
|
+
state: "ReminderQuestions",
|
|
27
|
+
message: "Frontend URL configuration is missing"
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const errors = [];
|
|
31
|
+
let processedCount = 0;
|
|
32
|
+
try {
|
|
33
|
+
const getQuestions = await stream.actions.data.getMany.execute({
|
|
34
|
+
model: "neu:tanya:question",
|
|
35
|
+
query: Query.define({
|
|
36
|
+
fields: {
|
|
37
|
+
id: 1,
|
|
38
|
+
code: 1,
|
|
39
|
+
askedAt: 1,
|
|
40
|
+
student: {
|
|
41
|
+
id: 1,
|
|
42
|
+
name: 1
|
|
43
|
+
},
|
|
44
|
+
teacher: {
|
|
45
|
+
id: 1,
|
|
46
|
+
name: 1,
|
|
47
|
+
user: {
|
|
48
|
+
id: 1,
|
|
49
|
+
name: 1,
|
|
50
|
+
email: 1,
|
|
51
|
+
phone: 1
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
subject: {
|
|
55
|
+
name: 1
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
filter: {
|
|
59
|
+
status: "waiting"
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}, stream);
|
|
63
|
+
const questions = getQuestions.payload.data || [];
|
|
64
|
+
if (questions.length === 0) {
|
|
65
|
+
return Result.ok({
|
|
66
|
+
state: "ReminderQuestions",
|
|
67
|
+
message: "No waiting questions found"
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
for (const question of questions) {
|
|
71
|
+
try {
|
|
72
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
73
|
+
model: "neu:akademik:student",
|
|
74
|
+
query: Query.define({
|
|
75
|
+
fields: {
|
|
76
|
+
id: 1,
|
|
77
|
+
userId: 1,
|
|
78
|
+
user: {
|
|
79
|
+
id: 1,
|
|
80
|
+
name: 1,
|
|
81
|
+
email: 1,
|
|
82
|
+
phone: 1
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
filter: {
|
|
86
|
+
_id: question.student.id
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
}, stream);
|
|
90
|
+
const students = studentResult.payload.data || [];
|
|
91
|
+
if (students.length === 0) {
|
|
92
|
+
errors.push(`Student not found for question ${question.id}`);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
for (const student of students) {
|
|
96
|
+
try {
|
|
97
|
+
const identifier = await dbIdentitas.findOne({
|
|
98
|
+
userId: student.userId
|
|
99
|
+
});
|
|
100
|
+
const email = identifier?.email || student.user?.email;
|
|
101
|
+
const firstName = student.user?.name || identifier?.profile?.given_name || "";
|
|
102
|
+
const lastName = identifier?.profile?.family_name || "";
|
|
103
|
+
if (!email) {
|
|
104
|
+
errors.push(`No email found for student ${student.id} in question ${question.id}`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
await ofetch(`${config.novuApi.url}/v1/events/trigger`, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: {
|
|
110
|
+
"Authorization": `ApiKey ${config.novuApi.token}`,
|
|
111
|
+
"Content-Type": "application/json"
|
|
112
|
+
},
|
|
113
|
+
body: JSON.stringify({
|
|
114
|
+
name: "question-reminder",
|
|
115
|
+
to: {
|
|
116
|
+
subscriberId: student.userId || identifier?.userId,
|
|
117
|
+
email,
|
|
118
|
+
firstName,
|
|
119
|
+
lastName
|
|
120
|
+
},
|
|
121
|
+
payload: {
|
|
122
|
+
totalQuestions: questions.length,
|
|
123
|
+
questionId: question.id,
|
|
124
|
+
code: question.code || "",
|
|
125
|
+
studentName: question.student.name,
|
|
126
|
+
subject: question.subject?.name,
|
|
127
|
+
timeAgo: DateUtil.diff(question.askedAt, /* @__PURE__ */ new Date()),
|
|
128
|
+
date: DateUtil.formatTz(question.askedAt, {
|
|
129
|
+
pattern: "yyyy-MM-dd HH:mm"
|
|
130
|
+
}),
|
|
131
|
+
url: `${config.appFluffyUrl}/tanya/${question.id}`
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
processedCount++;
|
|
136
|
+
} catch (notificationError) {
|
|
137
|
+
const errorMessage = notificationError instanceof Error ? notificationError.message : "Unknown notification error";
|
|
138
|
+
errors.push(`Failed to send notification to student ${student.id}: ${errorMessage}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} catch (studentError) {
|
|
142
|
+
const errorMessage = studentError instanceof Error ? studentError.message : "Unknown student lookup error";
|
|
143
|
+
errors.push(`Failed to process question ${question.id}: ${errorMessage}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return Result.ok({
|
|
147
|
+
state: "ReminderQuestions",
|
|
148
|
+
message: `Successfully processed ${processedCount} reminders${errors.length > 0 ? ` with ${errors.length} errors` : ""}`
|
|
149
|
+
});
|
|
150
|
+
} catch (error) {
|
|
151
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
152
|
+
return Result.fail({
|
|
153
|
+
state: "ReminderQuestions",
|
|
154
|
+
message: `Failed to process reminders: ${errorMessage}`
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export { reminderQuestions };
|
|
@@ -4,6 +4,7 @@ const core = require('@neon.id/core');
|
|
|
4
4
|
const operation = require('@neon.id/operation');
|
|
5
5
|
const query = require('@neon.id/query');
|
|
6
6
|
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
7
8
|
|
|
8
9
|
const sendAnswer = operation.Action.define({
|
|
9
10
|
key: "sendAnswer",
|
|
@@ -14,6 +15,8 @@ const sendAnswer = operation.Action.define({
|
|
|
14
15
|
utils.guard(stream, "streamRequired");
|
|
15
16
|
utils.guard(input, "inputRequired");
|
|
16
17
|
const dbs = stream.core.dbs;
|
|
18
|
+
const config = stream?.context?.config;
|
|
19
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
17
20
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
18
21
|
const resultQuestion = await stream.actions.data.getOne.execute(
|
|
19
22
|
{
|
|
@@ -54,6 +57,52 @@ const sendAnswer = operation.Action.define({
|
|
|
54
57
|
}
|
|
55
58
|
);
|
|
56
59
|
}
|
|
60
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
61
|
+
model: "neu:akademik:student",
|
|
62
|
+
query: query.Query.define({
|
|
63
|
+
fields: {
|
|
64
|
+
id: 1,
|
|
65
|
+
user: {
|
|
66
|
+
id: 1,
|
|
67
|
+
name: 1,
|
|
68
|
+
email: 1,
|
|
69
|
+
phone: 1
|
|
70
|
+
},
|
|
71
|
+
userId: 1
|
|
72
|
+
},
|
|
73
|
+
filter: {
|
|
74
|
+
_id: input.studentId
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}, stream);
|
|
78
|
+
const students = studentResult.payload.data || [];
|
|
79
|
+
for (const student of students) {
|
|
80
|
+
const identifier = await dbIdentitas.findOne({ userId: student.userId });
|
|
81
|
+
await ofetch.ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: {
|
|
84
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
name: "question-answered",
|
|
89
|
+
to: {
|
|
90
|
+
subscriberId: student.userId || identifier.userId,
|
|
91
|
+
email: student.user.email || identifier.email,
|
|
92
|
+
firstName: student.user.name || identifier.profile.given_name,
|
|
93
|
+
lastName: student.user.name || identifier.profile.given_name
|
|
94
|
+
},
|
|
95
|
+
payload: {
|
|
96
|
+
questionId: input.questionId,
|
|
97
|
+
code: input.code,
|
|
98
|
+
studentName: input.studentName,
|
|
99
|
+
subject: input.subjectName,
|
|
100
|
+
date: utils.DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
101
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
});
|
|
105
|
+
}
|
|
57
106
|
return core.Result.ok({
|
|
58
107
|
state: "sendAnswer",
|
|
59
108
|
message: "Jawaban berhasil dikirim"
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { Action } from '@neon.id/operation';
|
|
2
2
|
export interface SendAnswerInput {
|
|
3
3
|
questionId: string;
|
|
4
|
+
askedAt: any;
|
|
5
|
+
studentId: string;
|
|
6
|
+
studentName: string;
|
|
7
|
+
code: string;
|
|
8
|
+
subjectName: string;
|
|
9
|
+
branchIds: string[];
|
|
4
10
|
}
|
|
5
11
|
export interface SendAnswerOutput {
|
|
6
12
|
code: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Result } from '@neon.id/core';
|
|
2
2
|
import { Action } from '@neon.id/operation';
|
|
3
3
|
import { Query } from '@neon.id/query';
|
|
4
|
-
import { guard } from '@neon.id/utils';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
5
6
|
|
|
6
7
|
const sendAnswer = Action.define({
|
|
7
8
|
key: "sendAnswer",
|
|
@@ -12,6 +13,8 @@ const sendAnswer = Action.define({
|
|
|
12
13
|
guard(stream, "streamRequired");
|
|
13
14
|
guard(input, "inputRequired");
|
|
14
15
|
const dbs = stream.core.dbs;
|
|
16
|
+
const config = stream?.context?.config;
|
|
17
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
15
18
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
16
19
|
const resultQuestion = await stream.actions.data.getOne.execute(
|
|
17
20
|
{
|
|
@@ -52,6 +55,52 @@ const sendAnswer = Action.define({
|
|
|
52
55
|
}
|
|
53
56
|
);
|
|
54
57
|
}
|
|
58
|
+
const studentResult = await stream.actions.data.getMany.execute({
|
|
59
|
+
model: "neu:akademik:student",
|
|
60
|
+
query: Query.define({
|
|
61
|
+
fields: {
|
|
62
|
+
id: 1,
|
|
63
|
+
user: {
|
|
64
|
+
id: 1,
|
|
65
|
+
name: 1,
|
|
66
|
+
email: 1,
|
|
67
|
+
phone: 1
|
|
68
|
+
},
|
|
69
|
+
userId: 1
|
|
70
|
+
},
|
|
71
|
+
filter: {
|
|
72
|
+
_id: input.studentId
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
}, stream);
|
|
76
|
+
const students = studentResult.payload.data || [];
|
|
77
|
+
for (const student of students) {
|
|
78
|
+
const identifier = await dbIdentitas.findOne({ userId: student.userId });
|
|
79
|
+
await ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: {
|
|
82
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
83
|
+
"Content-Type": "application/json"
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
name: "question-answered",
|
|
87
|
+
to: {
|
|
88
|
+
subscriberId: student.userId || identifier.userId,
|
|
89
|
+
email: student.user.email || identifier.email,
|
|
90
|
+
firstName: student.user.name || identifier.profile.given_name,
|
|
91
|
+
lastName: student.user.name || identifier.profile.given_name
|
|
92
|
+
},
|
|
93
|
+
payload: {
|
|
94
|
+
questionId: input.questionId,
|
|
95
|
+
code: input.code,
|
|
96
|
+
studentName: input.studentName,
|
|
97
|
+
subject: input.subjectName,
|
|
98
|
+
date: DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
99
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
55
104
|
return Result.ok({
|
|
56
105
|
state: "sendAnswer",
|
|
57
106
|
message: "Jawaban berhasil dikirim"
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const core = require('@neon.id/core');
|
|
4
4
|
const operation = require('@neon.id/operation');
|
|
5
|
+
const query = require('@neon.id/query');
|
|
5
6
|
const utils = require('@neon.id/utils');
|
|
7
|
+
const ofetch = require('ofetch');
|
|
6
8
|
|
|
7
9
|
const sendQuestion = operation.Action.define({
|
|
8
10
|
key: "sendQuestion",
|
|
@@ -12,8 +14,10 @@ const sendQuestion = operation.Action.define({
|
|
|
12
14
|
execute: async (input, stream) => {
|
|
13
15
|
utils.guard(stream, "streamRequired");
|
|
14
16
|
utils.guard(input, "inputRequired");
|
|
17
|
+
const config = stream?.context?.config;
|
|
15
18
|
const dbs = stream.core.dbs;
|
|
16
19
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
20
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
17
21
|
await dbQuestion.updateOne(
|
|
18
22
|
{
|
|
19
23
|
_id: input.questionId
|
|
@@ -23,6 +27,52 @@ const sendQuestion = operation.Action.define({
|
|
|
23
27
|
askedAt: /* @__PURE__ */ new Date()
|
|
24
28
|
}
|
|
25
29
|
);
|
|
30
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
31
|
+
model: "neu:akademik:teacher",
|
|
32
|
+
query: query.Query.define({
|
|
33
|
+
fields: {
|
|
34
|
+
id: 1,
|
|
35
|
+
user: {
|
|
36
|
+
id: 1,
|
|
37
|
+
name: 1,
|
|
38
|
+
email: 1,
|
|
39
|
+
phone: 1
|
|
40
|
+
},
|
|
41
|
+
userId: 1
|
|
42
|
+
},
|
|
43
|
+
filter: {
|
|
44
|
+
branchIds: { $in: input.branchIds },
|
|
45
|
+
subjectIds: { $in: [input.subjectId] }
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
}, stream);
|
|
49
|
+
const teachers = teachersResult.payload.data || [];
|
|
50
|
+
for (const teacher of teachers) {
|
|
51
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
52
|
+
await ofetch.ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: {
|
|
55
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
56
|
+
"Content-Type": "application/json"
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
name: "question-waited",
|
|
60
|
+
to: {
|
|
61
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
62
|
+
email: teacher.user.email || identifier.email,
|
|
63
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
64
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
65
|
+
},
|
|
66
|
+
payload: {
|
|
67
|
+
questionId: input.questionId,
|
|
68
|
+
code: input.code,
|
|
69
|
+
studentName: input.studentName,
|
|
70
|
+
date: utils.DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
71
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
}
|
|
26
76
|
return core.Result.ok({
|
|
27
77
|
state: "questionSend",
|
|
28
78
|
message: "Question has been send.",
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { Action } from '@neon.id/operation';
|
|
2
2
|
export interface SendQuestionInput {
|
|
3
3
|
questionId: string;
|
|
4
|
-
|
|
4
|
+
askedAt: any;
|
|
5
|
+
studentName: string;
|
|
6
|
+
code: string;
|
|
7
|
+
subjectId: string;
|
|
8
|
+
branchIds: string[];
|
|
5
9
|
}
|
|
6
10
|
export interface SendQuestionOutput {
|
|
7
11
|
code: number;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Result } from '@neon.id/core';
|
|
2
2
|
import { Action } from '@neon.id/operation';
|
|
3
|
-
import {
|
|
3
|
+
import { Query } from '@neon.id/query';
|
|
4
|
+
import { guard, DateUtil } from '@neon.id/utils';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
4
6
|
|
|
5
7
|
const sendQuestion = Action.define({
|
|
6
8
|
key: "sendQuestion",
|
|
@@ -10,8 +12,10 @@ const sendQuestion = Action.define({
|
|
|
10
12
|
execute: async (input, stream) => {
|
|
11
13
|
guard(stream, "streamRequired");
|
|
12
14
|
guard(input, "inputRequired");
|
|
15
|
+
const config = stream?.context?.config;
|
|
13
16
|
const dbs = stream.core.dbs;
|
|
14
17
|
const dbQuestion = dbs["neu-tanya"].models["neu:tanya:question"];
|
|
18
|
+
const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
|
|
15
19
|
await dbQuestion.updateOne(
|
|
16
20
|
{
|
|
17
21
|
_id: input.questionId
|
|
@@ -21,6 +25,52 @@ const sendQuestion = Action.define({
|
|
|
21
25
|
askedAt: /* @__PURE__ */ new Date()
|
|
22
26
|
}
|
|
23
27
|
);
|
|
28
|
+
const teachersResult = await stream.actions.data.getMany.execute({
|
|
29
|
+
model: "neu:akademik:teacher",
|
|
30
|
+
query: Query.define({
|
|
31
|
+
fields: {
|
|
32
|
+
id: 1,
|
|
33
|
+
user: {
|
|
34
|
+
id: 1,
|
|
35
|
+
name: 1,
|
|
36
|
+
email: 1,
|
|
37
|
+
phone: 1
|
|
38
|
+
},
|
|
39
|
+
userId: 1
|
|
40
|
+
},
|
|
41
|
+
filter: {
|
|
42
|
+
branchIds: { $in: input.branchIds },
|
|
43
|
+
subjectIds: { $in: [input.subjectId] }
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
}, stream);
|
|
47
|
+
const teachers = teachersResult.payload.data || [];
|
|
48
|
+
for (const teacher of teachers) {
|
|
49
|
+
const identifier = await dbIdentitas.findOne({ userId: teacher.userId });
|
|
50
|
+
await ofetch(`${config?.novuApi.url}/v1/events/trigger`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: {
|
|
53
|
+
"Authorization": `ApiKey ${config?.novuApi.token}`,
|
|
54
|
+
"Content-Type": "application/json"
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
name: "question-waited",
|
|
58
|
+
to: {
|
|
59
|
+
subscriberId: teacher.userId || identifier.userId,
|
|
60
|
+
email: teacher.user.email || identifier.email,
|
|
61
|
+
firstName: teacher.user.name || identifier.profile.given_name,
|
|
62
|
+
lastName: teacher.user.name || identifier.profile.given_name
|
|
63
|
+
},
|
|
64
|
+
payload: {
|
|
65
|
+
questionId: input.questionId,
|
|
66
|
+
code: input.code,
|
|
67
|
+
studentName: input.studentName,
|
|
68
|
+
date: DateUtil.formatTz(input.askedAt, { pattern: "yyyy-MM-dd HH:mm" }),
|
|
69
|
+
url: `${config?.appFluffyUrl}/tanya/${input.questionId}`
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
}
|
|
24
74
|
return Result.ok({
|
|
25
75
|
state: "questionSend",
|
|
26
76
|
message: "Question has been send.",
|
package/build/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ const action_hasUnderstand = require('./actions/tanya/action.hasUnderstand.cjs')
|
|
|
46
46
|
const action_notUnderstand = require('./actions/tanya/action.notUnderstand.cjs');
|
|
47
47
|
const action_sendAnswer = require('./actions/tanya/action.sendAnswer.cjs');
|
|
48
48
|
const action_sendQuestion = require('./actions/tanya/action.sendQuestion.cjs');
|
|
49
|
+
const action_reminderQuestions = require('./actions/tanya/action.reminderQuestions.cjs');
|
|
49
50
|
const prepareMediaScanterGradingInsert_action = require('./actions/mediaScanter/prepareMediaScanterGradingInsert/prepareMediaScanterGradingInsert.action.cjs');
|
|
50
51
|
const importData_action = require('./actions/importData/importData.action.cjs');
|
|
51
52
|
const action_clearGrading = require('./actions/rasionalisasi/action.clearGrading.cjs');
|
|
@@ -120,6 +121,7 @@ const actions = {
|
|
|
120
121
|
notUnderstand: action_notUnderstand.notUnderstand,
|
|
121
122
|
sendAnswer: action_sendAnswer.sendAnswer,
|
|
122
123
|
sendQuestion: action_sendQuestion.sendQuestion,
|
|
124
|
+
reminderQuestions: action_reminderQuestions.reminderQuestions,
|
|
123
125
|
// Media Scanter
|
|
124
126
|
prepareMediaScanterGradingInsert: prepareMediaScanterGradingInsert_action.prepareMediaScanterGradingInsert,
|
|
125
127
|
// Import Data
|
|
@@ -174,6 +176,7 @@ exports.hasUnderstand = action_hasUnderstand.hasUnderstand;
|
|
|
174
176
|
exports.notUnderstand = action_notUnderstand.notUnderstand;
|
|
175
177
|
exports.sendAnswer = action_sendAnswer.sendAnswer;
|
|
176
178
|
exports.sendQuestion = action_sendQuestion.sendQuestion;
|
|
179
|
+
exports.reminderQuestions = action_reminderQuestions.reminderQuestions;
|
|
177
180
|
exports.prepareMediaScanterGradingInsert = prepareMediaScanterGradingInsert_action.prepareMediaScanterGradingInsert;
|
|
178
181
|
exports.importData = importData_action.importData;
|
|
179
182
|
exports.clearGrading = action_clearGrading.clearGrading;
|
package/build/index.d.ts
CHANGED
|
@@ -80,6 +80,7 @@ export declare const actions: {
|
|
|
80
80
|
notUnderstand: import("@neon.id/operation").Action<"notUnderstand", import("./actions").NotUnderstandInput, import("./actions").NotUnderstandOutput, import("./actions").NotUnderstandMeta>;
|
|
81
81
|
sendAnswer: import("@neon.id/operation").Action<"sendAnswer", import("./actions").SendAnswerInput, import("./actions").SendAnswerOutput, import("./actions").SendAnswerMeta>;
|
|
82
82
|
sendQuestion: import("@neon.id/operation").Action<"sendQuestion", import("./actions").SendQuestionInput, import("./actions").SendQuestionOutput, import("./actions").SendQuestionMeta>;
|
|
83
|
+
reminderQuestions: import("@neon.id/operation").Action<"reminderQuestions", import("./actions").ReminderQuestionsInput, import("./actions").ReminderQuestionsOutput, import("./actions").ReminderQuestionsMeta>;
|
|
83
84
|
prepareMediaScanterGradingInsert: import("@neon.id/operation").Action<"prepareMediaScanterGradingInsert", {
|
|
84
85
|
eventId?: string | undefined;
|
|
85
86
|
}, import("./actions").PrepareMediaScanterGradingInsertOutput, import("./actions").PrepareMediaScanterGradingInsertMeta>;
|
package/build/index.mjs
CHANGED
|
@@ -46,6 +46,7 @@ import { hasUnderstand } from './actions/tanya/action.hasUnderstand.mjs';
|
|
|
46
46
|
import { notUnderstand } from './actions/tanya/action.notUnderstand.mjs';
|
|
47
47
|
import { sendAnswer } from './actions/tanya/action.sendAnswer.mjs';
|
|
48
48
|
import { sendQuestion } from './actions/tanya/action.sendQuestion.mjs';
|
|
49
|
+
import { reminderQuestions } from './actions/tanya/action.reminderQuestions.mjs';
|
|
49
50
|
import { prepareMediaScanterGradingInsert } from './actions/mediaScanter/prepareMediaScanterGradingInsert/prepareMediaScanterGradingInsert.action.mjs';
|
|
50
51
|
import { importData } from './actions/importData/importData.action.mjs';
|
|
51
52
|
import { clearGrading } from './actions/rasionalisasi/action.clearGrading.mjs';
|
|
@@ -120,10 +121,11 @@ const actions = {
|
|
|
120
121
|
notUnderstand,
|
|
121
122
|
sendAnswer,
|
|
122
123
|
sendQuestion,
|
|
124
|
+
reminderQuestions,
|
|
123
125
|
// Media Scanter
|
|
124
126
|
prepareMediaScanterGradingInsert,
|
|
125
127
|
// Import Data
|
|
126
128
|
importData
|
|
127
129
|
};
|
|
128
130
|
|
|
129
|
-
export { acceptQuestion, actions, addManyGradingComponent, allConflict, calculateGrading, calculateManyComparator, calculateOneComparator, checkClassAttendance, classSessionInventoryOccurs, classSessionInventoryPreparation, clearAllOverrides, clearGrading, clearOneOverrides, createGradingAndScores, createManySession, customSaveOneClassSession, deleteManySession, editAnswer, generateGrading, getClassSessionConflicts, getGradingCount, getQuestionCount, getStaffId, getStaffPoint, getStudentId, getStudentPoint, getTeacherPoint, hasUnderstand, importData, notUnderstand, prepareConflict, prepareExperience, prepareMediaScanterGradingInsert, presenceSessionStudent, presenceSessionTeacher, rasionalizeGrading, refreshGrading, refreshManyGrading, refreshModuleAccess, replaceModuleAccess, sendAnswer, sendQuestion, setTravelWageSessions, syncClassSessions, syncCommitment, syncStudentAdmisi, syncStudentBranch, syncStudentInformation, syncStudentReport, updateGradingAndScores, updateMany, userCountStats };
|
|
131
|
+
export { acceptQuestion, actions, addManyGradingComponent, allConflict, calculateGrading, calculateManyComparator, calculateOneComparator, checkClassAttendance, classSessionInventoryOccurs, classSessionInventoryPreparation, clearAllOverrides, clearGrading, clearOneOverrides, createGradingAndScores, createManySession, customSaveOneClassSession, deleteManySession, editAnswer, generateGrading, getClassSessionConflicts, getGradingCount, getQuestionCount, getStaffId, getStaffPoint, getStudentId, getStudentPoint, getTeacherPoint, hasUnderstand, importData, notUnderstand, prepareConflict, prepareExperience, prepareMediaScanterGradingInsert, presenceSessionStudent, presenceSessionTeacher, rasionalizeGrading, refreshGrading, refreshManyGrading, refreshModuleAccess, reminderQuestions, replaceModuleAccess, sendAnswer, sendQuestion, setTravelWageSessions, syncClassSessions, syncCommitment, syncStudentAdmisi, syncStudentBranch, syncStudentInformation, syncStudentReport, updateGradingAndScores, updateMany, userCountStats };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neutron.co.id/pendidikan-operation",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.21-beta.1",
|
|
4
4
|
"description": "Operation package of Neutron Pendidikan.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"contributors": [
|
|
@@ -39,12 +39,13 @@
|
|
|
39
39
|
"@neon.id/types": "^1.69.0",
|
|
40
40
|
"@neon.id/utils": "^1.52.0",
|
|
41
41
|
"@neon.id/z": "^1.16.0",
|
|
42
|
-
"@neutron.co.id/akademik-models": "^1.19.
|
|
43
|
-
"@neutron.co.id/jadwal-models": "^1.19.
|
|
44
|
-
"@neutron.co.id/pendidikan-types": "^1.22.
|
|
45
|
-
"@neutron.co.id/penilaian-models": "^1.17.
|
|
42
|
+
"@neutron.co.id/akademik-models": "^1.19.16-beta.1",
|
|
43
|
+
"@neutron.co.id/jadwal-models": "^1.19.11-beta.1",
|
|
44
|
+
"@neutron.co.id/pendidikan-types": "^1.22.15-beta.1",
|
|
45
|
+
"@neutron.co.id/penilaian-models": "^1.17.8",
|
|
46
46
|
"@neutron.co.id/personalia-models": "^1.11.6",
|
|
47
|
-
"@neutron.co.id/tanya-models": "^1.13.1"
|
|
47
|
+
"@neutron.co.id/tanya-models": "^1.13.1",
|
|
48
|
+
"node-cron": "^4.1.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@neon.id/cli": "0.23.0",
|
|
@@ -73,15 +74,15 @@
|
|
|
73
74
|
"@neon.id/types": "^1.69.0",
|
|
74
75
|
"@neon.id/utils": "^1.52.0",
|
|
75
76
|
"@neon.id/z": "^1.16.0",
|
|
76
|
-
"@neutron.co.id/akademik-models": "^1.19.
|
|
77
|
-
"@neutron.co.id/jadwal-models": "^1.19.
|
|
78
|
-
"@neutron.co.id/pendidikan-types": "^1.22.
|
|
79
|
-
"@neutron.co.id/penilaian-models": "^1.17.
|
|
77
|
+
"@neutron.co.id/akademik-models": "^1.19.16-beta.1",
|
|
78
|
+
"@neutron.co.id/jadwal-models": "^1.19.11-beta.1",
|
|
79
|
+
"@neutron.co.id/pendidikan-types": "^1.22.15-beta.1",
|
|
80
|
+
"@neutron.co.id/penilaian-models": "^1.17.8",
|
|
80
81
|
"@neutron.co.id/personalia-models": "^1.11.6",
|
|
81
82
|
"@neutron.co.id/tanya-models": "^1.13.1"
|
|
82
83
|
},
|
|
83
84
|
"publishConfig": {
|
|
84
85
|
"access": "public"
|
|
85
86
|
},
|
|
86
|
-
"build":
|
|
87
|
+
"build": 109
|
|
87
88
|
}
|