Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification mechanism not working in react + django + celery + firebase #629

Open
Nuna7 opened this issue Jun 19, 2024 · 0 comments
Open

Comments

@Nuna7
Copy link

Nuna7 commented Jun 19, 2024

I am trying to implement a notification features which notify the user every selected day of a week at a specific selected time. I use celery, redis, firebase for this task.

My backend (Django):

pms_backend (main app or the default one):

settings.py:

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

celery.py (same directory as settings.py) :

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pms_backend.settings')

app = Celery('pms_backend')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

internal_services (another app):

tasks.py:

c```
red = credentials.Certificate(os.path.join(settings.BASE_DIR, 'firebase.json'))
firebase_admin.initialize_app(cred)

@shared_task
def send_push_notification(title, body, user_tokens):
message = messaging.MulticastMessage(
notification=messaging.Notification(
title=title,
body=body
),
tokens=user_tokens
)
try:
response = messaging.send_multicast(message)
print('Successfully sent message:', response)
except Exception as e:
print('Error sending message:', e)


views.py:


class ProductivityModeView(generics.CreateAPIView):
serializer_class = Productivity
permission_classes = [IsAuthenticated]

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    if serializer.is_valid():
        productivity = serializer.save()

        ProductivityModeUser.objects.create(
            user_id=request.user,
            productivity_id=productivity
        )

        user_tokens = [user.firebase_token for user in User.objects.filter(id=request.user.id) if user.firebase_token]
        for day in productivity.selected_day:
            schedule_task(
                f'productivity_start_{request.user.id}_{day}_{productivity.start_time}',
                day_of_week=day,
                task_time=time(hour=productivity.start_time.hour, minute=productivity.start_time.minute),
                args=['Productivity Mode Started', f'Your productivity mode has started at {productivity.start_time}', user_tokens]
            )
            schedule_task(
                f'productivity_end_{request.user.id}_{day}_{productivity.start_time}',
                day_of_week=day,
                task_time=time(hour=productivity.end_time.hour, minute=productivity.end_time.minute),
                args=['Productivity Mode Ended', f'Your productivity mode has ended at {productivity.end_time}', user_tokens]
            )

        return Response({"message": "Productivity mode created successfully"}, status=status.HTTP_201_CREATED)
    else:
        print("Serializer errors:", serializer.errors)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


My Frontend (React):

public/firebase-messaging-sw.js

importScripts('https://www.gstatic.com/firebasejs/10.1.0/firebase-app-compat.js')
importScripts('https://www.gstatic.com/firebasejs/10.1.0/firebase-messaging-compat.js')

firebase.initializeApp({
apiKey: "AIzaSyD6na5iVJPYZdFGRB79iKIwMdpBKxDLowg",
authDomain: "aqueous-thought-426115-i6.firebaseapp.com",
projectId: "aqueous-thought-426115-i6",
storageBucket: "aqueous-thought-426115-i6.appspot.com",
messagingSenderId: "505424754285",
appId: "1:505424754285:web:d99417903cef886f36b164",
measurementId: "G-W4LKDCL06Y"
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
console.log('Received background message ', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
};

self.registration.showNotification(notificationTitle, notificationOptions);

});


components/Productivity/

`
const ProductivityModeForm = () => {
const vapidKey = 'BPQqDxdT7jRvEXZFNvgTNn355V3hLx4OAX78s7aDiiWO6RGzyxkBv5vD4eEMzOYK6Btywn6uOQyQ3Pkbequfi90';
const [productivityConfig, setProductivityConfig] = useState({
start_time: '',
end_time: '',
selected_day: []
});

const handleChange = (event) => {
    const { name, value, type, checked } = event.target;
    setProductivityConfig(prevConfig => ({
        ...prevConfig,
        [name]: type === 'checkbox' ? checked : value
    }));
};

const handleSubmit = async (event) => {
    event.preventDefault();
    try {
        console.log(productivityConfig);
        const res = await api.post(PRODUCTIVITY, productivityConfig, {
            withCredentials: true,
            headers: {
                'X-CSRFToken': getCsrfToken()
            }
        });
        console.log(res);
    } catch (error) {
        console.log(error);
    }
};

useEffect(() => {
    const requestPermissionAndFetchToken = async () => {
        try {
            console.log('Requesting notification permission...');
            const permission = await Notification.requestPermission();
            if (permission === 'granted') {
                console.log('Notification permission granted.');
                const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
                const token = await getToken(messaging, { vapidKey, serviceWorkerRegistration: registration });
                console.log('Firebase token:', token);

                const data = { firebase_token: token };
                console.log(TOKEN_URL)
                const res = await api.post(TOKEN_URL, data, {
                    withCredentials: true,
                    headers: {
                        'X-CSRFToken': getCsrfToken()
                    }
                });
                console.log('Token response:', res);
            } else {
                console.error('Notification permission not granted');
            }
        } catch (error) {
            console.error('Error getting Firebase token:', error);
        }
    };

    requestPermissionAndFetchToken();
}, []);

useEffect(() => {
    console.log('Subscribing to messages...');
    const unsubscribe = onMessage(messaging, (payload) => {
        console.log('Message received:', payload);
        const notificationTitle = payload.notification.title;
        const notificationOptions = {
            body: payload.notification.body,
            icon: 'logo192.png',
        };
        new Notification(notificationTitle, notificationOptions);
    });

    return unsubscribe;
}, []);

return (
    <form onSubmit={handleSubmit}>
        <h2>Productivity Mode</h2>
        <label>
            Start Time:
            <input type="time" name="start_time" value={productivityConfig.start_time} onChange={handleChange}/>
        </label>
        <br />
        <label>
            End Time:
            <input type="time" name="end_time" value={productivityConfig.end_time} onChange={handleChange}/>
        </label>
        <br />
        <label>
            Select Day(s) of the Week:
            <select multiple name="selected_day" value={productivityConfig.selected_day} onChange={handleChange}>
                <option value={1}>Monday</option>
                <option value={2}>Tuesday</option>
                <option value={3}>Wednesday</option>
                <option value={4}>Thursday</option>
                <option value={5}>Friday</option>
                <option value={6}>Saturday</option>
                <option value={7}>Sunday</option>
            </select>
        </label>
        <br />
        <button type="submit">Submit</button>
    </form>
);

};

