90dc-core 1.6.0 → 1.6.2

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 (38) hide show
  1. package/dist/lib/dbmodels/DeviceTokens.d.ts +6 -0
  2. package/dist/lib/dbmodels/DeviceTokens.js +34 -0
  3. package/dist/lib/dbmodels/DeviceTokens.js.map +1 -0
  4. package/dist/lib/dbmodels/NotificationModels.d.ts +8 -0
  5. package/dist/lib/dbmodels/NotificationModels.js +38 -0
  6. package/dist/lib/dbmodels/NotificationModels.js.map +1 -0
  7. package/dist/lib/dbmodels/TranslatedNotification.d.ts +9 -0
  8. package/dist/lib/dbmodels/TranslatedNotification.js +45 -0
  9. package/dist/lib/dbmodels/TranslatedNotification.js.map +1 -0
  10. package/dist/lib/dbmodels/program/ThirtyDayChallenge.d.ts +13 -0
  11. package/dist/lib/dbmodels/program/ThirtyDayChallenge.js +70 -0
  12. package/dist/lib/dbmodels/program/ThirtyDayChallenge.js.map +1 -0
  13. package/dist/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.d.ts +11 -0
  14. package/dist/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.js +55 -0
  15. package/dist/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.js.map +1 -0
  16. package/dist/lib/enums/ProgramTemplates.d.ts +8 -0
  17. package/dist/lib/enums/ProgramTemplates.js +738 -0
  18. package/dist/lib/enums/ProgramTemplates.js.map +1 -0
  19. package/dist/lib/enums/cert.d.ts +13 -0
  20. package/dist/lib/enums/cert.js +15 -0
  21. package/dist/lib/enums/cert.js.map +1 -0
  22. package/dist/lib/models/NotificationInterfaces.d.ts +50 -0
  23. package/dist/lib/models/NotificationInterfaces.js +11 -0
  24. package/dist/lib/models/NotificationInterfaces.js.map +1 -0
  25. package/dist/lib/utils/NotificationsUtil.d.ts +14 -0
  26. package/dist/lib/utils/NotificationsUtil.js +147 -0
  27. package/dist/lib/utils/NotificationsUtil.js.map +1 -0
  28. package/package.json +4 -1
  29. package/src/lib/dbmodels/DeviceTokens.ts +24 -0
  30. package/src/lib/dbmodels/NotificationModels.ts +39 -0
  31. package/src/lib/dbmodels/TranslatedNotification.ts +42 -0
  32. package/src/lib/dbmodels/program/ThirtyDayChallenge.ts +46 -0
  33. package/src/lib/dbmodels/program/ThirtyDayChallengeStrengthTest.ts +39 -0
  34. package/src/lib/enums/ProgramTemplates.ts +881 -0
  35. package/src/lib/enums/cert.ts +16 -0
  36. package/src/lib/models/NotificationInterfaces.ts +66 -0
  37. package/src/lib/utils/NotificationsUtil.ts +188 -0
  38. package/tsconfig.json +1 -1
