Merged upstream master into task/3730/refactor_price_parameter
This commit is contained in:
		
				commit
				
					
						39a2455817
					
				
			
		
					 18 changed files with 883 additions and 285 deletions
				
			
		|  | @ -4,6 +4,8 @@ Pre-changelog: 1.2.3 2017-09-20 | ||||||
|     * #3628: [dcl] on hosting, VM is created at credit card info submit |     * #3628: [dcl] on hosting, VM is created at credit card info submit | ||||||
|     * #3772: [dcl] Updated hosting app billing into monthly subscription and added new text and translations |     * #3772: [dcl] Updated hosting app billing into monthly subscription and added new text and translations | ||||||
|     * #3786: [hosting] Redesigned the hosting invoice and order-confirmation page |     * #3786: [hosting] Redesigned the hosting invoice and order-confirmation page | ||||||
|  |     * #3728: [hosting] VM Termination animation added | ||||||
|  |     * #3777: [hosting] Create new VM calculator added like dcl landing | ||||||
|     * Feature: [cms, blog] Added /cms prefix for all the django-cms generated urls |     * Feature: [cms, blog] Added /cms prefix for all the django-cms generated urls | ||||||
|     * Bugfix: [dcl, hosting] added host to celery error mails |     * Bugfix: [dcl, hosting] added host to celery error mails | ||||||
|     * Bugfix: [ungleich] Fixed wrong subdomain digitalglarus.ungleich.ch |     * Bugfix: [ungleich] Fixed wrong subdomain digitalglarus.ungleich.ch | ||||||
|  |  | ||||||
|  | @ -188,13 +188,13 @@ msgid "All Rights Reserved" | ||||||
| msgstr "Alle Rechte vorbehalten" | msgstr "Alle Rechte vorbehalten" | ||||||
| 
 | 
 | ||||||
| msgid "Toggle navigation" | msgid "Toggle navigation" | ||||||
| msgstr "Konfiguration" | msgstr "Umschalten" | ||||||
| 
 | 
 | ||||||
| msgid "Why Data Center Light?" | msgid "Why Data Center Light?" | ||||||
| msgstr "Warum Data Center Light?" | msgstr "Warum Data Center Light?" | ||||||
| 
 | 
 | ||||||
| msgid "Login" | msgid "Login" | ||||||
| msgstr "" | msgstr "Anmelden" | ||||||
| 
 | 
 | ||||||
| msgid "Dashboard" | msgid "Dashboard" | ||||||
| msgstr "" | msgstr "" | ||||||
|  |  | ||||||
|  | @ -147,7 +147,6 @@ | ||||||
| 
 | 
 | ||||||
