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 const vehicleName =
47 travel.firstname && travel.lastname
48 ? `${travel.firstname} ${travel.lastname[0]}.`
49 : travel.vehicleName;
50 await pMap(filteredTripAlerts, async (tripAlert) => {
51 strapi.log.debug(
52 `Create trip alert notification for user ${tripAlert.user.id}`
53 );
54 strapi.entityService.create("api::notification.notification", {
55 data: {
56 type: "NewTripAlert",
57 event: eventId,
58 user: tripAlert.user.id,
59 payload: { travel, vehicleName },
60 },
61 });
62 });
63 },
64 })
65);