@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.
@@ -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
  }
@@ -12,6 +12,7 @@ export interface CreateManySessionInput {
12
12
  subjectIds: string;
13
13
  teacherRepeaterIds: string;
14
14
  classSessionPurposeId: string;
15
+ createdBy: string;
15
16
  }
16
17
  export interface CreateManySessionOutput {
17
18
  code: number;
@@ -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 { guard } from '@neon.id/utils';
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 { guard } from '@neon.id/utils';
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
- status: string;
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 { guard } from '@neon.id/utils';
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.",
@@ -5,3 +5,4 @@ export * from './action.hasUnderstand';
5
5
  export * from './action.notUnderstand';
6
6
  export * from './action.sendAnswer';
7
7
  export * from './action.sendQuestion';
8
+ export * from './action.reminderQuestions';
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.19",
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.12",
43
- "@neutron.co.id/jadwal-models": "^1.19.8",
44
- "@neutron.co.id/pendidikan-types": "^1.22.11",
45
- "@neutron.co.id/penilaian-models": "^1.17.6",
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.12",
77
- "@neutron.co.id/jadwal-models": "^1.19.8",
78
- "@neutron.co.id/pendidikan-types": "^1.22.11",
79
- "@neutron.co.id/penilaian-models": "^1.17.6",
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": 107
87
+ "build": 109
87
88
  }