@neutron.co.id/pendidikan-operation 1.27.6 → 1.27.8

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.
Files changed (46) hide show
  1. package/build/actions/index.d.ts +1 -0
  2. package/build/actions/jadwal/index.d.ts +2 -0
  3. package/build/actions/jadwal/sendClassConsultationNotification/index.d.ts +2 -0
  4. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.action.cjs +110 -0
  5. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.action.d.ts +5 -0
  6. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.action.mjs +108 -0
  7. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.schema.cjs +12 -0
  8. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.schema.d.ts +15 -0
  9. package/build/actions/jadwal/sendClassConsultationNotification/sendClassConsultationNotification.schema.mjs +10 -0
  10. package/build/actions/jadwal/sendClassSessionNotification/index.d.ts +2 -0
  11. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.action.cjs +217 -0
  12. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.action.d.ts +5 -0
  13. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.action.mjs +215 -0
  14. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.schema.cjs +12 -0
  15. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.schema.d.ts +15 -0
  16. package/build/actions/jadwal/sendClassSessionNotification/sendClassSessionNotification.schema.mjs +10 -0
  17. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.action.cjs +15 -2
  18. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.action.d.ts +1 -0
  19. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.action.mjs +15 -2
  20. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.schema.cjs +3 -0
  21. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.schema.d.ts +3 -0
  22. package/build/actions/jadwal/setAksesModulSiswaDiClassGroup/setAksesModulSiswaDiClassGroup.schema.mjs +3 -0
  23. package/build/actions/penilaian/index.d.ts +1 -0
  24. package/build/actions/penilaian/refreshManyGrading/refreshManyGrading.action.cjs +29 -0
  25. package/build/actions/penilaian/refreshManyGrading/refreshManyGrading.action.mjs +29 -0
  26. package/build/actions/penilaian/sendScoreNotification/index.d.ts +2 -0
  27. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.action.cjs +183 -0
  28. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.action.d.ts +5 -0
  29. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.action.mjs +181 -0
  30. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.schema.cjs +12 -0
  31. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.schema.d.ts +15 -0
  32. package/build/actions/penilaian/sendScoreNotification/sendScoreNotification.schema.mjs +10 -0
  33. package/build/actions/replaceModuleAccessManyStudent/index.d.ts +2 -0
  34. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.action.cjs +131 -0
  35. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.action.d.ts +14 -0
  36. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.action.mjs +129 -0
  37. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.schema.cjs +17 -0
  38. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.schema.d.ts +14 -0
  39. package/build/actions/replaceModuleAccessManyStudent/replaceModuleAccessManyStudent.schema.mjs +15 -0
  40. package/build/hooks/hook.officePendidikan.cjs +34 -0
  41. package/build/hooks/hook.officePendidikan.mjs +34 -0
  42. package/build/index.cjs +21 -0
  43. package/build/index.d.ts +15 -0
  44. package/build/index.mjs +14 -1
  45. package/build/utils/util.email.d.ts +41 -0
  46. package/package.json +2 -2
@@ -6,6 +6,7 @@ export * from './penilaian';
6
6
  export * from './prepareExperience';
7
7
  export * from './replaceModuleAccess';
8
8
  export * from './refreshModuleAccess';
9
+ export * from './replaceModuleAccessManyStudent';
9
10
  export * from './rasionalisasi';
10
11
  export * from './tanya';
11
12
  export * from './updateMany';
@@ -12,3 +12,5 @@ export * from './setAksesModulSiswaDiClassGroup';
12
12
  export * from './setTravelWageSessions';
13
13
  export * from './action.customSaveOneClassSession';
14
14
  export * from './syncClassGroups';
