@lyxa.ai/marketing 1.0.49 → 1.0.50

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 (211) hide show
  1. package/dist/lib/index.d.ts +236 -17
  2. package/dist/lib/index.d.ts.map +1 -1
  3. package/dist/lib/modules/tournament/config/config.repository.d.ts +3 -0
  4. package/dist/lib/modules/tournament/config/config.repository.d.ts.map +1 -1
  5. package/dist/lib/modules/tournament/config/config.repository.js +3 -0
  6. package/dist/lib/modules/tournament/config/config.repository.js.map +1 -1
  7. package/dist/lib/modules/tournament/config/config.router.d.ts +10 -10
  8. package/dist/lib/modules/tournament/config/config.validation.d.ts +37 -36
  9. package/dist/lib/modules/tournament/config/config.validation.d.ts.map +1 -1
  10. package/dist/lib/modules/tournament/config/config.validation.js +4 -3
  11. package/dist/lib/modules/tournament/config/config.validation.js.map +1 -1
  12. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.d.ts.map +1 -1
  13. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js +9 -1
  14. package/dist/lib/modules/tournament/match/events/evaluate-predictions.consumer.js.map +1 -1
  15. package/dist/lib/modules/tournament/match/match.builder.d.ts.map +1 -1
  16. package/dist/lib/modules/tournament/match/match.builder.js +2 -1
  17. package/dist/lib/modules/tournament/match/match.builder.js.map +1 -1
  18. package/dist/lib/modules/tournament/match/match.repository.d.ts +2 -0
  19. package/dist/lib/modules/tournament/match/match.repository.d.ts.map +1 -1
  20. package/dist/lib/modules/tournament/match/match.repository.js +10 -0
  21. package/dist/lib/modules/tournament/match/match.repository.js.map +1 -1
  22. package/dist/lib/modules/tournament/match/match.router.d.ts +16 -4
  23. package/dist/lib/modules/tournament/match/match.router.d.ts.map +1 -1
  24. package/dist/lib/modules/tournament/match/match.service.d.ts +0 -1
  25. package/dist/lib/modules/tournament/match/match.service.d.ts.map +1 -1
  26. package/dist/lib/modules/tournament/match/match.service.js +3 -9
  27. package/dist/lib/modules/tournament/match/match.service.js.map +1 -1
  28. package/dist/lib/modules/tournament/match/match.validation.d.ts +50 -0
  29. package/dist/lib/modules/tournament/match/match.validation.d.ts.map +1 -1
  30. package/dist/lib/modules/tournament/match/match.validation.js +1 -0
  31. package/dist/lib/modules/tournament/match/match.validation.js.map +1 -1
  32. package/dist/lib/modules/tournament/notification/jobs/notification.producer.d.ts +2 -5
  33. package/dist/lib/modules/tournament/notification/jobs/notification.producer.d.ts.map +1 -1
  34. package/dist/lib/modules/tournament/notification/jobs/notification.producer.js +1 -6
  35. package/dist/lib/modules/tournament/notification/jobs/notification.producer.js.map +1 -1
  36. package/dist/lib/modules/tournament/notification/jobs/notification.worker.d.ts +2 -0
  37. package/dist/lib/modules/tournament/notification/jobs/notification.worker.d.ts.map +1 -1
  38. package/dist/lib/modules/tournament/notification/jobs/notification.worker.js +15 -9
  39. package/dist/lib/modules/tournament/notification/jobs/notification.worker.js.map +1 -1
  40. package/dist/lib/modules/tournament/notification/notification-template.repository.d.ts +8 -0
  41. package/dist/lib/modules/tournament/notification/notification-template.repository.d.ts.map +1 -0
  42. package/dist/lib/modules/tournament/notification/notification-template.repository.js +60 -0
  43. package/dist/lib/modules/tournament/notification/notification-template.repository.js.map +1 -0
  44. package/dist/lib/modules/tournament/notification/notification.config.d.ts +10 -0
  45. package/dist/lib/modules/tournament/notification/notification.config.d.ts.map +1 -0
  46. package/dist/lib/modules/tournament/notification/notification.config.js +15 -0
  47. package/dist/lib/modules/tournament/notification/notification.config.js.map +1 -0
  48. package/dist/lib/modules/tournament/notification/notification.schedule.config.d.ts +10 -0
  49. package/dist/lib/modules/tournament/notification/notification.schedule.config.d.ts.map +1 -0
  50. package/dist/lib/modules/tournament/notification/notification.schedule.config.js +15 -0
  51. package/dist/lib/modules/tournament/notification/notification.schedule.config.js.map +1 -0
  52. package/dist/lib/modules/tournament/notification/notification.scheduler.service.d.ts +4 -4
  53. package/dist/lib/modules/tournament/notification/notification.scheduler.service.d.ts.map +1 -1
  54. package/dist/lib/modules/tournament/notification/notification.scheduler.service.js +15 -28
  55. package/dist/lib/modules/tournament/notification/notification.scheduler.service.js.map +1 -1
  56. package/dist/lib/modules/tournament/notification/notification.service.d.ts +5 -4
  57. package/dist/lib/modules/tournament/notification/notification.service.d.ts.map +1 -1
  58. package/dist/lib/modules/tournament/notification/notification.service.js +33 -28
  59. package/dist/lib/modules/tournament/notification/notification.service.js.map +1 -1
  60. package/dist/lib/modules/tournament/participant/participant.repository.d.ts +1 -0
  61. package/dist/lib/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  62. package/dist/lib/modules/tournament/participant/participant.repository.js +6 -0
  63. package/dist/lib/modules/tournament/participant/participant.repository.js.map +1 -1
  64. package/dist/lib/modules/tournament/prediction/prediction.builder.d.ts.map +1 -1
  65. package/dist/lib/modules/tournament/prediction/prediction.builder.js +3 -2
  66. package/dist/lib/modules/tournament/prediction/prediction.builder.js.map +1 -1
  67. package/dist/lib/modules/tournament/prediction/prediction.service.d.ts +1 -0
  68. package/dist/lib/modules/tournament/prediction/prediction.service.d.ts.map +1 -1
  69. package/dist/lib/modules/tournament/prediction/prediction.service.js +10 -1
  70. package/dist/lib/modules/tournament/prediction/prediction.service.js.map +1 -1
  71. package/dist/lib/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  72. package/dist/lib/modules/tournament/reward/reward.builder.js +2 -1
  73. package/dist/lib/modules/tournament/reward/reward.builder.js.map +1 -1
  74. package/dist/lib/modules/tournament/reward/reward.repository.d.ts +8 -0
  75. package/dist/lib/modules/tournament/reward/reward.repository.d.ts.map +1 -0
  76. package/dist/lib/modules/tournament/reward/reward.repository.js +66 -0
  77. package/dist/lib/modules/tournament/reward/reward.repository.js.map +1 -0
  78. package/dist/lib/modules/tournament/schedule/schedule.router.d.ts +27 -0
  79. package/dist/lib/modules/tournament/schedule/schedule.router.d.ts.map +1 -0
  80. package/dist/lib/modules/tournament/schedule/schedule.router.js +17 -0
  81. package/dist/lib/modules/tournament/schedule/schedule.router.js.map +1 -0
  82. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts +10 -0
  83. package/dist/lib/modules/tournament/schedule/schedule.service.d.ts.map +1 -0
  84. package/dist/lib/modules/tournament/schedule/schedule.service.js +87 -0
  85. package/dist/lib/modules/tournament/schedule/schedule.service.js.map +1 -0
  86. package/dist/lib/modules/tournament/score/score.repository.d.ts +8 -1
  87. package/dist/lib/modules/tournament/score/score.repository.d.ts.map +1 -1
  88. package/dist/lib/modules/tournament/score/score.repository.js +12 -2
  89. package/dist/lib/modules/tournament/score/score.repository.js.map +1 -1
  90. package/dist/lib/modules/tournament/score/score.router.d.ts +98 -0
  91. package/dist/lib/modules/tournament/score/score.router.d.ts.map +1 -0
  92. package/dist/lib/modules/tournament/score/score.router.js +20 -0
  93. package/dist/lib/modules/tournament/score/score.router.js.map +1 -0
  94. package/dist/lib/modules/tournament/score/score.service.d.ts +7 -0
  95. package/dist/lib/modules/tournament/score/score.service.d.ts.map +1 -1
  96. package/dist/lib/modules/tournament/score/score.service.js +49 -0
  97. package/dist/lib/modules/tournament/score/score.service.js.map +1 -1
  98. package/dist/lib/modules/tournament/score/score.validation.d.ts +375 -0
  99. package/dist/lib/modules/tournament/score/score.validation.d.ts.map +1 -0
  100. package/dist/lib/modules/tournament/score/score.validation.js +19 -0
  101. package/dist/lib/modules/tournament/score/score.validation.js.map +1 -0
  102. package/dist/lib/modules/tournament/statistics/statistics.builder.d.ts +10 -0
  103. package/dist/lib/modules/tournament/statistics/statistics.builder.d.ts.map +1 -0
  104. package/dist/lib/modules/tournament/statistics/statistics.builder.js +53 -0
  105. package/dist/lib/modules/tournament/statistics/statistics.builder.js.map +1 -0
  106. package/dist/lib/modules/tournament/statistics/statistics.router.d.ts +80 -0
  107. package/dist/lib/modules/tournament/statistics/statistics.router.d.ts.map +1 -0
  108. package/dist/lib/modules/tournament/statistics/statistics.router.js +21 -0
  109. package/dist/lib/modules/tournament/statistics/statistics.router.js.map +1 -0
  110. package/dist/lib/modules/tournament/statistics/statistics.service.d.ts +11 -0
  111. package/dist/lib/modules/tournament/statistics/statistics.service.d.ts.map +1 -0
  112. package/dist/lib/modules/tournament/statistics/statistics.service.js +80 -0
  113. package/dist/lib/modules/tournament/statistics/statistics.service.js.map +1 -0
  114. package/dist/lib/modules/tournament/statistics/statistics.validation.d.ts +404 -0
  115. package/dist/lib/modules/tournament/statistics/statistics.validation.d.ts.map +1 -0
  116. package/dist/lib/modules/tournament/statistics/statistics.validation.js +36 -0
  117. package/dist/lib/modules/tournament/statistics/statistics.validation.js.map +1 -0
  118. package/dist/lib/modules/tournament/team/team.router.d.ts +9 -3
  119. package/dist/lib/modules/tournament/team/team.router.d.ts.map +1 -1
  120. package/dist/lib/modules/tournament/team/team.service.d.ts +1 -0
  121. package/dist/lib/modules/tournament/team/team.service.d.ts.map +1 -1
  122. package/dist/lib/modules/tournament/team/team.service.js +21 -16
  123. package/dist/lib/modules/tournament/team/team.service.js.map +1 -1
  124. package/dist/lib/modules/tournament/team/team.validation.d.ts +54 -4
  125. package/dist/lib/modules/tournament/team/team.validation.d.ts.map +1 -1
  126. package/dist/lib/modules/tournament/team/team.validation.js +4 -2
  127. package/dist/lib/modules/tournament/team/team.validation.js.map +1 -1
  128. package/dist/lib/modules/tournament/tournament.router.d.ts +236 -17
  129. package/dist/lib/modules/tournament/tournament.router.d.ts.map +1 -1
  130. package/dist/lib/modules/tournament/tournament.router.js +6 -0
  131. package/dist/lib/modules/tournament/tournament.router.js.map +1 -1
  132. package/dist/lib/modules/tournament/tournament.types.d.ts +9 -0
  133. package/dist/lib/modules/tournament/tournament.types.d.ts.map +1 -0
  134. package/dist/lib/modules/tournament/tournament.types.js +14 -0
  135. package/dist/lib/modules/tournament/tournament.types.js.map +1 -0
  136. package/dist/lib/modules/tournament/tournament.utils.d.ts +2 -0
  137. package/dist/lib/modules/tournament/tournament.utils.d.ts.map +1 -0
  138. package/dist/lib/modules/tournament/tournament.utils.js +6 -0
  139. package/dist/lib/modules/tournament/tournament.utils.js.map +1 -0
  140. package/dist/types/index.d.ts +236 -17
  141. package/dist/types/index.d.ts.map +1 -1
  142. package/dist/types/modules/tournament/config/config.repository.d.ts +3 -0
  143. package/dist/types/modules/tournament/config/config.repository.d.ts.map +1 -1
  144. package/dist/types/modules/tournament/config/config.router.d.ts +10 -10
  145. package/dist/types/modules/tournament/config/config.validation.d.ts +37 -36
  146. package/dist/types/modules/tournament/config/config.validation.d.ts.map +1 -1
  147. package/dist/types/modules/tournament/match/events/evaluate-predictions.consumer.d.ts.map +1 -1
  148. package/dist/types/modules/tournament/match/match.builder.d.ts.map +1 -1
  149. package/dist/types/modules/tournament/match/match.repository.d.ts +2 -0
  150. package/dist/types/modules/tournament/match/match.repository.d.ts.map +1 -1
  151. package/dist/types/modules/tournament/match/match.router.d.ts +16 -4
  152. package/dist/types/modules/tournament/match/match.router.d.ts.map +1 -1
  153. package/dist/types/modules/tournament/match/match.service.d.ts +0 -1
  154. package/dist/types/modules/tournament/match/match.service.d.ts.map +1 -1
  155. package/dist/types/modules/tournament/match/match.validation.d.ts +50 -0
  156. package/dist/types/modules/tournament/match/match.validation.d.ts.map +1 -1
  157. package/dist/types/modules/tournament/notification/jobs/notification.producer.d.ts +2 -5
  158. package/dist/types/modules/tournament/notification/jobs/notification.producer.d.ts.map +1 -1
  159. package/dist/types/modules/tournament/notification/jobs/notification.worker.d.ts +2 -0
  160. package/dist/types/modules/tournament/notification/jobs/notification.worker.d.ts.map +1 -1
  161. package/dist/types/modules/tournament/notification/notification-template.repository.d.ts +8 -0
  162. package/dist/types/modules/tournament/notification/notification-template.repository.d.ts.map +1 -0
  163. package/dist/types/modules/tournament/notification/notification.config.d.ts +10 -0
  164. package/dist/types/modules/tournament/notification/notification.config.d.ts.map +1 -0
  165. package/dist/types/modules/tournament/notification/notification.schedule.config.d.ts +10 -0
  166. package/dist/types/modules/tournament/notification/notification.schedule.config.d.ts.map +1 -0
  167. package/dist/types/modules/tournament/notification/notification.scheduler.service.d.ts +4 -4
  168. package/dist/types/modules/tournament/notification/notification.scheduler.service.d.ts.map +1 -1
  169. package/dist/types/modules/tournament/notification/notification.service.d.ts +5 -4
  170. package/dist/types/modules/tournament/notification/notification.service.d.ts.map +1 -1
  171. package/dist/types/modules/tournament/participant/participant.repository.d.ts +1 -0
  172. package/dist/types/modules/tournament/participant/participant.repository.d.ts.map +1 -1
  173. package/dist/types/modules/tournament/prediction/prediction.builder.d.ts.map +1 -1
  174. package/dist/types/modules/tournament/prediction/prediction.service.d.ts +1 -0
  175. package/dist/types/modules/tournament/prediction/prediction.service.d.ts.map +1 -1
  176. package/dist/types/modules/tournament/reward/reward.builder.d.ts.map +1 -1
  177. package/dist/types/modules/tournament/reward/reward.repository.d.ts +8 -0
  178. package/dist/types/modules/tournament/reward/reward.repository.d.ts.map +1 -0
  179. package/dist/types/modules/tournament/schedule/schedule.router.d.ts +27 -0
  180. package/dist/types/modules/tournament/schedule/schedule.router.d.ts.map +1 -0
  181. package/dist/types/modules/tournament/schedule/schedule.service.d.ts +10 -0
  182. package/dist/types/modules/tournament/schedule/schedule.service.d.ts.map +1 -0
  183. package/dist/types/modules/tournament/score/score.repository.d.ts +8 -1
  184. package/dist/types/modules/tournament/score/score.repository.d.ts.map +1 -1
  185. package/dist/types/modules/tournament/score/score.router.d.ts +98 -0
  186. package/dist/types/modules/tournament/score/score.router.d.ts.map +1 -0
  187. package/dist/types/modules/tournament/score/score.service.d.ts +7 -0
  188. package/dist/types/modules/tournament/score/score.service.d.ts.map +1 -1
  189. package/dist/types/modules/tournament/score/score.validation.d.ts +375 -0
  190. package/dist/types/modules/tournament/score/score.validation.d.ts.map +1 -0
  191. package/dist/types/modules/tournament/statistics/statistics.builder.d.ts +10 -0
  192. package/dist/types/modules/tournament/statistics/statistics.builder.d.ts.map +1 -0
  193. package/dist/types/modules/tournament/statistics/statistics.router.d.ts +80 -0
  194. package/dist/types/modules/tournament/statistics/statistics.router.d.ts.map +1 -0
  195. package/dist/types/modules/tournament/statistics/statistics.service.d.ts +11 -0
  196. package/dist/types/modules/tournament/statistics/statistics.service.d.ts.map +1 -0
  197. package/dist/types/modules/tournament/statistics/statistics.validation.d.ts +404 -0
  198. package/dist/types/modules/tournament/statistics/statistics.validation.d.ts.map +1 -0
  199. package/dist/types/modules/tournament/team/team.router.d.ts +9 -3
  200. package/dist/types/modules/tournament/team/team.router.d.ts.map +1 -1
  201. package/dist/types/modules/tournament/team/team.service.d.ts +1 -0
  202. package/dist/types/modules/tournament/team/team.service.d.ts.map +1 -1
  203. package/dist/types/modules/tournament/team/team.validation.d.ts +54 -4
  204. package/dist/types/modules/tournament/team/team.validation.d.ts.map +1 -1
  205. package/dist/types/modules/tournament/tournament.router.d.ts +236 -17
  206. package/dist/types/modules/tournament/tournament.router.d.ts.map +1 -1
  207. package/dist/types/modules/tournament/tournament.types.d.ts +9 -0
  208. package/dist/types/modules/tournament/tournament.types.d.ts.map +1 -0
  209. package/dist/types/modules/tournament/tournament.utils.d.ts +2 -0
  210. package/dist/types/modules/tournament/tournament.utils.d.ts.map +1 -0
  211. package/package.json +2 -2
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScheduledTarget = exports.NotificationTag = void 0;
4
+ var NotificationTag;
5
+ (function (NotificationTag) {
6
+ NotificationTag["TOURNAMENT_ACTIVATION"] = "tournament-activation";
7
+ NotificationTag["MATCH_RESULT_WINNER"] = "match-result-winner";
8
+ NotificationTag["MATCH_RESULT_LOSER"] = "match-result-loser";
9
+ })(NotificationTag || (exports.NotificationTag = NotificationTag = {}));
10
+ var ScheduledTarget;
11
+ (function (ScheduledTarget) {
12
+ ScheduledTarget["GLOBAL"] = "global";
13
+ ScheduledTarget["UNPREDICTED_PARTICIPANTS"] = "unpredicted-participants";
14
+ })(ScheduledTarget || (exports.ScheduledTarget = ScheduledTarget = {}));
15
+ //# sourceMappingURL=notification.schedule.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.schedule.config.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.schedule.config.ts"],"names":[],"mappings":";;;AAAA,IAAY,eAIX;AAJD,WAAY,eAAe;IACvB,kEAA+C,CAAA;IAC/C,8DAA2C,CAAA;IAC3C,4DAAyC,CAAA;AAC7C,CAAC,EAJW,eAAe,+BAAf,eAAe,QAI1B;AAED,IAAY,eAGX;AAHD,WAAY,eAAe;IACvB,oCAAiB,CAAA;IACjB,wEAAqD,CAAA;AACzD,CAAC,EAHW,eAAe,+BAAf,eAAe,QAG1B","sourcesContent":["export enum NotificationTag {\n TOURNAMENT_ACTIVATION = 'tournament-activation',\n MATCH_RESULT_WINNER = 'match-result-winner',\n MATCH_RESULT_LOSER = 'match-result-loser',\n}\n\nexport enum ScheduledTarget {\n GLOBAL = 'global',\n UNPREDICTED_PARTICIPANTS = 'unpredicted-participants',\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { mongoose } from '@typegoose/typegoose';
2
+ import { ScheduledNotificationConfig } from '@lyxa.ai/core/dist/libraries/mongo/models';
2
3
  export declare class NotificationSchedulerService {
3
- private jobId3h;
4
- private jobId15min;
4
+ private jobId;
5
5
  private buildJobData;
6
- scheduleForMatch(matchId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId, startingDate: Date): Promise<void>;
7
- cancelForMatch(matchId: mongoose.Types.ObjectId): Promise<void>;
6
+ scheduleForMatch(matchId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId, startingDate: Date, scheduledNotifications: ScheduledNotificationConfig[]): Promise<void>;
7
+ cancelForMatch(matchId: mongoose.Types.ObjectId, scheduledNotifications: ScheduledNotificationConfig[]): Promise<void>;
8
8
  }
