backend/src/api/trip-alert/services/trip-alert.ts (view raw)
1import { factories } from "@strapi/strapi";
2import pMap from "p-map";
3import {
4 Coordinates,
5 calculateHaversineDistance,
6} from "../../../utils/geography";
7
8export default factories.createCoreService(
9 "api::trip-alert.trip-alert",
10 ({ strapi }) => ({
11 async sendTripAlerts(eventId: string, travel) {
12 const eventTripAlerts = await strapi.entityService.findMany(
13 "api::trip-alert.trip-alert",
14 {
15 filters: {
16 enabled: true,
17 event: { id: eventId },
18 },
19 populate: ["user"],
20 }
21 );
22 const filteredTripAlerts = eventTripAlerts.filter((tripAlert) => {
23 // If alert has no geographical info, send alert on each new trip
24 if (!tripAlert.latitude || !tripAlert.longitude || !tripAlert.radius)
25 return true;
26 // If travel has no geographical info, send alert to all
27 else if (!travel.meeting_latitude || !travel.meeting_longitude)
28 return true;
29
30 // Else, check if new travel is in alert area
31 const alertCoordinates: Coordinates = [
32 tripAlert.latitude,
33 tripAlert.longitude,
34 ];
35 const travelCoordinates: Coordinates = [
36 travel.meeting_latitude,
37 travel.meeting_longitude,
38 ];
39 const distance = calculateHaversineDistance(
40 travelCoordinates,
41 alertCoordinates
42 );
43 return distance <= tripAlert.radius;
44 });
45
46 await pMap(filteredTripAlerts, async (tripAlert) => {
47 strapi.log.debug(
48 `Create trip alert notification for user ${tripAlert.user.id}`
49 );
50 strapi.entityService.create("api::notification.notification", {
51 data: {
52 type: "NewTrip",
53 event: eventId,
54 user: tripAlert.user.id,
55 payload: { travel },
56 },
57 });
58 });
59 },
60 })
61);