@@ -0,0 +1,16 @@
1
+ export const cert_key = {
2
+ type: "service_account",
3
+ project_id: "dayschallenge-373510",
4
+ private_key_id: "728533f268b61808b2566c1a26166db36b422f44",
5
+ private_key:
6
+ "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCvQREgqfl+hC+\nsoVNksqOI+IN1TxhhCzfwl/mb4TR+L09i7VcdN/vgQL/zDH6++31evKruqTBaLha\nOk2OZPUd29FXG3qxZJtKMxhKpyhw/NQjABHFQ4K2JDCk9VqDASve2M5JHp1YXzJb\n5rEap3RM+dHNxR37zWU0kfLSo8OBSrAj/DCsezd5QqXqt0aB2N4VjlEijm05z7Of\nJRTSUL+u1Ftt+ToSM2xih3AMMGMHhcqPjuZSWK6uVXG5Qo2SH11C1N5MX/qeACEB\n2wABJjrcMb+CmVzW+ZPkSeKFSuPk0390RodDvC6eZHCtM9ruhPJM7cvwlyxHhCUX\nu/bRRMyNAgMBAAECggEACH9ut2ig2AByCPL0WIlpImEUJQ4NjPnTas4/bhL8D5zp\nm80ZacKbNQctsNOMc3XZO/GUs6642sxtja5molSV0lWRzIR2oFVnZgpVwIg2fmZi\nAXGoKjIDJbHtl30yE8O80i7ReE+y27TdFzU5ZumGFzJ9l8ZGw9gCLGmZWDIXlBrb\nwo5t+sHc2JEGoh9XoLKPmyom1icVWAwZ4nnd774McbJkh8bfjgtz3DsVvBzAJu2R\n0phK4hq7ODqzV79iyhCRum2ETGLfPL437rTeJXjUGhk6V3je4Z6xmckLPoAMdiuR\nzVqBbdG1vUqb5lQEmLtIra5JTmZS5iBDQtqo5VQ+NwKBgQD+/JVzL0w3JAf2Cgte\nSIpe6P9hYZQDZqwNFNdefE2zxow+3rhB7e/zL/74fRdcAbdCXNXtZuO/GjpbIcRq\nUeKj7B7t8a28YIj53BDmOMzEFgbxOYkxcJGMSYiSidEdRRMOTTdVWnzPvzIVRipv\nZECAsn5ZaKazc+itWaS5evgxEwKBgQDDgyNRFWtPi7YFk1yp0BvZNOetJE2S4seT\nJzeMzkrhjzLFhS1OSv5NHAKGV1xRz95eaM8/sO7fOwPWaeTS5mu8/oQLIM8hdyW5\nAVg4VjRLHKPDBLLsFVur9QxxfLH68Pgypc0MIuIa2s8gbqNZXGqKbp7crhOJEDHo\ns245+zRf3wKBgAHJLRbIbwU32GJtwZSgd2+gvCEneMzpTC0vRy7fOgAXVOYf0zSL\nARI39NYyshYv4OOzGMB35wJwoZX/z4tbFXZGchUCi0/1cSAm3WtvXGfHK7dGyuIw\nwqQz46P7GR7WXALOoaOUZali0mv5uNRc5GLCXUYtCHXbSvbj2NZ/uPtHAoGAdnec\ny8H9zypp9gDv8hme9kNfaoOH2cw+gAUQXOqXZwudCSCEbl90rgad5QdEcnJRXMWH\nZyFv7KXW0nJB7CUg/Vj/a7rKp42JtwuAiEp7z1OgS0gqnnDmplCK5K1ZLyQaUJ40\nm/j7JqiVPyKrKjecextCeZelULUWeNlYnhuABeMCgYAiSHmLx8qm67kcOsSRsTxr\nU01s5jxlHFYz+no3ZxiS6fwvsuxppiFeqRYD/zUBOcFZ+tKPU/5hH2Icu43ZApZx\n0CwN2biiMKRMft8Wg8Lx5ZjS7il6roYPKHFlySQtoSoZXaHQLTMsW+wB+vUg5+YQ\nTBN30eKadMx9Ws8RgLKQ/A==\n-----END PRIVATE KEY-----\n",
7
+ client_email:
8
+ "firebase-adminsdk-2yp4f@dayschallenge-373510.iam.gserviceaccount.com",
9
+ client_id: "104734701364860430708",
10
+ auth_uri: "https://accounts.google.com/o/oauth2/auth",
11
+ token_uri: "https://oauth2.googleapis.com/token",
12
+ auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
13
+ client_x509_cert_url:
14
+ "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-2yp4f%40dayschallenge-373510.iam.gserviceaccount.com",
15
+ universe_domain: "googleapis.com",
16
+ };
@@ -0,0 +1,66 @@
1
+ export interface AndroidMessage {
2
+ message: {
3
+ token: string | string[];
4
+ notification: { body: string; title: string };
5
+ };
6
+ }
7
+
8
+ export interface NotificationPayload {
9
+ name: string;
10
+ userUuid: string;
11
+ reminderType?: string;
12
+ delayHours?: number;
13
+ }
14
+
15
+ export interface EmailReminderPayload {
16
+ email: string,
17
+ timeZone?: string
18
+ }
19
+
20
+ export interface NotificationTranslationRequest {
21
+ language: string;
22
+ text: string;
23
+ type?: NotificationTypes;
24
+ originalNotificationUuid: string;
25
+ }
26
+
27
+ export type NotificationTypes =
28
+ | "challenge_reminder_no_streak"
29
+ | "challenge_reminder_streak"
30
+ | "workout_reminder_no_streak"
31
+ | "workout_reminder"
32
+ | "rest_reminder_no_streak"
33
+ | "rest_reminder"
34
+ | "challenge_alert"
35
+ | "workout_alert"
36
+ | "rest_alert"
37
+ | "workout_exp_alert"
38
+ | "challenge_exp_alert";
39
+
40
+ export interface CreateNotificationRequest {
41
+ text: string;
42
+ type: NotificationTypes;
43
+ }
44
+
45
+ export interface WorkoutReminder extends NotificationPayload {
46
+ programUuid: string;
47
+ }
48
+ export interface NotificationRequest {
49
+ title: string;
50
+ body: string;
51
+ redirectPath?: string;
52
+ }
53
+
54
+ export interface GroupNotificationRequest {
55
+ notification: NotificationRequest;
56
+ group: NotificationGroups;
57
+ }
58
+
59
+ export enum NotificationGroups {
60
+ ALL = "ALL",
61
+ PREMIUM = "PREMIUM",
62
+ FREE = "FREE",
63
+ ALL_SHRED = "ALL_SHRED",
64
+ PREMIUM_SHRED = "PREMIUM_SHRED",
65
+ FREE_SHRED = "FREE_SHRED",
66
+ }
@@ -0,0 +1,188 @@
1
+ import apn, { Provider } from "apn";
2
+ import axios, { isAxiosError } from "axios";
3
+ import * as dotenv from "dotenv";
4
+ import { google } from "googleapis";
5
+ import type { JWT } from "google-auth-library";
6
+ import { cert_key } from "../enums/cert";
7
+ import type {
8
+ AndroidMessage,
9
+ NotificationRequest
10
+ } from "../models/NotificationInterfaces";
11
+ import {DeviceTokens} from "../dbmodels/DeviceTokens";
12
+ dotenv.config();
13
+
14
+ export default class NotificationsUtil {
15
+ private static apnProvider: Provider = this.getAPNProvider();
16
+
17
+ private static async getAccessToken(): Promise<string> {
18
+ const key = cert_key;
19
+
20
+ const jwtClient: JWT = new google.auth.JWT({
21
+ email: key.client_email,
22
+ key: key.private_key,
23
+ scopes: ["https://www.googleapis.com/auth/firebase.messaging"],
24
+ });
25
+
26
+ return new Promise<string>((resolve, reject) => {
27
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
28
+ jwtClient.authorize((err: any, tokens: any) => {
29
+ if (err) {
30
+ reject(err);
31
+ return;
32
+ }
33
+
34
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
35
+ resolve(tokens.access_token as string);
36
+ });
37
+ });
38
+ }
39
+
40
+ private static getAPNProvider(): Provider {
41
+ return new apn.Provider({
42
+ token: {
43
+ key: process.env.APN_KEY_PATH as string,
44
+ keyId: process.env.NOTIFICATIONS_KEY_ID as string,
45
+ teamId: process.env.NOTIFICATIONS_TEAM_ID as string,
46
+ },
47
+ production: true,
48
+ });
49
+ }
50
+
51
+ public static async sendAppleNotification(
52
+ notification: apn.Notification,
53
+ token: string | string[]
54
+ ) {
55
+ try {
56
+ await this.apnProvider.send(notification, token);
57
+ } catch (e) {
58
+ console.error(
59
+ `ERROR: Could not send apple notification: ${(e as Error).message}`
60
+ );
61
+ }
62
+ }
63
+
64
+ public static async sendAndroidNotification(notification: AndroidMessage) {
65
+ try {
66
+ await axios.post(
67
+ "https://fcm.googleapis.com/v1/projects/dayschallenge-373510/messages:send",
68
+ notification,
69
+ {
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ Authorization: `Bearer ${await this.getAccessToken()}`,
73
+ },
74
+ }
75
+ );
76
+ } catch (e) {
77
+ if (isAxiosError(e)) {
78
+ console.error(
79
+ `ERROR: Could not send android notification: ${(e as Error).message}`
80
+ );
81
+ }
82
+ }
83
+ }
84
+
85
+ private static buildAppleNotification(notificationReq: NotificationRequest) {
86
+ const notification: apn.Notification = new apn.Notification();
87
+ notification.topic = process.env.APPLE_BUNDLE_ID as string;
88
+ notification.priority = 10;
89
+ notification.expiry = Math.floor(Date.now() / 1000) + 3600;
90
+ notification.rawPayload = {
91
+ aps: {
92
+ alert: {
93
+ title: notificationReq.title,
94
+ body: notificationReq.body,
95
+ },
96
+ "content-available": 1,
97
+ sound: "default",
98
+ redirectPath: notificationReq.redirectPath,
99
+ },
100
+ };
101
+ return notification;
102
+ }
103
+
104
+ private static buildAndroidNotification(
105
+ notificationReq: NotificationRequest,
106
+ token: string | string[]
107
+ ): AndroidMessage {
108
+ if (Array.isArray(token)) {
109
+ return {
110
+ message: {
111
+ token: token,
112
+ notification: {
113
+ title: notificationReq.title,
114
+ body: notificationReq.body,
115
+ },
116
+ },
117
+ };
118
+ }
119
+
120
+ return {
121
+ message: {
122
+ token: token,
123
+ notification: {
124
+ title: notificationReq.title,
125
+ body: notificationReq.body,
126
+ },
127
+ },
128
+ };
129
+ }
130
+
131
+
132
+ public static async sendNotification(
133
+ userUuid: string,
134
+ notification: NotificationRequest
135
+ ) {
136
+ const deviceToken: DeviceTokens | null = await DeviceTokens.findOne({
137
+ where: { userUuid: userUuid },
138
+ raw: true,
139
+ });
140
+
141
+ if (!deviceToken) {
142
+ console.error(`ERROR: No token found for user ${userUuid}}`);
143
+ return;
144
+ }
145
+
146
+ deviceToken.platform === "ios"
147
+ ? await this.sendAppleNotification(
148
+ this.buildAppleNotification(notification),
149
+ deviceToken.deviceToken
150
+ )
151
+ : await this.sendAndroidNotification(
152
+ this.buildAndroidNotification(notification, deviceToken.deviceToken)
153
+ );
154
+ }
155
+
156
+ public static calculateDelayUntil10AM(timeZone: string, additionalDelay = 0) {
157
+ const now = new Date(new Date().toLocaleString("en-US", { timeZone }));
158
+
159
+ // Create a Date object for 10 AM today in the user's time zone
160
+ const next10AM = new Date(now);
161
+ next10AM.setHours(10, 0, 0, 0);
162
+
163
+ // If the current time is past 10 AM, set the next 10 AM to tomorrow
164
+ if (now.getTime() > next10AM.getTime()) {
165
+ next10AM.setDate(next10AM.getDate() + 1);
166
+ }
167
+ next10AM.setDate(next10AM.getDate() + additionalDelay);
168
+ // Calculate the delay in milliseconds
169
+ return next10AM.getTime() - now.getTime();
170
+ }
171
+
172
+ public static calculateDelayUntil6PM(timeZone: string) {
173
+ // Get the current date and time in the user's time zone
174
+ const now = new Date(new Date().toLocaleString("en-US", { timeZone }));
175
+
176
+ // Create a Date object for 6 PM today in the user's time zone
177
+ const next6PM = new Date(now);
178
+ next6PM.setHours(18, 0, 0, 0);
179
+
180
+ // If the current time is past 6 PM, set the next 6 PM to tomorrow
181
+ if (now.getTime() > next6PM.getTime()) {
182
+ next6PM.setDate(next6PM.getDate() + 1);
183
+ }
184
+
185
+ // Calculate the delay in milliseconds
186
+ return next6PM.getTime() - now.getTime();
187
+ }
188
+ }
package/tsconfig.json CHANGED
@@ -23,7 +23,7 @@
23
23
  "noImplicitAny": true,
24
24
  "noImplicitOverride": true,
25
25
  "noImplicitReturns": true,
26
- "noUnusedLocals": true,
26
+ "noUnusedLocals": false,
27
27
  "noUnusedParameters": true,
28
28
  "importsNotUsedAsValues": "error",
29
29
  "allowJs": false,