|     function _fetchPricing() { |     function _fetchPricing() { | ||||||
|         Object.keys(cardPricing).map(function(element) { |         Object.keys(cardPricing).map(function(element) { | ||||||
|             //$('#'+cardPricing[element].id).val(cardPricing[element].value);
 |  | ||||||
|             $('input[name=' + element + ']').val(cardPricing[element].value); |             $('input[name=' + element + ']').val(cardPricing[element].value); | ||||||
|         }); |         }); | ||||||
|         _calcPricing(); |         _calcPricing(); | ||||||
|  |  | ||||||
|  | @ -26,9 +26,9 @@ | ||||||
|             <div class="help-block with-errors"> |             <div class="help-block with-errors"> | ||||||
|                 {% for message in messages %} |                 {% for message in messages %} | ||||||
|                     {% if 'cores' in message.tags %} |                     {% if 'cores' in message.tags %} | ||||||
|                      <ul class="list-unstyled"><li> |                         <ul class="list-unstyled"> | ||||||
|                         {{ message|safe }} |                             <li>{{ message|safe }}</li> | ||||||
|                     </li></ul> |                         </ul> | ||||||
|                     {% endif %} |                     {% endif %} | ||||||
|                 {% endfor %} |                 {% endfor %} | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|  | @ -110,6 +110,27 @@ msgstr "vorherige" | ||||||
| msgid "next" | msgid "next" | ||||||
| msgstr "nächste" | msgstr "nächste" | ||||||
| 
 | 
 | ||||||
|  | msgid "Month" | ||||||
|  | msgstr "Monat" | ||||||
|  | 
 | ||||||
|  | msgid "VAT included" | ||||||
|  | msgstr "MwSt. inklusive" | ||||||
|  | 
 | ||||||
|  | msgid "Please enter a value in range 1 - 48." | ||||||
|  | msgstr "Bitte gib einen Wert von 1 bis 48 ein." | ||||||
|  | 
 | ||||||
|  | msgid "Please enter a value in range 2 - 200." | ||||||
|  | msgstr "Bitte gib einen Wert von 2 bis 200 ein." | ||||||
|  | 
 | ||||||
|  | msgid "Please enter a value in range 10 - 2000." | ||||||
|  | msgstr "Bitte gib einen Wert von 10 bis 200 ein." | ||||||
|  | 
 | ||||||
|  | msgid "GB Storage (SSD)" | ||||||
|  | msgstr "GB Storage (SSD)" | ||||||
|  | 
 | ||||||
|  | msgid "Continue" | ||||||
|  | msgstr "Weiter" | ||||||
|  | 
 | ||||||
| msgid "SSH Key" | msgid "SSH Key" | ||||||
| msgstr "SSH Key" | msgstr "SSH Key" | ||||||
| 
 | 
 | ||||||
|  | @ -149,30 +170,12 @@ msgstr "Hast Du bereits ein Benutzerkonto?" | ||||||
| msgid "Login" | msgid "Login" | ||||||
| msgstr "Anmelden" | msgstr "Anmelden" | ||||||
| 
 | 
 | ||||||
| msgid "New Virtual Machine" | msgid "Create VM" | ||||||
| msgstr "Neue virtuelle Maschine" | msgstr "VM erstellen" | ||||||
| 
 |  | ||||||
| msgid "Step 1. Select VM Template:" |  | ||||||
| msgstr "Wähle eine Vorlage" |  | ||||||
| 
 |  | ||||||
| msgid "Step2. Select VM Configuration" |  | ||||||
| msgstr "Wähle eine Konfiguration" |  | ||||||
| 
 |  | ||||||
| msgid "Price " |  | ||||||
| msgstr "Preis" |  | ||||||
| 
 |  | ||||||
| msgid "CHF/Month" |  | ||||||
| msgstr "CHF/Monat" |  | ||||||
| 
 |  | ||||||
| msgid "Start VM" |  | ||||||
| msgstr "VM jetzt starten" |  | ||||||
| 
 | 
 | ||||||
| msgid "My Dashboard" | msgid "My Dashboard" | ||||||
| msgstr "Mein Dashboard" | msgstr "Mein Dashboard" | ||||||
| 
 | 
 | ||||||
| msgid "Create VM" |  | ||||||
| msgstr "VM erstellen" |  | ||||||
| 
 |  | ||||||
| msgid "My VMs" | msgid "My VMs" | ||||||
| msgstr "Meine VMs" | msgstr "Meine VMs" | ||||||
| 
 | 
 | ||||||
|  | @ -286,10 +289,10 @@ msgstr "" | ||||||
| "%(base_url)s%(my_virtual_machines_url)s\n" | "%(base_url)s%(my_virtual_machines_url)s\n" | ||||||
| 
 | 
 | ||||||
| msgid "Toggle navigation" | msgid "Toggle navigation" | ||||||
| msgstr "Konfiguration" | msgstr "Umschalten" | ||||||
| 
 | 
 | ||||||
| msgid "Dashboard" | msgid "Dashboard" | ||||||
| msgstr "Mein Dashboard" | msgstr "Dashboard" | ||||||
| 
 | 
 | ||||||
| msgid "Logout" | msgid "Logout" | ||||||
| msgstr "Abmelden" | msgstr "Abmelden" | ||||||
|  | @ -414,9 +417,6 @@ msgstr "Konfiguration" | ||||||
| msgid "including VAT" | msgid "including VAT" | ||||||
| msgstr "inkl. Mehrwertsteuer" | msgstr "inkl. Mehrwertsteuer" | ||||||
| 
 | 
 | ||||||
| msgid "Month" |  | ||||||
| msgstr "Monat" |  | ||||||
| 
 |  | ||||||
| msgid "Billing Address" | msgid "Billing Address" | ||||||
| msgstr "Rechnungsadresse" | msgstr "Rechnungsadresse" | ||||||
| 
 | 
 | ||||||
|  | @ -561,6 +561,9 @@ msgstr "Aktueller Preis" | ||||||
| msgid "Your VM is" | msgid "Your VM is" | ||||||
| msgstr "Deine VM ist" | msgstr "Deine VM ist" | ||||||
| 
 | 
 | ||||||
|  | msgid "Terminating" | ||||||
|  | msgstr "Beenden" | ||||||
|  | 
 | ||||||
| msgid "Pending" | msgid "Pending" | ||||||
| msgstr "In Vorbereitung" | msgstr "In Vorbereitung" | ||||||
| 
 | 
 | ||||||
|  | @ -573,6 +576,11 @@ msgstr "Fehlgeschlagen" | ||||||
| msgid "Terminate VM" | msgid "Terminate VM" | ||||||
| msgstr "VM Beenden" | msgstr "VM Beenden" | ||||||
| 
 | 
 | ||||||
|  | msgid "Sorry, there was an unexpected error. Kindly retry." | ||||||
|  | msgstr "" | ||||||
|  | "Bitte entschuldige, es scheint ein unerwarteter Fehler aufgetreten zu sein. " | ||||||
|  | "Versuche es doch bitte noch einmal." | ||||||
|  | 
 | ||||||
| msgid "Something doesn't work?" | msgid "Something doesn't work?" | ||||||
| msgstr "Etwas funktioniert nicht?" | msgstr "Etwas funktioniert nicht?" | ||||||
| 
 | 
 | ||||||
|  | @ -591,6 +599,11 @@ msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst" | ||||||
| msgid "OK" | msgid "OK" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | #, python-format | ||||||
|  | msgid "" | ||||||
|  | "Your Virtual Machine %(virtual_machine.name)s is successfully terminated!" | ||||||
|  | msgstr "Deine Virtuelle Machine (VM) %(virtual_machine.name)s wurde erfolgreich beendet!" | ||||||
|  | 
 | ||||||
| msgid "Virtual Machines" | msgid "Virtual Machines" | ||||||
| msgstr "Virtuelle Maschinen" | msgstr "Virtuelle Maschinen" | ||||||
| 
 | 
 | ||||||
|  | @ -664,17 +677,55 @@ msgstr "" | ||||||
| "Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du " | "Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du " | ||||||
| "auf sie zugreifen kannst." | "auf sie zugreifen kannst." | ||||||
| 
 | 
 | ||||||
|  | msgid "Invalid number of cores" | ||||||
|  | msgstr "Ungültige Anzahle CPU-Kerne" | ||||||
|  | 
 | ||||||
|  | msgid "Invalid RAM size" | ||||||
|  | msgstr "Ungültige RAM-Grösse" | ||||||
|  | 
 | ||||||
|  | msgid "Invalid storage size" | ||||||
|  | msgstr "Ungültige Speicher-Grösse" | ||||||
|  | 
 | ||||||
| msgid "" | msgid "" | ||||||
| "We could not find the requested VM. Please                            " | "We could not find the requested VM. Please                            " | ||||||
| "contact Data Center Light Support." | "contact Data Center Light Support." | ||||||
| msgstr "Kontaktiere den Data Center Light Support." | msgstr "Kontaktiere den Data Center Light Support." | ||||||
| 
 | 
 | ||||||
|  | msgid "Terminated" | ||||||
|  | msgstr "Beendet" | ||||||
|  | 
 | ||||||
|  | msgid "Error terminating VM" | ||||||
|  | msgstr "Fehler beenden VM" | ||||||
|  | 
 | ||||||
| msgid "Virtual Machine Cancellation" | msgid "Virtual Machine Cancellation" | ||||||
| msgstr "VM Kündigung" | msgstr "VM Kündigung" | ||||||
| 
 | 
 | ||||||
| #, python-format | #~ msgid "Close" | ||||||
| msgid "VM %(VM_ID)s terminated successfully" | #~ msgstr "Schliessen" | ||||||
| msgstr "VM %(VM_ID)s erfolgreich beendet" | 
 | ||||||
|  | #~ msgid "VM %(VM_ID)s terminated successfully" | ||||||
|  | #~ msgstr "VM %(VM_ID)s erfolgreich beendet" | ||||||
|  | 
 | ||||||
|  | #~ msgid "days" | ||||||
|  | #~ msgstr "tage" | ||||||
|  | 
 | ||||||
|  | #~ msgid "New Virtual Machine" | ||||||
|  | #~ msgstr "Neue virtuelle Maschine" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Step 1. Select VM Template:" | ||||||
|  | #~ msgstr "Wähle eine Vorlage" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Step2. Select VM Configuration" | ||||||
|  | #~ msgstr "Wähle eine Konfiguration" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Price " | ||||||
|  | #~ msgstr "Preis" | ||||||
|  | 
 | ||||||
|  | #~ msgid "CHF/Month" | ||||||
|  | #~ msgstr "CHF/Monat" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Start VM" | ||||||
|  | #~ msgstr "VM jetzt starten" | ||||||
| 
 | 
 | ||||||
| #~ msgid "Finish Configuration" | #~ msgid "Finish Configuration" | ||||||
| #~ msgstr "Konfiguration beenden" | #~ msgstr "Konfiguration beenden" | ||||||
|  | @ -730,9 +781,6 @@ msgstr "VM %(VM_ID)s erfolgreich beendet" | ||||||
| #~ msgid "Ipv6" | #~ msgid "Ipv6" | ||||||
| #~ msgstr "IPv6" | #~ msgstr "IPv6" | ||||||
| 
 | 
 | ||||||
| #~ msgid "Close" |  | ||||||
| #~ msgstr "Schliessen" |  | ||||||
| 
 |  | ||||||
| #~ msgid "Cancel" | #~ msgid "Cancel" | ||||||
| #~ msgstr "Beenden" | #~ msgstr "Beenden" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -139,6 +139,10 @@ | ||||||
| .modal-text p:not(:last-of-type){ | .modal-text p:not(:last-of-type){ | ||||||
| 	margin-bottom: 5px; | 	margin-bottom: 5px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .modal-title + .modal-footer { | ||||||
|  |     margin-top: 5px; | ||||||
|  | } | ||||||
| .modal-footer { | .modal-footer { | ||||||
|     border-top: 0px solid #e5e5e5; |     border-top: 0px solid #e5e5e5; | ||||||
|     width: 100%; |     width: 100%; | ||||||
|  |  | ||||||
|  | @ -853,6 +853,9 @@ a.list-group-item-danger:focus, | ||||||
| .panel-danger > .panel-heading { | .panel-danger > .panel-heading { | ||||||
|     color: #eb4d5c; |     color: #eb4d5c; | ||||||
| } | } | ||||||
|  | .alert-danger{ | ||||||
|  |     background: rgba(235, 204, 209, 0.2); | ||||||
|  | } | ||||||
| .has-error .form-control, | .has-error .form-control, | ||||||
| .has-error .input-group-addon { | .has-error .input-group-addon { | ||||||
|     color: #eb4d5c; |     color: #eb4d5c; | ||||||
|  |  | ||||||
							
								
								
									
										237
									
								
								hosting/static/hosting/css/price_calculator.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								hosting/static/hosting/css/price_calculator.css
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,237 @@ | ||||||
|  | /* Create VM calculator */ | ||||||
|  | 
 | ||||||
|  | .price-calc-section { | ||||||
|  |     padding: 80px 40px !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |     .price-calc-section { | ||||||
|  |         margin-top: 40px; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .text { | ||||||
|  |     width: 50%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .text .section-heading { | ||||||
|  |     font-size: 48px; | ||||||
|  |     line-height: 48px; | ||||||
|  |     padding-bottom: 27px; | ||||||
|  |     color: #3a3a3a; | ||||||
|  |     letter-spacing: 1px; | ||||||
|  |     position: relative; | ||||||
|  |     text-align: right; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .text .description { | ||||||
|  |     font-size: 20px; | ||||||
|  |     text-align: right; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .text .section-heading::before { | ||||||
|  |     content: ""; | ||||||
|  |     position: absolute; | ||||||
|  |     bottom: 0; | ||||||
|  |     background: #29427A; | ||||||
|  |     height: 7px; | ||||||
|  |     width: 70px; | ||||||
|  |     right: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card { | ||||||
|  |     width: 50%; | ||||||
|  |     margin: 0 auto; | ||||||
|  |     background: #fff; | ||||||
|  |     box-shadow: 1px 3px 6px 2px rgba(0, 0, 0, 0.2); | ||||||
|  |     padding-bottom: 30px; | ||||||
|  |     text-align: center; | ||||||
|  |     max-width: 320px; | ||||||
|  |     position: relative; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 768px) { | ||||||
|  |     .price-calc-section .card { | ||||||
|  |         margin-left: 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .landing { | ||||||
|  |     width: 100% !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .no-padding { | ||||||
|  |     padding: 0 !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .img-beta { | ||||||
|  |     position: absolute; | ||||||
|  |     top: 5px; | ||||||
|  |     width: 60px; | ||||||
|  |     left: 3px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .title { | ||||||
|  |     padding: 15px 40px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .title h3 { | ||||||
|  |     /*font-family: 'Lato', sans-serif;*/ | ||||||
|  |     font-weight: normal; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .price { | ||||||
|  |     background: #5A74AF; | ||||||
|  |     padding: 22px; | ||||||
|  |     color: #fff; | ||||||
|  |     font-size: 32px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .price .price-text { | ||||||
|  |     font-size: 14px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description { | ||||||
|  |     padding: 7px 8px 2px; | ||||||
|  |     position: relative; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: space-around !important; | ||||||
|  |     align-items: center !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description span { | ||||||
|  |     font-size: 14px; | ||||||
|  |     margin-left: 5px; | ||||||
|  |     /* margin-left: 0px; */ | ||||||
|  |     /* justify-self: start; */ | ||||||
|  |     width: 29%; | ||||||
|  |     text-align: left; | ||||||
|  |     line-height: 16px; | ||||||
|  |     /* font-weight: normal; */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description .select-number{ | ||||||
|  |     font-size: 16px; | ||||||
|  |     text-align: center; | ||||||
|  |     width: 85px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description i { | ||||||
|  |     color: #29427a; | ||||||
|  |     cursor: pointer; | ||||||
|  |     font-size: 20px; | ||||||
|  |     border: 1px solid #ccc; | ||||||
|  |     padding: 5px 6px 3px; | ||||||
|  |     border-radius: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description .left { | ||||||
|  |     margin-right: 7px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description .right { | ||||||
|  |     margin-left: 7px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .descriptions { | ||||||
|  |     padding: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description p { | ||||||
|  |     margin: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .btn { | ||||||
|  |     margin-top: 15px; | ||||||
|  |     font-size: 20px; | ||||||
|  |     width: 150px; | ||||||
|  |     border: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .select-configuration select { | ||||||
|  |     outline: none; | ||||||
|  |     background: #fff; | ||||||
|  |     border-color: #d0d0d0; | ||||||
|  |     height: 32px; | ||||||
|  |     width: 150px; | ||||||
|  |     text-align: center; | ||||||
|  |     font-size: 14px; | ||||||
|  |     margin-left: 10px; | ||||||
|  |     padding: 6px; | ||||||
|  |     border-radius: 4px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .check-ip { | ||||||
|  |     font-size: 18px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .justify-center { | ||||||
|  |     justify-content: center !important; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description.input label { | ||||||
|  |     font-size: 15px; | ||||||
|  |     font-weight: 700; | ||||||
|  |     /*font-weight: 800;*/ | ||||||
|  |     /*font-family: 'Lato';*/ | ||||||
|  |     margin-bottom: 0; | ||||||
|  |     width: 40px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /*Changed class****.price-calc-section .card .description.input input*/ | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .description input { | ||||||
|  |     width: 200px; | ||||||
|  |     font-size: 14px; | ||||||
|  |     text-align: left; | ||||||
|  |     padding: 4px 10px; | ||||||
|  |     border-radius: 4px; | ||||||
|  |     border: 1px solid #d0d0d0; | ||||||
|  |     background: #fff; | ||||||
|  |     margin-left: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .card .check-ip input[type=checkbox] { | ||||||
|  |     font-size: 17px; | ||||||
|  |     margin: 0 8px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .help-block.with-errors { | ||||||
|  |     text-align: center; | ||||||
|  |     margin: 0 0; | ||||||
|  |     padding: 0 0 5px; | ||||||
|  | } | ||||||
|  | .price-calc-section .help-block.with-errors ul { | ||||||
|  |     margin-bottom: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .form-group { | ||||||
|  |     margin: 0; | ||||||
|  |     position: relative; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .form-group:after { | ||||||
|  |     content: ' '; | ||||||
|  |     display: block; | ||||||
|  |     position: absolute; | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 18%; | ||||||
|  |     z-index: 20; | ||||||
|  |     height: 1px; | ||||||
|  |     width: 65%; | ||||||
|  |     background: rgba(128, 128, 128, 0.2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .price-calc-section .btn-primary { | ||||||
|  |     background: #29427A; | ||||||
|  |     border-color: #29427A; | ||||||
|  |     color: #fff; | ||||||
|  |     width: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media(min-width: 768px) { | ||||||
|  |     .create-vm-container { | ||||||
|  |         padding-top: 120px; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -290,6 +290,11 @@ | ||||||
|   text-align: center; |   text-align: center; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .vm-vmid .alert { | ||||||
|  |   margin-top: 15px; | ||||||
|  |   margin-bottom: -60px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .vm-item-lg { | .vm-item-lg { | ||||||
|   font-size: 22px; |   font-size: 22px; | ||||||
|   margin-top: 5px; |   margin-top: 5px; | ||||||
|  | @ -305,6 +310,10 @@ | ||||||
|   color: #e47f2f; |   color: #e47f2f; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .vm-color-failed { | ||||||
|  |   color: #eb4d5c; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .vm-detail-item .value{ | .vm-detail-item .value{ | ||||||
|   font-weight: 400; |   font-weight: 400; | ||||||
| } | } | ||||||
|  | @ -512,7 +521,7 @@ | ||||||
|   color: #87B6EA; |   color: #87B6EA; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .vm-status, .vm-status-active, .vm-status-failed { | .vm-status, .vm-status-active, .vm-status-failed, .vm-status-pending { | ||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
| } | } | ||||||
| .vm-status-active { | .vm-status-active { | ||||||
|  | @ -521,6 +530,9 @@ | ||||||
| .vm-status-failed { | .vm-status-failed { | ||||||
|   color: #eb4d5c; |   color: #eb4d5c; | ||||||
| } | } | ||||||
|  | .vm-status-pending { | ||||||
|  |   color: #e47f2f; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| @media (min-width:768px) { | @media (min-width:768px) { | ||||||
|   .dashboard-subtitle { |   .dashboard-subtitle { | ||||||
|  | @ -628,3 +640,27 @@ | ||||||
|     right: 8px; |     right: 8px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .processing > .btn { | ||||||
|  |   position: relative; | ||||||
|  |   border-color: #eee; | ||||||
|  | } | ||||||
|  | .processing > .btn:hover, | ||||||
|  | .processing > .btn:focus, | ||||||
|  | .processing > .btn:active { | ||||||
|  |   border-color: #eee; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .processing > .btn:after { | ||||||
|  |   content: ' '; | ||||||
|  |   display: block; | ||||||
|  |   position: absolute; | ||||||
|  |   background-image: url('/static/hosting/img/ajax-loader.gif'); | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   background-position: center; | ||||||
|  |   background-color: #eee; | ||||||
|  |   width: 100%; | ||||||
|  |   top: 0; | ||||||
|  |   height: 100%; | ||||||
|  |   left: 0; | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								hosting/static/hosting/img/ajax-loader.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								hosting/static/hosting/img/ajax-loader.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 404 B | 
|  | @ -1,73 +1,75 @@ | ||||||
| (function($){ | (function($){ | ||||||
|     "use strict"; // Start of use strict
 |     "use strict"; // Start of use strict
 | ||||||
| 
 | 
 | ||||||
|  |     var cardPricing = { | ||||||
|  |         'cpu': { | ||||||
|  |             'id': 'coreValue', | ||||||
|  |             'value': 1, | ||||||
|  |             'min': 1, | ||||||
|  |             'max': 48, | ||||||
|  |             'interval': 1 | ||||||
|  |         }, | ||||||
|  |         'ram': { | ||||||
|  |             'id': 'ramValue', | ||||||
|  |             'value': 2, | ||||||
|  |             'min': 2, | ||||||
|  |             'max': 200, | ||||||
|  |             'interval': 1 | ||||||
|  |         }, | ||||||
|  |         'storage': { | ||||||
|  |             'id': 'storageValue', | ||||||
|  |             'value': 10, | ||||||
|  |             'min': 10, | ||||||
|  |             'max': 2000, | ||||||
|  |             'interval': 10 | ||||||
|  |         } | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     $(window).load(function(){ |     function _initPricing() { | ||||||
|  |         _fetchPricing(); | ||||||
| 
 | 
 | ||||||
|  |         $('.fa-minus.left').click(function(event) { | ||||||
|  |             var data = $(this).data('minus'); | ||||||
| 
 | 
 | ||||||
|  |             if (cardPricing[data].value > cardPricing[data].min) { | ||||||
|  |                 cardPricing[data].value = Number(cardPricing[data].value) - cardPricing[data].interval; | ||||||
|  |             } | ||||||
|  |             _fetchPricing(); | ||||||
|         }); |         }); | ||||||
|  |         $('.fa-plus.right').click(function(event) { | ||||||
|  |             var data = $(this).data('plus'); | ||||||
|  |             if (cardPricing[data].value < cardPricing[data].max) { | ||||||
|  |                 cardPricing[data].value = Number(cardPricing[data].value) + cardPricing[data].interval; | ||||||
|  |             } | ||||||
|  |             _fetchPricing(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         $('.input-price').change(function() { | ||||||
|  |             var data = $(this).attr("name"); | ||||||
|  |             cardPricing[data].value = $('input[name=' + data + ']').val(); | ||||||
|  |             _fetchPricing(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function _fetchPricing() { | ||||||
|  |         Object.keys(cardPricing).map(function(element) { | ||||||
|  |             $('input[name=' + element + ']').val(cardPricing[element].value); | ||||||
|  |         }); | ||||||
|  |         _calcPricing(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function _calcPricing() { | ||||||
|  |         var total = (cardPricing['cpu'].value * 5) + (2 * cardPricing['ram'].value) + (0.6 * cardPricing['storage'].value); | ||||||
|  |         total = parseFloat(total.toFixed(2)); | ||||||
|  | 
 | ||||||
|  |         $("#total").text(total); | ||||||
|  |         $('input[name=total]').val(total); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     $(document).ready(function() { |     $(document).ready(function() { | ||||||
|       _initOs(); |         _initPricing(); | ||||||
|         |  | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     $(window).resize(function(){ |  | ||||||
|          |  | ||||||
|          |  | ||||||
|     }); |  | ||||||
|      |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|    	function _initOs(){ |  | ||||||
| 
 |  | ||||||
|    		 |  | ||||||
|    		$('.os-circle').click(function(event){ |  | ||||||
|    			$('.os-circle').removeClass('active'); |  | ||||||
|    			$(this).addClass('active'); |  | ||||||
| 
 |  | ||||||
|         var idTemplate = $(this).data('id'); |  | ||||||
|         $('input[name=vm_template_id]').val(idTemplate); |  | ||||||
|    		}); |  | ||||||
|    		$('.config-box').click(function(event){ |  | ||||||
|    			$('.config-box').removeClass('active'); |  | ||||||
|    			$(this).addClass('active'); |  | ||||||
|         var idConfig = $(this).data('id'); |  | ||||||
|         var price = $(this).data('price'); |  | ||||||
|         $('input[name=configuration]').val(idConfig); |  | ||||||
|         $('.container-button').fadeIn(); |  | ||||||
|         $('#priceValue').text(price); |  | ||||||
|    		}); |  | ||||||
| 
 |  | ||||||
| 		$('.owl-carousel').owlCarousel({ |  | ||||||
|         items:4, |  | ||||||
|         nav: true, |  | ||||||
|         margin:30, |  | ||||||
|         responsiveClass:true, |  | ||||||
|         navText: ['<i class="fa fa-angle-left"></i>', '<i class="fa fa-angle-right"></i>'], |  | ||||||
|         responsive:{ |  | ||||||
|             0:{ |  | ||||||
|                 items:1, |  | ||||||
|                 nav:true |  | ||||||
|             }, |  | ||||||
|             600:{ |  | ||||||
|                 items:2, |  | ||||||
|                 nav:true |  | ||||||
|             }, |  | ||||||
|             768:{ |  | ||||||
|                 items:3, |  | ||||||
|                 nav:true |  | ||||||
|             }, |  | ||||||
|             990:{ |  | ||||||
|                 items:4, |  | ||||||
|                 nav:true |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
|      |  | ||||||
|      |  | ||||||
|      |  | ||||||
| })(jQuery); | })(jQuery); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										73
									
								
								hosting/static/hosting/js/createvm_old.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								hosting/static/hosting/js/createvm_old.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | (function($){ | ||||||
|  |     "use strict"; // Start of use strict
 | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     $(window).load(function(){ | ||||||
|  |      | ||||||
|  |    | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  |     $(document).ready(function(){ | ||||||
|  |       _initOs(); | ||||||
|  |         | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  |     $(window).resize(function(){ | ||||||
|  |          | ||||||
|  |          | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |    	function _initOs(){ | ||||||
|  | 
 | ||||||
|  |    		 | ||||||
|  |    		$('.os-circle').click(function(event){ | ||||||
|  |    			$('.os-circle').removeClass('active'); | ||||||
|  |    			$(this).addClass('active'); | ||||||
|  | 
 | ||||||
|  |         var idTemplate = $(this).data('id'); | ||||||
|  |         $('input[name=vm_template_id]').val(idTemplate); | ||||||
|  |    		}); | ||||||
|  |    		$('.config-box').click(function(event){ | ||||||
|  |    			$('.config-box').removeClass('active'); | ||||||
|  |    			$(this).addClass('active'); | ||||||
|  |         var idConfig = $(this).data('id'); | ||||||
|  |         var price = $(this).data('price'); | ||||||
|  |         $('input[name=configuration]').val(idConfig); | ||||||
|  |         $('.container-button').fadeIn(); | ||||||
|  |         $('#priceValue').text(price); | ||||||
|  |    		}); | ||||||
|  | 
 | ||||||
|  | 		$('.owl-carousel').owlCarousel({ | ||||||
|  |         items:4, | ||||||
|  |         nav: true, | ||||||
|  |         margin:30, | ||||||
|  |         responsiveClass:true, | ||||||
|  |         navText: ['<i class="fa fa-angle-left"></i>', '<i class="fa fa-angle-right"></i>'], | ||||||
|  |         responsive:{ | ||||||
|  |             0:{ | ||||||
|  |                 items:1, | ||||||
|  |                 nav:true | ||||||
|  |             }, | ||||||
|  |             600:{ | ||||||
|  |                 items:2, | ||||||
|  |                 nav:true | ||||||
|  |             }, | ||||||
|  |             768:{ | ||||||
|  |                 items:3, | ||||||
|  |                 nav:true | ||||||
|  |             }, | ||||||
|  |             990:{ | ||||||
|  |                 items:4, | ||||||
|  |                 nav:true | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 		}); | ||||||
|  | 	} | ||||||
|  |      | ||||||
|  |      | ||||||
|  |      | ||||||
|  | })(jQuery);  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @ -1,4 +1,84 @@ | ||||||
|  | function VMTerminateStatus($container, url) { | ||||||
|  |     $.ajax({ | ||||||
|  |         url: url, | ||||||
|  |         type: 'GET', | ||||||
|  |         dataType: 'json', | ||||||
|  |         success: function(data) { | ||||||
|  |             VMTerminateSuccess($container, data); | ||||||
|  |         }, | ||||||
|  |         error: function() { | ||||||
|  |             setTimeout(function(){ | ||||||
|  |                 VMTerminateStatus($container, url); | ||||||
|  |             }, 5000); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function VMTerminateActive($container, altText) { | ||||||
|  |     $container.find('.alert-danger').addClass('hide'); | ||||||
|  |     $container.addClass('processing') | ||||||
|  |         .find('.vm-item-lg').attr('class', '') | ||||||
|  |         .addClass('vm-item-lg vm-color-failed') | ||||||
|  |         .text(altText); | ||||||
|  |     $container.find('.btn').prop('disabled', true); | ||||||
|  |     $('#confirm-cancel').modal('hide'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function VMTerminateSuccess($container, data) { | ||||||
|  |     $container.addClass('terminate-success') | ||||||
|  |         .find('.vm-item-lg').text(data.text); | ||||||
|  |     $container.find('.btn').remove(); | ||||||
|  |     $('#terminate-success').modal('show'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function VMTerminateFail($container, data, text) { | ||||||
|  |     $container.addClass('terminate-fail') | ||||||
|  |         .find('.vm-item-lg').text(text); | ||||||
|  |     $container.find('.btn').prop('disabled', false); | ||||||
|  |     $container.find('.alert-danger').text(data.text).removeClass('hide'); | ||||||
|  |     $container.removeClass('processing'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| $(document).ready(function() { | $(document).ready(function() { | ||||||
|  |     $('#confirm-cancel').on('click', '.btn-ok', function(e) { | ||||||
|  |         var url = $('#virtual_machine_cancel_form').attr('action'); | ||||||
|  |         var $container = $('#terminate-VM'); | ||||||
|  |         var text = $container.find('.vm-item-lg').text(); | ||||||
|  |         var altText = $container.attr('data-alt'); | ||||||
|  |         VMTerminateActive($container, altText); | ||||||
|  | 
 | ||||||
|  |         $.post(url) | ||||||
|  |             .done(function(data) { | ||||||
|  |                 if (data.status == true) { | ||||||
|  |                     VMTerminateSuccess($container, data); | ||||||
|  |                 } else { | ||||||
|  |                     if ('text' in data) { | ||||||
|  |                         VMTerminateFail($container, data, text); | ||||||
|  |                     } else { | ||||||
|  |                         VMTerminateStatus($container, url); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |             .fail(function(data) { | ||||||
|  |                 if (data.status==504) { | ||||||
|  |                     VMTerminateStatus($container, url); | ||||||
|  |                 } else { | ||||||
|  |                     VMTerminateFail($container, data, text); | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     var hash = window.location.hash; | ||||||
|  |     hash && $('ul.nav a[href="' + hash + '"]').tab('show'); | ||||||
|  | 
 | ||||||
|  |     $('.nav-tabs a').click(function(e) { | ||||||
|  |         $(this).tab('show'); | ||||||
|  |         var scrollmem = $('body').scrollTop() || $('html').scrollTop(); | ||||||
|  |         window.location.hash = this.hash; | ||||||
|  |         $('html,body').scrollTop(scrollmem); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|     $('.modal-text').removeClass('hide'); |     $('.modal-text').removeClass('hide'); | ||||||
|     var create_vm_form = $('#virtual_machine_create_form'); |     var create_vm_form = $('#virtual_machine_create_form'); | ||||||
|     create_vm_form.submit(function () { |     create_vm_form.submit(function () { | ||||||
|  | @ -32,19 +112,4 @@ $(document).ready(function () { | ||||||
|         }); |         }); | ||||||
|         return false; |         return false; | ||||||
|     }); |     }); | ||||||
| 
 |  | ||||||
|     $('#confirm-cancel').on('click', '.btn-ok', function (e) { |  | ||||||
|         $('#virtual_machine_cancel_form').trigger('submit'); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     var hash = window.location.hash; |  | ||||||
|     hash && $('ul.nav a[href="' + hash + '"]').tab('show'); |  | ||||||
| 
 |  | ||||||
|     $('.nav-tabs a').click(function (e) { |  | ||||||
|         $(this).tab('show'); |  | ||||||
|         var scrollmem = $('body').scrollTop() || $('html').scrollTop(); |  | ||||||
|         window.location.hash = this.hash; |  | ||||||
|         $('html,body').scrollTop(scrollmem); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
|     <link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet"> |     <link href="{% static 'hosting/css/commons.css' %}" rel="stylesheet"> | ||||||
|     <link href="{% static 'hosting/css/virtual-machine.css' %}" rel="stylesheet"> |     <link href="{% static 'hosting/css/virtual-machine.css' %}" rel="stylesheet"> | ||||||
|     <link href="{% static 'hosting/css/dashboard.css' %}" rel="stylesheet"> |     <link href="{% static 'hosting/css/dashboard.css' %}" rel="stylesheet"> | ||||||
|  |     <link href="{% static 'hosting/css/price_calculator.css' %}" rel="stylesheet"> | ||||||
|     {% block css_extra %} |     {% block css_extra %} | ||||||
|     {% endblock css_extra %} |     {% endblock css_extra %} | ||||||
| 
 | 
 | ||||||
|  | @ -33,9 +34,6 @@ | ||||||
|     <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> |     <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css"> | ||||||
|     <link href="//fonts.googleapis.com/css?family=Lato:300,400,500,700,300italic,400italic,700italic" rel="stylesheet" type="text/css"> |     <link href="//fonts.googleapis.com/css?family=Lato:300,400,500,700,300italic,400italic,700italic" rel="stylesheet" type="text/css"> | ||||||
|     <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" /> |     <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" /> | ||||||
|     <link rel="stylesheet" href="{% static 'hosting/css/owl.carousel.min.css' %}"> |  | ||||||
|     <link rel="stylesheet" href="{% static 'hosting/css/owl.theme.default.min.css' %}"> |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> |     <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> | ||||||
|     <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> |     <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | ||||||
|  | @ -76,8 +74,8 @@ | ||||||
|     {% endif %} |     {% endif %} | ||||||
|     <!-- jQuery --> |     <!-- jQuery --> | ||||||
|     <script src="{% static 'hosting/js/jquery.js' %}"></script> |     <script src="{% static 'hosting/js/jquery.js' %}"></script> | ||||||
|     <script type="text/javascript" src="//cdn.jsdelivr.net/jquery.validation/1.13.1/jquery.validate.min.js"></script> |     <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script> | ||||||
|     <script src="{% static 'hosting/js/vendor/owl.carousel.min.js'%}"></script> |     <script src="//cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.9/validator.min.js"></script> | ||||||
|     <!-- Copy Clipboard --> |     <!-- Copy Clipboard --> | ||||||
|     <script src="//cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.10/clipboard.min.js"></script> |     <script src="//cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.10/clipboard.min.js"></script> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										87
									
								
								hosting/templates/hosting/calculator_form.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								hosting/templates/hosting/calculator_form.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,87 @@ | ||||||
|  | {% load staticfiles i18n%} | ||||||
|  | <form id="order_form" method="POST" action="" data-toggle="validator" role="form"> | ||||||
|  |     {% csrf_token %} | ||||||
|  |     <div class="price"> | ||||||
|  |         <span id="total">15</span> | ||||||
|  |         <span>CHF/{% trans "Month" %}</span> | ||||||
|  |         <div class="price-text"> | ||||||
|  |             <span>{% trans "VAT included" %}</span> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="descriptions"> | ||||||
|  |         <div class="form-group"> | ||||||
|  |             <div class="description input"> | ||||||
|  |                 <i class="fa fa-minus left" data-minus="cpu" aria-hidden="true"></i> | ||||||
|  |                 <input class="input-price select-number" type="number" min="1" max="48" id="coreValue" name="cpu" data-error="{% trans 'Please enter a value in range 1 - 48.' %}" required> | ||||||
|  |                 <span> Core</span> | ||||||
|  |                 <i class="fa fa-plus right" data-plus="cpu" aria-hidden="true"></i> | ||||||
|  |             </div> | ||||||
|  |             <div class="help-block with-errors"> | ||||||
|  |                 {% for message in messages %} | ||||||
|  |                     {% if 'cores' in message.tags %} | ||||||
|  |                      <ul class="list-unstyled"><li> | ||||||
|  |                         {{ message|safe }} | ||||||
|  |                     </li></ul> | ||||||
|  |                     {% endif %} | ||||||
|  |                 {% endfor %} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="form-group"> | ||||||
|  |             <div class="description input"> | ||||||
|  |                 <i class="fa fa-minus left" data-minus="ram" aria-hidden="true"></i> | ||||||
|  |                 <input id="ramValue" class="input-price select-number" type="number" min="2" max="200" name="ram" | ||||||
|  |                        data-error="{% trans 'Please enter a value in range 2 - 200.' %}" required> | ||||||
|  |                 <span> GB RAM</span> | ||||||
|  |                 <i class="fa fa-plus right" data-plus="ram" aria-hidden="true"></i> | ||||||
|  |             </div> | ||||||
|  |             <div class="help-block with-errors"> | ||||||
|  |                 {% for message in messages %} | ||||||
|  |                     {% if 'memory' in message.tags %} | ||||||
|  |                      <ul class="list-unstyled"><li> | ||||||
|  |                         {{ message|safe }} | ||||||
|  |                     </li></ul> | ||||||
|  |                     {% endif %} | ||||||
|  |                 {% endfor %} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="form-group"> | ||||||
|  |             <div class="description input"> | ||||||
|  |                 <i class="fa fa-minus left" data-minus="storage" aria-hidden="true"></i> | ||||||
|  |                 <input id="storageValue" class="input-price select-number" type="number" min="10" max="2000" step="10" | ||||||
|  |                        name="storage" data-error="{% trans 'Please enter a value in range 10 - 2000.' %}" required> | ||||||
|  |                 <span>{% trans "GB Storage (SSD)" %}</span> | ||||||
|  |                 <i class="fa fa-plus right" data-plus="storage" aria-hidden="true"></i> | ||||||
|  |             </div> | ||||||
|  |             <div class="help-block with-errors"> | ||||||
|  |                 {% for message in messages %} | ||||||
|  |                     {% if 'storage' in message.tags %} | ||||||
|  |                      <ul class="list-unstyled"><li> | ||||||
|  |                         {{ message|safe }} | ||||||
|  |                     </li></ul> | ||||||
|  |                     {% endif %} | ||||||
|  |                 {% endfor %} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="form-group"> | ||||||
|  |             <div class="description select-configuration input justify-center"> | ||||||
|  |                 <label for="config">OS</label> | ||||||
|  |                 <select name="config" id=""> | ||||||
|  |                     {% for template in templates %} | ||||||
|  |                     <option value="{{template.opennebula_vm_template_id}}">{{template.name}}</option> | ||||||
|  |                     {% endfor %} | ||||||
|  |                 </select> | ||||||
|  |             </div> | ||||||
|  |             <div class="help-block with-errors"> | ||||||
|  |                 {% for message in messages %} | ||||||
|  |                     {% if 'cores' in message.tags %} | ||||||
|  |                      <ul class="list-unstyled"><li> | ||||||
|  |                         {{ message|safe }} | ||||||
|  |                     </li></ul> | ||||||
|  |                     {% endif %} | ||||||
|  |                 {% endfor %} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |         <input type="hidden" name="total"> | ||||||
|  |     </div> | ||||||
|  |     <input type="submit" class="btn btn-primary disabled" value="{% trans 'Continue' %}"></input> | ||||||
|  | </form> | ||||||
|  | @ -1,12 +1,12 @@ | ||||||
| {% extends "hosting/base_short.html" %} | {% extends "hosting/base_short.html" %} | ||||||
| {% load staticfiles bootstrap3 i18n %} | {% load staticfiles bootstrap3 i18n %} | ||||||
| {% block content %}  |  | ||||||
| <div> |  | ||||||
|     <div class="dashboard-container" > |  | ||||||
|         <div class="row"> |  | ||||||
| 
 | 
 | ||||||
|                 <div class="col-md-12"> | {% block content %} | ||||||
|                     <br/> | <div class="dashboard-container create-vm-container"> | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-sm-5"> | ||||||
|  |           <div class="dashboard-container-head"> | ||||||
|  |                 <h3 class="dashboard-title-thin"><img src="{% static 'hosting/img/plusVM.svg' %}" class="un-icon" style="margin-top: -18px;width: 42px;height: 42px;"> {% trans "Create VM" %}</h3> | ||||||
|                 {% if messages %} |                 {% if messages %} | ||||||
|                     <div class="alert alert-warning"> |                     <div class="alert alert-warning"> | ||||||
|                         {% for message in messages %} |                         {% for message in messages %} | ||||||
|  | @ -15,56 +15,16 @@ | ||||||
|                     </div> |                     </div> | ||||||
|                 {% endif %} |                 {% endif %} | ||||||
|           </div> |           </div> | ||||||
|                 {% if not error %} |  | ||||||
|                 <div class="dashboard-title"> |  | ||||||
|                     <h3>{% trans "New Virtual Machine"%} </h3> |  | ||||||
|                     <hr/> |  | ||||||
|         </div> |         </div> | ||||||
| 
 |         <div class="col-sm-6"> | ||||||
|                 <form method="POST" action=""> |             <div class="price-calc-section no-padding"> | ||||||
|                     {% csrf_token %} |                 <div class="landing card"> | ||||||
|              |                     <div class="caption"> | ||||||
|                     <div class="step-title"> |                         {% include "hosting/calculator_form.html" %} | ||||||
|                         <h4>{% trans "Step 1. Select VM Template:" %} </h4> |                     </div> | ||||||
|                     </div> |                 </div> | ||||||
|                     <div class="parent-container"> |             </div> | ||||||
|                         <div class="container-os owl-carousel owl-theme" id="containerOs"> |  | ||||||
|                              |  | ||||||
|                             {% for template in templates %} |  | ||||||
|                                 <div class="os-circle" data-id="{{template.id}}"> |  | ||||||
|                                     <span class="text" >{{template.name}}</span> |  | ||||||
|                                 </div> |  | ||||||
|                             {% endfor %} |  | ||||||
|                         </div> |  | ||||||
|                         <input type="hidden" name="vm_template_id"> |  | ||||||
|                     </div> |  | ||||||
|                      <div class="step-title"> |  | ||||||
|                         <h4>{% trans "Step2. Select VM Configuration" %}</h4> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="parent-container"> |  | ||||||
|                         <div class="container-os config owl-carousel owl-theme"> |  | ||||||
|                             |  | ||||||
|                             {% for config in configuration_options %} |  | ||||||
|                                 <div class="config-box" data-id="{{config.id}}" data-price="{{config.price|floatformat}}"> |  | ||||||
|                                     <span>CORE: {{config.cpu|floatformat}}</span> |  | ||||||
|                                     <span>RAM: {{config.memory|floatformat}} GB</span> |  | ||||||
|                                     <span>SSD: {{config.disk_size|floatformat}} GB</span> |  | ||||||
|                                 </div> |  | ||||||
|                             {% endfor %} |  | ||||||
|                         </div> |  | ||||||
|                          <input type="hidden" name="configuration"> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="container-button"> |  | ||||||
|                           <div class="price"> |  | ||||||
|                             <span class="label-price">{% trans "Price " %}<span id="priceValue">0</span>{% trans "CHF/Month" %}</span> |  | ||||||
|                           </div> |  | ||||||
|                          <button class="btn btn-success" >{% trans "Start VM"%} </button>    |  | ||||||
|                     </div> |  | ||||||
|                 </form> |  | ||||||
|                 {% endif %} |  | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
| 
 |  | ||||||
| </div> | </div> | ||||||
| 
 |  | ||||||
| {%endblock%} | {%endblock%} | ||||||
|  | @ -53,22 +53,29 @@ | ||||||
| 				<h2 class="vm-detail-title">{% trans "Status" %} <img src="{% static 'hosting/img/connected.svg' %}" class="un-icon"></h2> | 				<h2 class="vm-detail-title">{% trans "Status" %} <img src="{% static 'hosting/img/connected.svg' %}" class="un-icon"></h2> | ||||||
| 				<div class="vm-vmid"> | 				<div class="vm-vmid"> | ||||||
| 					<div class="vm-item-subtitle">{% trans "Your VM is" %}</div> | 					<div class="vm-item-subtitle">{% trans "Your VM is" %}</div> | ||||||
|  | 						<div id="terminate-VM" data-alt="{% trans 'Terminating' %}"> | ||||||
| 							{% if virtual_machine.state == 'PENDING' %} | 							{% if virtual_machine.state == 'PENDING' %} | ||||||
| 								<div class="vm-item-lg vm-color-pending">{% trans "Pending" %}</div> | 								<div class="vm-item-lg vm-color-pending">{% trans "Pending" %}</div> | ||||||
| 							{% elif  virtual_machine.state == 'ACTIVE' %} | 							{% elif  virtual_machine.state == 'ACTIVE' %} | ||||||
| 								<div class="vm-item-lg vm-color-online">{% trans "Online" %}</div> | 								<div class="vm-item-lg vm-color-online">{% trans "Online" %}</div> | ||||||
| 							{% elif  virtual_machine.state == 'FAILED'%} | 							{% elif  virtual_machine.state == 'FAILED'%} | ||||||
| 								<div class="vm-item-lg vm-color-failed">{% trans "Failed" %}</div> | 								<div class="vm-item-lg vm-color-failed">{% trans "Failed" %}</div> | ||||||
|  | 							{% else %} | ||||||
|  | 								<div class="vm-item-lg"></div> | ||||||
| 							{% endif %} | 							{% endif %} | ||||||
| 							{% if not virtual_machine.status == 'canceled' %} | 							{% if not virtual_machine.status == 'canceled' %} | ||||||
| 								<form method="POST" id="virtual_machine_cancel_form" class="cancel-form" action="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}"> | 								<form method="POST" id="virtual_machine_cancel_form" class="cancel-form" action="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}"> | ||||||
| 									{% csrf_token %} | 									{% csrf_token %} | ||||||
| 								</form> | 								</form> | ||||||
| 						<button data-href="{% url 'hosting:virtual_machines' virtual_machine.vm_id %}" data-toggle="modal" data-target="#confirm-cancel" class="btn btn-vm-term">{% trans "Terminate VM" %}</button> | 								<button data-toggle="modal" data-target="#confirm-cancel" class="btn btn-vm-term">{% trans "Terminate VM" %}</button> | ||||||
|  | 								<div class="alert alert-danger hide"> | ||||||
|  | 									{% trans "Sorry, there was an unexpected error. Kindly retry." %} | ||||||
|  | 								</div> | ||||||
| 							{% endif %} | 							{% endif %} | ||||||
| 						</div> | 						</div> | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
|  | 		</div> | ||||||
| 		<div class="vm-contact-us"> | 		<div class="vm-contact-us"> | ||||||
| 			<div> | 			<div> | ||||||
| 				<h2 class="vm-detail-title">{% trans "Support / Contact" %} <img class="un-icon visible-xs" src="{% static 'hosting/img/24-hours-support.svg' %}"></h2> | 				<h2 class="vm-detail-title">{% trans "Support / Contact" %} <img class="un-icon visible-xs" src="{% static 'hosting/img/24-hours-support.svg' %}"></h2> | ||||||
|  | @ -109,4 +116,21 @@ | ||||||
|     </div> |     </div> | ||||||
| 	</div> | 	</div> | ||||||
| 	<!-- / Cancel Modal --> | 	<!-- / Cancel Modal --> | ||||||
|  | 	<!-- Success Modal --> | ||||||
|  | 	<div class="modal fade" id="terminate-success" tabindex="-1" role="dialog" aria-hidden="true"> | ||||||
|  |     <div class="modal-dialog"> | ||||||
|  |       <div class="modal-content"> | ||||||
|  | 				<div class="modal-header"> | ||||||
|  | 				</div> | ||||||
|  |         <div class="modal-body"> | ||||||
|  | 					<div class="modal-icon"><i class="fa fa-check" aria-hidden="true"></i></div> | ||||||
|  | 					<h4 class="modal-title" id="ModalLabel">{% blocktrans with machine_name=virtual_machine.name %}Your Virtual Machine <strong>{{machine_name}}</strong> is successfully terminated!{% endblocktrans %}</h4> | ||||||
|  |           <div class="modal-footer"> | ||||||
|  |             <a href="{% url 'hosting:virtual_machines' %}"	class="btn btn-success btn-wide">{% trans "OK" %}</a> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  | 	</div> | ||||||
|  | 	<!-- / Cancel Modal --> | ||||||
| {%endblock%} | {%endblock%} | ||||||
|  |  | ||||||
							
								
								
									
										174
									
								
								hosting/views.py
									
										
									
									
									
								
							
							
						
						
									
										174
									
								
								hosting/views.py
									
										
									
									
									
								
							|  | @ -1,23 +1,27 @@ | ||||||
| import json | import json | ||||||
| import logging | import logging | ||||||
| import uuid | import uuid | ||||||
|  | from time import sleep | ||||||
| 
 | 
 | ||||||
|  | from django import forms | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.contrib import messages | from django.contrib import messages | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | 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.exceptions import ValidationError | ||||||
| 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 | 
 | ||||||
| from django.http import HttpResponseRedirect, HttpResponse | from django.http import Http404, HttpResponseRedirect, HttpResponse | ||||||
| from django.shortcuts import redirect | from django.shortcuts import redirect, render | ||||||
| from django.shortcuts import 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 get_language, ugettext_lazy as _ | from django.utils.translation import get_language, ugettext_lazy as _ | ||||||
| from django.views.generic import View, CreateView, FormView, ListView, \ | from django.utils.translation import ugettext | ||||||
|     DetailView, \ | from django.views.generic import ( | ||||||
|     DeleteView, TemplateView, UpdateView |     View, CreateView, FormView, ListView, DetailView, DeleteView, | ||||||
|  |     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 | ||||||
|  | @ -28,18 +32,21 @@ 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, VMTemplateSerializer | ||||||
| from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | ||||||
|     UserBillingAddressForm |     UserBillingAddressForm | ||||||
|  | from utils.hosting_utils import get_vm_price | ||||||
| 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 utils.hosting_utils import get_vm_price | ) | ||||||
| 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 | ||||||
| from .models import HostingOrder, HostingBill, HostingPlan, UserHostingKey | from .models import HostingOrder, HostingBill, HostingPlan, UserHostingKey | ||||||
|  | from datacenterlight.models import VMTemplate | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| logger = logging.getLogger(__name__) | logger = logging.getLogger(__name__) | ||||||
| 
 | 
 | ||||||
|  | @ -866,48 +873,80 @@ class CreateVirtualMachinesView(LoginRequiredMixin, View): | ||||||
|     template_name = "hosting/create_virtual_machine.html" |     template_name = "hosting/create_virtual_machine.html" | ||||||
|     login_url = reverse_lazy('hosting:login') |     login_url = reverse_lazy('hosting:login') | ||||||
| 
 | 
 | ||||||
|     def get(self, request, *args, **kwargs): |     def validate_cores(self, value): | ||||||
|  |         if (value > 48) or (value < 1): | ||||||
|  |             raise ValidationError(_('Invalid number of cores')) | ||||||
| 
 | 
 | ||||||
|  |     def validate_memory(self, value): | ||||||
|  |         if (value > 200) or (value < 2): | ||||||
|  |             raise ValidationError(_('Invalid RAM size')) | ||||||
|  | 
 | ||||||
|  |     def validate_storage(self, value): | ||||||
|  |         if (value > 2000) or (value < 10): | ||||||
|  |             raise ValidationError(_('Invalid storage size')) | ||||||
|  | 
 | ||||||
|  |     def get(self, request, *args, **kwargs): | ||||||
|         if not UserHostingKey.objects.filter(user=self.request.user).exists(): |         if not UserHostingKey.objects.filter(user=self.request.user).exists(): | ||||||
|             messages.success( |             messages.success( | ||||||
|                 request, |                 request, | ||||||
|                 _( |                 _( | ||||||
|                     'In order to create a VM, you need to create/upload your SSH KEY first.') |                     'In order to create a VM, you need to ' | ||||||
|  |                     'create/upload your SSH KEY first.' | ||||||
|  |                 ) | ||||||
|             ) |             ) | ||||||
|             return HttpResponseRedirect(reverse('hosting:ssh_keys')) |             return HttpResponseRedirect(reverse('hosting:ssh_keys')) | ||||||
| 
 |         context = {'templates': VMTemplate.objects.all()} | ||||||
|         try: |  | ||||||
|             manager = OpenNebulaManager() |  | ||||||
|             templates = manager.get_templates() |  | ||||||
|             configuration_options = HostingPlan.get_serialized_configs() |  | ||||||
| 
 |  | ||||||
|             context = { |  | ||||||
|                 'templates': VirtualMachineTemplateSerializer(templates, |  | ||||||
|                                                               many=True).data, |  | ||||||
|                 'configuration_options': configuration_options, |  | ||||||
|             } |  | ||||||
|         except: |  | ||||||
|             messages.error( |  | ||||||
|                 request, |  | ||||||
|                 'We could not load the VM templates due to a backend connection \ |  | ||||||
|                 error. Please try again in a few minutes' |  | ||||||
|             ) |  | ||||||
|             context = { |  | ||||||
|                 'error': 'connection' |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
| 
 | 
 | ||||||
|     def post(self, request): |     def post(self, request): | ||||||
|         manager = OpenNebulaManager() |         cores = request.POST.get('cpu') | ||||||
|         template_id = request.POST.get('vm_template_id') |         cores_field = forms.IntegerField(validators=[self.validate_cores]) | ||||||
|         template = manager.get_template(template_id) |         memory = request.POST.get('ram') | ||||||
|         configuration_id = int(request.POST.get('configuration')) |         memory_field = forms.IntegerField(validators=[self.validate_memory]) | ||||||
|         configuration = HostingPlan.objects.get(id=configuration_id) |         storage = request.POST.get('storage') | ||||||
|         request.session['template'] = VirtualMachineTemplateSerializer( |         storage_field = forms.IntegerField(validators=[self.validate_storage]) | ||||||
|             template).data |         template_id = int(request.POST.get('config')) | ||||||
|  |         template = VMTemplate.objects.filter( | ||||||
|  |             opennebula_vm_template_id=template_id).first() | ||||||
|  |         template_data = VMTemplateSerializer(template).data | ||||||
| 
 | 
 | ||||||
|         request.session['specs'] = configuration.serialize() |         try: | ||||||
|  |             cores = cores_field.clean(cores) | ||||||
|  |         except ValidationError as err: | ||||||
|  |             msg = '{} : {}.'.format(cores, str(err)) | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='cores') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('datacenterlight:index') + "#order_form") | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             memory = memory_field.clean(memory) | ||||||
|  |         except ValidationError as err: | ||||||
|  |             msg = '{} : {}.'.format(memory, str(err)) | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='memory') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('datacenterlight:index') + "#order_form") | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|  |             storage = storage_field.clean(storage) | ||||||
|  |         except ValidationError as err: | ||||||
|  |             msg = '{} : {}.'.format(storage, str(err)) | ||||||
|  |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|  |                                  extra_tags='storage') | ||||||
|  |             return HttpResponseRedirect( | ||||||
|  |                 reverse('datacenterlight:index') + "#order_form") | ||||||
|  |         price = get_vm_price(cpu=cores, memory=memory, | ||||||
|  |                              disk_size=storage)	 | ||||||
|  |         specs = { | ||||||
|  |             'cpu': cores, | ||||||
|  |             'memory': memory, | ||||||
|  |             'disk_size': storage, | ||||||
|  |             'price': price | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         request.session['specs'] = specs | ||||||
|  |         request.session['template'] = template_data | ||||||
|         return redirect(reverse('hosting:payment')) |         return redirect(reverse('hosting:payment')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -949,7 +988,19 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|         vm = self.get_object() |         vm = self.get_object() | ||||||
|         if vm is None: |         if vm is None: | ||||||
|  |             if self.request.is_ajax(): | ||||||
|  |                 storage = messages.get_messages(request) | ||||||
|  |                 for m in storage: | ||||||
|  |                     pass | ||||||
|  |                 storage.used = True | ||||||
|  |                 return HttpResponse( | ||||||
|  |                     json.dumps({'text': ugettext('Terminated')}), | ||||||
|  |                     content_type="application/json" | ||||||
|  |                 ) | ||||||
|  |             else: | ||||||
|                 return redirect(reverse('hosting:virtual_machines')) |                 return redirect(reverse('hosting:virtual_machines')) | ||||||
|  |         elif self.request.is_ajax(): | ||||||
|  |             return HttpResponse() | ||||||
|         try: |         try: | ||||||
|             serializer = VirtualMachineSerializer(vm) |             serializer = VirtualMachineSerializer(vm) | ||||||
|             context = { |             context = { | ||||||
|  | @ -964,6 +1015,7 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
| 
 | 
 | ||||||
|     def post(self, request, *args, **kwargs): |     def post(self, request, *args, **kwargs): | ||||||
|  |         response = {'status': False} | ||||||
|         owner = self.request.user |         owner = self.request.user | ||||||
|         vm = self.get_object() |         vm = self.get_object() | ||||||
| 
 | 
 | ||||||
|  | @ -973,17 +1025,29 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|             email=owner.email, |             email=owner.email, | ||||||
|             password=owner.password |             password=owner.password | ||||||
|         ) |         ) | ||||||
|  | 
 | ||||||
|  |         try: | ||||||
|             vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data |             vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data | ||||||
|         terminated = manager.delete_vm( |         except WrongIdError: | ||||||
|             vm.id |             return redirect(reverse('hosting:virtual_machines')) | ||||||
|         ) | 
 | ||||||
|  |         terminated = manager.delete_vm(vm.id) | ||||||
| 
 | 
 | ||||||
|         if not terminated: |         if not terminated: | ||||||
|             messages.error( |             response['text'] = ugettext( | ||||||
|                 request, |                 'Error terminating VM') + opennebula_vm_id | ||||||
|                 'Error terminating VM %s' % (opennebula_vm_id) |         else: | ||||||
|             ) |             for t in range(15): | ||||||
|             return HttpResponseRedirect(self.get_success_url()) |                 try: | ||||||
|  |                     manager.get_vm(opennebula_vm_id) | ||||||
|  |                 except WrongIdError: | ||||||
|  |                     response['status'] = True | ||||||
|  |                     response['text'] = ugettext('Terminated') | ||||||
|  |                     break | ||||||
|  |                 except BaseException: | ||||||
|  |                     break | ||||||
|  |                 else: | ||||||
|  |                     sleep(2) | ||||||
|             context = { |             context = { | ||||||
|                 'vm': vm_data, |                 'vm': vm_data, | ||||||
|                 'base_url': "{0}://{1}".format(self.request.scheme, |                 'base_url': "{0}://{1}".format(self.request.scheme, | ||||||
|  | @ -1000,15 +1064,11 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|             } |             } | ||||||
|             email = BaseEmail(**email_data) |             email = BaseEmail(**email_data) | ||||||
|             email.send() |             email.send() | ||||||
| 
 |         return HttpResponse( | ||||||
|         messages.error( |             json.dumps(response), | ||||||
|             request, |             content_type="application/json" | ||||||
|             _('VM %(VM_ID)s terminated successfully') % { |  | ||||||
|                 'VM_ID': opennebula_vm_id} |  | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         return HttpResponseRedirect(self.get_success_url()) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class HostingBillListView(PermissionRequiredMixin, LoginRequiredMixin, | class HostingBillListView(PermissionRequiredMixin, LoginRequiredMixin, | ||||||
|                           ListView): |                           ListView): | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue