From f044b83b8f1be5220270dbb12980459c5d2a7b69 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Tue, 3 Oct 2017 13:06:26 +0200 Subject: [PATCH 01/12] Add Stripe unsubscribe_customer method --- utils/stripe_utils.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py index 8fcf0ab1..58840be0 100644 --- a/utils/stripe_utils.py +++ b/utils/stripe_utils.py @@ -232,6 +232,17 @@ class StripeUtils(object): ) return subscription_result + @handleStripeError + def unsubscribe_customer(self, subscription_id): + """ + Cancels a given subscription + + :param subscription_id: The Stripe subscription id string + :return: + """ + sub = stripe.Subscription.retrieve(subscription_id) + return sub.delete() + @handleStripeError def make_payment(self, customer, amount, token): charge = self.stripe.Charge.create( From 777aab711503d268767ba096043073df79129066 Mon Sep 17 00:00:00 2001 From: "M.Ravi" Date: Tue, 3 Oct 2017 13:07:41 +0200 Subject: [PATCH 02/12] Add cancel subscription code on VM cancel --- hosting/views.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/hosting/views.py b/hosting/views.py index 6d4f15ca..d534ccbe 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -11,6 +11,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ValidationError from django.core.files.base import ContentFile +from django.core.mail import EmailMessage from django.core.urlresolvers import reverse_lazy, reverse from django.http import Http404, HttpResponseRedirect, HttpResponse @@ -1071,6 +1072,52 @@ class VirtualMachineView(LoginRequiredMixin, View): vm_id=opennebula_vm_id).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() + # Cancel subscription + stripe_utils = StripeUtils() + error_msg_subject = ( + 'Error canceling subscription for ' + '{user} and vm id {vm_id}'.format( + user=owner.email, + vm_id=opennebula_vm_id + ) + ) + try: + hosting_order = HostingOrder.objects.get( + vm_id=opennebula_vm_id + ) + result = stripe_utils.unsubscribe_customer( + subscription_id=hosting_order.subscription_id + ) + stripe_subscription_obj = result.get( + 'response_object') + # Check if the subscription was canceled + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'canceled'): + error_msg = result.get('error') + logger.error(error_msg) + email_data = { + 'subject': error_msg_subject, + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': settings.DCL_ERROR_EMAILS_TO_LIST, + 'body': error_msg, + } + email = EmailMessage(**email_data) + email.send() + except HostingOrder.DoesNotExist: + error_msg = ( + "HostingOrder corresponding to vm_id={vm_id} does" + "not exist. Hence, can not find subscription to " + "cancel ".format(vm_id=opennebula_vm_id) + ) + logger.error(error_msg) + email_data = { + 'subject': error_msg_subject, + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': settings.DCL_ERROR_EMAILS_TO_LIST, + 'body': error_msg, + } + email = EmailMessage(**email_data) + email.send() break except BaseException: break From a04aa8542d7f12760596973ca12343a26eb48b57 Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 12 Dec 2017 22:55:30 +0100 Subject: [PATCH 03/12] Add some logger debug messages --- hosting/views.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index bfb420f0..66df04ba 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1012,7 +1012,7 @@ class VirtualMachineView(LoginRequiredMixin, View): ) return None except Exception as error: - print(error) + logger.error(str(error)) raise Http404() def get_success_url(self): @@ -1068,12 +1068,17 @@ class VirtualMachineView(LoginRequiredMixin, View): try: vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data vm_name = vm_data.get('name') - except WrongIdError: + except WrongIdError as wrong_id_err: + logger.error(str(wrong_id_err)) return redirect(reverse('hosting:virtual_machines')) terminated = manager.delete_vm(vm.id) if not terminated: + logger.debug( + "manager.delete_vm returned False. Hence, error making " + "xml-rpc call to delete vm failed." + ) response['text'] = ugettext( 'Error terminating VM') + opennebula_vm_id else: @@ -1084,7 +1089,8 @@ class VirtualMachineView(LoginRequiredMixin, View): response['status'] = True response['text'] = ugettext('Terminated') vm_detail_obj = VMDetail.objects.filter( - vm_id=opennebula_vm_id).first() + vm_id=opennebula_vm_id + ).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() # Cancel subscription From b4e26ac51f3398e5bf1dae1952346191535617dc Mon Sep 17 00:00:00 2001 From: PCoder Date: Tue, 12 Dec 2017 23:56:39 +0100 Subject: [PATCH 04/12] Add delete_vm_task (wip) --- datacenterlight/tasks.py | 66 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index 3db6eb54..422a6b6d 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -1,4 +1,5 @@ from datetime import datetime +from time import sleep from celery.exceptions import MaxRetriesExceededError from celery.utils.log import get_task_logger @@ -8,6 +9,7 @@ from django.core.mail import EmailMessage from django.core.urlresolvers import reverse from django.utils import translation from django.utils.translation import ugettext_lazy as _ +from oca.pool import WrongIdError from dynamicweb.celery import app from hosting.models import HostingOrder, HostingBill @@ -219,3 +221,67 @@ def create_vm_task(self, vm_template_id, user, specs, template, return return vm_id + + +@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) +def delete_vm_task(self, user_id, vm_id): + return_value = False + owner = CustomUser.objects.get(id=user_id) + logger.debug( + "Running delete_vm_task on {host} for {user} and VM {vm_id}".format( + host=current_task.request.hostname, user=owner.email, + vm_id=vm_id + ) + ) + + manager = OpenNebulaManager( + email=owner.email, + password=owner.password + ) + + terminated = manager.delete_vm(vm_id) + + try: + if not terminated: + logger.error( + "manager.delete_vm returned False. Hence, error making " + "xml-rpc call to delete vm failed." + ) + else: + logger.debug("Start polling for delete vm") + for t in range(15): + try: + manager.get_vm(vm_id) + except BaseException as base_exception: + logger.error( + "manager.get_vm returned exception: {details}. Hence, " + "the vm with id {vm_id} is no more accessible".format( + details=str(base_exception), vm_id=vm_id + ) + ) + return_value = True + break + else: + sleep(5) + if return_value is False: + raise Exception("Could not delete vm {}".format(vm_id)) + except Exception as e: + logger.error(str(e)) + try: + retry_task(self) + except MaxRetriesExceededError: + msg_text = 'Finished {} retries for delete_vm_task'.format( + self.request.retries + ) + logger.error(msg_text) + # Try sending email and stop + email_data = { + 'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, + msg_text), + 'from_email': current_task.request.hostname, + 'to': settings.DCL_ERROR_EMAILS_TO_LIST, + 'body': ',\n'.join(str(i) for i in self.request.args) + } + email = EmailMessage(**email_data) + email.send() + return return_value From 8356c3bf95b41a12be6c8aa7efb71ddf4a4d40ee Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Dec 2017 19:27:45 +0100 Subject: [PATCH 05/12] Refactor some code --- datacenterlight/tasks.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index 422a6b6d..cd50610c 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -233,15 +233,14 @@ def delete_vm_task(self, user_id, vm_id): vm_id=vm_id ) ) - - manager = OpenNebulaManager( - email=owner.email, - password=owner.password - ) - - terminated = manager.delete_vm(vm_id) - try: + manager = OpenNebulaManager( + email=owner.email, + password=owner.password + ) + + terminated = manager.delete_vm(vm_id) + if not terminated: logger.error( "manager.delete_vm returned False. Hence, error making " @@ -249,6 +248,8 @@ def delete_vm_task(self, user_id, vm_id): ) else: logger.debug("Start polling for delete vm") + # Time between two get_vm polls in seconds + inter_get_vm_poll_time = 5 for t in range(15): try: manager.get_vm(vm_id) @@ -262,7 +263,13 @@ def delete_vm_task(self, user_id, vm_id): return_value = True break else: - sleep(5) + logger.debug( + "VM {vm_id} is still accessible. So, sleeping for " + "{sleep_time} and then retrying".format( + vm_id=vm_id, sleep_time=inter_get_vm_poll_time + ) + ) + sleep(inter_get_vm_poll_time) if return_value is False: raise Exception("Could not delete vm {}".format(vm_id)) except Exception as e: From 78fa06aa948ffc859fee49744244a1486cda534b Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Dec 2017 19:35:38 +0100 Subject: [PATCH 06/12] Log exception details --- datacenterlight/tasks.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index cd50610c..36c399de 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -9,7 +9,6 @@ from django.core.mail import EmailMessage from django.core.urlresolvers import reverse from django.utils import translation from django.utils.translation import ugettext_lazy as _ -from oca.pool import WrongIdError from dynamicweb.celery import app from hosting.models import HostingOrder, HostingBill @@ -273,6 +272,12 @@ def delete_vm_task(self, user_id, vm_id): if return_value is False: raise Exception("Could not delete vm {}".format(vm_id)) except Exception as e: + logger.error( + "An exception occurred while deleting VM {vm_id}. Details " + "below".format( + vm_id=vm_id + ) + ) logger.error(str(e)) try: retry_task(self) From 7d683e125786b166d3943b93f8e469d99519f032 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Dec 2017 20:20:42 +0100 Subject: [PATCH 07/12] Move Stripe subscription cancelation before deleting vm --- hosting/views.py | 97 ++++++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 66df04ba..9ce1a9a4 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1060,6 +1060,53 @@ class VirtualMachineView(LoginRequiredMixin, View): opennebula_vm_id = self.kwargs.get('pk') + # Cancel subscription + stripe_utils = StripeUtils() + error_msg_subject = ( + 'Error canceling subscription for ' + '{user} and vm id {vm_id}'.format( + user=owner.email, + vm_id=opennebula_vm_id + ) + ) + try: + hosting_order = HostingOrder.objects.get( + vm_id=opennebula_vm_id + ) + result = stripe_utils.unsubscribe_customer( + subscription_id=hosting_order.subscription_id + ) + stripe_subscription_obj = result.get('response_object') + # Check if the subscription was canceled + if (stripe_subscription_obj is None or + stripe_subscription_obj.status != 'canceled'): + error_msg = result.get('error') + logger.error(error_msg_subject) + logger.error(error_msg) + email_data = { + 'subject': error_msg_subject, + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': settings.DCL_ERROR_EMAILS_TO_LIST, + 'body': error_msg, + } + email = EmailMessage(**email_data) + email.send() + except HostingOrder.DoesNotExist: + error_msg = ( + "HostingOrder corresponding to vm_id={vm_id} does" + "not exist. Hence, can not find subscription to " + "cancel ".format(vm_id=opennebula_vm_id) + ) + logger.error(error_msg) + email_data = { + 'subject': error_msg_subject, + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': settings.DCL_ERROR_EMAILS_TO_LIST, + 'body': error_msg, + } + email = EmailMessage(**email_data) + email.send() + manager = OpenNebulaManager( email=owner.email, password=owner.password @@ -1093,54 +1140,14 @@ class VirtualMachineView(LoginRequiredMixin, View): ).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() - # Cancel subscription - stripe_utils = StripeUtils() - error_msg_subject = ( - 'Error canceling subscription for ' - '{user} and vm id {vm_id}'.format( - user=owner.email, + except BaseException as base_exception: + logger.error( + "manager.get_vm returned exception: {details}. Hence, " + "the vm with id {vm_id} is no more accessible".format( + details=str(base_exception), vm_id=opennebula_vm_id ) ) - try: - hosting_order = HostingOrder.objects.get( - vm_id=opennebula_vm_id - ) - result = stripe_utils.unsubscribe_customer( - subscription_id=hosting_order.subscription_id - ) - stripe_subscription_obj = result.get( - 'response_object') - # Check if the subscription was canceled - if (stripe_subscription_obj is None or - stripe_subscription_obj.status != 'canceled'): - error_msg = result.get('error') - logger.error(error_msg) - email_data = { - 'subject': error_msg_subject, - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': settings.DCL_ERROR_EMAILS_TO_LIST, - 'body': error_msg, - } - email = EmailMessage(**email_data) - email.send() - except HostingOrder.DoesNotExist: - error_msg = ( - "HostingOrder corresponding to vm_id={vm_id} does" - "not exist. Hence, can not find subscription to " - "cancel ".format(vm_id=opennebula_vm_id) - ) - logger.error(error_msg) - email_data = { - 'subject': error_msg_subject, - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': settings.DCL_ERROR_EMAILS_TO_LIST, - 'body': error_msg, - } - email = EmailMessage(**email_data) - email.send() - break - except BaseException: break else: sleep(2) From 96de92d3126c0897f22ab40a02c104958ca48e4c Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 20 Dec 2017 20:59:46 +0100 Subject: [PATCH 08/12] Reorganize code --- hosting/views.py | 97 ++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 9ce1a9a4..cc7c7657 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -42,6 +42,7 @@ from utils.forms import ( from utils.hosting_utils import get_vm_price from utils.mailer import BaseEmail from utils.stripe_utils import StripeUtils +from utils.tasks import send_plain_email_task from utils.views import ( PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin, ResendActivationLinkViewMixin @@ -1055,23 +1056,26 @@ class VirtualMachineView(LoginRequiredMixin, View): def post(self, request, *args, **kwargs): response = {'status': False} + admin_email_body = {} owner = self.request.user vm = self.get_object() - opennebula_vm_id = self.kwargs.get('pk') - - # Cancel subscription - stripe_utils = StripeUtils() - error_msg_subject = ( - 'Error canceling subscription for ' - '{user} and vm id {vm_id}'.format( - user=owner.email, - vm_id=opennebula_vm_id - ) + manager = OpenNebulaManager( + email=owner.email, + password=owner.password ) + try: + vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data + vm_name = vm_data.get('name') + except WrongIdError as wrong_id_err: + logger.error(str(wrong_id_err)) + return redirect(reverse('hosting:virtual_machines')) + + # Cancel Stripe subscription + stripe_utils = StripeUtils() try: hosting_order = HostingOrder.objects.get( - vm_id=opennebula_vm_id + vm_id=vm.id ) result = stripe_utils.unsubscribe_customer( subscription_id=hosting_order.subscription_id @@ -1081,43 +1085,20 @@ class VirtualMachineView(LoginRequiredMixin, View): if (stripe_subscription_obj is None or stripe_subscription_obj.status != 'canceled'): error_msg = result.get('error') - logger.error(error_msg_subject) + logger.error( + 'Error canceling subscription for {user} and vm id ' + '{vm_id}'.format(user=owner.email, vm_id=vm.id) + ) logger.error(error_msg) - email_data = { - 'subject': error_msg_subject, - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': settings.DCL_ERROR_EMAILS_TO_LIST, - 'body': error_msg, - } - email = EmailMessage(**email_data) - email.send() + admin_email_body['stripe_error_msg'] = error_msg except HostingOrder.DoesNotExist: error_msg = ( "HostingOrder corresponding to vm_id={vm_id} does" "not exist. Hence, can not find subscription to " - "cancel ".format(vm_id=opennebula_vm_id) + "cancel ".format(vm_id=vm.id) ) logger.error(error_msg) - email_data = { - 'subject': error_msg_subject, - 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, - 'to': settings.DCL_ERROR_EMAILS_TO_LIST, - 'body': error_msg, - } - email = EmailMessage(**email_data) - email.send() - - manager = OpenNebulaManager( - email=owner.email, - password=owner.password - ) - - try: - vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data - vm_name = vm_data.get('name') - except WrongIdError as wrong_id_err: - logger.error(str(wrong_id_err)) - return redirect(reverse('hosting:virtual_machines')) + admin_email_body['stripe_error_msg'] = error_msg terminated = manager.delete_vm(vm.id) @@ -1126,26 +1107,24 @@ class VirtualMachineView(LoginRequiredMixin, View): "manager.delete_vm returned False. Hence, error making " "xml-rpc call to delete vm failed." ) - response['text'] = ugettext( - 'Error terminating VM') + opennebula_vm_id + response['text'] = ugettext('Error terminating VM') + vm.id else: for t in range(15): try: - manager.get_vm(opennebula_vm_id) + manager.get_vm(vm.id) except WrongIdError: response['status'] = True response['text'] = ugettext('Terminated') vm_detail_obj = VMDetail.objects.filter( - vm_id=opennebula_vm_id + vm_id=vm.id ).first() vm_detail_obj.terminated_at = datetime.utcnow() vm_detail_obj.save() except BaseException as base_exception: logger.error( - "manager.get_vm returned exception: {details}. Hence, " - "the vm with id {vm_id} is no more accessible".format( - details=str(base_exception), - vm_id=opennebula_vm_id + "manager.get_vm({vm_id}) returned exception: " + "{details}.".format( + details=str(base_exception), vm_id=vm.id ) ) break @@ -1153,10 +1132,12 @@ class VirtualMachineView(LoginRequiredMixin, View): sleep(2) context = { 'vm_name': vm_name, - 'base_url': "{0}://{1}".format(self.request.scheme, - self.request.get_host()), + 'base_url': "{0}://{1}".format( + self.request.scheme, self.request.get_host() + ), 'page_header': _('Virtual Machine %(vm_name)s Cancelled') % { - 'vm_name': vm_name} + 'vm_name': vm_name + } } email_data = { 'subject': context['page_header'], @@ -1168,6 +1149,18 @@ class VirtualMachineView(LoginRequiredMixin, View): } email = BaseEmail(**email_data) email.send() + admin_email_body.update(response) + email_to_admin_data = { + 'subject': "Deleted Subscription for VM: {vm_id} and " + "user: {user}".format( + vm_id=vm.id, user=owner.email + ), + 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, + 'to': ['info@ungleich.ch'], + 'body': "\n".join( + ["%s=%s" % (k, v) for (k, v) in admin_email_body]), + } + send_plain_email_task.delay(email_to_admin_data) return HttpResponse( json.dumps(response), content_type="application/json" From f61abf44c8955813c7c9cc362cc399959177c883 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 20 Dec 2017 21:28:07 +0100 Subject: [PATCH 09/12] Remove unused import --- hosting/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hosting/views.py b/hosting/views.py index cc7c7657..42051049 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -11,7 +11,6 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ValidationError from django.core.files.base import ContentFile -from django.core.mail import EmailMessage from django.core.urlresolvers import reverse_lazy, reverse from django.http import Http404, HttpResponseRedirect, HttpResponse From 77002a1c9eac023970c52eadff0243d9e77abadf Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 20 Dec 2017 21:32:02 +0100 Subject: [PATCH 10/12] Revert back celery task for delete_vm. Better to do it in another PR. --- datacenterlight/tasks.py | 78 ---------------------------------------- 1 file changed, 78 deletions(-) diff --git a/datacenterlight/tasks.py b/datacenterlight/tasks.py index 36c399de..3db6eb54 100644 --- a/datacenterlight/tasks.py +++ b/datacenterlight/tasks.py @@ -1,5 +1,4 @@ from datetime import datetime -from time import sleep from celery.exceptions import MaxRetriesExceededError from celery.utils.log import get_task_logger @@ -220,80 +219,3 @@ def create_vm_task(self, vm_template_id, user, specs, template, return return vm_id - - -@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) -def delete_vm_task(self, user_id, vm_id): - return_value = False - owner = CustomUser.objects.get(id=user_id) - logger.debug( - "Running delete_vm_task on {host} for {user} and VM {vm_id}".format( - host=current_task.request.hostname, user=owner.email, - vm_id=vm_id - ) - ) - try: - manager = OpenNebulaManager( - email=owner.email, - password=owner.password - ) - - terminated = manager.delete_vm(vm_id) - - if not terminated: - logger.error( - "manager.delete_vm returned False. Hence, error making " - "xml-rpc call to delete vm failed." - ) - else: - logger.debug("Start polling for delete vm") - # Time between two get_vm polls in seconds - inter_get_vm_poll_time = 5 - for t in range(15): - try: - manager.get_vm(vm_id) - except BaseException as base_exception: - logger.error( - "manager.get_vm returned exception: {details}. Hence, " - "the vm with id {vm_id} is no more accessible".format( - details=str(base_exception), vm_id=vm_id - ) - ) - return_value = True - break - else: - logger.debug( - "VM {vm_id} is still accessible. So, sleeping for " - "{sleep_time} and then retrying".format( - vm_id=vm_id, sleep_time=inter_get_vm_poll_time - ) - ) - sleep(inter_get_vm_poll_time) - if return_value is False: - raise Exception("Could not delete vm {}".format(vm_id)) - except Exception as e: - logger.error( - "An exception occurred while deleting VM {vm_id}. Details " - "below".format( - vm_id=vm_id - ) - ) - logger.error(str(e)) - try: - retry_task(self) - except MaxRetriesExceededError: - msg_text = 'Finished {} retries for delete_vm_task'.format( - self.request.retries - ) - logger.error(msg_text) - # Try sending email and stop - email_data = { - 'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, - msg_text), - 'from_email': current_task.request.hostname, - 'to': settings.DCL_ERROR_EMAILS_TO_LIST, - 'body': ',\n'.join(str(i) for i in self.request.args) - } - email = EmailMessage(**email_data) - email.send() - return return_value From 2628312bb9676382eb20aa7967a3324638335ec7 Mon Sep 17 00:00:00 2001 From: PCoder Date: Wed, 20 Dec 2017 22:26:36 +0100 Subject: [PATCH 11/12] Fix a bug and update delete vm email subject --- hosting/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hosting/views.py b/hosting/views.py index 42051049..e1231dc5 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -1150,14 +1150,14 @@ class VirtualMachineView(LoginRequiredMixin, View): email.send() admin_email_body.update(response) email_to_admin_data = { - 'subject': "Deleted Subscription for VM: {vm_id} and " + 'subject': "Deleted VM and Subscription for VM {vm_id} and " "user: {user}".format( vm_id=vm.id, user=owner.email ), 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, 'to': ['info@ungleich.ch'], 'body': "\n".join( - ["%s=%s" % (k, v) for (k, v) in admin_email_body]), + ["%s=%s" % (k, v) for (k, v) in admin_email_body.items()]), } send_plain_email_task.delay(email_to_admin_data) return HttpResponse( From 3e48b936f4fa8e521f1193e3b8d3e7aadfd0fc18 Mon Sep 17 00:00:00 2001 From: PCoder Date: Fri, 22 Dec 2017 23:03:58 +0100 Subject: [PATCH 12/12] Update Changelog --- Changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog b/Changelog index d3c2c549..adc81a25 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,8 @@ Next: * #3911: [dcl] Integrate resend activation link into dcl landing payment page * #3972: [hosting] Add ungleich company info to invoice footer * #3974: [hosting] Improve invoice number: Show 404 for invoice resources that do not belong to the user + * [ungleich] Add video cover to the header on ungleich.ch landing page and add corresponding cms plugin + * #3774: [hosting] |Update Stripe subscription on vm delete 1.2.13: 2017-12-09 * [cms] Introduce UngleichHeaderBackgroundImageAndTextSliderPlugin that allows to have scrolling images and texts * [cms] Remove

tag for ungleich cms customer item template