15
+ export * from './sendClassConsultationNotification';
16
+ export * from './sendClassSessionNotification';
@@ -0,0 +1,2 @@
1
+ export * from './sendClassConsultationNotification.action';
2
+ export * from './sendClassConsultationNotification.schema';
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ const operation = require('@neon.id/operation');
4
+ const core = require('@neon.id/core');
5
+ const ofetch = require('ofetch');
6
+ const query = require('@neon.id/query');
7
+ const sendClassConsultationNotification_schema = require('./sendClassConsultationNotification.schema.cjs');
8
+
9
+ const sendClassConsultationNotification = operation.Action.define({
10
+ key: "sendClassConsultationNotification",
11
+ name: "Send ClassConsultation Notification",
12
+ type: "command",
13
+ category: "domain",
14
+ execute: async (input, stream) => {
15
+ const config = stream?.context?.config;
16
+ const { validate } = operation.useValidation(stream, sendClassConsultationNotification_schema.SendClassConsultationNotificationSchema);
17
+ const data = validate(input);
18
+ if (!config?.novuApi?.url || !config?.novuApi?.token) {
19
+ console.warn("Novu API not configured, skipping notification");
20
+ return core.Result.ok({
21
+ state: "emailsSent",
22
+ message: "Novu not configured",
23
+ data: { sentCount: 0, transactionIds: [] }
24
+ });
25
+ }
26
+ try {
27
+ const classConsultation = await stream?.actions.data.getOne.execute({
28
+ model: "neu:jadwal:classConsultation",
29
+ id: data.classConsultationId,
30
+ query: query.Query.define({
31
+ fields: {
32
+ id: 1,
33
+ title: 1,
34
+ subtitle: 1,
35
+ startedAt: 1,
36
+ endedAt: 1,
37
+ subject: { name: 1 },
38
+ students: { userId: 1, user: { name: 1, email: 1 } },
39
+ topics: { name: 1 }
40
+ }
41
+ })
42
+ }, stream);
43
+ if (!classConsultation?.payload?.data) {
44
+ console.warn(`ClassConsultation ${data.classConsultationId} not found`);
45
+ return core.Result.ok({
46
+ state: "emailsSent",
47
+ message: "ClassConsultation not found",
48
+ data: { sentCount: 0, transactionIds: [] }
49
+ });
50
+ }
51
+ const consultation = classConsultation.payload.data;
52
+ const transactionIds = [];
53
+ let sentCount = 0;
54
+ for (const student of consultation.students || []) {
55
+ if (!student.userId)
56
+ continue;
57
+ try {
58
+ const response = await ofetch.ofetch(`${config.novuApi.url}/v1/events/trigger`, {
59
+ method: "POST",
60
+ headers: {
61
+ "Authorization": `ApiKey ${config.novuApi.token}`,
62
+ "Content-Type": "application/json"
63
+ },
64
+ body: JSON.stringify({
65
+ name: "consultation-created",
66
+ to: {
67
+ // subscriberId: student.userId,
68
+ subscriberId: "test-user-id",
69
+ email: student.user?.email || "",
70
+ firstName: student.user?.name || "Student",
71
+ lastName: ""
72
+ },
73
+ payload: {
74
+ // consultationId: consultation.id,
75
+ // title: consultation.title || 'Consultation',
76
+ subject: consultation.subject?.name || "Subject"
77
+ // topics: topicsList,
78
+ // teacherNames,
79
+ // date: DateUtil.formatTz(consultation.startedAt, { pattern: 'yyyy-MM-dd' }),
80
+ // startTime: DateUtil.formatTz(consultation.startedAt, { pattern: 'HH:mm' }),
81
+ // endTime: DateUtil.formatTz(consultation.endedAt, { pattern: 'HH:mm' }),
82
+ // branch: consultation.branch?.name || 'Branch',
83
+ // url: consultationUrl,
84
+ }
85
+ })
86
+ });
87
+ if (response?.data?.transactionId)
88
+ transactionIds.push(response.data.transactionId);
89
+ sentCount++;
90
+ } catch (error) {
91
+ console.error(`Failed to send consultation notification to student ${student.userId}:`, error);
92
+ }
93
+ }
94
+ return core.Result.ok({
95
+ state: "emailsSent",
96
+ message: `Sent ${sentCount} notification emails`,
97
+ data: { sentCount, transactionIds }
98
+ });
99
+ } catch (error) {
100
+ console.error("Failed to send consultation notifications:", error);
101
+ return core.Result.ok({
102
+ state: "emailsSent",
103
+ message: "Failed to send notifications",
104
+ data: { sentCount: 0, transactionIds: [] }
105
+ });
106
+ }
107
+ }
108
+ });
109
+
110
+ exports.sendClassConsultationNotification = sendClassConsultationNotification;
@@ -0,0 +1,5 @@
1
+ import { Action } from '@neon.id/operation';
2
+ import { type SendClassConsultationNotificationMeta, type SendClassConsultationNotificationOutput } from './sendClassConsultationNotification.schema';
3
+ export declare const sendClassConsultationNotification: Action<"sendClassConsultationNotification", {
4
+ classConsultationId: string;
5
+ }, SendClassConsultationNotificationOutput, SendClassConsultationNotificationMeta>;
@@ -0,0 +1,108 @@
1
+ import { Action, useValidation } from '@neon.id/operation';
2
+ import { Result } from '@neon.id/core';
3
+ import { ofetch } from 'ofetch';
4
+ import { Query } from '@neon.id/query';
5
+ import { SendClassConsultationNotificationSchema } from './sendClassConsultationNotification.schema.mjs';
6
+
7
+ const sendClassConsultationNotification = Action.define({
8
+ key: "sendClassConsultationNotification",
9
+ name: "Send ClassConsultation Notification",
10
+ type: "command",
11
+ category: "domain",
12
+ execute: async (input, stream) => {
13
+ const config = stream?.context?.config;
14
+ const { validate } = useValidation(stream, SendClassConsultationNotificationSchema);
15
+ const data = validate(input);
16
+ if (!config?.novuApi?.url || !config?.novuApi?.token) {
17
+ console.warn("Novu API not configured, skipping notification");
18
+ return Result.ok({
19
+ state: "emailsSent",
20
+ message: "Novu not configured",
21
+ data: { sentCount: 0, transactionIds: [] }
22
+ });
23
+ }
24
+ try {
25
+ const classConsultation = await stream?.actions.data.getOne.execute({
26
+ model: "neu:jadwal:classConsultation",
27
+ id: data.classConsultationId,
28
+ query: Query.define({
29
+ fields: {
30
+ id: 1,
31
+ title: 1,
32
+ subtitle: 1,
33
+ startedAt: 1,
34
+ endedAt: 1,
35
+ subject: { name: 1 },
36
+ students: { userId: 1, user: { name: 1, email: 1 } },
37
+ topics: { name: 1 }
38
+ }
39
+ })
40
+ }, stream);
41
+ if (!classConsultation?.payload?.data) {
42
+ console.warn(`ClassConsultation ${data.classConsultationId} not found`);
43
+ return Result.ok({
44
+ state: "emailsSent",
45
+ message: "ClassConsultation not found",
46
+ data: { sentCount: 0, transactionIds: [] }
47
+ });
48
+ }
49
+ const consultation = classConsultation.payload.data;
50
+ const transactionIds = [];
51
+ let sentCount = 0;
52
+ for (const student of consultation.students || []) {
53
+ if (!student.userId)
54
+ continue;
55
+ try {
56
+ const response = await ofetch(`${config.novuApi.url}/v1/events/trigger`, {
57
+ method: "POST",
58
+ headers: {
59
+ "Authorization": `ApiKey ${config.novuApi.token}`,
60
+ "Content-Type": "application/json"
61
+ },
62
+ body: JSON.stringify({
63
+ name: "consultation-created",
64
+ to: {
65
+ // subscriberId: student.userId,
66
+ subscriberId: "test-user-id",
67
+ email: student.user?.email || "",
68
+ firstName: student.user?.name || "Student",
69
+ lastName: ""
70
+ },
71
+ payload: {
72
+ // consultationId: consultation.id,
73
+ // title: consultation.title || 'Consultation',
74
+ subject: consultation.subject?.name || "Subject"
75
+ // topics: topicsList,
76
+ // teacherNames,
77
+ // date: DateUtil.formatTz(consultation.startedAt, { pattern: 'yyyy-MM-dd' }),
78
+ // startTime: DateUtil.formatTz(consultation.startedAt, { pattern: 'HH:mm' }),
79
+ // endTime: DateUtil.formatTz(consultation.endedAt, { pattern: 'HH:mm' }),
80
+ // branch: consultation.branch?.name || 'Branch',
81
+ // url: consultationUrl,
82
+ }
83
+ })
84
+ });
85
+ if (response?.data?.transactionId)
86
+ transactionIds.push(response.data.transactionId);
87
+ sentCount++;
88
+ } catch (error) {
89
+ console.error(`Failed to send consultation notification to student ${student.userId}:`, error);
90
+ }
91
+ }
92
+ return Result.ok({
93
+ state: "emailsSent",
94
+ message: `Sent ${sentCount} notification emails`,
95
+ data: { sentCount, transactionIds }
96
+ });
97
+ } catch (error) {
98
+ console.error("Failed to send consultation notifications:", error);
99
+ return Result.ok({
100
+ state: "emailsSent",
101
+ message: "Failed to send notifications",
102
+ data: { sentCount: 0, transactionIds: [] }
103
+ });
104
+ }
105
+ }
106
+ });
107
+
108
+ export { sendClassConsultationNotification };
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ const z = require('@neon.id/z');
4
+
5
+ const SendClassConsultationNotificationSchema = z.z.object({
6
+ classConsultationId: z.z.objectId().explain({
7
+ label: "Class Consultation ID",
8
+ description: "The ID of the consultation to send notifications for"
9
+ })
10
+ });
11
+
12
+ exports.SendClassConsultationNotificationSchema = SendClassConsultationNotificationSchema;
@@ -0,0 +1,15 @@
1
+ import { z } from '@neon.id/z';
2
+ export declare const SendClassConsultationNotificationSchema: z.ZodObject<{
3
+ classConsultationId: z.ZodEffects<z.ZodString, string, string>;
4
+ }, "strip", z.ZodTypeAny, {
5
+ classConsultationId: string;
6
+ }, {
7
+ classConsultationId: string;
8
+ }>;
9
+ export type SendClassConsultationNotificationInput = z.parse<typeof SendClassConsultationNotificationSchema>;
10
+ export interface SendClassConsultationNotificationOutput {
11
+ }
12
+ export interface SendClassConsultationNotificationMeta {
13
+ input: SendClassConsultationNotificationInput;
14
+ output: SendClassConsultationNotificationOutput;
15
+ }
@@ -0,0 +1,10 @@
1
+ import { z } from '@neon.id/z';
2
+
3
+ const SendClassConsultationNotificationSchema = z.object({
4
+ classConsultationId: z.objectId().explain({
5
+ label: "Class Consultation ID",
6
+ description: "The ID of the consultation to send notifications for"
7
+ })
8
+ });
9
+
10
+ export { SendClassConsultationNotificationSchema };
@@ -0,0 +1,2 @@
1
+ export * from './sendClassSessionNotification.action';
2
+ export * from './sendClassSessionNotification.schema';
@@ -0,0 +1,217 @@
1
+ 'use strict';
2
+
3
+ const operation = require('@neon.id/operation');
4
+ const ofetch = require('ofetch');
5
+ const core = require('@neon.id/core');
6
+ const date = require('@neon.id/utils/date');
7
+ const query = require('@neon.id/query');
8
+ const sendClassSessionNotification_schema = require('./sendClassSessionNotification.schema.cjs');
9
+
10
+ async function resolveEmail(dbs, userId) {
11
+ if (!userId)
12
+ return null;
13
+ try {
14
+ const dbIdentitas = dbs["neo-identitas"].models["neo:identitas:identifier"];
15
+ const identifier = await dbIdentitas.findOne({ userId });
16
+ return identifier?.email || identifier?.profile?.email || (identifier?.provider === "email" ? identifier?.value : null) || null;
17
+ } catch (error) {
18
+ console.error(`Failed to resolve email for userId ${userId}:`, error);
19
+ return null;
20
+ }
21
+ }
22
+ const sendClassSessionNotification = operation.Action.define({
23
+ key: "sendClassSessionNotification",
24
+ name: "Send ClassSession Notification",
25
+ type: "command",
26
+ category: "domain",
27
+ execute: async (input, stream) => {
28
+ const config = stream?.context?.config;
29
+ const { validate } = operation.useValidation(stream, sendClassSessionNotification_schema.SendClassSessionNotificationSchema);
30
+ const data = validate(input);
31
+ const dbs = stream?.core.dbs;
32
+ if (!config?.novuApi?.url || !config?.novuApi?.token) {
33
+ console.warn("Novu API not configured, skipping notification");
34
+ return core.Result.ok({
35
+ state: "emailsSent",
36
+ message: "Novu not configured",
37
+ data: { sentCount: 0, transactionIds: [] }
38
+ });
39
+ }
40
+ try {
41
+ const classSession = await stream?.actions.data.getOne.execute({
42
+ model: "neu:jadwal:classSession",
43
+ id: data.classSessionId,
44
+ query: query.Query.define({
45
+ fields: {
46
+ id: 1,
47
+ title: 1,
48
+ subtitle: 1,
49
+ startedAt: 1,
50
+ endedAt: 1,
51
+ type: 1,
52
+ locationType: 1,
53
+ link: 1,
54
+ password: 1,
55
+ building: { name: 1 },
56
+ room: { name: 1 },
57
+ branches: { name: 1 },
58
+ subjects: { name: 1 },
59
+ teachers: { userId: 1, user: { name: 1, email: 1 } },
60
+ groups: {
61
+ name: 1,
62
+ studentGroups: {
63
+ student: { userId: 1, user: { name: 1, email: 1 } }
64
+ }
65
+ },
66
+ classSessionPurpose: { name: 1 },
67
+ stage: { name: 1 }
68
+ }
69
+ })
70
+ }, stream);
71
+ if (!classSession?.payload.data) {
72
+ console.warn(`ClassSession ${data.classSessionId} not found`);
73
+ return core.Result.ok({
74
+ state: "emailsSent",
75
+ message: "ClassSession not found",
76
+ data: { sentCount: 0, transactionIds: [] }
77
+ });
78
+ }
79
+ const session = classSession.payload.data;
80
+ const transactionIds = [];
81
+ let sentCount = 0;
82
+ const teacherNames = session.teachers?.map((t) => t.user?.name || "Unknown").join(", ") || "No teachers assigned";
83
+ const subjectsList = session.subjects?.map((s) => s.name).join(", ") || "No subjects specified";
84
+ const groupNames = session.groups?.map((g) => g.name).join(", ") || "No groups";
85
+ const sessionUrl = `${config?.appFluffyUrl || config?.appFrontendUrl || ""}/sessions/${session.id}`;
86
+ let locationText = "";
87
+ if (session.locationType === "building" && session.building && session.room)
88
+ locationText = `${session.building.name} - ${session.room.name}`;
89
+ else if (session.locationType === "link")
90
+ locationText = "Online (see link below)";
91
+ else if (session.locationType === "school")
92
+ locationText = "At School";
93
+ else
94
+ locationText = session.locationType || "Location TBD";
95
+ const students = [];
96
+ for (const group of session.groups || []) {
97
+ for (const studentGroup of group.studentGroups || []) {
98
+ if (studentGroup.student)
99
+ students.push(studentGroup.student);
100
+ }
101
+ }
102
+ const uniqueStudents = students.filter(
103
+ (student, index, self) => index === self.findIndex((s) => s.userId === student.userId)
104
+ );
105
+ for (const student of uniqueStudents) {
106
+ if (!student.userId)
107
+ continue;
108
+ const email = await resolveEmail(dbs, student.userId);
109
+ if (!email) {
110
+ console.warn(`No email found for student userId: ${student.userId}`);
111
+ continue;
112
+ }
113
+ try {
114
+ const response = await ofetch.ofetch(`${config.novuApi.url}/v1/events/trigger`, {
115
+ method: "POST",
116
+ headers: {
117
+ "Authorization": `ApiKey ${config.novuApi.token}`,
118
+ "Content-Type": "application/json"
119
+ },
120
+ body: JSON.stringify({
121
+ name: "session-created",
122
+ to: {
123
+ subscriberId: student.userId,
124
+ email,
125
+ firstName: student.user?.name || "Student",
126
+ lastName: ""
127
+ },
128
+ payload: {
129
+ sessionId: session.id,
130
+ title: session.title || "Class Session",
131
+ subtitle: session.subtitle || "",
132
+ subjects: subjectsList,
133
+ teacherNames,
134
+ date: date.DateUtil.formatTz(session.startedAt, { pattern: "yyyy-MM-dd" }),
135
+ startTime: date.DateUtil.formatTz(session.startedAt, { pattern: "HH:mm" }),
136
+ endTime: date.DateUtil.formatTz(session.endedAt, { pattern: "HH:mm" }),
137
+ type: session.type || "offline",
138
+ location: locationText,
139
+ link: session.link || "",
140
+ password: session.password || "",
141
+ purpose: session.classSessionPurpose?.name || "",
142
+ url: sessionUrl
143
+ }
144
+ })
145
+ });
146
+ if (response?.data?.transactionId)
147
+ transactionIds.push(response.data.transactionId);
148
+ sentCount++;
149
+ } catch (error) {
150
+ console.error(`Failed to send session notification to student ${student.userId}:`, error);
151
+ }
152
+ }
153
+ const studentCount = uniqueStudents.length;
154
+ for (const teacher of session.teachers || []) {
155
+ if (!teacher.userId)
156
+ continue;
157
+ const email = await resolveEmail(dbs, teacher.userId);
158
+ if (!email) {
159
+ console.warn(`No email found for teacher userId: ${teacher.userId}`);
160
+ continue;
161
+ }
162
+ try {
163
+ await ofetch.ofetch(`${config.novuApi.url}/v1/events/trigger`, {
164
+ method: "POST",
165
+ headers: {
166
+ "Authorization": `ApiKey ${config.novuApi.token}`,
167
+ "Content-Type": "application/json"
168
+ },
169
+ body: JSON.stringify({
170
+ name: "session-created-teacher",
171
+ to: {
172
+ subscriberId: teacher.userId,
173
+ email,
174
+ firstName: teacher.user?.name || "Teacher",
175
+ lastName: ""
176
+ },
177
+ payload: {
178
+ sessionId: session.id,
179
+ title: session.title || "Class Session",
180
+ subtitle: session.subtitle || "",
181
+ subjects: subjectsList,
182
+ studentCount,
183
+ groupNames,
184
+ date: date.DateUtil.formatTz(session.startedAt, { pattern: "yyyy-MM-dd" }),
185
+ startTime: date.DateUtil.formatTz(session.startedAt, { pattern: "HH:mm" }),
186
+ endTime: date.DateUtil.formatTz(session.endedAt, { pattern: "HH:mm" }),
187
+ type: session.type || "offline",
188
+ location: locationText,
189
+ link: session.link || "",
190
+ password: session.password || "",
191
+ purpose: session.classSessionPurpose?.name || "",
192
+ url: sessionUrl
193
+ }
194
+ })
195
+ });
196
+ sentCount++;
197
+ } catch (error) {
198
+ console.error(`Failed to send session notification to teacher ${teacher.userId}:`, error);
199
+ }
200
+ }
201
+ return core.Result.ok({
202
+ state: "emailsSent",
203
+ message: `Sent ${sentCount} notification emails`,
204
+ data: { sentCount, transactionIds }
205
+ });
206
+ } catch (error) {
207
+ console.error("Failed to send session notifications:", error);
208
+ return core.Result.ok({
209
+ state: "emailsSent",
210
+ message: "Failed to send notifications",
211
+ data: { sentCount: 0, transactionIds: [] }
212
+ });
213
+ }
214
+ }
215
+ });
216
+
217
+ exports.sendClassSessionNotification = sendClassSessionNotification;
@@ -0,0 +1,5 @@
1
+ import { Action } from '@neon.id/operation';
2
+ import { type SendClassSessionNotificationMeta, type SendClassSessionNotificationOutput } from './sendClassSessionNotification.schema';
3
+ export declare const sendClassSessionNotification: Action<"sendClassSessionNotification", {
4
+ classSessionId: string;
5
+ }, SendClassSessionNotificationOutput, SendClassSessionNotificationMeta>;