From 81cfb043f06ab71da7c021a063f80f6df58305cc Mon Sep 17 00:00:00 2001 From: Parker Berberian Date: Wed, 24 Oct 2018 15:12:32 -0400 Subject: Rewrite Notification subsystem In this commit: - delete a lot of really bad and / or unused code - redesign a much simpler Notification model - create and send notifications to the user's inbox on booking start & end - migrations - emails user when booking is ready and when it ends Not in this commit: - Creating notifications from lab messages - warning messages when a booking is about to end - creating "summary" notifications when e.g. a booking has been fulfilled by a lab Change-Id: I69b4dc36c3f2bce76d810106baadeef5a562cc7d Signed-off-by: Parker Berberian --- dashboard/src/notifier/manager.py | 181 ++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 77 deletions(-) (limited to 'dashboard/src/notifier/manager.py') diff --git a/dashboard/src/notifier/manager.py b/dashboard/src/notifier/manager.py index a705d00..cc1aa16 100644 --- a/dashboard/src/notifier/manager.py +++ b/dashboard/src/notifier/manager.py @@ -1,98 +1,125 @@ ############################################################################## -# Copyright (c) 2018 Sawyer Bergeron and others. +# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron and others. # # All rights reserved. This program and the accompanying materials # are made available under the terms of the Apache License, Version 2.0 # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +import os +from notifier.models import Notification -from booking.models import * -from notifier.models import Notifier, MetaBooking, LabMessage -from django.utils import timezone -from datetime import timedelta -from django.template import Template, Context -from account.models import UserProfile +from django.core.mail import send_mail +from django.template.loader import render_to_string -from django.db import models -class NotifyPeriodic(object): - def task(): - bookings_new = Booking.objects.filter(metabooking__isnull=True) - bookings_old = Booking.objects.filter(end__lte=timezone.now() + timedelta(hours=24)).filter(metabooking__ended_notified=False) +class NotificationHandler(object): - for booking in bookings_old: - metabooking = booking.metabooking - if booking.end <= timezone.now() + timedelta(hours=24): - if not metabooking.ending_notified: - Notify().notify(Notify.TOCLEAN, booking) - metabooking.ending_notified = True - metabooking.save() - if booking.end <= timezone.now(): - metabooking = booking.metabooking - if not metabooking.ended_notified: - Notify().notify(Notify.CLEANED, booking) - metabooking.ended_notified = True - metabooking.save() + @classmethod + def notify_new_booking(cls, booking): + template = "notifier/new_booking.html" + titles = ["You have a new Booking", "You have been added to a Booking"] + cls.booking_notify(booking, template, titles) - for booking in bookings_new: - metabooking = MetaBooking() - metabooking.booking = booking - metabooking.created_notified = True - metabooking.save() + @classmethod + def notify_booking_end(cls, booking): + template = "notifier/end_booking.html" + titles = ["Your booking has ended", "A booking you collaborate on has ended"] + cls.booking_notify(booking, template, titles) - Notify().notify(Notify.CREATED, booking) + @classmethod + def booking_notify(cls, booking, template, titles): + """ + Creates a notification for a booking owner and collaborators + using the template. + titles is a list - the first is the title for the owner's notification, + the last is the title for the collaborators' + """ + owner_notif = Notification.objects.create( + title=titles[0], + content=render_to_string(template, context={ + "booking": booking, + "owner": True + }) + ) + owner_notif.recipients.add(booking.owner) + if not booking.collaborators.all().exists(): + return # no collaborators - were done + collab_notif = Notification.objects.create( + title=titles[-1], + content=render_to_string(template, context={ + "booking": booking, + "owner": False + }) + ) + for c in booking.collaborators.all(): + collab_notif.recipients.add(c) -class Notify(object): + @classmethod + def email_job_fulfilled(cls, job): + template_name = "notifier/email_fulfilled.txt" + all_tasks = job.get_tasklist() + users = list(job.booking.collaborators.all()) + users.append(job.booking.owner) + for user in users: + user_tasklist = [] + # gather up all the relevant messages from the lab + for task in all_tasks: + if (not hasattr(task, "user")) or task.user == user: + user_tasklist.append({ + "title": task.type_str + " Message: ", + "content": task.message + }) + # gather up all the other needed info + context = { + "user_name": user.userprofile.full_name, + "messages": user_tasklist, + "booking_url": os.environ.get("DASHBOARD_URL", "") + "/booking/detail/" + str(job.booking.id) + "/" + } - CREATED = "created" - TOCLEAN = "toclean" - CLEANED = "cleaned" + # render email template + message = render_to_string(template_name, context) - TITLES = {} - TITLES["created"] = "Your booking has been confirmed" - TITLES["toclean"] = "Your booking is ending soon" - TITLES["cleaned"] = "Your booking has ended" + # finally, send the email + send_mail( + "Your Booking is Ready", + message, + os.environ.get("DEFAULT_FROM_EMAIL", "opnfv@pharos-dashboard"), + user.userprofile.email_addr, + fail_silently=False + ) - """ - Lab message is provided with the following context elements: - * if is for owner or for collaborator (if owner) - * recipient username (.username) - * recipient full name (.userprofile.full_name) - * booking it pertains to (booking) - * status message should convey (currently "created", "toclean" and "cleaned" as strings) - It should be a django template that can be rendered with these context elements - and should generally use all of them in one way or another. - It should be applicable to email, the web based general view, and should be scalable for - all device formats across those mediums. - """ - def notify(self, notifier_type, booking): - template = Template(LabMessage.objects.filter(lab=booking.lab).first().msg) + @classmethod + def email_booking_over(cls, booking): + template_name = "notifier/email_ended.txt" + hostnames = [host.template.resource.name for host in booking.resource.hosts.all()] + users = list(booking.collaborators.all()) + users.append(booking.owner) + for user in users: + context = { + "user_name": user.userprofile.full_name, + "booking": booking, + "hosts": hostnames, + "booking_url": os.environ.get("DASHBOARD_URL", "") + "/booking/detail/" + str(booking.id) + "/" + } - context = {} - context["owner"] = booking.owner - context["notify_type"] = notifier_type - context["booking"] = booking - message = template.render(Context(context)) - notifier = Notifier() - notifier.title = self.TITLES[notifier_type] - notifier.content = message - notifier.user = booking.owner.userprofile - notifier.sender = str(booking.lab) - notifier.save() - notifier.send() + message = render_to_string(template_name, context) + send_mail( + "Your Booking has Expired", + message, + os.environ.get("DEFAULT_FROM_EMAIL", "opnfv@pharos-dashboard"), + user.userprofile.email_addr, + fail_silently=False + ) - context["owner"] = False - - for user in booking.collaborators.all(): - context["collaborator"] = user - message = template.render(Context(context)) - notifier = Notifier() - notifier.title = self.TITLES[notifier_type] - notifier.content = message - notifier.user = UserProfile.objects.get(user=user) - notifier.sender = str(booking.lab) - notifier.save() - notifier.send() + @classmethod + def task_updated(cls, task): + """ + called every time a lab updated info about a task. + currently only checks if the job is now done so I can send an email, + may add more functionality later + """ + if task.job.is_fulfilled(): + cls.email_job_fulfilled(task.job) -- cgit 1.2.3-korg