eletrotupi / tcc/ commit / ce0e2eb

all: remove the notification demo path

The test-push button and the unauthenticated /moods/notify broadcast
existed only to fake a notification the system couldn't yet produce.
Both are gone, so the only way to push is through the service that
writes the row first
Pedro Lucas Porcellis porcellis@eletrotupi.com · 11 days ago ce0e2eb7abbf8316bd9002e290d658d6c7da055f Browse files
Parents f6425d4
Changed files
5
Additions
+16
Deletions
-69
api/src/controllers/moods.ts
1 -
import { Request, Response, NextFunction } from 'express';
1 +
import { Response, NextFunction } from 'express';
2 2
import { AuthenticatedRequest } from '@app/middleware/auth';
3 -
import { User } from '@prisma/client';
4 3
import {
5 4
  createMood,
6 5
  getMoodsByUserId,
7 6
  getMoodById,
8 7
  destroyMoodById
9 8
} from '@app/services/mood.service';
10 -

11 -
import { findUsersElligibleForPush } from '@app/services/user.service';
12 -
import { sendPushNotification } from '@app/lib/sendPushNotification';
13 9

14 10
import {
15 11
  CreateMoodSchema
16 12
} from '@app/schemas'
17 13
import { formatValidationError } from '@app/lib/errors/validationError'
69 65
  destroy: async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
70 66
    try {
71 67
      const result = await destroyMoodById(req.userId!, Number(req.params.id!));
72 68

73 69
      return res.status(200).json({})
74 -
    } catch (err) {
75 -
      next(err);
76 -
    }
77 -
  },
78 -

79 -
  sendNotification: async (req: Request, res: Response, next: NextFunction) => {
80 -
    try {
81 -
      const users = await findUsersElligibleForPush();
82 -

83 -
      if (users) {
84 -
        await Promise.all(
85 -
          users
86 -
            .filter((user: User) => user.pushToken)
87 -
            .map((user: User) =>
88 -
              sendPushNotification({
89 -
                token: user.pushToken!,
90 -
                title: 'Como você está?',
91 -
                body: 'Adicione mais registros de humor.',
92 -
                data: { screen: 'notifications' },
93 -
              })
94 -
            )
95 -
        );
96 -
      }
97 -

98 -
      return res.status(200).json(users)
99 70
    } catch (err) {
100 71
      next(err);
101 72
    }
102 73
  }
103 74
};
api/src/routes/moods.ts
1 1
import { Router } from "express";
2 2
import { MoodsController } from '@app/controllers/moods'
3 3
import { requireAuth } from '@app/middleware/auth';
4 4

5 5
const router = Router();
6 6

7 7
router.get('/', requireAuth, MoodsController.index);
8 8
router.get('/:id', requireAuth, MoodsController.show);
9 9
router.post('/', requireAuth, MoodsController.create);
10 10
router.delete('/:id', requireAuth, MoodsController.destroy);
11 -
router.post('/notify', MoodsController.sendNotification);
12 11

13 12
export default router;
api/src/services/user.service.ts
1 1
import { prisma } from '@app/lib/prisma';
2 2
import { User } from '@prisma/client';
3 3
import bcrypt from 'bcryptjs';
4 4

5 5
import {
61 61
      id: input.id
62 62
    },
63 63
    data: updateData
64 64
  })
65 65
}
66 -

67 -
export const findUsersElligibleForPush = async (): Promise<User[]> => {
68 -
  return await prisma.user.findMany({
69 -
    where: {
70 -
      pushToken: {
71 -
        not: null
72 -
      }
73 -
    }
74 -
  });
75 -
}
/dev/null → api/tests/moods/notify.test.ts
1 +
import { describe, it, expect } from 'vitest'
2 +
import request from 'supertest'
3 +
import { createApp } from '@app/createApp'
4 +

5 +
const app = createApp()
6 +

7 +
// The unauthenticated demo broadcast was deleted once notifications became
8 +
// stored records; this guards against reintroducing it.
9 +
describe('POST /moods/notify', () => {
10 +
  it('is no longer routed', async () => {
11 +
    const res = await request(app).post('/moods/notify').send({})
12 +

13 +
    expect(res.status).toBe(404)
14 +
  })
15 +
})
frontend/app/notifications.tsx
1 1
import {
2 2
  StyleSheet,
3 3
  ScrollView,
4 4
  KeyboardAvoidingView,
5 5
} from "react-native";
6 6
import { Text } from "@/components/ui/Text";
7 7

8 8
import { useState, useEffect } from "react";
9 9
import * as Notifications from "expo-notifications";
10 -
import { registerForPushNotifications } from "@/hooks/useRegisterPushToken";
11 10
import { useLocalSearchParams } from "expo-router";
12 11
import { StatusBar } from "expo-status-bar";
13 12
import { SafeAreaView } from "react-native-safe-area-context";
14 -
import { Button } from "@/components/ui/Button";
15 13
import { Colors, Spacing } from "@/constants/theme";
16 14
import { Card } from "@/components/ui/Cards";
17 15
import { Section, SectionHeader } from "@/components/ui/Sections";
18 16

19 17
type NotificationParams = {
41 39
    return () => sub.remove();
42 40
  }, []);
43 41

44 42
  const displayed = liveNotification ?? (params.title || params.body ? { title: params.title, body: params.body } : null);
45 43

46 -
  async function sendPushNotification() {
47 -
    const expoPushToken = await registerForPushNotifications();
48 -

49 -
    if (expoPushToken) {
50 -
      const message = {
51 -
        to: expoPushToken,
52 -
        sound: "default",
53 -
        title: "Oi meu querido",
54 -
        body: "Vamo escutar um The Doors",
55 -
        data: { screen: "notifications" },
56 -
      };
57 -

58 -
      await fetch("https://exp.host/--/api/v2/push/send", {
59 -
        method: "POST",
60 -
        headers: {
61 -
          Accept: "application/json",
62 -
          "Accept-encoding": "gzip, deflate",
63 -
          "Content-Type": "application/json",
64 -
        },
65 -
        body: JSON.stringify(message),
66 -
      });
67 -
    }
68 -
  }
69 -

70 44
  return (
71 45
    <SafeAreaView style={styles.container}>
72 46
      <StatusBar style={"dark"} />
73 47
      <KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
74 48
        <ScrollView
87 61
              <Card style={{ padding: Spacing.cardGap }}>
88 62
                <Text>Nenhuma notificação recebida.</Text>
89 63
              </Card>
90 64
            )}
91 65
          </Section>
92 -

93 -
          <Button title="Quer ver uma coisa?" onPress={sendPushNotification} />
94 66
        </ScrollView>
95 67
      </KeyboardAvoidingView>
96 68
    </SafeAreaView>
97 69
  );
98 70
}
114 86
  header: {
115 87
    alignItems: "flex-start",
116 88
    marginBottom: 40,
117 89
  },
118 90
});