merged master
This commit is contained in:
		
				commit
				
					
						f4766c7d7c
					
				
			
		
					 8 changed files with 470 additions and 216 deletions
				
			
		|  | @ -8,7 +8,7 @@ msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PACKAGE VERSION\n" | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: \n" | "Report-Msgid-Bugs-To: \n" | ||||||
| "POT-Creation-Date: 2017-09-03 16:44+0000\n" | "POT-Creation-Date: 2017-09-16 14:09+0000\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
|  | @ -18,6 +18,10 @@ msgstr "" | ||||||
| "Content-Transfer-Encoding: 8bit\n" | "Content-Transfer-Encoding: 8bit\n" | ||||||
| "Plural-Forms: nplurals=2; plural=(n != 1);\n" | "Plural-Forms: nplurals=2; plural=(n != 1);\n" | ||||||
| 
 | 
 | ||||||
|  | #, python-format | ||||||
|  | msgid "Your New VM %(vm_name)s at Data Center Light" | ||||||
|  | msgstr "Deine neue VM %(vm_name)s bei Data Center Light" | ||||||
|  | 
 | ||||||
| msgid "Enter name" | msgid "Enter name" | ||||||
| msgstr "Name" | msgstr "Name" | ||||||
| 
 | 
 | ||||||
|  | @ -183,9 +187,18 @@ msgstr "Kontakt" | ||||||
| msgid "All Rights Reserved" | msgid "All Rights Reserved" | ||||||
| msgstr "Alle Rechte vorbehalten" | msgstr "Alle Rechte vorbehalten" | ||||||
| 
 | 
 | ||||||
|  | msgid "Toggle navigation" | ||||||
|  | msgstr "Konfiguration" | ||||||
|  | 
 | ||||||
| msgid "Why Data Center Light?" | msgid "Why Data Center Light?" | ||||||
| msgstr "Warum Data Center Light?" | msgstr "Warum Data Center Light?" | ||||||
| 
 | 
 | ||||||
|  | msgid "Login" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "Dashboard" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
| msgid "Finally, an affordable VM hosting in Switzerland!" | msgid "Finally, an affordable VM hosting in Switzerland!" | ||||||
| msgstr "Endlich: bezahlbares VM Hosting in der Schweiz" | msgstr "Endlich: bezahlbares VM Hosting in der Schweiz" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,15 +1,22 @@ | ||||||
| from dynamicweb.celery import app | from datetime import datetime | ||||||
|  | 
 | ||||||
|  | from celery.exceptions import MaxRetriesExceededError | ||||||
| from celery.utils.log import get_task_logger | from celery.utils.log import get_task_logger | ||||||
|  | from celery import current_task | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
|  | from django.core.mail import EmailMessage | ||||||
|  | from django.utils import translation | ||||||
|  | from django.utils.translation import ugettext_lazy as _ | ||||||
|  | 
 | ||||||
|  | from dynamicweb.celery import app | ||||||
|  | from hosting.models import HostingOrder, HostingBill | ||||||
|  | from membership.models import StripeCustomer, CustomUser | ||||||
| from opennebula_api.models import OpenNebulaManager | from opennebula_api.models import OpenNebulaManager | ||||||
| from opennebula_api.serializers import VirtualMachineSerializer | from opennebula_api.serializers import VirtualMachineSerializer | ||||||
| from hosting.models import HostingOrder, HostingBill | from utils.hosting_utils import get_all_public_keys | ||||||
| from utils.forms import UserBillingAddressForm | from utils.forms import UserBillingAddressForm | ||||||
| from datetime import datetime | from utils.mailer import BaseEmail | ||||||
| from membership.models import StripeCustomer |  | ||||||
| from django.core.mail import EmailMessage |  | ||||||
| from utils.models import BillingAddress | from utils.models import BillingAddress | ||||||
| from celery.exceptions import MaxRetriesExceededError |  | ||||||
| 
 | 
 | ||||||
| logger = get_task_logger(__name__) | logger = get_task_logger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -45,25 +52,36 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|                    stripe_customer_id, billing_address_data, |                    stripe_customer_id, billing_address_data, | ||||||
|                    billing_address_id, |                    billing_address_id, | ||||||
|                    charge, cc_details): |                    charge, cc_details): | ||||||
|  |     logger.debug("Running create_vm_task on {}".format(current_task.request.hostname)) | ||||||
|     vm_id = None |     vm_id = None | ||||||
|     try: |     try: | ||||||
|         final_price = specs.get('price') |         final_price = specs.get('price') | ||||||
|         billing_address = BillingAddress.objects.filter( |         billing_address = BillingAddress.objects.filter( | ||||||
|             id=billing_address_id).first() |             id=billing_address_id).first() | ||||||
|         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | ||||||
|         # Create OpenNebulaManager |  | ||||||
|         manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, |  | ||||||
|                                     password=settings.OPENNEBULA_PASSWORD) |  | ||||||
| 
 | 
 | ||||||
|         # Create a vm using oneadmin, also specify the name |         if 'pass' in user: | ||||||
|  |             on_user = user.get('email') | ||||||
|  |             on_pass = user.get('pass') | ||||||
|  |             logger.debug("Using user {user} to create VM".format(user=on_user)) | ||||||
|  |             vm_name = None | ||||||
|  |         else: | ||||||
|  |             on_user = settings.OPENNEBULA_USERNAME | ||||||
|  |             on_pass = settings.OPENNEBULA_PASSWORD | ||||||
|  |             logger.debug("Using OpenNebula admin user to create VM") | ||||||
|  |             vm_name = "{email}-{template_name}-{date}".format( | ||||||
|  |                 email=user.get('email'), | ||||||
|  |                 template_name=template.get('name'), | ||||||
|  |                 date=int(datetime.now().strftime("%s"))) | ||||||
|  | 
 | ||||||
|  |         # Create OpenNebulaManager | ||||||
|  |         manager = OpenNebulaManager(email=on_user, password=on_pass) | ||||||
|  | 
 | ||||||
|         vm_id = manager.create_vm( |         vm_id = manager.create_vm( | ||||||
|             template_id=vm_template_id, |             template_id=vm_template_id, | ||||||
|             specs=specs, |             specs=specs, | ||||||
|             ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY, |             ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY, | ||||||
|             vm_name="{email}-{template_name}-{date}".format( |             vm_name=vm_name | ||||||
|                 email=user.get('email'), |  | ||||||
|                 template_name=template.get('name'), |  | ||||||
|                 date=int(datetime.now().strftime("%s"))) |  | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         if vm_id is None: |         if vm_id is None: | ||||||
|  | @ -122,6 +140,54 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|         } |         } | ||||||
|         email = EmailMessage(**email_data) |         email = EmailMessage(**email_data) | ||||||
|         email.send() |         email.send() | ||||||
|  | 
 | ||||||