export default ProductivityModeForm;


When I create a productivity instance, everything is fine and the fcm token are also stored to user table in the database. Celery worker and beat didn't output any error.

However, I never got notification.

The logs of celery worker :

celery -A pms_backend worker -l info

-------------- [email protected] v5.3.6 (emerald-rush)
--- ***** -----
-- ******* ---- macOS-10.16-x86_64-i386-64bit 2024-06-19 16:37:23

  • *** --- * ---
  • ** ---------- [config]
  • ** ---------- .> app: pms_backend:0x7f9cc87063d0
  • ** ---------- .> transport: redis://localhost:6379/0
  • ** ---------- .> results: redis://localhost:6379/0
  • *** --- * --- .> concurrency: 8 (prefork)
    -- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
    --- ***** -----
    -------------- [queues]
    .> celery exchange=celery(direct) key=celery

[tasks]
. internal_services.tasks.send_push_notification

[2024-06-19 16:37:24,916: INFO/MainProcess] Connected to redis://localhost:6379/0
[2024-06-19 16:37:24,916: WARNING/MainProcess]

[2024-06-19 16:37:24,919: INFO/MainProcess] mingle: searching for neighbors
[2024-06-19 16:37:25,944: INFO/MainProcess] mingle: all alone
[2024-06-19 16:37:25,971: INFO/MainProcess] [email protected] ready.


The logs of celery beat :


celery -A pms_backend beat -l info
celery beat v5.3.6 (emerald-rush) is starting.
__ - ... __ - _
LocalTime -> 2024-06-19 16:37:37
Configuration ->
. broker -> redis://localhost:6379/0
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2024-06-19 16:37:37,614: INFO/MainProcess] beat: Starting...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant