From 24371b629a904a37696262f8c350f115f0f97a10 Mon Sep 17 00:00:00 2001 From: Thomas Steen Rasmussen Date: Sat, 26 May 2018 10:24:52 +0200 Subject: [PATCH] reenable mails to Content team when speaker/eventproposals are created/updated, change so proposal URLs are opened in new window, add a message in browser when proposals are approved in the admin --- src/program/admin.py | 4 +- src/program/models.py | 25 ++++++++-- .../includes/event_proposal_table.html | 2 +- .../includes/eventproposalurl_table.html | 2 +- .../includes/speaker_proposal_table.html | 2 +- .../includes/speakerproposalurl_table.html | 2 +- src/program/views.py | 50 +++++++++++++++++-- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/program/admin.py b/src/program/admin.py index 1686fee3..72ef2b10 100644 --- a/src/program/admin.py +++ b/src/program/admin.py @@ -24,7 +24,7 @@ from .models import ( class SpeakerProposalAdmin(admin.ModelAdmin): def mark_speakerproposal_as_approved(self, request, queryset): for sp in queryset: - sp.mark_as_approved() + sp.mark_as_approved(request) mark_speakerproposal_as_approved.description = 'Approve and create Speaker object(s)' actions = ['mark_speakerproposal_as_approved'] @@ -43,7 +43,7 @@ class EventProposalAdmin(admin.ModelAdmin): return False else: try: - ep.mark_as_approved() + ep.mark_as_approved(request) except ValidationError as e: messages.error(request, e) return False diff --git a/src/program/models.py b/src/program/models.py index 653f7a59..72fd9ad4 100644 --- a/src/program/models.py +++ b/src/program/models.py @@ -247,7 +247,7 @@ class SpeakerProposal(UserSubmittedModel): def get_absolute_url(self): return reverse_lazy('program:speakerproposal_detail', kwargs={'camp_slug': self.camp.slug, 'pk': self.uuid}) - def mark_as_approved(self): + def mark_as_approved(self, request): speakermodel = apps.get_model('program', 'speaker') speakerproposalmodel = apps.get_model('program', 'speakerproposal') speaker = speakermodel() @@ -261,6 +261,16 @@ class SpeakerProposal(UserSubmittedModel): self.proposal_status = speakerproposalmodel.PROPOSAL_APPROVED self.save() + # copy all the URLs too + for url in self.urls.all(): + Url.objects.create( + url=url.url, + urltype=url.urltype, + speaker=speaker + ) + + messages.success(request, "Speaker object %s has been created" % speaker) + class EventProposal(UserSubmittedModel): """ An event proposal """ @@ -336,11 +346,11 @@ class EventProposal(UserSubmittedModel): user=self.user ).exclude(uuid__in=self.speakers.all().values_list('uuid')) - def mark_as_approved(self): + def mark_as_approved(self, request): eventmodel = apps.get_model('program', 'event') eventproposalmodel = apps.get_model('program', 'eventproposal') event = eventmodel() - event.camp = self.camp + event.track = self.track event.title = self.title event.abstract = self.abstract event.event_type = self.event_type @@ -358,6 +368,15 @@ class EventProposal(UserSubmittedModel): self.proposal_status = eventproposalmodel.PROPOSAL_APPROVED self.save() + # copy all the URLs too + for url in self.urls.all(): + Url.objects.create( + url=url.url, + urltype=url.urltype, + event=event + ) + + messages.success(request, "Event object %s has been created" % event) ############################################################################### diff --git a/src/program/templates/includes/event_proposal_table.html b/src/program/templates/includes/event_proposal_table.html index 7bc954a0..6d872a5a 100644 --- a/src/program/templates/includes/event_proposal_table.html +++ b/src/program/templates/includes/event_proposal_table.html @@ -15,7 +15,7 @@ {{ eventproposal.title }} {{ eventproposal.event_type }} - {% for url in eventproposal.urls.all %} {% empty %}N/A{% endfor %} + {% for url in eventproposal.urls.all %} {% empty %}N/A{% endfor %} {% for person in eventproposal.speakers.all %} {% endfor %} {{ eventproposal.track.name }} {{ eventproposal.proposal_status }} diff --git a/src/program/templates/includes/eventproposalurl_table.html b/src/program/templates/includes/eventproposalurl_table.html index 5af137d2..e224038c 100644 --- a/src/program/templates/includes/eventproposalurl_table.html +++ b/src/program/templates/includes/eventproposalurl_table.html @@ -10,7 +10,7 @@ {% for url in eventproposal.urls.all %} {{ url.urltype.name }} - {{ url }} + {{ url }} {% if not camp.read_only %} Update diff --git a/src/program/templates/includes/speaker_proposal_table.html b/src/program/templates/includes/speaker_proposal_table.html index fea5d254..df4988a0 100644 --- a/src/program/templates/includes/speaker_proposal_table.html +++ b/src/program/templates/includes/speaker_proposal_table.html @@ -23,7 +23,7 @@ {% for url in speakerproposal.urls.all %} - + {% empty %} N/A {% endfor %} diff --git a/src/program/templates/includes/speakerproposalurl_table.html b/src/program/templates/includes/speakerproposalurl_table.html index 32e0dfa6..77ad2134 100644 --- a/src/program/templates/includes/speakerproposalurl_table.html +++ b/src/program/templates/includes/speakerproposalurl_table.html @@ -10,7 +10,7 @@ {% for url in speakerproposal.urls.all %} {{ url.urltype.name }} - {{ url }} + {{ url }} {% if not camp.read_only %} Update diff --git a/src/program/views.py b/src/program/views.py index a37a8317..c48235ef 100644 --- a/src/program/views.py +++ b/src/program/views.py @@ -28,6 +28,8 @@ from .mixins import ( UrlViewMixin, ) from .email import ( + add_new_eventproposal_email, + add_new_speakerproposal_email, add_speakerproposal_updated_email, add_eventproposal_updated_email ) @@ -151,6 +153,10 @@ class SpeakerProposalCreateView(LoginRequiredMixin, CampViewMixin, EnsureWritabl # add speakerproposal to eventproposal self.eventproposal.speakers.add(speakerproposal) + # send mail to content team + if not add_new_speakerproposal_email(speakerproposal): + logger.error("Unable to send email to content team after new speakerproposal") + return redirect( reverse('program:proposal_list', kwargs={'camp_slug': self.camp.slug}) ) @@ -163,8 +169,6 @@ class SpeakerProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureWritabl model = models.SpeakerProposal template_name = 'speakerproposal_form.html' - def get_success_url(self): - return reverse('program:proposal_list', kwargs={'camp_slug': self.camp.slug}) def get_form_class(self): """ Get the appropriate form class based on the eventtype """ @@ -181,6 +185,22 @@ class SpeakerProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureWritabl # more than one type of event for this person, return the generic speakerproposal form return BaseSpeakerProposalForm + def form_valid(self, form): + """ + Change the speakerproposal status to pending + """ + # set proposal status to pending + form.instance.proposal_status = models.SpeakerProposal.PROPOSAL_PENDING + speakerproposal = form.save() + + # send mail to content team + if not add_speakerproposal_updated_email(speakerproposal): + logger.error("Unable to send email to content team after speakerproposal update") + + # message user and redirect + messages.info(self.request, "Your proposal is now pending approval by the content team.") + return redirect(reverse('program:proposal_list', kwargs={'camp_slug': self.camp.slug})) + class SpeakerProposalDeleteView(LoginRequiredMixin, CampViewMixin, EnsureWritableCampMixin, EnsureUserOwnsProposalMixin, EnsureCFPOpenMixin, DeleteView): """ @@ -391,6 +411,10 @@ class EventProposalCreateView(LoginRequiredMixin, CampViewMixin, EnsureWritableC # add the speakerproposal to the eventproposal eventproposal.speakers.add(self.speakerproposal) + # send mail to content team + if not add_new_eventproposal_email(eventproposal): + logger.error("Unable to send email to content team after new eventproposal") + # all good return redirect(self.get_success_url()) @@ -406,8 +430,6 @@ class EventProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureWritableC """ Get the appropriate form class based on the eventtype """ return get_eventproposal_form_class(self.get_object().event_type) - def get_success_url(self): - return reverse('program:proposal_list', kwargs={'camp_slug': self.camp.slug}) def get_context_data(self, *args, **kwargs): """ Make speakerproposal and eventtype objects available in the template """ @@ -425,6 +447,19 @@ class EventProposalUpdateView(LoginRequiredMixin, CampViewMixin, EnsureWritableC form.fields['track'].queryset = models.EventTrack.objects.filter(camp=self.camp) return form + def form_valid(self, form): + # set status to pending and save eventproposal + form.instance.proposal_status = models.EventProposal.PROPOSAL_PENDING + eventproposal = form.save() + + # send email to content team + if not add_eventproposal_updated_email(eventproposal): + logger.error("Unable to send email to content team after eventproposal update") + + # message for the user and redirect + messages.info(self.request, "Your proposal is now pending approval by the content team.") + return redirect(reverse('program:proposal_list', kwargs={'camp_slug': self.camp.slug})) + class EventProposalDeleteView(LoginRequiredMixin, CampViewMixin, EnsureWritableCampMixin, EnsureUserOwnsProposalMixin, EnsureCFPOpenMixin, DeleteView): model = models.EventProposal @@ -543,6 +578,13 @@ class CombinedProposalSubmitView(LoginRequiredMixin, CampViewMixin, CreateView): # add the speakerproposal to the eventproposal eventproposal.speakers.add(speakerproposal) + # send mail(s) to content team + if not add_new_eventproposal_email(eventproposal): + logger.error("Unable to send email to content team after new eventproposal") + if not hasattr(self, 'speakerproposal'): + if not add_new_speakerproposal_email(speakerproposal): + logger.error("Unable to send email to content team after new speakerproposal") + # all good return redirect(reverse_lazy('program:proposal_list', kwargs={'camp_slug': self.camp.slug}))