|  |         if 'pass' in user: | ||||||
|  |             lang = 'en-us'  | ||||||
|  |             if user.get('language') is not None: | ||||||
|  |                 logger.debug("Language is set to {}".format(user.get('language'))) | ||||||
|  |                 lang = user.get('language') | ||||||
|  |             translation.activate(lang) | ||||||
|  |             # Send notification to the user as soon as VM has been booked | ||||||
|  |             context = { | ||||||
|  |                 'vm': vm, | ||||||
|  |                 'order': order, | ||||||
|  |                 'base_url': "{0}://{1}".format(user.get('request_scheme'), | ||||||
|  |                                                user.get('request_host')), | ||||||
|  |                 'page_header': _( | ||||||
|  |                     'Your New VM %(vm_name)s at Data Center Light') % { | ||||||
|  |                                    'vm_name': vm.get('name')} | ||||||
|  |             } | ||||||
|  |             email_data = { | ||||||
|  |                 'subject': context.get('page_header'), | ||||||
|  |                 'to': user.get('email'), | ||||||
|  |                 'context': context, | ||||||
|  |                 'template_name': 'new_booked_vm', | ||||||
|  |                 'template_path': 'hosting/emails/', | ||||||
|  |                 'from_address': settings.DCL_SUPPORT_FROM_ADDRESS, | ||||||
|  |             } | ||||||
|  |             email = BaseEmail(**email_data) | ||||||
|  |             email.send() | ||||||
|  | 
 | ||||||