9
9
  export declare const notificationSchedulerService: NotificationSchedulerService;
10
10
  //# sourceMappingURL=notification.scheduler.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notification.scheduler.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.scheduler.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAWhD,qBACa,4BAA4B;IACrC,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAIP,gBAAgB,CACzB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,YAAY,EAAE,IAAI,GACnB,OAAO,CAAC,IAAI,CAAC;IAsBH,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CAI/E;AAED,eAAO,MAAM,4BAA4B,8BAA8C,CAAC"}
1
+ {"version":3,"file":"notification.scheduler.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.scheduler.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AAGxF,qBACa,4BAA4B;IACrC,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,YAAY;IAIP,gBAAgB,CACzB,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,YAAY,EAAE,IAAI,EAClB,sBAAsB,EAAE,2BAA2B,EAAE,GACtD,OAAO,CAAC,IAAI,CAAC;IAcH,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtI;AAED,eAAO,MAAM,4BAA4B,8BAA8C,CAAC"}
@@ -42,40 +42,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.notificationSchedulerService = exports.NotificationSchedulerService = void 0;
43
43
  const typedi_1 = __importStar(require("typedi"));
44
44
  const notification_producer_1 = require("./jobs/notification.producer");
45
- const THREE_HOURS_MS = 3 * 60 * 60 * 1000;
46
- const FIFTEEN_MINUTES_MS = 15 * 60 * 1000;
47
45
  let NotificationSchedulerService = class NotificationSchedulerService {
48
- jobId3h(matchId) {
49
- return `tournament-notify-3h-${matchId}`;
46
+ jobId(type, matchId) {
47
+ return `tournament-${type}-${matchId}`;
50
48
  }
51
- jobId15min(matchId) {
52
- return `tournament-notify-15min-${matchId}`;
49
+ buildJobData(tournamentId, matchId, target) {
50
+ return { tournamentId: tournamentId.toString(), matchId: matchId.toString(), target };
53
51
  }
54
- buildJobData(tournamentId, matchId) {
55
- return { tournamentId: tournamentId.toString(), matchId: matchId.toString() };
56
- }
57
- async scheduleForMatch(matchId, tournamentId, startingDate) {
58
- const data = this.buildJobData(tournamentId, matchId);
59
- const delay3h = startingDate.getTime() - THREE_HOURS_MS - Date.now();
60
- if (delay3h > 0) {
61
- await (0, notification_producer_1.addNotificationJob)(notification_producer_1.TournamentNotificationJobName.NOTIFY_3H_BEFORE, data, {
62
- delay: delay3h,
63
- jobId: this.jobId3h(matchId),
64
- removeOnComplete: true,
65
- });
66
- }
67
- const delay15min = startingDate.getTime() - FIFTEEN_MINUTES_MS - Date.now();
68
- if (delay15min > 0) {
69
- await (0, notification_producer_1.addNotificationJob)(notification_producer_1.TournamentNotificationJobName.NOTIFY_15MIN_BEFORE, data, {
70
- delay: delay15min,
71
- jobId: this.jobId15min(matchId),
52
+ async scheduleForMatch(matchId, tournamentId, startingDate, scheduledNotifications) {
53
+ await Promise.all(scheduledNotifications.map(({ type, durationMins, target }) => {
54
+ const delay = startingDate.getTime() - durationMins * 60 * 1000 - Date.now();
55
+ if (delay <= 0)
56
+ return Promise.resolve();
57
+ return (0, notification_producer_1.addNotificationJob)(type, this.buildJobData(tournamentId, matchId, target), {
58
+ delay,
59
+ jobId: this.jobId(type, matchId),
72
60
  removeOnComplete: true,
73
61
  });
74
- }
62
+ }));
75
63
  }
76
- async cancelForMatch(matchId) {
77
- await (0, notification_producer_1.removeNotificationJob)(this.jobId3h(matchId));
78
- await (0, notification_producer_1.removeNotificationJob)(this.jobId15min(matchId));
64
+ async cancelForMatch(matchId, scheduledNotifications) {
65
+ await Promise.all(scheduledNotifications.map(({ type }) => (0, notification_producer_1.removeNotificationJob)(this.jobId(type, matchId))));
79
66
  }
80
67
  };
81
68
  exports.NotificationSchedulerService = NotificationSchedulerService;
@@ -1 +1 @@
1
- {"version":3,"file":"notification.scheduler.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.scheduler.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAE5C,wEAKsC;AAEtC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC1C,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAGnC,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAC7B,OAAO,CAAC,OAAgC;QAC5C,OAAO,wBAAwB,OAAO,EAAE,CAAC;IAC7C,CAAC;IAEO,UAAU,CAAC,OAAgC;QAC/C,OAAO,2BAA2B,OAAO,EAAE,CAAC;IAChD,CAAC;IAEO,YAAY,CAAC,YAAqC,EAAE,OAAgC;QACxF,OAAO,EAAE,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;IAClF,CAAC;IAEM,KAAK,CAAC,gBAAgB,CACzB,OAAgC,EAChC,YAAqC,EACrC,YAAkB;QAElB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAEtD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACrE,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,IAAA,0CAAkB,EAAC,qDAA6B,CAAC,gBAAgB,EAAE,IAAI,EAAE;gBAC3E,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC5B,gBAAgB,EAAE,IAAI;aACzB,CAAC,CAAC;QACP,CAAC;QAED,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5E,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,IAAA,0CAAkB,EAAC,qDAA6B,CAAC,mBAAmB,EAAE,IAAI,EAAE;gBAC9E,KAAK,EAAE,UAAU;gBACjB,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAC/B,gBAAgB,EAAE,IAAI;aACzB,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,OAAgC;QACxD,MAAM,IAAA,6CAAqB,EAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,MAAM,IAAA,6CAAqB,EAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;CACJ,CAAA;AA3CY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,gBAAO,GAAE;GACG,4BAA4B,CA2CxC;AAEY,QAAA,4BAA4B,GAAG,gBAAS,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport {\n TournamentNotificationJobName,\n TournamentNotificationJobData,\n addNotificationJob,\n removeNotificationJob,\n} from './jobs/notification.producer';\n\nconst THREE_HOURS_MS = 3 * 60 * 60 * 1000;\nconst FIFTEEN_MINUTES_MS = 15 * 60 * 1000;\n\n@Service()\nexport class NotificationSchedulerService {\n private jobId3h(matchId: mongoose.Types.ObjectId): string {\n return `tournament-notify-3h-${matchId}`;\n }\n\n private jobId15min(matchId: mongoose.Types.ObjectId): string {\n return `tournament-notify-15min-${matchId}`;\n }\n\n private buildJobData(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId): TournamentNotificationJobData {\n return { tournamentId: tournamentId.toString(), matchId: matchId.toString() };\n }\n\n public async scheduleForMatch(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n startingDate: Date\n ): Promise<void> {\n const data = this.buildJobData(tournamentId, matchId);\n\n const delay3h = startingDate.getTime() - THREE_HOURS_MS - Date.now();\n if (delay3h > 0) {\n await addNotificationJob(TournamentNotificationJobName.NOTIFY_3H_BEFORE, data, {\n delay: delay3h,\n jobId: this.jobId3h(matchId),\n removeOnComplete: true,\n });\n }\n\n const delay15min = startingDate.getTime() - FIFTEEN_MINUTES_MS - Date.now();\n if (delay15min > 0) {\n await addNotificationJob(TournamentNotificationJobName.NOTIFY_15MIN_BEFORE, data, {\n delay: delay15min,\n jobId: this.jobId15min(matchId),\n removeOnComplete: true,\n });\n }\n }\n\n public async cancelForMatch(matchId: mongoose.Types.ObjectId): Promise<void> {\n await removeNotificationJob(this.jobId3h(matchId));\n await removeNotificationJob(this.jobId15min(matchId));\n }\n}\n\nexport const notificationSchedulerService = Container.get(NotificationSchedulerService);\n"]}
1
+ {"version":3,"file":"notification.scheduler.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.scheduler.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAG5C,wEAAwH;AAGjH,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAC7B,KAAK,CAAC,IAAY,EAAE,OAAgC;QACxD,OAAO,cAAc,IAAI,IAAI,OAAO,EAAE,CAAC;IAC3C,CAAC;IAEO,YAAY,CAAC,YAAqC,EAAE,OAAgC,EAAE,MAAc;QACxG,OAAO,EAAE,YAAY,EAAE,YAAY,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC;IAC1F,CAAC;IAEM,KAAK,CAAC,gBAAgB,CACzB,OAAgC,EAChC,YAAqC,EACrC,YAAkB,EAClB,sBAAqD;QAErD,MAAM,OAAO,CAAC,GAAG,CACb,sBAAsB,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE;YAC1D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,YAAY,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7E,IAAI,KAAK,IAAI,CAAC;gBAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,OAAO,IAAA,0CAAkB,EAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE;gBAC9E,KAAK;gBACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;gBAChC,gBAAgB,EAAE,IAAI;aACzB,CAAC,CAAC;QACP,CAAC,CAAC,CACL,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,OAAgC,EAAE,sBAAqD;QAC/G,MAAM,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAA,6CAAqB,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAClH,CAAC;CACJ,CAAA;AA/BY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,gBAAO,GAAE;GACG,4BAA4B,CA+BxC;AAEY,QAAA,4BAA4B,GAAG,gBAAS,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport { ScheduledNotificationConfig } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { addNotificationJob, removeNotificationJob, TournamentNotificationJobData } from './jobs/notification.producer';\n\n@Service()\nexport class NotificationSchedulerService {\n private jobId(type: string, matchId: mongoose.Types.ObjectId): string {\n return `tournament-${type}-${matchId}`;\n }\n\n private buildJobData(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId, target: string): TournamentNotificationJobData {\n return { tournamentId: tournamentId.toString(), matchId: matchId.toString(), target };\n }\n\n public async scheduleForMatch(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n startingDate: Date,\n scheduledNotifications: ScheduledNotificationConfig[]\n ): Promise<void> {\n await Promise.all(\n scheduledNotifications.map(({ type, durationMins, target }) => {\n const delay = startingDate.getTime() - durationMins * 60 * 1000 - Date.now();\n if (delay <= 0) return Promise.resolve();\n return addNotificationJob(type, this.buildJobData(tournamentId, matchId, target), {\n delay,\n jobId: this.jobId(type, matchId),\n removeOnComplete: true,\n });\n })\n );\n }\n\n public async cancelForMatch(matchId: mongoose.Types.ObjectId, scheduledNotifications: ScheduledNotificationConfig[]): Promise<void> {\n await Promise.all(scheduledNotifications.map(({ type }) => removeNotificationJob(this.jobId(type, matchId))));\n }\n}\n\nexport const notificationSchedulerService = Container.get(NotificationSchedulerService);\n"]}
@@ -1,12 +1,13 @@
1
1
  import { mongoose } from '@typegoose/typegoose';
2
+ import { NotificationMessage } from '@lyxa.ai/core/dist/libraries/mongo/models';
2
3
  export declare class TournamentNotificationService {
3
4
  private participantService;
4
5
  constructor();
6
+ private getTemplate;
5
7
  private hasNotPredicted;
6
- private publishNotification;
7
- notifyUnpredictedParticipants(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId, type: 'before3h' | 'before15min'): Promise<void>;
8
- private readonly matchResultTemplates;
9
- notifyMatchResult(winnerIds: mongoose.Types.ObjectId[], loserIds: mongoose.Types.ObjectId[]): Promise<void>;
8
+ notifyGlobal(title: string, body: string): Promise<void>;
9
+ notifyUsers(title: string, body: string, userIds: mongoose.Types.ObjectId[]): Promise<void>;
10
+ dispatchScheduledJob(type: string, target: string, templates: Map<string, NotificationMessage>, tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId): Promise<void>;
10
11
  }
11
12
  export declare const tournamentNotificationService: TournamentNotificationService;
12
13
  //# sourceMappingURL=notification.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"notification.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOhD,qBACa,6BAA6B;IACtC,OAAO,CAAC,kBAAkB,CAAqB;;IAM/C,OAAO,CAAC,eAAe;YAIT,mBAAmB;IAqBpB,6BAA6B,CACtC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,IAAI,EAAE,UAAU,GAAG,aAAa,GACjC,OAAO,CAAC,IAAI,CAAC;IAahB,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CASnC;IAEW,iBAAiB,CAC1B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,EACpC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GACpC,OAAO,CAAC,IAAI,CAAC;CAOnB;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}
1
+ {"version":3,"file":"notification.service.d.ts","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAI9C,OAAO,EAAC,mBAAmB,EAAC,MAAM,2CAA2C,CAAC;AAK9E,qBACa,6BAA6B;IACtC,OAAO,CAAC,kBAAkB,CAAqB;;IAM/C,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,eAAe;IAIV,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB3F,oBAAoB,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EAC3C,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACjC,OAAO,CAAC,IAAI,CAAC;CAWnB;AAED,eAAO,MAAM,6BAA6B,+BAA+C,CAAC"}
@@ -48,53 +48,58 @@ const event_1 = require("@lyxa.ai/core/dist/libraries/event");
48
48
  const notification_1 = require("@lyxa.ai/core/dist/libraries/notification");
49
49
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
50
50
  const participant_service_1 = require("../participant/participant.service");
51
+ const notification_config_1 = require("./notification.config");
51
52
  let TournamentNotificationService = class TournamentNotificationService {
52
53
  participantService;
53
54
  constructor() {
54
55
  this.participantService = typedi_1.default.get(participant_service_1.ParticipantService);
55
56
  }
57
+ getTemplate(templates, tag) {
58
+ const t = templates.get(tag);
59
+ if (!t)
60
+ throw new Error(`No notification template for tag: ${tag}`);
61
+ return t;
62
+ }
56
63
  hasNotPredicted(participant, matchId) {
57
64
  return !participant.predictions.some(p => p.matchId.toString() === matchId.toString());
58
65
  }
59
- async publishNotification(recipientId, title, body) {
60
- await (0, event_1.publishEvent)(new notification_1.NotificationEvent({
66
+ async notifyGlobal(title, body) {
67
+ await (0, event_1.publishEvent)(new notification_1.NotificationGlobalEvent({
61
68
  title,
62
69
  body,
63
70
  data: {
64
71
  saveNotification: true,
65
72
  accountType: enum_1.NotificationAccountType.USER,
66
- recipientId,
67
- isGlobal: false,
73
+ isGlobal: true,
68
74
  isClickable: true,
69
75
  clickType: enum_1.ClickType.CLICKABLE_FALLBACK,
70
76
  },
71
77
  }));
72
78
  }
73
- async notifyUnpredictedParticipants(tournamentId, matchId, type) {
74
- const participants = await this.participantService.getAll(tournamentId);
75
- const unpredicted = participants.filter(p => this.hasNotPredicted(p, matchId));
76
- const title = type === 'before3h' ? "⏰ Don't miss today's match!" : '🚨 Final call!';
77
- const body = type === 'before3h'
78
- ? 'You still have time to predict the exact score and win'
79
- : 'Only 15 minutes left to submit your prediction';
80
- await Promise.all(unpredicted.map(p => this.publishNotification(p.userId, title, body)));
79
+ async notifyUsers(title, body, userIds) {
80
+ await Promise.all(userIds.map(recipientId => (0, event_1.publishEvent)(new notification_1.NotificationEvent({
81
+ title,
82
+ body,
83
+ data: {
84
+ saveNotification: true,
85
+ accountType: enum_1.NotificationAccountType.USER,
86
+ recipientId,
87
+ isGlobal: false,
88
+ isClickable: true,
89
+ clickType: enum_1.ClickType.CLICKABLE_FALLBACK,
90
+ },
91
+ }))));
81
92
  }
82
- matchResultTemplates = {
83
- winner: {
84
- title: '🎉 Your prediction was correct.',
85
- body: 'Your coupon is now available',
86
- },
87
- loser: {
88
- title: 'Full-time whistle 🏁',
89
- body: 'Better luck next match. New predictions are now open.',
90
- },
91
- };
92
- async notifyMatchResult(winnerIds, loserIds) {
93
- const { winner, loser } = this.matchResultTemplates;
94
- await Promise.all([
95
- ...winnerIds.map(id => this.publishNotification(id, winner.title, winner.body)),
96
- ...loserIds.map(id => this.publishNotification(id, loser.title, loser.body)),
97
- ]);
93
+ async dispatchScheduledJob(type, target, templates, tournamentId, matchId) {
94
+ const { title, body } = this.getTemplate(templates, type);
95
+ if (target === notification_config_1.ScheduledTarget.GLOBAL) {
96
+ await this.notifyGlobal(title, body);
97
+ }
98
+ else {
99
+ const participants = await this.participantService.getAll(tournamentId);
100
+ const unpredicted = participants.filter(p => this.hasNotPredicted(p, matchId));
101
+ await this.notifyUsers(title, body, unpredicted.map(p => p.userId));
102
+ }
98
103
  }
99
104
  };
100
105
  exports.TournamentNotificationService = TournamentNotificationService;
@@ -1 +1 @@
1
- {"version":3,"file":"notification.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport { publishEvent } from '@lyxa.ai/core/dist/libraries/event';\nimport { NotificationEvent } from '@lyxa.ai/core/dist/libraries/notification';\nimport { ClickType, NotificationAccountType } from '@lyxa.ai/core/dist/utilities/enum';\nimport { ParticipantService } from '../participant/participant.service';\nimport { TournamentParticipantOutputDTO } from '../participant/participant.validation';\n\n@Service()\nexport class TournamentNotificationService {\n private participantService: ParticipantService;\n\n constructor() {\n this.participantService = Container.get(ParticipantService);\n }\n\n private hasNotPredicted(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId): boolean {\n return !participant.predictions.some(p => p.matchId.toString() === matchId.toString());\n }\n\n private async publishNotification(\n recipientId: mongoose.Types.ObjectId,\n title: string,\n body: string\n ): Promise<void> {\n await publishEvent(\n new NotificationEvent({\n title,\n body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n recipientId,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_FALLBACK,\n },\n })\n );\n }\n\n public async notifyUnpredictedParticipants(\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId,\n type: 'before3h' | 'before15min'\n ): Promise<void> {\n const participants = await this.participantService.getAll(tournamentId);\n const unpredicted = participants.filter(p => this.hasNotPredicted(p, matchId));\n\n const title = type === 'before3h' ? \"⏰ Don't miss today's match!\" : '🚨 Final call!';\n const body =\n type === 'before3h'\n ? 'You still have time to predict the exact score and win'\n : 'Only 15 minutes left to submit your prediction';\n\n await Promise.all(unpredicted.map(p => this.publishNotification(p.userId, title, body)));\n }\n\n private readonly matchResultTemplates: Record<'winner' | 'loser', {title: string; body: string}> = {\n winner: {\n title: '🎉 Your prediction was correct.',\n body: 'Your coupon is now available',\n },\n loser: {\n title: 'Full-time whistle 🏁',\n body: 'Better luck next match. New predictions are now open.',\n },\n };\n\n public async notifyMatchResult(\n winnerIds: mongoose.Types.ObjectId[],\n loserIds: mongoose.Types.ObjectId[]\n ): Promise<void> {\n const {winner, loser} = this.matchResultTemplates;\n await Promise.all([\n ...winnerIds.map(id => this.publishNotification(id, winner.title, winner.body)),\n ...loserIds.map(id => this.publishNotification(id, loser.title, loser.body)),\n ]);\n }\n}\n\nexport const tournamentNotificationService = Container.get(TournamentNotificationService);\n"]}
1
+ {"version":3,"file":"notification.service.js","sourceRoot":"/","sources":["modules/tournament/notification/notification.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {publishEvent} from '@lyxa.ai/core/dist/libraries/event';\nimport {NotificationEvent, NotificationGlobalEvent} from '@lyxa.ai/core/dist/libraries/notification';\nimport {ClickType, NotificationAccountType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {NotificationMessage} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {ParticipantService} from '../participant/participant.service';\nimport {TournamentParticipantOutputDTO} from '../participant/participant.validation';\nimport {ScheduledTarget} from './notification.config';\n\n@Service()\nexport class TournamentNotificationService {\n private participantService: ParticipantService;\n\n constructor() {\n this.participantService = Container.get(ParticipantService);\n }\n\n private getTemplate(templates: Map<string, NotificationMessage>, tag: string): NotificationMessage {\n const t = templates.get(tag);\n if (!t) throw new Error(`No notification template for tag: ${tag}`);\n return t;\n }\n\n private hasNotPredicted(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId): boolean {\n return !participant.predictions.some(p => p.matchId.toString() === matchId.toString());\n }\n\n public async notifyGlobal(title: string, body: string): Promise<void> {\n await publishEvent(\n new NotificationGlobalEvent({\n title,\n body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n isGlobal: true,\n isClickable: true,\n clickType: ClickType.CLICKABLE_FALLBACK,\n },\n })\n );\n }\n\n public async notifyUsers(title: string, body: string, userIds: mongoose.Types.ObjectId[]): Promise<void> {\n await Promise.all(\n userIds.map(recipientId =>\n publishEvent(\n new NotificationEvent({\n title,\n body,\n data: {\n saveNotification: true,\n accountType: NotificationAccountType.USER,\n recipientId,\n isGlobal: false,\n isClickable: true,\n clickType: ClickType.CLICKABLE_FALLBACK,\n },\n })\n )\n )\n );\n }\n\n public async dispatchScheduledJob(\n type: string,\n target: string,\n templates: Map<string, NotificationMessage>,\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId\n ): Promise<void> {\n const {title, body} = this.getTemplate(templates, type);\n\n if (target === ScheduledTarget.GLOBAL) {\n await this.notifyGlobal(title, body);\n } else {\n const participants = await this.participantService.getAll(tournamentId);\n const unpredicted = participants.filter(p => this.hasNotPredicted(p, matchId));\n await this.notifyUsers(title, body, unpredicted.map(p => p.userId));\n }\n }\n}\n\nexport const tournamentNotificationService = Container.get(TournamentNotificationService);\n"]}
@@ -7,6 +7,7 @@ export declare class TournamentParticipantRepository {
7
7
  create(input: object): Promise<ParticipantModelType>;
8
8
  findByUserAndTournament(userId: mongoose.Types.ObjectId, tournamentId: mongoose.Types.ObjectId): Promise<ParticipantModelType | null>;
9
9
  findByTournament(tournamentId: mongoose.Types.ObjectId): Promise<ParticipantModelType[]>;
10
+ findByUser(userId: mongoose.Types.ObjectId): Promise<ParticipantModelType | null>;
10
11
  }
11
12
  export declare const tournamentParticipantRepository: TournamentParticipantRepository;
12
13
  //# sourceMappingURL=participant.repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"participant.repository.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EACH,qBAAqB,IAAI,oBAAoB,EAEhD,MAAM,2CAA2C,CAAC;AAEnD,qBACa,+BAA+B;IACxC,OAAO,CAAC,gBAAgB,CAAoC;;IAMtD,yBAAyB,CAC3B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,OAAO,CAAC;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAKpD,uBAAuB,CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAIjC,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAGjG;AAED,eAAO,MAAM,+BAA+B,iCAAiD,CAAC"}
1
+ {"version":3,"file":"participant.repository.d.ts","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EACH,qBAAqB,IAAI,oBAAoB,EAEhD,MAAM,2CAA2C,CAAC;AAEnD,qBACa,+BAA+B;IACxC,OAAO,CAAC,gBAAgB,CAAoC;;IAMtD,yBAAyB,CAC3B,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,OAAO,CAAC;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAKpD,uBAAuB,CACzB,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAC/B,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GACtC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAIjC,gBAAgB,CAAC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAIxF,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;CAM1F;AAED,eAAO,MAAM,+BAA+B,iCAAiD,CAAC"}
@@ -63,6 +63,12 @@ let TournamentParticipantRepository = class TournamentParticipantRepository {
63
63
  async findByTournament(tournamentId) {
64
64
  return this.participantModel.find({ tournamentId }).lean();
65
65
  }
66
+ async findByUser(userId) {
67
+ return this.participantModel
68
+ .findOne({ userId })
69
+ .sort({ createdAt: -1 })
70
+ .lean();
71
+ }
66
72
  };
67
73
  exports.TournamentParticipantRepository = TournamentParticipantRepository;
68
74
  exports.TournamentParticipantRepository = TournamentParticipantRepository = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"participant.repository.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAE5C,sEAGmD;AAG5C,IAAM,+BAA+B,GAArC,MAAM,+BAA+B;IAChC,gBAAgB,CAAoC;IAE5D;QACI,IAAI,CAAC,gBAAgB,GAAG,mCAA0B,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC3B,MAA+B,EAC/B,YAAqC;QAErC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,uBAAuB,CACzB,MAA+B,EAC/B,YAAqC;QAErC,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAA0C,CAAC;IAClH,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAqC;QACxD,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAAqC,CAAC;IAClG,CAAC;CACJ,CAAA;AA7BY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,gBAAO,GAAE;;GACG,+BAA+B,CA6B3C;AAEY,QAAA,+BAA+B,GAAG,gBAAS,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport {\n TournamentParticipant as ParticipantModelType,\n TournamentParticipantModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\n\n@Service()\nexport class TournamentParticipantRepository {\n private participantModel: typeof TournamentParticipantModel;\n\n constructor() {\n this.participantModel = TournamentParticipantModel;\n }\n\n async existsByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<boolean> {\n return !!(await this.participantModel.exists({ userId, tournamentId }));\n }\n\n async create(input: object): Promise<ParticipantModelType> {\n const doc = await this.participantModel.create(input);\n return doc.toObject();\n }\n\n async findByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<ParticipantModelType | null> {\n return this.participantModel.findOne({ userId, tournamentId }).lean() as Promise<ParticipantModelType | null>;\n }\n\n async findByTournament(tournamentId: mongoose.Types.ObjectId): Promise<ParticipantModelType[]> {\n return this.participantModel.find({ tournamentId }).lean() as Promise<ParticipantModelType[]>;\n }\n}\n\nexport const tournamentParticipantRepository = Container.get(TournamentParticipantRepository);"]}
1
+ {"version":3,"file":"participant.repository.js","sourceRoot":"/","sources":["modules/tournament/participant/participant.repository.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAE5C,sEAGmD;AAG5C,IAAM,+BAA+B,GAArC,MAAM,+BAA+B;IAChC,gBAAgB,CAAoC;IAE5D;QACI,IAAI,CAAC,gBAAgB,GAAG,mCAA0B,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,yBAAyB,CAC3B,MAA+B,EAC/B,YAAqC;QAErC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa;QACtB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,uBAAuB,CACzB,MAA+B,EAC/B,YAAqC;QAErC,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAA0C,CAAC;IAClH,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,YAAqC;QACxD,OAAO,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,EAAqC,CAAC;IAClG,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAA+B;QAC5C,OAAO,IAAI,CAAC,gBAAgB;aACvB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;aACnB,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC;aACvB,IAAI,EAA0C,CAAC;IACxD,CAAC;CACJ,CAAA;AApCY,0EAA+B;0CAA/B,+BAA+B;IAD3C,IAAA,gBAAO,GAAE;;GACG,+BAA+B,CAoC3C;AAEY,QAAA,+BAA+B,GAAG,gBAAS,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport {\n TournamentParticipant as ParticipantModelType,\n TournamentParticipantModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\n\n@Service()\nexport class TournamentParticipantRepository {\n private participantModel: typeof TournamentParticipantModel;\n\n constructor() {\n this.participantModel = TournamentParticipantModel;\n }\n\n async existsByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<boolean> {\n return !!(await this.participantModel.exists({ userId, tournamentId }));\n }\n\n async create(input: object): Promise<ParticipantModelType> {\n const doc = await this.participantModel.create(input);\n return doc.toObject();\n }\n\n async findByUserAndTournament(\n userId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId\n ): Promise<ParticipantModelType | null> {\n return this.participantModel.findOne({ userId, tournamentId }).lean() as Promise<ParticipantModelType | null>;\n }\n\n async findByTournament(tournamentId: mongoose.Types.ObjectId): Promise<ParticipantModelType[]> {\n return this.participantModel.find({ tournamentId }).lean() as Promise<ParticipantModelType[]>;\n }\n\n async findByUser(userId: mongoose.Types.ObjectId): Promise<ParticipantModelType | null> {\n return this.participantModel\n .findOne({ userId })\n .sort({ createdAt: -1 })\n .lean() as Promise<ParticipantModelType | null>;\n }\n}\n\nexport const tournamentParticipantRepository = Container.get(TournamentParticipantRepository);"]}
@@ -1 +1 @@
1
- {"version":3,"file":"prediction.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,UAAU,oBAAoB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;IAC1B,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,GAAG;QAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAA;KAAE;IAU1J,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAMhF"}
1
+ {"version":3,"file":"prediction.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG9D,UAAU,oBAAoB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAiB;IAC1B,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,GAAG;QAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAA;KAAE;IAU1J,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAMhF"}
@@ -2,20 +2,21 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PredictionBuilder = void 0;
4
4
  const typegoose_1 = require("@typegoose/typegoose");
5
+ const tournament_utils_1 = require("../tournament.utils");
5
6
  class PredictionBuilder {
6
7
  static buildPrediction(matchId, score) {
7
8
  return {
8
9
  _id: new typegoose_1.mongoose.Types.ObjectId(),
9
10
  matchId,
10
11
  score,
11
- predictionTime: new Date(),
12
+ predictionTime: (0, tournament_utils_1.utcNow)(),
12
13
  succeeded: null,
13
14
  };
14
15
  }
15
16
  static buildScoreUpdate(score) {
16
17
  return {
17
18
  'predictions.$.score': score,
18
- 'predictions.$.predictionTime': new Date(),
19
+ 'predictions.$.predictionTime': (0, tournament_utils_1.utcNow)(),
19
20
  };
20
21
  }
21
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prediction.builder.js","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.builder.ts"],"names":[],"mappings":";;;AAAA,oDAAgD;AAQhD,MAAa,iBAAiB;IAC1B,MAAM,CAAC,eAAe,CAAC,OAAgC,EAAE,KAA2B;QAChF,OAAO;YACH,GAAG,EAAE,IAAI,oBAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE;YAClC,OAAO;YACP,KAAK;YACL,cAAc,EAAE,IAAI,IAAI,EAAE;YAC1B,SAAS,EAAE,IAAI;SAClB,CAAC;IACN,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,KAA2B;QAC/C,OAAO;YACH,qBAAqB,EAAE,KAAK;YAC5B,8BAA8B,EAAE,IAAI,IAAI,EAAE;SAC7C,CAAC;IACN,CAAC;CACJ;AAjBD,8CAiBC","sourcesContent":["import { mongoose } from '@typegoose/typegoose';\nimport { PredictionOutputDTO } from './prediction.validation';\n\ninterface PredictionScoreInput {\n team1: number;\n team2: number;\n}\n\nexport class PredictionBuilder {\n static buildPrediction(matchId: mongoose.Types.ObjectId, score: PredictionScoreInput): Omit<PredictionOutputDTO, '_id'> & { _id: mongoose.Types.ObjectId } {\n return {\n _id: new mongoose.Types.ObjectId(),\n matchId,\n score,\n predictionTime: new Date(),\n succeeded: null,\n };\n }\n\n static buildScoreUpdate(score: PredictionScoreInput): Record<string, unknown> {\n return {\n 'predictions.$.score': score,\n 'predictions.$.predictionTime': new Date(),\n };\n }\n}\n"]}
1
+ {"version":3,"file":"prediction.builder.js","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.builder.ts"],"names":[],"mappings":";;;AAAA,oDAAgD;AAEhD,0DAA2C;AAO3C,MAAa,iBAAiB;IAC1B,MAAM,CAAC,eAAe,CAAC,OAAgC,EAAE,KAA2B;QAChF,OAAO;YACH,GAAG,EAAE,IAAI,oBAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE;YAClC,OAAO;YACP,KAAK;YACL,cAAc,EAAE,IAAA,yBAAM,GAAE;YACxB,SAAS,EAAE,IAAI;SAClB,CAAC;IACN,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,KAA2B;QAC/C,OAAO;YACH,qBAAqB,EAAE,KAAK;YAC5B,8BAA8B,EAAE,IAAA,yBAAM,GAAE;SAC3C,CAAC;IACN,CAAC;CACJ;AAjBD,8CAiBC","sourcesContent":["import { mongoose } from '@typegoose/typegoose';\nimport { PredictionOutputDTO } from './prediction.validation';\nimport {utcNow} from '../tournament.utils';\n\ninterface PredictionScoreInput {\n team1: number;\n team2: number;\n}\n\nexport class PredictionBuilder {\n static buildPrediction(matchId: mongoose.Types.ObjectId, score: PredictionScoreInput): Omit<PredictionOutputDTO, '_id'> & { _id: mongoose.Types.ObjectId } {\n return {\n _id: new mongoose.Types.ObjectId(),\n matchId,\n score,\n predictionTime: utcNow(),\n succeeded: null,\n };\n }\n\n static buildScoreUpdate(score: PredictionScoreInput): Record<string, unknown> {\n return {\n 'predictions.$.score': score,\n 'predictions.$.predictionTime': utcNow(),\n };\n }\n}\n"]}
@@ -7,6 +7,7 @@ export declare class PredictionService {
7
7
  constructor();
8
8
  private findMatch;
9
9
  private ensureMatchIsOpen;
10
+ private ensureMatchInvolvesParticipantTeam;
10
11
  private ensureNoPriorPrediction;
11
12
  private findPrediction;
12
13
  private resolveOutcomes;
@@ -1 +1 @@
1
- {"version":3,"file":"prediction.service.d.ts","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EACH,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACtB,MAAM,yBAAyB,CAAC;AAOjC,qBACa,iBAAiB;IAC1B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,kBAAkB,CAAqB;;YAQjC,SAAS;IAQvB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IAmBV,QAAQ,CACjB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAA;KAAC,CAAC;IAO1E,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IActG,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAoBlG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;CAKvH;AAED,eAAO,MAAM,iBAAiB,mBAAmC,CAAC"}
1
+ {"version":3,"file":"prediction.service.d.ts","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EACH,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACtB,MAAM,yBAAyB,CAAC;AAQjC,qBACa,iBAAiB;IAC1B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,kBAAkB,CAAqB;;YAQjC,SAAS;IAQvB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,uBAAuB;IAK/B,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IAmBV,QAAQ,CACjB,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC;QAAC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAA;KAAC,CAAC;IAO1E,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAetG,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAqBlG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;CAKvH;AAED,eAAO,MAAM,iBAAiB,mBAAmC,CAAC"}
@@ -49,6 +49,7 @@ const prediction_repository_1 = require("./prediction.repository");
49
49
  const prediction_builder_1 = require("./prediction.builder");
50
50
  const participant_service_1 = require("../participant/participant.service");
51
51
  const match_repository_1 = require("../match/match.repository");
52
+ const tournament_utils_1 = require("../tournament.utils");
52
53
  let PredictionService = class PredictionService {
53
54
  repository;
54
55
  matchRepository;
@@ -70,10 +71,16 @@ let PredictionService = class PredictionService {
70
71
  ensureMatchIsOpen(match) {
71
72
  if (match.endDate)
72
73
  throw (0, error_common_1.badRequestError)('This match has already ended');
73
- if (match.startingDate && match.startingDate <= new Date()) {
74
+ if (match.startingDate && match.startingDate <= (0, tournament_utils_1.utcNow)()) {
74
75
  throw (0, error_common_1.badRequestError)('The prediction window for this match has closed');
75
76
  }
76
77
  }
78
+ ensureMatchInvolvesParticipantTeam(match, participant) {
79
+ const teamId = participant.teamId.toString();
80
+ const involved = match.team1.teamId.toString() === teamId || match.team2.teamId.toString() === teamId;
81
+ if (!involved)
82
+ throw (0, error_common_1.badRequestError)('You can only predict for matches involving your selected team');
83
+ }
77
84
  ensureNoPriorPrediction(participant, matchId) {
78
85
  const exists = participant.predictions.some(p => p.matchId.toString() === matchId.toString());
79
86
  if (exists)
@@ -107,6 +114,7 @@ let PredictionService = class PredictionService {
107
114
  const match = await this.findMatch(input.tournamentId, input.matchId);
108
115
  this.ensureMatchIsOpen(match);
109
116
  const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);
117
+ this.ensureMatchInvolvesParticipantTeam(match, participant);
110
118
  this.ensureNoPriorPrediction(participant, input.matchId);
111
119
  const prediction = prediction_builder_1.PredictionBuilder.buildPrediction(input.matchId, input.score);
112
120
  const result = await this.repository.addPrediction(participant._id, prediction);
@@ -118,6 +126,7 @@ let PredictionService = class PredictionService {
118
126
  const match = await this.findMatch(input.tournamentId, input.matchId);
119
127
  this.ensureMatchIsOpen(match);
120
128
  const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);
129
+ this.ensureMatchInvolvesParticipantTeam(match, participant);
121
130
  this.findPrediction(participant, input.matchId);
122
131
  const result = await this.repository.updatePrediction(participant._id, input.matchId, prediction_builder_1.PredictionBuilder.buildScoreUpdate(input.score));
123
132
  if (!result)
@@ -1 +1 @@
1
- {"version":3,"file":"prediction.service.js","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {badRequestError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {\n CreatePredictionInputDTO,\n EditPredictionInputDTO,\n GetPredictionInputDTO,\n PredictionOutputDTO\n} from './prediction.validation';\nimport {PredictionRepository} from './prediction.repository';\nimport {PredictionBuilder} from './prediction.builder';\nimport {ParticipantService} from '../participant/participant.service';\nimport {TournamentParticipantOutputDTO} from '../participant/participant.validation';\nimport {TournamentMatchRepository} from '../match/match.repository';\n\n@Service()\nexport class PredictionService {\n private repository: PredictionRepository;\n private matchRepository: TournamentMatchRepository;\n private participantService: ParticipantService;\n\n constructor() {\n this.repository = Container.get(PredictionRepository);\n this.matchRepository = Container.get(TournamentMatchRepository);\n this.participantService = Container.get(ParticipantService);\n }\n\n private async findMatch(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId) {\n const tournament = await this.matchRepository.findMatchInTournament(tournamentId, matchId);\n if (!tournament) throw notFoundError('Match not found in this tournament');\n const match = tournament.matches.find(m => m._id.toString() === matchId.toString());\n if (!match) throw notFoundError('Match not found');\n return match;\n }\n\n private ensureMatchIsOpen(match: { startingDate?: Date | null; endDate?: Date | null }) {\n if (match.endDate) throw badRequestError('This match has already ended');\n if (match.startingDate && match.startingDate <= new Date()) {\n throw badRequestError('The prediction window for this match has closed');\n }\n }\n\n private ensureNoPriorPrediction(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId) {\n const exists = participant.predictions.some(p => p.matchId.toString() === matchId.toString());\n if (exists) throw badRequestError('You have already predicted for this match');\n }\n\n private findPrediction(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId) {\n const prediction = participant.predictions.find(p => p.matchId.toString() === matchId.toString());\n if (!prediction) throw notFoundError('No prediction found for this match');\n return prediction;\n }\n\n private resolveOutcomes(\n participants: TournamentParticipantOutputDTO[],\n matchId: mongoose.Types.ObjectId,\n finalScore: { team1: number; team2: number }\n ): {winnerIds: mongoose.Types.ObjectId[]; loserIds: mongoose.Types.ObjectId[]} {\n const winnerIds: mongoose.Types.ObjectId[] = [];\n const loserIds: mongoose.Types.ObjectId[] = [];\n\n for (const participant of participants) {\n const prediction = participant.predictions.find(p => p.matchId.toString() === matchId.toString());\n if (!prediction) continue;\n\n const isWinner = prediction.score.team1 === finalScore.team1 && prediction.score.team2 === finalScore.team2;\n (isWinner ? winnerIds : loserIds).push(participant.userId);\n }\n\n return {winnerIds, loserIds};\n }\n\n public async evaluate(\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId,\n finalScore: { team1: number; team2: number }\n ): Promise<{winnerIds: mongoose.Types.ObjectId[]; loserIds: mongoose.Types.ObjectId[]}> {\n const participants = await this.participantService.getAll(tournamentId);\n const outcomes = this.resolveOutcomes(participants, matchId, finalScore);\n await this.repository.evaluate(tournamentId, matchId, finalScore);\n return outcomes;\n }\n\n public async create(userId: mongoose.Types.ObjectId, input: CreatePredictionInputDTO): Promise<PredictionOutputDTO> {\n const match = await this.findMatch(input.tournamentId, input.matchId);\n this.ensureMatchIsOpen(match);\n\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n this.ensureNoPriorPrediction(participant, input.matchId);\n\n const prediction = PredictionBuilder.buildPrediction(input.matchId, input.score);\n const result = await this.repository.addPrediction(participant._id, prediction);\n if (!result) throw notFoundError('Participant not found');\n\n return prediction as PredictionOutputDTO;\n }\n\n public async edit(userId: mongoose.Types.ObjectId, input: EditPredictionInputDTO): Promise<PredictionOutputDTO> {\n const match = await this.findMatch(input.tournamentId, input.matchId);\n this.ensureMatchIsOpen(match);\n\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n this.findPrediction(participant, input.matchId);\n\n const result = await this.repository.updatePrediction(\n participant._id,\n input.matchId,\n PredictionBuilder.buildScoreUpdate(input.score)\n );\n if (!result) throw notFoundError('Participant not found');\n\n const updated = result.predictions.find(p => p.matchId.toString() === input.matchId.toString());\n if (!updated) throw notFoundError('Prediction not found after update');\n\n return updated as unknown as PredictionOutputDTO;\n }\n\n public async get(userId: mongoose.Types.ObjectId, input: GetPredictionInputDTO): Promise<PredictionOutputDTO | null> {\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n const prediction = participant.predictions.find(p => p.matchId.toString() === input.matchId.toString());\n return (prediction as unknown as PredictionOutputDTO) ?? null;\n }\n}\n\nexport const predictionService = Container.get(PredictionService);\n"]}
1
+ {"version":3,"file":"prediction.service.js","sourceRoot":"/","sources":["modules/tournament/prediction/prediction.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, {Service} from 'typedi';\nimport {mongoose} from '@typegoose/typegoose';\nimport {badRequestError, notFoundError} from '@lyxa.ai/core/dist/utilities/error-common';\nimport {\n CreatePredictionInputDTO,\n EditPredictionInputDTO,\n GetPredictionInputDTO,\n PredictionOutputDTO\n} from './prediction.validation';\nimport {PredictionRepository} from './prediction.repository';\nimport {PredictionBuilder} from './prediction.builder';\nimport {ParticipantService} from '../participant/participant.service';\nimport {TournamentParticipantOutputDTO} from '../participant/participant.validation';\nimport {TournamentMatchRepository} from '../match/match.repository';\nimport {utcNow} from '../tournament.utils';\n\n@Service()\nexport class PredictionService {\n private repository: PredictionRepository;\n private matchRepository: TournamentMatchRepository;\n private participantService: ParticipantService;\n\n constructor() {\n this.repository = Container.get(PredictionRepository);\n this.matchRepository = Container.get(TournamentMatchRepository);\n this.participantService = Container.get(ParticipantService);\n }\n\n private async findMatch(tournamentId: mongoose.Types.ObjectId, matchId: mongoose.Types.ObjectId) {\n const tournament = await this.matchRepository.findMatchInTournament(tournamentId, matchId);\n if (!tournament) throw notFoundError('Match not found in this tournament');\n const match = tournament.matches.find(m => m._id.toString() === matchId.toString());\n if (!match) throw notFoundError('Match not found');\n return match;\n }\n\n private ensureMatchIsOpen(match: { startingDate?: Date | null; endDate?: Date | null }) {\n if (match.endDate) throw badRequestError('This match has already ended'); // change to flag \"matchEnded\n if (match.startingDate && match.startingDate <= utcNow()) {\n throw badRequestError('The prediction window for this match has closed');\n }\n }\n\n private ensureMatchInvolvesParticipantTeam(\n match: { team1: { teamId: mongoose.Types.ObjectId }; team2: { teamId: mongoose.Types.ObjectId } },\n participant: TournamentParticipantOutputDTO\n ) {\n const teamId = participant.teamId.toString();\n const involved = match.team1.teamId.toString() === teamId || match.team2.teamId.toString() === teamId;\n if (!involved) throw badRequestError('You can only predict for matches involving your selected team');\n }\n\n private ensureNoPriorPrediction(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId) {\n const exists = participant.predictions.some(p => p.matchId.toString() === matchId.toString());\n if (exists) throw badRequestError('You have already predicted for this match');\n }\n\n private findPrediction(participant: TournamentParticipantOutputDTO, matchId: mongoose.Types.ObjectId) {\n const prediction = participant.predictions.find(p => p.matchId.toString() === matchId.toString());\n if (!prediction) throw notFoundError('No prediction found for this match');\n return prediction;\n }\n\n private resolveOutcomes(\n participants: TournamentParticipantOutputDTO[],\n matchId: mongoose.Types.ObjectId,\n finalScore: { team1: number; team2: number }\n ): {winnerIds: mongoose.Types.ObjectId[]; loserIds: mongoose.Types.ObjectId[]} {\n const winnerIds: mongoose.Types.ObjectId[] = [];\n const loserIds: mongoose.Types.ObjectId[] = [];\n\n for (const participant of participants) {\n const prediction = participant.predictions.find(p => p.matchId.toString() === matchId.toString());\n if (!prediction) continue;\n\n const isWinner = prediction.score.team1 === finalScore.team1 && prediction.score.team2 === finalScore.team2;\n (isWinner ? winnerIds : loserIds).push(participant.userId);\n }\n\n return {winnerIds, loserIds};\n }\n\n public async evaluate(\n tournamentId: mongoose.Types.ObjectId,\n matchId: mongoose.Types.ObjectId,\n finalScore: { team1: number; team2: number }\n ): Promise<{winnerIds: mongoose.Types.ObjectId[]; loserIds: mongoose.Types.ObjectId[]}> {\n const participants = await this.participantService.getAll(tournamentId);\n const outcomes = this.resolveOutcomes(participants, matchId, finalScore);\n await this.repository.evaluate(tournamentId, matchId, finalScore);\n return outcomes;\n }\n\n public async create(userId: mongoose.Types.ObjectId, input: CreatePredictionInputDTO): Promise<PredictionOutputDTO> {\n const match = await this.findMatch(input.tournamentId, input.matchId);\n this.ensureMatchIsOpen(match);\n\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n this.ensureMatchInvolvesParticipantTeam(match, participant);\n this.ensureNoPriorPrediction(participant, input.matchId);\n\n const prediction = PredictionBuilder.buildPrediction(input.matchId, input.score);\n const result = await this.repository.addPrediction(participant._id, prediction);\n if (!result) throw notFoundError('Participant not found');\n\n return prediction as PredictionOutputDTO;\n }\n\n public async edit(userId: mongoose.Types.ObjectId, input: EditPredictionInputDTO): Promise<PredictionOutputDTO> {\n const match = await this.findMatch(input.tournamentId, input.matchId);\n this.ensureMatchIsOpen(match);\n\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n this.ensureMatchInvolvesParticipantTeam(match, participant);\n this.findPrediction(participant, input.matchId);\n\n const result = await this.repository.updatePrediction(\n participant._id,\n input.matchId,\n PredictionBuilder.buildScoreUpdate(input.score)\n );\n if (!result) throw notFoundError('Participant not found');\n\n const updated = result.predictions.find(p => p.matchId.toString() === input.matchId.toString());\n if (!updated) throw notFoundError('Prediction not found after update');\n\n return updated as unknown as PredictionOutputDTO;\n }\n\n public async get(userId: mongoose.Types.ObjectId, input: GetPredictionInputDTO): Promise<PredictionOutputDTO | null> {\n const participant = await this.participantService.getByUserAndTournament(userId, input.tournamentId);\n const prediction = participant.predictions.find(p => p.matchId.toString() === input.matchId.toString());\n return (prediction as unknown as PredictionOutputDTO) ?? null;\n }\n}\n\nexport const predictionService = Container.get(PredictionService);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"reward.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAO7C,qBAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GACrC,aAAa;CAiCnB"}
1
+ {"version":3,"file":"reward.builder.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAQ7C,qBAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAChC,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EACrC,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GACrC,aAAa;CAiCnB"}
@@ -2,12 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RewardBuilder = void 0;
4
4
  const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
5
+ const tournament_utils_1 = require("../tournament.utils");
5
6
  const FWC_DISCOUNT_PERCENTAGE = 10;
6
7
  const FWC_MAX_DISCOUNT_AMOUNT = 5;
7
8
  const FWC_MIN_ORDER_VALUE = 5;
8
9
  class RewardBuilder {
9
10
  static buildCouponRewardContext(matchId, tournamentId, winnerIds) {
10
- const now = new Date();
11
+ const now = (0, tournament_utils_1.utcNow)();
11
12
  const expiresAt = new Date(now);
12
13
  expiresAt.setMonth(expiresAt.getMonth() + 1);
13
14
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"reward.builder.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":";;;AACA,4DAAkF;AAIlF,MAAM,uBAAuB,GAAG,EAAE,CAAC;AACnC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAClC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,MAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAgC,EAChC,YAAqC,EACrC,SAAoC;QAEpC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAE7C,OAAO;YACH,OAAO,EAAE,SAAS;YAClB,YAAY;YACZ,OAAO;YACP,OAAO,EAAE;gBACL,UAAU,EAAE,iBAAU,CAAC,eAAe;gBACtC,SAAS,EAAE,gBAAS,CAAC,UAAU;gBAC/B,KAAK,EAAE,uBAAuB;gBAC9B,gBAAgB,EAAE,uBAAuB;gBACzC,QAAQ,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC;gBACtC,mBAAmB,EAAE,KAAK;gBAC1B,UAAU,EAAE,IAAI;gBAChB,0BAA0B,EAAE,IAAI;gBAChC,iBAAiB,EAAE,CAAC;gBACpB,sBAAsB,EAAE,IAAI;gBAC5B,aAAa,EAAE,mBAAmB;gBAClC,SAAS,EAAE;oBACP,eAAQ,CAAC,IAAI;oBACb,eAAQ,CAAC,OAAO;oBAChB,eAAQ,CAAC,QAAQ;oBACjB,eAAQ,CAAC,MAAM;oBACf,eAAQ,CAAC,MAAM;oBACf,eAAQ,CAAC,GAAG;oBACZ,eAAQ,CAAC,cAAc;iBAC1B;aACJ;SACJ,CAAC;IACN,CAAC;CACJ;AAtCD,sCAsCC","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {RewardContext} from './reward.types';\n\n// TODO: make these admin-configurable via tournament reward settings\nconst FWC_DISCOUNT_PERCENTAGE = 10;\nconst FWC_MAX_DISCOUNT_AMOUNT = 5;\nconst FWC_MIN_ORDER_VALUE = 5;\n\nexport class RewardBuilder {\n static buildCouponRewardContext(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n winnerIds: mongoose.Types.ObjectId[]\n ): RewardContext {\n const now = new Date();\n const expiresAt = new Date(now);\n expiresAt.setMonth(expiresAt.getMonth() + 1);\n\n return {\n userIds: winnerIds,\n tournamentId,\n matchId,\n payload: {\n couponType: CouponType.INDIVIDUAL_USER,\n valueType: ValueType.PERCENTAGE,\n value: FWC_DISCOUNT_PERCENTAGE,\n maxDiscountLimit: FWC_MAX_DISCOUNT_AMOUNT,\n duration: {start: now, end: expiresAt},\n isSpendLimitEnabled: false,\n spendLimit: null,\n isOrderLimitPerUserEnabled: true,\n orderLimitPerUser: 1,\n isMinOrderValueEnabled: true,\n minOrderValue: FWC_MIN_ORDER_VALUE,\n itemTypes: [\n ItemType.FOOD,\n ItemType.GROCERY,\n ItemType.PHARMACY,\n ItemType.COFFEE,\n ItemType.FLOWER,\n ItemType.PET,\n ItemType.HEALTHY_CORNER,\n ],\n },\n };\n }\n}\n"]}
1
+ {"version":3,"file":"reward.builder.js","sourceRoot":"/","sources":["modules/tournament/reward/reward.builder.ts"],"names":[],"mappings":";;;AACA,4DAAkF;AAElF,0DAA2C;AAG3C,MAAM,uBAAuB,GAAG,EAAE,CAAC;AACnC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAClC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,MAAa,aAAa;IACtB,MAAM,CAAC,wBAAwB,CAC3B,OAAgC,EAChC,YAAqC,EACrC,SAAoC;QAEpC,MAAM,GAAG,GAAG,IAAA,yBAAM,GAAE,CAAC;QACrB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAE7C,OAAO;YACH,OAAO,EAAE,SAAS;YAClB,YAAY;YACZ,OAAO;YACP,OAAO,EAAE;gBACL,UAAU,EAAE,iBAAU,CAAC,eAAe;gBACtC,SAAS,EAAE,gBAAS,CAAC,UAAU;gBAC/B,KAAK,EAAE,uBAAuB;gBAC9B,gBAAgB,EAAE,uBAAuB;gBACzC,QAAQ,EAAE,EAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAC;gBACtC,mBAAmB,EAAE,KAAK;gBAC1B,UAAU,EAAE,IAAI;gBAChB,0BAA0B,EAAE,IAAI;gBAChC,iBAAiB,EAAE,CAAC;gBACpB,sBAAsB,EAAE,IAAI;gBAC5B,aAAa,EAAE,mBAAmB;gBAClC,SAAS,EAAE;oBACP,eAAQ,CAAC,IAAI;oBACb,eAAQ,CAAC,OAAO;oBAChB,eAAQ,CAAC,QAAQ;oBACjB,eAAQ,CAAC,MAAM;oBACf,eAAQ,CAAC,MAAM;oBACf,eAAQ,CAAC,GAAG;oBACZ,eAAQ,CAAC,cAAc;iBAC1B;aACJ;SACJ,CAAC;IACN,CAAC;CACJ;AAtCD,sCAsCC","sourcesContent":["import {mongoose} from '@typegoose/typegoose';\nimport {CouponType, ItemType, ValueType} from '@lyxa.ai/core/dist/utilities/enum';\nimport {RewardContext} from './reward.types';\nimport {utcNow} from '../tournament.utils';\n\n// TODO: make these admin-configurable via tournament reward settings\nconst FWC_DISCOUNT_PERCENTAGE = 10;\nconst FWC_MAX_DISCOUNT_AMOUNT = 5;\nconst FWC_MIN_ORDER_VALUE = 5;\n\nexport class RewardBuilder {\n static buildCouponRewardContext(\n matchId: mongoose.Types.ObjectId,\n tournamentId: mongoose.Types.ObjectId,\n winnerIds: mongoose.Types.ObjectId[]\n ): RewardContext {\n const now = utcNow();\n const expiresAt = new Date(now);\n expiresAt.setMonth(expiresAt.getMonth() + 1);\n\n return {\n userIds: winnerIds,\n tournamentId,\n matchId,\n payload: {\n couponType: CouponType.INDIVIDUAL_USER,\n valueType: ValueType.PERCENTAGE,\n value: FWC_DISCOUNT_PERCENTAGE,\n maxDiscountLimit: FWC_MAX_DISCOUNT_AMOUNT,\n duration: {start: now, end: expiresAt},\n isSpendLimitEnabled: false,\n spendLimit: null,\n isOrderLimitPerUserEnabled: true,\n orderLimitPerUser: 1,\n isMinOrderValueEnabled: true,\n minOrderValue: FWC_MIN_ORDER_VALUE,\n itemTypes: [\n ItemType.FOOD,\n ItemType.GROCERY,\n ItemType.PHARMACY,\n ItemType.COFFEE,\n ItemType.FLOWER,\n ItemType.PET,\n ItemType.HEALTHY_CORNER,\n ],\n },\n };\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { mongoose } from '@typegoose/typegoose';
2
+ export declare class RewardRepository {
3
+ private couponModel;
4
+ constructor();
5
+ findCouponCodesByIds(ids: mongoose.Types.ObjectId[]): Promise<Map<string, string>>;
6
+ }
7
+ export declare const rewardRepository: RewardRepository;
8
+ //# sourceMappingURL=reward.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reward.repository.d.ts","sourceRoot":"/","sources":["modules/tournament/reward/reward.repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,qBACa,gBAAgB;IACzB,OAAO,CAAC,WAAW,CAAqB;;IAMlC,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAK3F;AAED,eAAO,MAAM,gBAAgB,kBAAkC,CAAC"}