|  |             # try to see if we have the IP and that if the ssh keys can | ||||||
|  |             # be configured | ||||||
|  |             new_host = manager.get_primary_ipv4(vm_id) | ||||||
|  |             logger.debug("New VM ID is {vm_id}".format(vm_id=vm_id)) | ||||||
|  |             if new_host is not None: | ||||||
|  |                 custom_user = CustomUser.objects.get(email=user.get('email')) | ||||||
|  |                 if custom_user is not None: | ||||||
|  |                     public_keys = get_all_public_keys(custom_user) | ||||||
|  |                     keys = [{'value': key, 'state': True} for key in | ||||||
|  |                             public_keys] | ||||||
|  |                     if len(keys) > 0: | ||||||
|  |                         logger.debug( | ||||||
|  |                             "Calling configure on {host} for {num_keys} keys".format( | ||||||
|  |                                 host=new_host, num_keys=len(keys))) | ||||||
|  |                         # Let's delay the task by 75 seconds to be sure | ||||||
|  |                         # that we run the cdist configure after the host | ||||||
|  |                         # is up | ||||||
|  |                         manager.manage_public_key(keys, | ||||||
|  |                                                   hosts=[new_host], | ||||||
|  |                                                   countdown=75) | ||||||
|     except Exception as e: |     except Exception as e: | ||||||
|         logger.error(str(e)) |         logger.error(str(e)) | ||||||
|         try: |         try: | ||||||
|  | @ -134,8 +200,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|             email_data = { |             email_data = { | ||||||
|                 'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, |                 'subject': '{} CELERY TASK ERROR: {}'.format(settings.DCL_TEXT, | ||||||
|                                                              msg_text), |                                                              msg_text), | ||||||
|                 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, |                 'from_email': current_task.request.hostname, | ||||||
|                 'to': ['info@ungleich.ch'], |                 'to': settings.DCL_ERROR_EMAILS_TO_LIST, | ||||||
|                 'body': ',\n'.join(str(i) for i in self.request.args) |                 'body': ',\n'.join(str(i) for i in self.request.args) | ||||||
|             } |             } | ||||||
|             email = EmailMessage(**email_data) |             email = EmailMessage(**email_data) | ||||||
|  |  | ||||||
|  | @ -173,7 +173,8 @@ TEMPLATES = [ | ||||||
|                  os.path.join(PROJECT_DIR, 'nosystemd/templates/'), |                  os.path.join(PROJECT_DIR, 'nosystemd/templates/'), | ||||||
|                  os.path.join(PROJECT_DIR, |                  os.path.join(PROJECT_DIR, | ||||||
|                               'ungleich/templates/djangocms_blog/'), |                               'ungleich/templates/djangocms_blog/'), | ||||||
|                  os.path.join(PROJECT_DIR, 'ungleich/templates/cms/ungleichch'), |                  os.path.join(PROJECT_DIR, | ||||||
|  |                               'ungleich/templates/cms/ungleichch'), | ||||||
|                  os.path.join(PROJECT_DIR, 'ungleich/templates/ungleich'), |                  os.path.join(PROJECT_DIR, 'ungleich/templates/ungleich'), | ||||||
|                  os.path.join(PROJECT_DIR, |                  os.path.join(PROJECT_DIR, | ||||||
|                               'ungleich_page/templates/ungleich_page'), |                               'ungleich_page/templates/ungleich_page'), | ||||||
|  | @ -559,9 +560,21 @@ CELERY_RESULT_BACKEND = env('CELERY_RESULT_BACKEND') | ||||||
| CELERY_ACCEPT_CONTENT = ['application/json'] | CELERY_ACCEPT_CONTENT = ['application/json'] | ||||||
| CELERY_TASK_SERIALIZER = 'json' | CELERY_TASK_SERIALIZER = 'json' | ||||||
| CELERY_RESULT_SERIALIZER = 'json' | CELERY_RESULT_SERIALIZER = 'json' | ||||||
| #CELERY_TIMEZONE = 'Europe/Zurich' | # CELERY_TIMEZONE = 'Europe/Zurich' | ||||||
| CELERY_MAX_RETRIES = int_env('CELERY_MAX_RETRIES', 5) | CELERY_MAX_RETRIES = int_env('CELERY_MAX_RETRIES', 5) | ||||||
| 
 | 
 | ||||||
|  | DCL_ERROR_EMAILS_TO = env('DCL_ERROR_EMAILS_TO') | ||||||
|  | 
 | ||||||
|  | DCL_ERROR_EMAILS_TO_LIST = [] | ||||||
|  | if DCL_ERROR_EMAILS_TO is not None: | ||||||
|  |     DCL_ERROR_EMAILS_TO_LIST = [x.strip() for x in | ||||||
|  |                                 DCL_ERROR_EMAILS_TO.split( | ||||||
|  |                                             ',')] \ | ||||||
|  |         if "," in DCL_ERROR_EMAILS_TO else [DCL_ERROR_EMAILS_TO.strip()] | ||||||
|  | 
 | ||||||
|  | if 'info@ungleich.ch' not in DCL_ERROR_EMAILS_TO_LIST: | ||||||
|  |     DCL_ERROR_EMAILS_TO_LIST.append('info@ungleich.ch') | ||||||
|  | 
 | ||||||
| ENABLE_DEBUG_LOGGING = bool_env('ENABLE_DEBUG_LOGGING') | ENABLE_DEBUG_LOGGING = bool_env('ENABLE_DEBUG_LOGGING') | ||||||
| 
 | 
 | ||||||
| if ENABLE_DEBUG_LOGGING: | if ENABLE_DEBUG_LOGGING: | ||||||
|  |  | ||||||
|  | @ -79,4 +79,35 @@ $(document).ready(function() { | ||||||
|         $('html,body').scrollTop(scrollmem); |         $('html,body').scrollTop(scrollmem); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     var create_vm_form = $('#virtual_machine_create_form'); | ||||||
|  |     create_vm_form.submit(function () { | ||||||
|  |         $('#btn-create-vm').prop('disabled', true); | ||||||
|  |         $.ajax({ | ||||||
|  |             url: create_vm_form.attr('action'), | ||||||
|  |             type: 'POST', | ||||||
|  |             data: create_vm_form.serialize(), | ||||||
|  |             success: function (data) { | ||||||
|  |                 if (data.status === true) { | ||||||
|  |                     fa_icon = $('.modal-icon > .fa'); | ||||||
|  |                     fa_icon.attr('class', 'fa fa-check'); | ||||||
|  |                     $('.modal-header > .close').attr('class', 'close'); | ||||||
|  |                     $('#createvm-modal-title').text(data.msg_title); | ||||||
|  |                     $('#createvm-modal-body').text(data.msg_body); | ||||||
|  |                     $('#createvm-modal').on('hidden.bs.modal', function () { | ||||||
|  |                         window.location = data.redirect; | ||||||
|  |                     }) | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             error: function (xmlhttprequest, textstatus, message) { | ||||||
|  |                     fa_icon = $('.modal-icon > .fa'); | ||||||
|  |                     fa_icon.attr('class', 'fa fa-times'); | ||||||
|  |                     $('.modal-header > .close').attr('class', 'close'); | ||||||
|  |                     if (typeof(create_vm_error_message) !== 'undefined') { | ||||||
|  |                         $('#createvm-modal-title').text(create_vm_error_message); | ||||||
|  |                     } | ||||||
|  |                     $('#btn-create-vm').prop('disabled', false); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         return false; | ||||||
|  |     }); | ||||||
| }); | }); | ||||||
|  | @ -1,63 +1,100 @@ | ||||||
| {% extends "hosting/base_short.html" %} | {% extends "hosting/base_short.html" %} | ||||||
| {% load staticfiles bootstrap3 %} | {% load staticfiles bootstrap3 %} | ||||||
| {% load i18n %} | {% load i18n %} | ||||||
|  | {% load custom_tags %} | ||||||
|  | 
 | ||||||
| {% block content %} | {% block content %} | ||||||
| 
 | 
 | ||||||
| <div class="order-detail-container"> | <div class="order-detail-container"> | ||||||
|    {% if messages %} |     {% if messages %} | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|         <div class="col-xs-12 col-md-8 col-md-offset-2"> |         <div class="col-xs-12 col-md-8 col-md-offset-2"> | ||||||
|             <br/> |             <br/> | ||||||
|                 <div class="alert alert-warning"> |             <div class="alert alert-warning"> | ||||||
|                     {% for message in messages %} |                 {% for message in messages %} | ||||||
|                     <span>{{ message }}</span> |                 <span>{{ message }}</span> | ||||||
|                     {% endfor %} |                 {% endfor %} | ||||||
|                 </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|     {% endif %} |     {% endif %} | ||||||
|     {% if not error %} |     {% if not error %} | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|         <div class="col-xs-12 col-md-8 col-md-offset-2"> |         <div class="col-xs-12 col-md-8 col-md-offset-2"> | ||||||
|     		<div class="invoice-title"> |             <div class="invoice-title"> | ||||||
|     			<h2>{{page_header_text}}</h2><h3 class="pull-right">{% trans "Order #"%} {{order.id}}</h3> |                 <h2>{{page_header_text}}</h2> | ||||||
|     		</div> |                 <h3 class="pull-right"> | ||||||
|     		<hr> |                     {% if order %} | ||||||
|     		<div class="row"> |                     {% trans "Order #"%} {{order.id}} | ||||||
| 				<div class="col-xs-12 col-md-6 pull-right order-confirm-date"> |                     {% endif %} | ||||||
|  |                 </h3> | ||||||
|  |             </div> | ||||||
|  |             <hr> | ||||||
|  |             <div class="row"> | ||||||
|  |                 <div class="col-xs-12 col-md-6 pull-right order-confirm-date"> | ||||||
|                     <address> |                     <address> | ||||||
|                         <strong>{% trans "Date"%}:</strong><br> |                         <strong>{% trans "Date"%}:</strong><br> | ||||||
|                         <span id="order-created_at">{{order.created_at|date:'Y-m-d H:i'}}</span><br><br> |                         <span id="order-created_at"> | ||||||
|  |                                 {% if order %} | ||||||
|  |                                     {{order.created_at|date:'Y-m-d H:i'}} | ||||||
|  |                                 {% else %} | ||||||
|  |                                     {% now "Y-m-d H:i" %} | ||||||
|  |                                 {% endif %} | ||||||
|  |                             </span><br><br> | ||||||
|  |                         {% if order %} | ||||||
|                         <strong>{% trans "Status:"%}</strong><br> |                         <strong>{% trans "Status:"%}</strong><br> | ||||||
|                         {% if order.status == 'Approved' %} |                         {% if order.status == 'Approved' %} | ||||||
|                             <strong class="text-success">{% trans "Approved" %}</strong> |                         <strong class="text-success"> | ||||||
|  |                             {% trans "Approved" %} | ||||||
|  |                         </strong> | ||||||
|                         {% else %} |                         {% else %} | ||||||
|                             <strong class="text-danger">{% trans "Declined" %}</strong> |                         <strong class="text-danger"> | ||||||
|  |                             {% trans "Declined" %} | ||||||
|  |                         </strong> | ||||||
|                         {% endif %} |                         {% endif %} | ||||||
|                         <br><br> |                         <br><br> | ||||||
|  |                         {% endif %} | ||||||
|                     </address> |                     </address> | ||||||
| 
 | 
 | ||||||
|                 </div> |                 </div> | ||||||
|     			<div class="col-xs-12 col-md-6"> |                 <div class="col-xs-12 col-md-6"> | ||||||
|     				<address> |                     <address> | ||||||
|                     <h3><b>{% trans "Billed To:"%}</b></h3> |                         <h3><b>{% trans "Billed To:"%}</b></h3> | ||||||
|     					{{user.name}}<br> |                         {% if order %} | ||||||
|  |                         {{user.name}}<br> | ||||||
|                         {{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br> |                         {{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br> | ||||||
|                         {{order.billing_address.city}}, {{order.billing_address.country}}. |                         {{order.billing_address.city}}, | ||||||
|     				</address> |                         {{order.billing_address.country}}. | ||||||
|     			</div> |                         {% else %} | ||||||
|  |                         {% with request.session.billing_address_data as billing_address %} | ||||||
|  |                         {{billing_address|get_value_from_dict:'cardholder_name'}}<br> | ||||||
|  |                         {{billing_address|get_value_from_dict:'street_address'}}, | ||||||
|  |                         {{billing_address|get_value_from_dict:'postal_code'}}<br> | ||||||
|  |                         {{billing_address|get_value_from_dict:'city'}}, | ||||||
|  |                         {{billing_address|get_value_from_dict:'country'}}. | ||||||
|  |                         {% endwith %} | ||||||
|  |                         {% endif %} | ||||||
|  |                     </address> | ||||||
|  |                 </div> | ||||||
| 
 | 
 | ||||||
|     		</div> |             </div> | ||||||
|     		<div class="row"> |             <div class="row"> | ||||||
|     			<div class="col-xs-6"> |                 <div class="col-xs-6"> | ||||||
|     				<address> |                     <address> | ||||||
|     					<strong>{% trans "Payment Method:"%}</strong><br> |                         <strong>{% trans "Payment Method:"%}</strong><br> | ||||||
|     					{{order.cc_brand}} {% trans "ending in" %} **** {{order.last4}}<br> |                         {% if order %} | ||||||
|     					{{user.email}} |                         {{order.cc_brand}} {% trans "ending in" %} **** | ||||||
|     				</address> |                         {{order.last4}}<br> | ||||||
|     			</div> |                         {{user.email}} | ||||||
|     		</div> |                         {% else %} | ||||||
|     	</div> |                         {{cc_brand}} {% trans "ending in" %} **** | ||||||
|  |                         {{cc_last4}}<br> | ||||||
|  |                         {{request.session.user.email}} | ||||||
|  |                         {% endif %} | ||||||
|  |                     </address> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|  | @ -65,33 +102,113 @@ | ||||||
|             <h3><b>{% trans "Order summary"%}</b></h3> |             <h3><b>{% trans "Order summary"%}</b></h3> | ||||||
|             <hr> |             <hr> | ||||||
|             <div class="content"> |             <div class="content"> | ||||||
|                 <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cores}}</span></p> |                 {% if request.session.specs %} | ||||||
|  |                 {% with request.session.specs as vm %} | ||||||
|  |                 <p><b>{% trans "Cores"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.cpu}}</span> | ||||||
|  |                 </p> | ||||||
|                 <hr> |                 <hr> | ||||||
|                 <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p> |                 <p><b>{% trans "Memory"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.memory}} GB</span> | ||||||
|  |                 </p> | ||||||
|                 <hr> |                 <hr> | ||||||
|                 <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p> |                 <p><b>{% trans "Disk space"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.disk_size}} GB</span> | ||||||
|  |                 </p> | ||||||
|                 <hr> |                 <hr> | ||||||
|                                 <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4> |                 <p><b>{% trans "Configuration"%}</b> | ||||||
|  |                     <span class="pull-right">{{request.session.template.name}}</span> | ||||||
|  |                 </p> | ||||||
|  |                 <hr> | ||||||
|  |                 <h4>{% trans "Total"%} | ||||||
|  |                     <p class="pull-right"> | ||||||
|  |                         <b>{{vm.price}} CHF</b> | ||||||
|  |                         <span class="dcl-price-month"> /{% trans "Month" %} | ||||||
|  |                                 </span> | ||||||
|  |                     </p> | ||||||
|  |                 </h4> | ||||||
|  |                 {% endwith %} | ||||||
|  |                 {% else %} | ||||||
|  |                 <p><b>{% trans "Cores"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.cores}}</span> | ||||||
|  |                 </p> | ||||||
|  |                 <hr> | ||||||
|  |                 <p><b>{% trans "Memory"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.memory}} GB</span> | ||||||
|  |                 </p> | ||||||
|  |                 <hr> | ||||||
|  |                 <p><b>{% trans "Disk space"%}</b> | ||||||
|  |                     <span class="pull-right">{{vm.disk_size}} GB</span> | ||||||
|  |                 </p> | ||||||
|  |                 <hr> | ||||||
|  |                 <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} | ||||||
|  |                     CHF</b><span | ||||||
|  |                         class="dcl-price-month"> /{% trans "Month" %}</span> | ||||||
|  |                 </p></h4> | ||||||
|  |                 {% endif %} | ||||||
|             </div> |             </div> | ||||||
|             <br/> |             <br/> | ||||||
|             {% url 'hosting:payment' as payment_url %} |             {% if not order %} | ||||||
|             {% if payment_url in request.META.HTTP_REFERER  %} |             <form method="post" id="virtual_machine_create_form"> | ||||||
|             <div class=" content pull-right"> |                 {% csrf_token %} | ||||||
|                 <a href="{% url 'hosting:virtual_machines'%}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a> |                 <div class="row"> | ||||||
|             </div> |                     <div class="col-sm-8"> | ||||||
|  |                         <p class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</p> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="col-sm-4 content"> | ||||||
|  |                         <button class="btn btn-info pull-right" | ||||||
|  |                                 id="btn-create-vm" | ||||||
|  |                                 data-href="{% url 'hosting:order-confirmation' %}" | ||||||
|  |                                 data-toggle="modal" | ||||||
|  |                                 data-target="#createvm-modal"> | ||||||
|  |                             {% trans "Place order"%} | ||||||
|  |                         </button> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </form> | ||||||
|             {% endif %} |             {% endif %} | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|     {% endif %} |     {% endif %} | ||||||
| </div> | </div> | ||||||
|  | <!-- Create VM Modal --> | ||||||
|  | <div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog" | ||||||
|  |      aria-hidden="true" data-backdrop="static" data-keyboard="false"> | ||||||
|  |     <div class="modal-dialog"> | ||||||
|  |         <div class="modal-content"> | ||||||
|  |             <div class="modal-header"> | ||||||
|  |                 <button type="button" class="close hidden" data-dismiss="modal" | ||||||
|  |                         aria-label="create-vm-close"> | ||||||
|  |                     <span aria-hidden="true">×</span> | ||||||
|  |                 </button> | ||||||
|  |             </div> | ||||||
|  |             <div class="modal-body"> | ||||||
|  |                 <div class="modal-icon"> | ||||||
|  |                     <i class="fa fa-cog fa-spin fa-3x fa-fw"></i> | ||||||
|  |                     <span class="sr-only">{% trans "Processing..." %}</span> | ||||||
|  |                 </div> | ||||||
|  |                 <h4 class="modal-title" id="createvm-modal-title"> | ||||||
|  |                 </h4> | ||||||
|  |                 <div class="modal-text" id="createvm-modal-body"> | ||||||
|  |                     {% trans "Hold tight, we are processing your request" %} | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | <!-- / Create VM Modal --> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| <script type="text/javascript"> | <script type="text/javascript"> | ||||||
|  |     {% trans "Some problem encountered. Please try again later." as err_msg %} | ||||||
|  |     var create_vm_error_message = '{{err_msg|safe}}.'; | ||||||
| 
 | 
 | ||||||
|     window.onload = function () { |     window.onload = function () { | ||||||
|             var locale_date = moment.utc(document.getElementById("order-created_at").textContent,'YYYY-MM-DD HH:mm').toDate(); |         var locale_date = moment.utc(document.getElementById("order-created_at").textContent, 'YYYY-MM-DD HH:mm').toDate(); | ||||||
|             locale_date =  moment(locale_date).format("YYYY-MM-DD h:mm:ss a"); |         locale_date = moment(locale_date).format("YYYY-MM-DD h:mm:ss a"); | ||||||
|             document.getElementById('order-created_at').innerHTML = locale_date; |         document.getElementById('order-created_at').innerHTML = locale_date; | ||||||
| 
 | 
 | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -21,9 +21,13 @@ urlpatterns = [ | ||||||
|     url(r'payment/?$', PaymentVMView.as_view(), name='payment'), |     url(r'payment/?$', PaymentVMView.as_view(), name='payment'), | ||||||
|     url(r'settings/?$', SettingsView.as_view(), name='settings'), |     url(r'settings/?$', SettingsView.as_view(), name='settings'), | ||||||
|     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), |     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'), | ||||||
|     url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'), |     url(r'order-confirmation/?$', OrdersHostingDetailView.as_view(), | ||||||
|  |         name='order-confirmation'), | ||||||
|  |     url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), | ||||||
|  |         name='orders'), | ||||||
|     url(r'bills/?$', HostingBillListView.as_view(), name='bills'), |     url(r'bills/?$', HostingBillListView.as_view(), name='bills'), | ||||||
|     url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), name='bills'), |     url(r'bills/(?P<pk>\d+)/?$', HostingBillDetailView.as_view(), | ||||||
|  |         name='bills'), | ||||||
|     url(r'cancel_order/(?P<pk>\d+)/?$', |     url(r'cancel_order/(?P<pk>\d+)/?$', | ||||||
|         OrdersHostingDeleteView.as_view(), name='delete_order'), |         OrdersHostingDeleteView.as_view(), name='delete_order'), | ||||||
|     url(r'create_virtual_machine/?$', CreateVirtualMachinesView.as_view(), |     url(r'create_virtual_machine/?$', CreateVirtualMachinesView.as_view(), | ||||||
|  | @ -40,13 +44,16 @@ urlpatterns = [ | ||||||
|         name='delete_ssh_key'), |         name='delete_ssh_key'), | ||||||
|     url(r'create_ssh_key/?$', SSHKeyCreateView.as_view(), |     url(r'create_ssh_key/?$', SSHKeyCreateView.as_view(), | ||||||
|         name='create_ssh_key'), |         name='create_ssh_key'), | ||||||
|     url(r'^notifications/$', NotificationsView.as_view(), name='notifications'), |     url(r'^notifications/$', NotificationsView.as_view(), | ||||||
|  |         name='notifications'), | ||||||
|     url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(), |     url(r'^notifications/(?P<pk>\d+)/?$', MarkAsReadNotificationView.as_view(), | ||||||
|         name='read_notification'), |         name='read_notification'), | ||||||
|     url(r'login/?$', LoginView.as_view(), name='login'), |     url(r'login/?$', LoginView.as_view(), name='login'), | ||||||
|     url(r'signup/?$', SignupView.as_view(), name='signup'), |     url(r'signup/?$', SignupView.as_view(), name='signup'), | ||||||
|     url(r'signup-validate/?$', SignupValidateView.as_view(), name='signup-validate'), |     url(r'signup-validate/?$', SignupValidateView.as_view(), | ||||||
|     url(r'reset-password/?$', PasswordResetView.as_view(), name='reset_password'), |         name='signup-validate'), | ||||||
|  |     url(r'reset-password/?$', PasswordResetView.as_view(), | ||||||
|  |         name='reset_password'), | ||||||
|     url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', |     url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', | ||||||
|         PasswordResetConfirmView.as_view(), name='reset_password_confirm'), |         PasswordResetConfirmView.as_view(), name='reset_password_confirm'), | ||||||
|     url(r'^logout/?$', auth_views.logout, |     url(r'^logout/?$', auth_views.logout, | ||||||
|  |  | ||||||
							
								
								
									
										288
									
								
								hosting/views.py
									
										
									
									
									
								
							
							
						
						
									
										288
									
								
								hosting/views.py
									
										
									
									
									
								
							|  | @ -1,6 +1,6 @@ | ||||||
|  | import json | ||||||
| import logging | import logging | ||||||
| import uuid | import uuid | ||||||
| import json |  | ||||||
| from time import sleep | from time import sleep | ||||||
| 
 | 
 | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
|  | @ -9,32 +9,35 @@ from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.contrib.auth.tokens import default_token_generator | from django.contrib.auth.tokens import default_token_generator | ||||||
| from django.core.files.base import ContentFile | from django.core.files.base import ContentFile | ||||||
| from django.core.urlresolvers import reverse_lazy, reverse | from django.core.urlresolvers import reverse_lazy, reverse | ||||||
|  | 
 | ||||||
| from django.http import Http404, HttpResponseRedirect, HttpResponse | from django.http import Http404, HttpResponseRedirect, HttpResponse | ||||||
| from django.shortcuts import redirect, render | from django.shortcuts import redirect, render | ||||||
| from django.utils.http import urlsafe_base64_decode | from django.utils.http import urlsafe_base64_decode | ||||||
| from django.utils.safestring import mark_safe | from django.utils.safestring import mark_safe | ||||||
| from django.utils.translation import ugettext_lazy as _ | from django.utils.translation import ugettext_lazy as _ | ||||||
| from django.utils.translation import ugettext | from django.utils.translation import ugettext | ||||||
| from django.views.generic import View, CreateView, FormView, ListView, \ | from django.views.generic import ( | ||||||
|     DetailView, \ |     View, CreateView, FormView, ListView, DetailView, DeleteView, | ||||||
|     DeleteView, TemplateView, UpdateView |     TemplateView, UpdateView | ||||||
|  | ) | ||||||
| from guardian.mixins import PermissionRequiredMixin | from guardian.mixins import PermissionRequiredMixin | ||||||
| from oca.pool import WrongIdError | from oca.pool import WrongIdError | ||||||
| from stored_messages.api import mark_read | from stored_messages.api import mark_read | ||||||
| from stored_messages.models import Message | from stored_messages.models import Message | ||||||
| from stored_messages.settings import stored_messages_settings | from stored_messages.settings import stored_messages_settings | ||||||
| 
 | 
 | ||||||
|  | from datacenterlight.tasks import create_vm_task | ||||||
| from membership.models import CustomUser, StripeCustomer | from membership.models import CustomUser, StripeCustomer | ||||||
| from opennebula_api.models import OpenNebulaManager | from opennebula_api.models import OpenNebulaManager | ||||||
| from opennebula_api.serializers import VirtualMachineSerializer, \ | from opennebula_api.serializers import VirtualMachineSerializer, \ | ||||||
|     VirtualMachineTemplateSerializer |     VirtualMachineTemplateSerializer | ||||||
| from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | ||||||
|     UserBillingAddressForm |     UserBillingAddressForm | ||||||
| from utils.hosting_utils import get_all_public_keys |  | ||||||
| from utils.mailer import BaseEmail | from utils.mailer import BaseEmail | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| from utils.views import PasswordResetViewMixin, PasswordResetConfirmViewMixin, \ | from utils.views import ( | ||||||
|     LoginViewMixin |     PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin | ||||||
|  | ) | ||||||
| from .forms import HostingUserSignupForm, HostingUserLoginForm, \ | from .forms import HostingUserSignupForm, HostingUserLoginForm, \ | ||||||
|     UserHostingKeyForm, generate_ssh_key_name |     UserHostingKeyForm, generate_ssh_key_name | ||||||
| from .mixins import ProcessVMSelectionMixin | from .mixins import ProcessVMSelectionMixin | ||||||
|  | @ -607,23 +610,10 @@ class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
|     def post(self, request, *args, **kwargs): |     def post(self, request, *args, **kwargs): | ||||||
|         form = self.get_form() |         form = self.get_form() | ||||||
|         if form.is_valid(): |         if form.is_valid(): | ||||||
| 
 |  | ||||||
|             # Get billing address data |             # Get billing address data | ||||||
|             billing_address_data = form.cleaned_data |             billing_address_data = form.cleaned_data | ||||||
| 
 |  | ||||||
|             context = self.get_context_data() |  | ||||||
| 
 |  | ||||||
|             template = request.session.get('template') |  | ||||||
|             specs = request.session.get('specs') |  | ||||||
| 
 |  | ||||||
|             vm_template_id = template.get('id', 1) |  | ||||||
| 
 |  | ||||||
|             final_price = specs.get('price') |  | ||||||
| 
 |  | ||||||
|             token = form.cleaned_data.get('token') |             token = form.cleaned_data.get('token') | ||||||
| 
 |  | ||||||
|             owner = self.request.user |             owner = self.request.user | ||||||
| 
 |  | ||||||
|             # Get or create stripe customer |             # Get or create stripe customer | ||||||
|             customer = StripeCustomer.get_or_create(email=owner.email, |             customer = StripeCustomer.get_or_create(email=owner.email, | ||||||
|                                                     token=token) |                                                     token=token) | ||||||
|  | @ -637,115 +627,18 @@ class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
| 
 | 
 | ||||||
|             # Create Billing Address |             # Create Billing Address | ||||||
|             billing_address = form.save() |             billing_address = form.save() | ||||||
| 
 |             request.session['billing_address_data'] = billing_address_data | ||||||
|             # Make stripe charge to a customer |             request.session['billing_address'] = billing_address.id | ||||||
|             stripe_utils = StripeUtils() |             request.session['token'] = token | ||||||
|             charge_response = stripe_utils.make_charge(amount=final_price, |             request.session['customer'] = customer.id | ||||||
|                                                        customer=customer.stripe_id) |             return HttpResponseRedirect("{url}?{query_params}".format( | ||||||
| 
 |                 url=reverse('hosting:order-confirmation'), | ||||||
|             # Check if the payment was approved |                 query_params='page=payment')) | ||||||
|             if not charge_response.get('response_object'): |  | ||||||
|                 msg = charge_response.get('error') |  | ||||||
|                 messages.add_message( |  | ||||||
|                     self.request, messages.ERROR, msg, |  | ||||||
|                     extra_tags='make_charge_error') |  | ||||||
|                 return HttpResponseRedirect( |  | ||||||
|                     reverse('hosting:payment') + '#payment_error') |  | ||||||
| 
 |  | ||||||
|             charge = charge_response.get('response_object') |  | ||||||
| 
 |  | ||||||
|             # Create OpenNebulaManager |  | ||||||
|             manager = OpenNebulaManager(email=owner.email, |  | ||||||
|                                         password=owner.password) |  | ||||||
|             # Get user ssh key |  | ||||||
|             if not UserHostingKey.objects.filter( |  | ||||||
|                     user=self.request.user).exists(): |  | ||||||
|                 context.update({ |  | ||||||
|                     'sshError': 'error', |  | ||||||
|                     'form': form |  | ||||||
|                 }) |  | ||||||
|                 return render(request, self.template_name, context) |  | ||||||
| 
 |  | ||||||
|             # Create a vm using logged user |  | ||||||
|             vm_id = manager.create_vm( |  | ||||||
|                 template_id=vm_template_id, |  | ||||||
|                 specs=specs, |  | ||||||
|                 ssh_key=settings.ONEADMIN_USER_SSH_PUBLIC_KEY, |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|             # Create a Hosting Order |  | ||||||
|             order = HostingOrder.create( |  | ||||||
|                 price=final_price, |  | ||||||
|                 vm_id=vm_id, |  | ||||||
|                 customer=customer, |  | ||||||
|                 billing_address=billing_address |  | ||||||
|             ) |  | ||||||
| 
 |  | ||||||
|             # Create a Hosting Bill |  | ||||||
|             HostingBill.create( |  | ||||||
|                 customer=customer, billing_address=billing_address) |  | ||||||
| 
 |  | ||||||
|             # Create Billing Address for User if he does not have one |  | ||||||
|             if not customer.user.billing_addresses.count(): |  | ||||||
|                 billing_address_data.update({ |  | ||||||
|                     'user': customer.user.id |  | ||||||
|                 }) |  | ||||||
|                 billing_address_user_form = UserBillingAddressForm( |  | ||||||
|                     billing_address_data) |  | ||||||
|                 billing_address_user_form.is_valid() |  | ||||||
|                 billing_address_user_form.save() |  | ||||||
| 
 |  | ||||||
|             # Associate an order with a stripe payment |  | ||||||
|             order.set_stripe_charge(charge) |  | ||||||
| 
 |  | ||||||
|             # If the Stripe payment was successed, set order status approved |  | ||||||
|             order.set_approved() |  | ||||||
| 
 |  | ||||||
|             vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data |  | ||||||
| 
 |  | ||||||
|             # Send notification to the user as soon as VM has been booked |  | ||||||
|             context = { |  | ||||||
|                 'vm': vm, |  | ||||||
|                 'order': order, |  | ||||||
|                 'base_url': "{0}://{1}".format(request.scheme, |  | ||||||
|                                                request.get_host()), |  | ||||||
|                 'page_header': _( |  | ||||||
|                     'Your New VM %(vm_name)s at Data Center Light') % { |  | ||||||
|                     'vm_name': vm.get('name')} |  | ||||||
|             } |  | ||||||
|             email_data = { |  | ||||||
|                 'subject': context.get('page_header'), |  | ||||||
|                 'to': request.user.email, |  | ||||||
|                 'context': context, |  | ||||||
|                 'template_name': 'new_booked_vm', |  | ||||||
|                 'template_path': 'hosting/emails/', |  | ||||||
|                 'from_address': settings.DCL_SUPPORT_FROM_ADDRESS, |  | ||||||
|             } |  | ||||||
|             email = BaseEmail(**email_data) |  | ||||||
|             email.send() |  | ||||||
| 
 |  | ||||||
|             # try to see if we have the IP and that if the ssh keys can |  | ||||||
|             # be configured |  | ||||||
|             new_host = manager.get_primary_ipv4(vm_id) |  | ||||||
|             if new_host is not None: |  | ||||||
|                 public_keys = get_all_public_keys(owner) |  | ||||||
|                 keys = [{'value': key, 'state': True} for key in public_keys] |  | ||||||
|                 logger.debug( |  | ||||||
|                     "Calling configure on {host} for {num_keys} keys".format( |  | ||||||
|                         host=new_host, num_keys=len(keys))) |  | ||||||
|                 # Let's delay the task by 75 seconds to be sure that we run |  | ||||||
|                 # the cdist configure after the host is up |  | ||||||
|                 manager.manage_public_key(keys, hosts=[new_host], countdown=75) |  | ||||||
| 
 |  | ||||||
|             return HttpResponseRedirect( |  | ||||||
|                 "{url}?{query_params}".format( |  | ||||||
|                     url=reverse('hosting:orders', kwargs={'pk': order.id}), |  | ||||||
|                     query_params='page=payment')) |  | ||||||
|         else: |         else: | ||||||
|             return self.form_invalid(form) |             return self.form_invalid(form) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, | class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|                               DetailView): |                               DetailView): | ||||||
|     template_name = "hosting/order_detail.html" |     template_name = "hosting/order_detail.html" | ||||||
|     context_object_name = "order" |     context_object_name = "order" | ||||||
|  | @ -753,34 +646,145 @@ class OrdersHostingDetailView(PermissionRequiredMixin, LoginRequiredMixin, | ||||||
|     permission_required = ['view_hostingorder'] |     permission_required = ['view_hostingorder'] | ||||||
|     model = HostingOrder |     model = HostingOrder | ||||||
| 
 | 
 | ||||||
|  |     def get_object(self): | ||||||
|  |         return HostingOrder.objects.filter( | ||||||
|  |             pk=self.kwargs.get('pk')) if self.kwargs.get('pk') else None | ||||||
|  | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         # Get context |         # Get context | ||||||
|         context = super(DetailView, self).get_context_data(**kwargs) |         context = super(DetailView, self).get_context_data(**kwargs) | ||||||
|         obj = self.get_object() |         obj = self.get_object() | ||||||
|         owner = self.request.user |         owner = self.request.user | ||||||
|         manager = OpenNebulaManager(email=owner.email, |         if 'specs' not in self.request.session: | ||||||
|                                     password=owner.password) |             return HttpResponseRedirect( | ||||||
|  |                 reverse('hosting:create_virtual_machine')) | ||||||
|  |         if 'token' not in self.request.session: | ||||||
|  |             return HttpResponseRedirect(reverse('hosting:payment')) | ||||||
|  |         stripe_customer_id = self.request.session.get('customer') | ||||||
|  |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | ||||||
|  |         stripe_utils = StripeUtils() | ||||||
|  |         card_details = stripe_utils.get_card_details(customer.stripe_id, | ||||||
|  |                                                      self.request.session.get( | ||||||
|  |                                                          'token')) | ||||||
|  |         if not card_details.get('response_object'): | ||||||
|  |             msg = card_details.get('error') | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='failed_payment') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('hosting:payment') + '#payment_error') | ||||||
|  | 
 | ||||||
|         if self.request.GET.get('page', '') == 'payment': |         if self.request.GET.get('page', '') == 'payment': | ||||||
|             context['page_header_text'] = _('Confirm Order') |             context['page_header_text'] = _('Confirm Order') | ||||||
|         else: |         else: | ||||||
|             context['page_header_text'] = _('Invoice') |             context['page_header_text'] = _('Invoice') | ||||||
|         try: | 
 | ||||||
|             vm = manager.get_vm(obj.vm_id) |         if obj is not None: | ||||||
|             context['vm'] = VirtualMachineSerializer(vm).data |             try: | ||||||
|         except WrongIdError: |                 manager = OpenNebulaManager(email=owner.email, | ||||||
|             messages.error(self.request, |                                             password=owner.password) | ||||||
|                            'The VM you are looking for is unavailable at the moment. \ |                 vm = manager.get_vm(obj.vm_id) | ||||||
|                             Please contact Data Center Light support.' |                 context['vm'] = VirtualMachineSerializer(vm).data | ||||||
|                            ) |             except WrongIdError: | ||||||
|             self.kwargs['error'] = 'WrongIdError' |                 messages.error(self.request, | ||||||
|             context['error'] = 'WrongIdError' |                                'The VM you are looking for is unavailable at the moment. \ | ||||||
|         except ConnectionRefusedError: |                                 Please contact Data Center Light support.' | ||||||
|             messages.error(self.request, |                                ) | ||||||
|                            _( |                 self.kwargs['error'] = 'WrongIdError' | ||||||
|                                'In order to create a VM, you need to create/upload your SSH KEY first.') |                 context['error'] = 'WrongIdError' | ||||||
|                            ) |             except ConnectionRefusedError: | ||||||
|  |                 messages.error(self.request, | ||||||
|  |                                'In order to create a VM, you need to create/upload your SSH KEY first.' | ||||||
|  |                                ) | ||||||
|  |         else: | ||||||
|  |             context['site_url'] = reverse('hosting:create_virtual_machine') | ||||||
|  |             context['cc_last4'] = card_details.get('response_object').get( | ||||||
|  |                 'last4') | ||||||
|  |             context['cc_brand'] = card_details.get('response_object').get( | ||||||
|  |                 'cc_brand') | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|  |     def post(self, request): | ||||||
|  |         template = request.session.get('template') | ||||||
|  |         specs = request.session.get('specs') | ||||||
|  |         stripe_customer_id = request.session.get('customer') | ||||||
|  |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | ||||||
|  |         billing_address_data = request.session.get('billing_address_data') | ||||||
|  |         billing_address_id = request.session.get('billing_address') | ||||||
|  |         vm_template_id = template.get('id', 1) | ||||||
|  | 
 | ||||||
|  |         # Make stripe charge to a customer | ||||||
|  |         stripe_utils = StripeUtils() | ||||||
|  |         card_details = stripe_utils.get_card_details(customer.stripe_id, | ||||||
|  |                                                      request.session.get( | ||||||
|  |                                                          'token')) | ||||||
|  |         if not card_details.get('response_object'): | ||||||
|  |             msg = card_details.get('error') | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='failed_payment') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('datacenterlight:payment') + '#payment_error') | ||||||
|  |         card_details_dict = card_details.get('response_object') | ||||||
|  |         cpu = specs.get('cpu') | ||||||
|  |         memory = specs.get('memory') | ||||||
|  |         disk_size = specs.get('disk_size') | ||||||
|  |         amount_to_be_charged = (cpu * 5) + (memory * 2) + (disk_size * 0.6) | ||||||
|  |         plan_name = "{cpu} Cores, {memory} GB RAM, {disk_size} GB SSD".format( | ||||||
|  |             cpu=cpu, | ||||||
|  |             memory=memory, | ||||||
|  |             disk_size=disk_size) | ||||||
|  | 
 | ||||||
|  |         stripe_plan_id = StripeUtils.get_stripe_plan_id(cpu=cpu, | ||||||
|  |                                                         ram=memory, | ||||||
|  |                                                         ssd=disk_size, | ||||||
|  |                                                         version=1, | ||||||
|  |                                                         app='dcl') | ||||||
|  |         stripe_plan = stripe_utils.get_or_create_stripe_plan( | ||||||
|  |             amount=amount_to_be_charged, | ||||||
|  |             name=plan_name, | ||||||
|  |             stripe_plan_id=stripe_plan_id) | ||||||
|  |         subscription_result = stripe_utils.subscribe_customer_to_plan( | ||||||
|  |             customer.stripe_id, | ||||||
|  |             [{"plan": stripe_plan.get( | ||||||
|  |                 'response_object').stripe_plan_id}]) | ||||||
|  |         stripe_subscription_obj = subscription_result.get('response_object') | ||||||
|  |         # Check if the subscription was approved and is active | ||||||
|  |         if stripe_subscription_obj is None or stripe_subscription_obj.status != 'active': | ||||||
|  |             msg = subscription_result.get('error') | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='failed_payment') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('hosting:payment') + '#payment_error') | ||||||
|  |         user = { | ||||||
|  |             'name': self.request.user.name, | ||||||
|  |             'email': self.request.user.email, | ||||||
|  |             'pass': self.request.user.password, | ||||||
|  |             'request_scheme': request.scheme, | ||||||
|  |             'request_host': request.get_host(), | ||||||
|  |             'language': get_language(), | ||||||
|  |         } | ||||||
|  |         create_vm_task.delay(vm_template_id, user, specs, template, | ||||||
|  |                              stripe_customer_id, billing_address_data, | ||||||
|  |                              billing_address_id, | ||||||
|  |                              stripe_subscription_obj, card_details_dict) | ||||||
|  | 
 | ||||||
|  |         for session_var in ['specs', 'template', 'billing_address', | ||||||
|  |                             'billing_address_data', | ||||||
|  |                             'token', 'customer']: | ||||||
|  |             if session_var in request.session: | ||||||
|  |                 del request.session[session_var] | ||||||
|  | 
 | ||||||
|  |         response = { | ||||||
|  |             'status': True, | ||||||
|  |             'redirect': reverse('hosting:virtual_machines'), | ||||||
|  |             'msg_title': str(_('Thank you for the order.')), | ||||||
|  |             'msg_body': str(_('Your VM will be up and running in a few moments.' | ||||||
|  |                               ' We will send you a confirmation email as soon as' | ||||||
|  |                               ' it is ready.')) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return HttpResponse(json.dumps(response), | ||||||
|  |                             content_type="application/json") | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class OrdersHostingListView(LoginRequiredMixin, ListView): | class OrdersHostingListView(LoginRequiredMixin, ListView): | ||||||
|     template_name = "hosting/orders.html" |     template_name = "hosting/orders.html" | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import tempfile | ||||||
| import cdist | import cdist | ||||||
| from cdist.integration import configure_hosts_simple | from cdist.integration import configure_hosts_simple | ||||||
| from celery.result import AsyncResult | from celery.result import AsyncResult | ||||||
|  | from celery import current_task | ||||||
| from celery.utils.log import get_task_logger | from celery.utils.log import get_task_logger | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.core.mail import EmailMessage | from django.core.mail import EmailMessage | ||||||
|  | @ -38,6 +39,8 @@ def save_ssh_key(self, hosts, keys): | ||||||
|                        'state': True         # whether key is to be added or |                        'state': True         # whether key is to be added or | ||||||
|                     }                        # removed |                     }                        # removed | ||||||
|     """ |     """ | ||||||
|  |     logger.debug( | ||||||
|  |         "Running save_ssh_key on {}".format(current_task.request.hostname)) | ||||||
|     logger.debug("""Running save_ssh_key task for |     logger.debug("""Running save_ssh_key task for | ||||||
|                     Hosts: {hosts_str} |                     Hosts: {hosts_str} | ||||||
|                     Keys: {keys_str}""".format(hosts_str=", ".join(hosts), |                     Keys: {keys_str}""".format(hosts_str=", ".join(hosts), | ||||||
|  | @ -70,8 +73,8 @@ def save_ssh_key(self, hosts, keys): | ||||||
|             email_data = { |             email_data = { | ||||||
|                 'subject': "celery save_ssh_key error - task id {0}".format( |                 'subject': "celery save_ssh_key error - task id {0}".format( | ||||||
|                     self.request.id.__str__()), |                     self.request.id.__str__()), | ||||||
|                 'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, |                 'from_email': current_task.request.hostname, | ||||||
|                 'to': ['info@ungleich.ch'], |                 'to': settings.DCL_ERROR_EMAILS_TO_LIST, | ||||||
|                 'body': "Task Id: {0}\nResult: {1}\nTraceback: {2}".format( |                 'body': "Task Id: {0}\nResult: {1}\nTraceback: {2}".format( | ||||||
|                     self.request.id.__str__(), False, str(cdist_exception)), |                     self.request.id.__str__(), False, str(cdist_exception)), | ||||||
|             } |             } | ||||||
|  | @ -87,8 +90,8 @@ def save_ssh_key_error_handler(uuid): | ||||||
|         uuid, exc, result.traceback)) |         uuid, exc, result.traceback)) | ||||||
|     email_data = { |     email_data = { | ||||||
|         'subject': "[celery error] Save SSH key error {0}".format(uuid), |         'subject': "[celery error] Save SSH key error {0}".format(uuid), | ||||||
|         'from_email': settings.DCL_SUPPORT_FROM_ADDRESS, |         'from_email': current_task.request.hostname, | ||||||
|         'to': ['info@ungleich.ch'], |         'to': settings.DCL_ERROR_EMAILS_TO_LIST, | ||||||
|         'body': "Task Id: {0}\nResult: {1}\nTraceback: {2}".format( |         'body': "Task Id: {0}\nResult: {1}\nTraceback: {2}".format( | ||||||
|             uuid, exc, result.traceback), |             uuid, exc, result.traceback), | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue