merged master
This commit is contained in:
		
				commit
				
					
						734a41a371
					
				
			
		
					 25 changed files with 330 additions and 370 deletions
				
			
		|  | @ -1,10 +1,15 @@ | ||||||
| Next: | 1.2.4: 2017-10-02 | ||||||
|  |     * #3780: [hosting] Store VM details locally | ||||||
|     * #3764: [hosting] Show cancelled VMs' invoices  |     * #3764: [hosting] Show cancelled VMs' invoices  | ||||||
|     * #3736: [dcl] Refactor the place where we compute the VM price |     * #3736: [dcl] Refactor the place where we compute the VM price | ||||||
|     * #3730: [dcl] Refactor price parameter passed in the DCL flow |     * #3730: [dcl] Refactor price parameter passed in the DCL flow | ||||||
|     * #3807: [dcl] Remove PricingView as it is no more used |     * #3807: [dcl] Remove PricingView as it is no more used | ||||||
|     * #3813: [hosting] JS error in create ssh key page |     * #3813: [hosting] JS error in create ssh key page | ||||||
|     * #3756: [dcl] Update landing calculator and billing info page |     * #3756: [dcl] Update landing calculator and billing info page | ||||||
|  |     * Bugfix: Fix PR 493 bug that creates a new StripeCustomer for each buying of VM with the same email id | ||||||
|  |     * #3835: [all] Forbidden (403) CSRF verification failed issue. | ||||||
|  |     * Bugfix: [hosting] Dashboard strictly available after login | ||||||
|  |     * #3808: [dcl] Order confirmation page redesign | ||||||
| 1.2.3: 2017-09-25 | 1.2.3: 2017-09-25 | ||||||
|     * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email |     * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email | ||||||
|     * #3731: [dcl, hosting] Added cdist ssh key handler  |     * #3731: [dcl, hosting] Added cdist ssh key handler  | ||||||
|  |  | ||||||
|  | @ -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-23 21:22+0000\n" | "POT-Creation-Date: 2017-10-01 22:13+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" | ||||||
|  | @ -388,24 +388,6 @@ msgstr "Weiter" | ||||||
| msgid "Enter your credit card number" | msgid "Enter your credit card number" | ||||||
| msgstr "Deine Kreditkartennummer" | msgstr "Deine Kreditkartennummer" | ||||||
| 
 | 
 | ||||||
| msgid "Confirm Order" |  | ||||||
| msgstr "Bestellung Bestätigen" |  | ||||||
| 
 |  | ||||||
| msgid "Date" |  | ||||||
| msgstr "Datum" |  | ||||||
| 
 |  | ||||||
| msgid "Billed To:" |  | ||||||
| msgstr "Rechnungsadresse" |  | ||||||
| 
 |  | ||||||
| msgid "Payment Method:" |  | ||||||
| msgstr "Bezahlmethode" |  | ||||||
| 
 |  | ||||||
| msgid "ending in" |  | ||||||
| msgstr "endend in" |  | ||||||
| 
 |  | ||||||
| msgid "Order summary" |  | ||||||
| msgstr "Bestellungsübersicht" |  | ||||||
| 
 |  | ||||||
| #, python-format | #, python-format | ||||||
| msgid "" | msgid "" | ||||||
| "By clicking \"Place order\" this plan will charge your credit card account " | "By clicking \"Place order\" this plan will charge your credit card account " | ||||||
|  | @ -417,36 +399,6 @@ msgstr "" | ||||||
| msgid "Place order" | msgid "Place order" | ||||||
| msgstr "Bestellen" | msgstr "Bestellen" | ||||||
| 
 | 
 | ||||||
| msgid "Processing..." |  | ||||||
| msgstr "Abarbeitung..." |  | ||||||
| 
 |  | ||||||
| msgid "Hold tight, we are processing your request" |  | ||||||
| msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade" |  | ||||||
| 
 |  | ||||||
| msgid "Some problem encountered. Please try again later." |  | ||||||
| msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." |  | ||||||
| 
 |  | ||||||
| msgid "We are cutting down the costs significantly!" |  | ||||||
| msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen" |  | ||||||
| 
 |  | ||||||
| msgid "Order Now!" |  | ||||||
| msgstr "Bestelle jetzt!" |  | ||||||
| 
 |  | ||||||
| msgid "" |  | ||||||
| "Our VMs are hosted in Glarus, Switzerland, and our website is currently " |  | ||||||
| "running in BETA mode. If you want more information that you did not find on " |  | ||||||
| "our website, or if your order is more detailed, or if you encounter any " |  | ||||||
| "technical hiccups, please contact us at support@datacenterlight.ch, our team " |  | ||||||
| "will get in touch with you asap." |  | ||||||
| msgstr "" |  | ||||||
| "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden sich " |  | ||||||
| "zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren und hast " |  | ||||||
| "auf unserer Website nicht genügend Informationen gefunden? Möchtest eine " |  | ||||||
| "detailliertere Bestellung aufgeben? Bist du auf technische Probleme " |  | ||||||
| "gestossen, die du uns mitteilen möchtest? Dann zögere nicht und kontaktiere " |  | ||||||
| "uns unter support@datacenterlight.ch. Unser Team wird sich umgehend um dein " |  | ||||||
| "Anliegen kümmern!" |  | ||||||
| 
 |  | ||||||
| msgid "Thank you for order! Our team will contact you via email" | msgid "Thank you for order! Our team will contact you via email" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit " | "Vielen Dank für die Bestellung. Unser Team setzt sich sobald wie möglich mit " | ||||||
|  | @ -540,6 +492,9 @@ msgstr "Ungültige RAM-Grösse" | ||||||
| msgid "Invalid storage size" | msgid "Invalid storage size" | ||||||
| msgstr "Ungültige Speicher-Grösse" | msgstr "Ungültige Speicher-Grösse" | ||||||
| 
 | 
 | ||||||
|  | msgid "Confirm Order" | ||||||
|  | msgstr "Bestellung Bestätigen" | ||||||
|  | 
 | ||||||
| msgid "Error." | msgid "Error." | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | @ -547,6 +502,8 @@ msgid "" | ||||||
| "There was a payment related error. On close of this popup, you will be " | "There was a payment related error. On close of this popup, you will be " | ||||||
| "redirected back to the payment page." | "redirected back to the payment page." | ||||||
| msgstr "" | msgstr "" | ||||||
|  | "Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom " | ||||||
|  | "Popup zur Bezahlseite weitergeleitet." | ||||||
| 
 | 
 | ||||||
| msgid "Thank you for the order." | msgid "Thank you for the order." | ||||||
| msgstr "Danke für Deine Bestellung." | msgstr "Danke für Deine Bestellung." | ||||||
|  | @ -558,6 +515,51 @@ 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 "Date" | ||||||
|  | #~ msgstr "Datum" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Billed To:" | ||||||
|  | #~ msgstr "Rechnungsadresse" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Payment Method:" | ||||||
|  | #~ msgstr "Bezahlmethode" | ||||||
|  | 
 | ||||||
|  | #~ msgid "ending in" | ||||||
|  | #~ msgstr "endend in" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Order summary" | ||||||
|  | #~ msgstr "Bestellungsübersicht" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Processing..." | ||||||
|  | #~ msgstr "Abarbeitung..." | ||||||
|  | 
 | ||||||
|  | #~ msgid "Hold tight, we are processing your request" | ||||||
|  | #~ msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Some problem encountered. Please try again later." | ||||||
|  | #~ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." | ||||||
|  | 
 | ||||||
|  | #~ msgid "We are cutting down the costs significantly!" | ||||||
|  | #~ msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen" | ||||||
|  | 
 | ||||||
|  | #~ msgid "Order Now!" | ||||||
|  | #~ msgstr "Bestelle jetzt!" | ||||||
|  | 
 | ||||||
|  | #~ msgid "" | ||||||
|  | #~ "Our VMs are hosted in Glarus, Switzerland, and our website is currently " | ||||||
|  | #~ "running in BETA mode. If you want more information that you did not find " | ||||||
|  | #~ "on our website, or if your order is more detailed, or if you encounter " | ||||||
|  | #~ "any technical hiccups, please contact us at support@datacenterlight.ch, " | ||||||
|  | #~ "our team will get in touch with you asap." | ||||||
|  | #~ msgstr "" | ||||||
|  | #~ "Unsere VMs werden in der Schweiz im Kanton Glarus gehostet und befinden " | ||||||
|  | #~ "sich zur Zeit noch in der BETA-Phase. Möchtest du mehr über uns erfahren " | ||||||
|  | #~ "und hast auf unserer Website nicht genügend Informationen gefunden? " | ||||||
|  | #~ "Möchtest eine detailliertere Bestellung aufgeben? Bist du auf technische " | ||||||
|  | #~ "Probleme gestossen, die du uns mitteilen möchtest? Dann zögere nicht und " | ||||||
|  | #~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich " | ||||||
|  | #~ "umgehend um dein Anliegen kümmern!" | ||||||
|  | 
 | ||||||
| #~ msgid "Email Address" | #~ msgid "Email Address" | ||||||
| #~ msgstr "E-Mail-Adresse" | #~ msgstr "E-Mail-Adresse" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1501,6 +1501,8 @@ tech-sub-sec h2 { | ||||||
|     font-size: 14px; |     font-size: 14px; | ||||||
|     font-weight: 300; |     font-weight: 300; | ||||||
|     letter-spacing: 2px; |     letter-spacing: 2px; | ||||||
|  |     line-height: 24px; | ||||||
|  |     display: block; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .content-section-a { | .content-section-a { | ||||||
|  |  | ||||||
|  | @ -50,15 +50,20 @@ def retry_task(task, exception=None): | ||||||
| @app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) | @app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES) | ||||||
| def create_vm_task(self, vm_template_id, user, specs, template, | 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, |                    stripe_subscription_id, cc_details): | ||||||
|                    charge, cc_details): |  | ||||||
|     logger.debug( |     logger.debug( | ||||||
|         "Running create_vm_task on {}".format(current_task.request.hostname)) |         "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( | ||||||
|             id=billing_address_id).first() |             cardholder_name=billing_address_data['cardholder_name'], | ||||||
|  |             street_address=billing_address_data['street_address'], | ||||||
|  |             city=billing_address_data['city'], | ||||||
|  |             postal_code=billing_address_data['postal_code'], | ||||||
|  |             country=billing_address_data['country'] | ||||||
|  |         ) | ||||||
|  |         billing_address.save() | ||||||
|         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | ||||||
| 
 | 
 | ||||||
|         if 'pass' in user: |         if 'pass' in user: | ||||||
|  | @ -111,8 +116,7 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|             billing_address_user_form.save() |             billing_address_user_form.save() | ||||||
| 
 | 
 | ||||||
|         # Associate an order with a stripe subscription |         # Associate an order with a stripe subscription | ||||||
|         charge_object = DictDotLookup(charge) |         order.set_subscription_id(stripe_subscription_id, cc_details) | ||||||
|         order.set_subscription_id(charge_object, cc_details) |  | ||||||
| 
 | 
 | ||||||
|         # If the Stripe payment succeeds, set order status approved |         # If the Stripe payment succeeds, set order status approved | ||||||
|         order.set_approved() |         order.set_approved() | ||||||
|  | @ -183,7 +187,8 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|                             public_keys] |                             public_keys] | ||||||
|                     if len(keys) > 0: |                     if len(keys) > 0: | ||||||
|                         logger.debug( |                         logger.debug( | ||||||
|                             "Calling configure on {host} for {num_keys} keys".format( |                             "Calling configure on {host} for " | ||||||
|  |                             "{num_keys} keys".format( | ||||||
|                                 host=new_host, num_keys=len(keys))) |                                 host=new_host, num_keys=len(keys))) | ||||||
|                         # Let's delay the task by 75 seconds to be sure |                         # Let's delay the task by 75 seconds to be sure | ||||||
|                         # that we run the cdist configure after the host |                         # that we run the cdist configure after the host | ||||||
|  | @ -212,32 +217,3 @@ def create_vm_task(self, vm_template_id, user, specs, template, | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|     return vm_id |     return vm_id | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DictDotLookup(object): |  | ||||||
|     """ |  | ||||||
|     Creates objects that behave much like a dictionaries, but allow nested |  | ||||||
|     key access using object '.' (dot) lookups. |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     def __init__(self, d): |  | ||||||
|         for k in d: |  | ||||||
|             if isinstance(d[k], dict): |  | ||||||
|                 self.__dict__[k] = DictDotLookup(d[k]) |  | ||||||
|             elif isinstance(d[k], (list, tuple)): |  | ||||||
|                 l = [] |  | ||||||
|                 for v in d[k]: |  | ||||||
|                     if isinstance(v, dict): |  | ||||||
|                         l.append(DictDotLookup(v)) |  | ||||||
|                     else: |  | ||||||
|                         l.append(v) |  | ||||||
|                 self.__dict__[k] = l |  | ||||||
|             else: |  | ||||||
|                 self.__dict__[k] = d[k] |  | ||||||
| 
 |  | ||||||
|     def __getitem__(self, name): |  | ||||||
|         if name in self.__dict__: |  | ||||||
|             return self.__dict__[name] |  | ||||||
| 
 |  | ||||||
|     def __iter__(self): |  | ||||||
|         return iter(self.__dict__.keys()) |  | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
|                         <hr class="intro-divider"> |                         <hr class="intro-divider"> | ||||||
|                         <ul class="list-inline intro-social-buttons"> |                         <ul class="list-inline intro-social-buttons"> | ||||||
|                             <li> |                             <li> | ||||||
|                                 <a class="btn btn-default btn-lg btn-transparent url" href="#how"><i class="#Services"></i> <span class="network-name">{% trans "Highlights" %}</span></a> |                                 <a class="btn btn-default btn-lg btn-transparent url" href="#how"><span class="network-name">{% trans "Highlights" %}</span></a> | ||||||
|                             </li> |                             </li> | ||||||
|                             <li> |                             <li> | ||||||
|                                 <a class="btn btn-primary btn-lg page-scroll url" href="#price"><span class="network-name">{% trans "I want it!" %}</span></a> |                                 <a class="btn btn-primary btn-lg page-scroll url" href="#price"><span class="network-name">{% trans "I want it!" %}</span></a> | ||||||
|  |  | ||||||
|  | @ -1,143 +1,24 @@ | ||||||
| {% extends "hosting/base_short.html" %} | {% extends "hosting/order_detail.html" %} | ||||||
| {% load staticfiles bootstrap3 %} |  | ||||||
| {% load i18n %} | {% load i18n %} | ||||||
| {% load custom_tags %} |  | ||||||
| 
 | 
 | ||||||
| {% block navbar %} | {% block navbar %} | ||||||
|     {% include "datacenterlight/includes/_navbar.html" %} |     {% include "datacenterlight/includes/_navbar.html" %} | ||||||
| {% endblock navbar %} | {% endblock navbar %} | ||||||
| 
 | 
 | ||||||
| {% block content %} | {% block submit_btn %} | ||||||
|  |   <form id="virtual_machine_create_form" action="" method="POST"> | ||||||
|  |       {% csrf_token %} | ||||||
|  |       <div class="row"> | ||||||
|  |           <div class="col-sm-8"> | ||||||
|  |               <div 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 %}.</div> | ||||||
|  |           </div> | ||||||
|  |           <div class="col-sm-4 order-confirm-btn text-right"> | ||||||
|  |               <button class="btn choice-btn" id="btn-create-vm" | ||||||
|  |                       data-toggle="modal" data-target="#createvm-modal"> | ||||||
|  | 				{% trans "Place order" %} | ||||||
|  |               </button> | ||||||
|  |           </div> | ||||||
|  |       </div> | ||||||
|  |   </form> | ||||||
|  | {% endblock submit_btn %} | ||||||
| 
 | 
 | ||||||
| <div class="order-detail-container"> |  | ||||||
|    {% if messages %} |  | ||||||
|         <div class="row"> |  | ||||||
|             <div class="col-xs-12 col-md-8 col-md-offset-2"> |  | ||||||
|                 <br/> |  | ||||||
|                 <div class="alert alert-warning"> |  | ||||||
|                     {% for message in messages %} |  | ||||||
|                     <span>{{ message }}</span> |  | ||||||
|                     {% endfor %} |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     {% endif %} |  | ||||||
|     {% if not error %} |  | ||||||
|         <div class="row"> |  | ||||||
|             <div class="col-xs-12 col-md-8 col-md-offset-2"> |  | ||||||
|                 <div class="invoice-title"> |  | ||||||
|                     <h2>{% trans "Confirm Order"%}</h2> |  | ||||||
|                 </div> |  | ||||||
|                 <hr> |  | ||||||
|                 <div class="row"> |  | ||||||
|                     <div class="col-xs-12 col-sm-6 pull-right order-confirm-date"> |  | ||||||
|                         <address> |  | ||||||
|                             <strong>{% trans "Date"%}:</strong><br> |  | ||||||
|                             <span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br> |  | ||||||
|                         </address> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="col-xs-12 col-sm-6"> |  | ||||||
|                         <address> |  | ||||||
|                         <h3><b>{% trans "Billed To:"%}</b></h3> |  | ||||||
|                         {% with billing_address_data as billing_address %} |  | ||||||
|                             {{billing_address.cardholder_name}}<br> {{billing_address.street_address}}, {{billing_address.postal_code}}<br> |  | ||||||
|                             {{billing_address.city}}, {{billing_address.country}}. |  | ||||||
|                         {% endwith %} |  | ||||||
|                         </address> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="row"> |  | ||||||
|                     <div class="col-xs-6"> |  | ||||||
|                         <address> |  | ||||||
|                             <strong>{% trans "Payment Method:"%}</strong><br> |  | ||||||
|                                 {{cc_brand}} {% trans "ending in" %} **** {{cc_last4}}<br> |  | ||||||
|                                 {{request.session.user.email}} |  | ||||||
|                         </address> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|         <div class="row"> |  | ||||||
|             <div class="col-md-8 col-md-offset-2"> |  | ||||||
|                 <h3><b>{% trans "Order summary"%}</b></h3> |  | ||||||
|                 <hr> |  | ||||||
|                 <div class="content"> |  | ||||||
|                     {% with request.session.specs as vm %} |  | ||||||
|                         <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cpu}}</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> |  | ||||||
|                         <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 %} |  | ||||||
|                 </div> |  | ||||||
|                 <br/> |  | ||||||
|                 <form method="post" id="virtual_machine_create_form"> |  | ||||||
|                     {% csrf_token %} |  | ||||||
|                     <div class="row"> |  | ||||||
|                         <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> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     {% endif %} |  | ||||||
| </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"> |  | ||||||
|                     <a id="createvm-modal-done-btn" class="btn btn-success btn-ok btn-wide hide" href="">{% trans "OK" %}</a> |  | ||||||
|                     <button id="createvm-modal-close-btn" type="button" class="btn btn-danger btn-ok btn-wide hide" data-dismiss="modal" aria-label="create-vm-close">{% trans "Close" %}</button> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|     </div> |  | ||||||
| </div> |  | ||||||
| <!-- / Create VM Modal --> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| <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 () { |  | ||||||
|         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"); |  | ||||||
|         document.getElementById('order-created_at').innerHTML = locale_date; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
| </script> |  | ||||||
| {%endblock%} |  | ||||||
|  |  | ||||||
|  | @ -13,7 +13,6 @@ from datacenterlight.tasks import create_vm_task | ||||||
| from membership.models import StripeCustomer | from membership.models import StripeCustomer | ||||||
| from opennebula_api.serializers import VMTemplateSerializer | from opennebula_api.serializers import VMTemplateSerializer | ||||||
| from utils.hosting_utils import get_vm_price | from utils.hosting_utils import get_vm_price | ||||||
| from utils.models import BillingAddress |  | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -75,21 +74,12 @@ class CeleryTaskTestCase(TestCase): | ||||||
|             stripe_customer.stripe_id, |             stripe_customer.stripe_id, | ||||||
|             self.token) |             self.token) | ||||||
|         card_details_dict = card_details.get('response_object') |         card_details_dict = card_details.get('response_object') | ||||||
|         billing_address = BillingAddress( |  | ||||||
|             cardholder_name=self.customer_name, |  | ||||||
|             postal_code='1232', |  | ||||||
|             country='CH', |  | ||||||
|             street_address='Monty\'s Street', |  | ||||||
|             city='Hollywood') |  | ||||||
|         billing_address.save() |  | ||||||
|         billing_address_data = {'cardholder_name': self.customer_name, |         billing_address_data = {'cardholder_name': self.customer_name, | ||||||
|                                 'postal_code': '1231', |                                 'postal_code': '1231', | ||||||
|                                 'country': 'CH', |                                 'country': 'CH', | ||||||
|                                 'token': self.token, |                                 'token': self.token, | ||||||
|                                 'street_address': 'Monty\'s Street', |                                 'street_address': 'Monty\'s Street', | ||||||
|                                 'city': 'Hollywood'} |                                 'city': 'Hollywood'} | ||||||
| 
 |  | ||||||
|         billing_address_id = billing_address.id |  | ||||||
|         vm_template_id = template_data.get('id', 1) |         vm_template_id = template_data.get('id', 1) | ||||||
| 
 | 
 | ||||||
|         cpu = specs.get('cpu') |         cpu = specs.get('cpu') | ||||||
|  | @ -125,8 +115,7 @@ class CeleryTaskTestCase(TestCase): | ||||||
|                                           template_data, |                                           template_data, | ||||||
|                                           stripe_customer.id, |                                           stripe_customer.id, | ||||||
|                                           billing_address_data, |                                           billing_address_data, | ||||||
|                                           billing_address_id, |                                           stripe_subscription_obj.id, | ||||||
|                                           stripe_subscription_obj, |  | ||||||
|                                           card_details_dict) |                                           card_details_dict) | ||||||
|         new_vm_id = 0 |         new_vm_id = 0 | ||||||
|         res = None |         res = None | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ from hosting.forms import HostingUserLoginForm | ||||||
| from membership.models import CustomUser, StripeCustomer | from membership.models import CustomUser, StripeCustomer | ||||||
| from opennebula_api.serializers import VMTemplateSerializer | from opennebula_api.serializers import VMTemplateSerializer | ||||||
| from utils.forms import ( | from utils.forms import ( | ||||||
|     BillingAddressForm, BillingAddressFormSignup, UserBillingAddressForm |     BillingAddressForm, BillingAddressFormSignup | ||||||
| ) | ) | ||||||
| from utils.hosting_utils import get_vm_price | from utils.hosting_utils import get_vm_price | ||||||
| from utils.mailer import BaseEmail | from utils.mailer import BaseEmail | ||||||
|  | @ -348,6 +348,11 @@ class PaymentOrderView(FormView): | ||||||
|             form_kwargs.update({ |             form_kwargs.update({ | ||||||
|                 'instance': self.request.user.billing_addresses.first() |                 'instance': self.request.user.billing_addresses.first() | ||||||
|             }) |             }) | ||||||
|  |         if 'billing_address_data' in self.request.session: | ||||||
|  |             billing_address_data = self.request.session['billing_address_data'] | ||||||
|  |             form_kwargs.update({ | ||||||
|  |                 'initial': billing_address_data | ||||||
|  |             }) | ||||||
|         return form_kwargs |         return form_kwargs | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|  | @ -379,14 +384,40 @@ class PaymentOrderView(FormView): | ||||||
|                     email=this_user.get('email'), |                     email=this_user.get('email'), | ||||||
|                     token=token) |                     token=token) | ||||||
|             else: |             else: | ||||||
|  |                 user_email = form.cleaned_data.get('email') | ||||||
|  |                 user_name = form.cleaned_data.get('name') | ||||||
|                 this_user = { |                 this_user = { | ||||||
|                     'email': form.cleaned_data.get('email'), |                     'email': user_email, | ||||||
|                     'name': form.cleaned_data.get('name') |                     'name': user_name | ||||||
|                 } |                 } | ||||||
|                 customer = StripeCustomer.create_stripe_api_customer( |                 try: | ||||||
|                     email=this_user.get('email'), |                     custom_user = CustomUser.objects.get(email=user_email) | ||||||
|                     token=token, |                     customer = StripeCustomer.objects.filter( | ||||||
|                     customer_name=form.cleaned_data.get('name')) |                         user_id=custom_user.id).first() | ||||||
|  |                     if customer is None: | ||||||
|  |                         logger.debug( | ||||||
|  |                             ("User {email} is already registered with us." | ||||||
|  |                              "But, StripeCustomer does not exist for {email}." | ||||||
|  |                              "Hence, creating a new StripeCustomer.").format( | ||||||
|  |                                 email=user_email | ||||||
|  |                             ) | ||||||
|  |                         ) | ||||||
|  |                         customer = StripeCustomer.create_stripe_api_customer( | ||||||
|  |                             email=user_email, | ||||||
|  |                             token=token, | ||||||
|  |                             customer_name=user_name) | ||||||
|  |                 except CustomUser.DoesNotExist: | ||||||
|  |                     logger.debug( | ||||||
|  |                         ("StripeCustomer does not exist for {email}." | ||||||
|  |                          "Hence, creating a new StripeCustomer.").format( | ||||||
|  |                             email=user_email | ||||||
|  |                         ) | ||||||
|  |                     ) | ||||||
|  |                     customer = StripeCustomer.create_stripe_api_customer( | ||||||
|  |                         email=user_email, | ||||||
|  |                         token=token, | ||||||
|  |                         customer_name=user_name) | ||||||
|  | 
 | ||||||
|             request.session['billing_address_data'] = form.cleaned_data |             request.session['billing_address_data'] = form.cleaned_data | ||||||
|             request.session['user'] = this_user |             request.session['user'] = this_user | ||||||
|             # Get or create stripe customer |             # Get or create stripe customer | ||||||
|  | @ -395,8 +426,10 @@ class PaymentOrderView(FormView): | ||||||
|                 return self.render_to_response( |                 return self.render_to_response( | ||||||
|                     self.get_context_data(form=form)) |                     self.get_context_data(form=form)) | ||||||
|             request.session['token'] = token |             request.session['token'] = token | ||||||
|             request.session[ |             if type(customer) is StripeCustomer: | ||||||
|                 'customer'] = customer.id if request.user.is_authenticated() else customer |                 request.session['customer'] = customer.stripe_id | ||||||
|  |             else: | ||||||
|  |                 request.session['customer'] = customer | ||||||
|             return HttpResponseRedirect( |             return HttpResponseRedirect( | ||||||
|                 reverse('datacenterlight:order_confirmation')) |                 reverse('datacenterlight:order_confirmation')) | ||||||
|         else: |         else: | ||||||
|  | @ -415,14 +448,7 @@ class OrderConfirmationView(DetailView): | ||||||
|             return HttpResponseRedirect(reverse('datacenterlight:index')) |             return HttpResponseRedirect(reverse('datacenterlight:index')) | ||||||
|         if 'token' not in request.session: |         if 'token' not in request.session: | ||||||
|             return HttpResponseRedirect(reverse('datacenterlight:payment')) |             return HttpResponseRedirect(reverse('datacenterlight:payment')) | ||||||
|         stripe_customer_id = request.session.get('customer') |         stripe_api_cus_id = request.session.get('customer') | ||||||
|         if request.user.is_authenticated(): |  | ||||||
|             customer = StripeCustomer.objects.filter( |  | ||||||
|                 id=stripe_customer_id).first() |  | ||||||
|             stripe_api_cus_id = customer.stripe_id |  | ||||||
|         else: |  | ||||||
|             stripe_api_cus_id = stripe_customer_id |  | ||||||
| 
 |  | ||||||
|         stripe_utils = StripeUtils() |         stripe_utils = StripeUtils() | ||||||
|         card_details = stripe_utils.get_card_details(stripe_api_cus_id, |         card_details = stripe_utils.get_card_details(stripe_api_cus_id, | ||||||
|                                                      request.session.get( |                                                      request.session.get( | ||||||
|  | @ -437,6 +463,8 @@ class OrderConfirmationView(DetailView): | ||||||
|             'site_url': reverse('datacenterlight:index'), |             'site_url': reverse('datacenterlight:index'), | ||||||
|             'cc_last4': card_details.get('response_object').get('last4'), |             'cc_last4': card_details.get('response_object').get('last4'), | ||||||
|             'cc_brand': card_details.get('response_object').get('brand'), |             'cc_brand': card_details.get('response_object').get('brand'), | ||||||
|  |             'vm': request.session.get('specs'), | ||||||
|  |             'page_header_text': _('Confirm Order'), | ||||||
|             'billing_address_data': request.session.get('billing_address_data') |             'billing_address_data': request.session.get('billing_address_data') | ||||||
|         } |         } | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
|  | @ -445,15 +473,8 @@ class OrderConfirmationView(DetailView): | ||||||
|         template = request.session.get('template') |         template = request.session.get('template') | ||||||
|         specs = request.session.get('specs') |         specs = request.session.get('specs') | ||||||
|         user = request.session.get('user') |         user = request.session.get('user') | ||||||
|         stripe_customer_id = request.session.get('customer') |         stripe_api_cus_id = request.session.get('customer') | ||||||
|         if request.user.is_authenticated(): |  | ||||||
|             customer = StripeCustomer.objects.filter( |  | ||||||
|                 id=stripe_customer_id).first() |  | ||||||
|             stripe_api_cus_id = customer.stripe_id |  | ||||||
|         else: |  | ||||||
|             stripe_api_cus_id = stripe_customer_id |  | ||||||
|         vm_template_id = template.get('id', 1) |         vm_template_id = template.get('id', 1) | ||||||
| 
 |  | ||||||
|         stripe_utils = StripeUtils() |         stripe_utils = StripeUtils() | ||||||
|         card_details = stripe_utils.get_card_details(stripe_api_cus_id, |         card_details = stripe_utils.get_card_details(stripe_api_cus_id, | ||||||
|                                                      request.session.get( |                                                      request.session.get( | ||||||
|  | @ -498,8 +519,8 @@ class OrderConfirmationView(DetailView): | ||||||
|                 'response_object').stripe_plan_id}]) |                 'response_object').stripe_plan_id}]) | ||||||
|         stripe_subscription_obj = subscription_result.get('response_object') |         stripe_subscription_obj = subscription_result.get('response_object') | ||||||
|         # Check if the subscription was approved and is active |         # Check if the subscription was approved and is active | ||||||
|         if stripe_subscription_obj is None or \ |         if (stripe_subscription_obj is None | ||||||
|                 stripe_subscription_obj.status != 'active': |                 or stripe_subscription_obj.status != 'active'): | ||||||
|             msg = subscription_result.get('error') |             msg = subscription_result.get('error') | ||||||
|             messages.add_message(self.request, messages.ERROR, msg, |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|                                  extra_tags='failed_payment') |                                  extra_tags='failed_payment') | ||||||
|  | @ -546,10 +567,10 @@ class OrderConfirmationView(DetailView): | ||||||
|                                         password=password) |                                         password=password) | ||||||
|                 login(request, new_user) |                 login(request, new_user) | ||||||
|         else: |         else: | ||||||
|             customer = StripeCustomer.objects.filter( |             # We assume that if the user is here, his/her StripeCustomer | ||||||
|                 id=stripe_customer_id).first() |             # object already exists | ||||||
|             custom_user = customer.user |             stripe_customer_id = request.user.stripecustomer.id | ||||||
|             stripe_customer_id = customer.id |             custom_user = request.user | ||||||
| 
 | 
 | ||||||
|         # Save billing address |         # Save billing address | ||||||
|         billing_address_data = request.session.get('billing_address_data') |         billing_address_data = request.session.get('billing_address_data') | ||||||
|  | @ -557,12 +578,6 @@ class OrderConfirmationView(DetailView): | ||||||
|         billing_address_data.update({ |         billing_address_data.update({ | ||||||
|             'user': custom_user.id |             'user': custom_user.id | ||||||
|         }) |         }) | ||||||
|         billing_address_user_form = UserBillingAddressForm( |  | ||||||
|             instance=custom_user.billing_addresses.first(), |  | ||||||
|             data=billing_address_data) |  | ||||||
|         billing_address = billing_address_user_form.save() |  | ||||||
|         billing_address_id = billing_address.id |  | ||||||
|         logger.debug("billing address id = {}".format(billing_address_id)) |  | ||||||
|         user = { |         user = { | ||||||
|             'name': custom_user.name, |             'name': custom_user.name, | ||||||
|             'email': custom_user.email, |             'email': custom_user.email, | ||||||
|  | @ -574,8 +589,7 @@ class OrderConfirmationView(DetailView): | ||||||
| 
 | 
 | ||||||
|         create_vm_task.delay(vm_template_id, user, specs, template, |         create_vm_task.delay(vm_template_id, user, specs, template, | ||||||
|                              stripe_customer_id, billing_address_data, |                              stripe_customer_id, billing_address_data, | ||||||
|                              billing_address_id, |                              stripe_subscription_obj.id, card_details_dict) | ||||||
|                              stripe_subscription_obj, card_details_dict) |  | ||||||
|         for session_var in ['specs', 'template', 'billing_address', |         for session_var in ['specs', 'template', 'billing_address', | ||||||
|                             'billing_address_data', |                             'billing_address_data', | ||||||
|                             'token', 'customer']: |                             'token', 'customer']: | ||||||
|  |  | ||||||
|  | @ -161,6 +161,8 @@ MIDDLEWARE_CLASSES = ( | ||||||
|     'cms.middleware.language.LanguageCookieMiddleware', |     'cms.middleware.language.LanguageCookieMiddleware', | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | CSRF_FAILURE_VIEW = 'hosting.views.forbidden_view' | ||||||
|  | 
 | ||||||
| ROOT_URLCONF = 'dynamicweb.urls' | ROOT_URLCONF = 'dynamicweb.urls' | ||||||
| 
 | 
 | ||||||
| TEMPLATES = [ | TEMPLATES = [ | ||||||
|  |  | ||||||
|  | @ -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-24 12:34+0000\n" | "POT-Creation-Date: 2017-10-01 22:12+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" | ||||||
|  | @ -331,12 +331,15 @@ msgstr "Alle Benachrichtigungen" | ||||||
| msgid "%(page_header_text)s" | msgid "%(page_header_text)s" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Invoice Date" | msgid "Date" | ||||||
| msgstr "Rechnung Datum" | msgstr "Datum" | ||||||
| 
 | 
 | ||||||
| msgid "Status" | msgid "Status" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  | msgid "Terminated" | ||||||
|  | msgstr "Beendet" | ||||||
|  | 
 | ||||||
| msgid "Approved" | msgid "Approved" | ||||||
| msgstr "Akzeptiert" | msgstr "Akzeptiert" | ||||||
| 
 | 
 | ||||||
|  | @ -352,12 +355,18 @@ msgstr "Bezahlmethode" | ||||||
| msgid "ending in" | msgid "ending in" | ||||||
| msgstr "endend in" | msgstr "endend in" | ||||||
| 
 | 
 | ||||||
|  | msgid "Credit Card" | ||||||
|  | msgstr "Kreditkarte" | ||||||
|  | 
 | ||||||
| msgid "Order summary" | msgid "Order summary" | ||||||
| msgstr "Bestellungsübersicht" | msgstr "Bestellungsübersicht" | ||||||
| 
 | 
 | ||||||
| msgid "Product" | msgid "Product" | ||||||
| msgstr "Produkt" | msgstr "Produkt" | ||||||
| 
 | 
 | ||||||
|  | msgid "Period" | ||||||
|  | msgstr "Periode" | ||||||
|  | 
 | ||||||
| msgid "Cores" | msgid "Cores" | ||||||
| msgstr "Prozessorkerne" | msgstr "Prozessorkerne" | ||||||
| 
 | 
 | ||||||
|  | @ -390,15 +399,18 @@ msgstr "Abarbeitung..." | ||||||
| msgid "Hold tight, we are processing your request" | msgid "Hold tight, we are processing your request" | ||||||
| msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade" | msgstr "Bitte warten - wir bearbeiten Deine Anfrage gerade" | ||||||
| 
 | 
 | ||||||
|  | msgid "OK" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "Close" | ||||||
|  | msgstr "Schliessen" | ||||||
|  | 
 | ||||||
| msgid "Some problem encountered. Please try again later." | msgid "Some problem encountered. Please try again later." | ||||||
| msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." | msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal." | ||||||
| 
 | 
 | ||||||
| msgid "Order Nr." | msgid "Order Nr." | ||||||
| msgstr "Bestellung Nr." | msgstr "Bestellung Nr." | ||||||
| 
 | 
 | ||||||
| msgid "Date" |  | ||||||
| msgstr "Datum" |  | ||||||
| 
 |  | ||||||
| msgid "Amount" | msgid "Amount" | ||||||
| msgstr "Betrag" | msgstr "Betrag" | ||||||
| 
 | 
 | ||||||
|  | @ -423,9 +435,6 @@ msgstr "inkl. Mehrwertsteuer" | ||||||
| msgid "Billing Address" | msgid "Billing Address" | ||||||
| msgstr "Rechnungsadresse" | msgstr "Rechnungsadresse" | ||||||
| 
 | 
 | ||||||
| msgid "Credit Card" |  | ||||||
| msgstr "Kreditkarte" |  | ||||||
| 
 |  | ||||||
| msgid "" | msgid "" | ||||||
| "\n" | "\n" | ||||||
| "                                Please fill in your credit card information " | "                                Please fill in your credit card information " | ||||||
|  | @ -599,16 +608,13 @@ msgstr "Deine Virtuelle Maschine beenden" | ||||||
| msgid "Do you want to cancel your Virtual Machine" | msgid "Do you want to cancel your Virtual Machine" | ||||||
| msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst" | msgstr "Bist Du sicher, dass Du Deine virtuelle Maschine beenden willst" | ||||||
| 
 | 
 | ||||||
| msgid "OK" |  | ||||||
| msgstr "" |  | ||||||
| 
 |  | ||||||
| #, python-format | #, python-format | ||||||
| msgid "" | msgid "" | ||||||
| "Your Virtual Machine <strong>%(machine_name)s</strong> is successfully " | "Your Virtual Machine <strong>%(machine_name)s</strong> is successfully " | ||||||
| "terminated!" | "terminated!" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde erfolgreich " | "Deine Virtuelle Machine (VM) <strong>%(machine_name)s</strong> wurde " | ||||||
| "beendet!" | "erfolgreich beendet!" | ||||||
| 
 | 
 | ||||||
| msgid "Virtual Machines" | msgid "Virtual Machines" | ||||||
| msgstr "Virtuelle Maschinen" | msgstr "Virtuelle Maschinen" | ||||||
|  | @ -616,6 +622,13 @@ msgstr "Virtuelle Maschinen" | ||||||
| msgid "To create a new virtual machine, click \"Create VM\"" | msgid "To create a new virtual machine, click \"Create VM\"" | ||||||
| msgstr "Um eine neue VM zu erzeugen, klicke \"Neue VM erzeugen\"" | msgstr "Um eine neue VM zu erzeugen, klicke \"Neue VM erzeugen\"" | ||||||
| 
 | 
 | ||||||
|  | #, python-format | ||||||
|  | msgid "" | ||||||
|  | "To access your VM, <a href=\"%(create_ssh_url)s\">add your SSH key here</a>" | ||||||
|  | msgstr "" | ||||||
|  | "Um auf Deine VM zuzugreifen, <a href=\"%(create_ssh_url)s\">füge Deinen SSH-" | ||||||
|  | "Key hinzu</a>" | ||||||
|  | 
 | ||||||
| msgid "CREATE VM" | msgid "CREATE VM" | ||||||
| msgstr "NEUE VM" | msgstr "NEUE VM" | ||||||
| 
 | 
 | ||||||
|  | @ -673,6 +686,16 @@ msgid "In order to create a VM, you need to create/upload your SSH KEY first." | ||||||
| msgstr "" | msgstr "" | ||||||
| "Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen." | "Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen." | ||||||
| 
 | 
 | ||||||
|  | msgid "Error." | ||||||
|  | msgstr "Fehler" | ||||||
|  | 
 | ||||||
|  | msgid "" | ||||||
|  | "There was a payment related error. On close of this popup, you will be " | ||||||
|  | "redirected back to the payment page." | ||||||
|  | msgstr "" | ||||||
|  | "Es ist ein Fehler bei der Zahlung betreten. Du wirst nach dem Schliessen vom " | ||||||
|  | "Popup zur Bezahlseite weitergeleitet" | ||||||
|  | 
 | ||||||
| msgid "Thank you for the order." | msgid "Thank you for the order." | ||||||
| msgstr "Danke für Deine Bestellung." | msgstr "Danke für Deine Bestellung." | ||||||
| 
 | 
 | ||||||
|  | @ -697,8 +720,11 @@ msgid "" | ||||||
| "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" | msgid "" | ||||||
| msgstr "Beendet" | "We could not find the requested VM. Please contact Data Center Light Support." | ||||||
|  | msgstr "" | ||||||
|  | "Wir konnten die gesucht VM nicht finden. Kontaktiere den Data Center Light " | ||||||
|  | "Support." | ||||||
| 
 | 
 | ||||||
| msgid "Error terminating VM" | msgid "Error terminating VM" | ||||||
| msgstr "Fehler beenden VM" | msgstr "Fehler beenden VM" | ||||||
|  | @ -706,8 +732,13 @@ msgstr "Fehler beenden VM" | ||||||
| msgid "Virtual Machine Cancellation" | msgid "Virtual Machine Cancellation" | ||||||
| msgstr "VM Kündigung" | msgstr "VM Kündigung" | ||||||
| 
 | 
 | ||||||
| #~ msgid "Close" | msgid "There was an error processing your request. Please try again." | ||||||
| #~ msgstr "Schliessen" | msgstr "" | ||||||
|  | "Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte versuche es " | ||||||
|  | "noch einmal." | ||||||
|  | 
 | ||||||
|  | #~ msgid "Invoice Date" | ||||||
|  | #~ msgstr "Rechnung Datum" | ||||||
| 
 | 
 | ||||||
| #~ msgid "VM %(VM_ID)s terminated successfully" | #~ msgid "VM %(VM_ID)s terminated successfully" | ||||||
| #~ msgstr "VM %(VM_ID)s erfolgreich beendet" | #~ msgstr "VM %(VM_ID)s erfolgreich beendet" | ||||||
|  | @ -842,5 +873,5 @@ msgstr "VM Kündigung" | ||||||
| #~ "Your SSH private key was already generated and downloaded, if you lost " | #~ "Your SSH private key was already generated and downloaded, if you lost " | ||||||
| #~ "it, contact us. " | #~ "it, contact us. " | ||||||
| #~ msgstr "" | #~ msgstr "" | ||||||
| #~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. " | #~ "Dein privater SSH Key wurde bereits generiert und heruntergeladen. Falls " | ||||||
| #~ "Falls Du ihn verloren hast, kontaktiere uns." | #~ "Du ihn verloren hast, kontaktiere uns." | ||||||
|  |  | ||||||
|  | @ -90,19 +90,19 @@ class HostingOrder(AssignPermissionsMixin, models.Model): | ||||||
|         self.cc_brand = stripe_charge.source.brand |         self.cc_brand = stripe_charge.source.brand | ||||||
|         self.save() |         self.save() | ||||||
| 
 | 
 | ||||||
|     def set_subscription_id(self, subscription_object, cc_details): |     def set_subscription_id(self, subscription_id, cc_details): | ||||||
|         """ |         """ | ||||||
|         When creating a Stripe subscription, we have subscription id. |         When creating a Stripe subscription, we have subscription id. | ||||||
|         We store this in the subscription_id field. |         We store this in the subscription_id field. | ||||||
|         This method sets the subscription id from subscription_object |         This method sets the subscription id | ||||||
|         and also the last4 and credit card brands used for this order. |         and the last4 and credit card brands used for this order. | ||||||
| 
 | 
 | ||||||
|         :param subscription_object: Stripe's subscription object |         :param subscription_id: Stripe's subscription id | ||||||
|         :param cc_details: A dict containing card details |         :param cc_details: A dict containing card details | ||||||
|         {last4, brand} |         {last4, brand} | ||||||
|         :return: |         :return: | ||||||
|         """ |         """ | ||||||
|         self.subscription_id = subscription_object.id |         self.subscription_id = subscription_id | ||||||
|         self.last4 = cc_details.get('last4') |         self.last4 = cc_details.get('last4') | ||||||
|         self.cc_brand = cc_details.get('brand') |         self.cc_brand = cc_details.get('brand') | ||||||
|         self.save() |         self.save() | ||||||
|  |  | ||||||
|  | @ -86,23 +86,31 @@ $(document).ready(function() { | ||||||
|             url: create_vm_form.attr('action'), |             url: create_vm_form.attr('action'), | ||||||
|             type: 'POST', |             type: 'POST', | ||||||
|             data: create_vm_form.serialize(), |             data: create_vm_form.serialize(), | ||||||
|  |             init: function(){ | ||||||
|  |                 ok_btn = $('#createvm-modal-done-btn'); | ||||||
|  |                 close_btn = $('#createvm-modal-close-btn'); | ||||||
|  |                 ok_btn.addClass('btn btn-success btn-ok btn-wide hide'); | ||||||
|  |                 close_btn.addClass('btn btn-danger btn-ok btn-wide hide'); | ||||||
|  |             }, | ||||||
|             success: function (data) { |             success: function (data) { | ||||||
|  |                 fa_icon = $('.modal-icon > .fa'); | ||||||
|  |                 modal_btn = $('#createvm-modal-done-btn'); | ||||||
|  |                 $('#createvm-modal-title').text(data.msg_title); | ||||||
|  |                 $('#createvm-modal-body').html(data.msg_body); | ||||||
|  |                 modal_btn.attr('href', data.redirect) | ||||||
|  |                     .removeClass('hide'); | ||||||
|                 if (data.status === true) { |                 if (data.status === true) { | ||||||
|                     fa_icon = $('.modal-icon > .fa'); |  | ||||||
|                     fa_icon.attr('class', 'checkmark'); |                     fa_icon.attr('class', 'checkmark'); | ||||||
|                     // $('.modal-header > .close').removeClass('hidden');
 |                 } else { | ||||||
|                     $('#createvm-modal-title').text(data.msg_title); |                     fa_icon.attr('class', 'fa fa-close'); | ||||||
|                     $('#createvm-modal-body').text(data.msg_body); |                     modal_btn.attr('class', '').addClass('btn btn-danger btn-ok btn-wide'); | ||||||
|                     $('#createvm-modal-done-btn') |  | ||||||
|                         .attr('href', data.redirect) |  | ||||||
|                         .removeClass('hide'); |  | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             error: function (xmlhttprequest, textstatus, message) { |             error: function (xmlhttprequest, textstatus, message) { | ||||||
|                     fa_icon = $('.modal-icon > .fa'); |                     fa_icon = $('.modal-icon > .fa'); | ||||||
|                     fa_icon.attr('class', 'fa fa-close'); |                     fa_icon.attr('class', 'fa fa-close'); | ||||||
|                     if (typeof(create_vm_error_message) !== 'undefined') { |                     if (typeof(create_vm_error_message) !== 'undefined') { | ||||||
|                         $('#createvm-modal-text').text(create_vm_error_message); |                         $('#createvm-modal-body').text(create_vm_error_message); | ||||||
|                     } |                     } | ||||||
|                     $('#btn-create-vm').prop('disabled', false); |                     $('#btn-create-vm').prop('disabled', false); | ||||||
|                     $('#createvm-modal-close-btn').removeClass('hide'); |                     $('#createvm-modal-close-btn').removeClass('hide'); | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								hosting/templates/hosting/includes/_messages.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								hosting/templates/hosting/includes/_messages.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | ||||||
|  | {% if messages %} | ||||||
|  |     <ul class="list-unstyled msg-list"> | ||||||
|  |     {% for message in messages %} | ||||||
|  |         <div | ||||||
|  |                 class="alert {% if message.tags and message.tags == 'error' %} alert-danger {% else %} alert-{{message.tags}} {% endif %}">{{ message|safe }}</div> | ||||||
|  |     {% endfor %} | ||||||
|  |     </ul> | ||||||
|  | {% endif %} | ||||||
|  | @ -16,13 +16,7 @@ | ||||||
|         <div class="auth-content"> |         <div class="auth-content"> | ||||||
|             <div class="intro-message auth-box"> |             <div class="intro-message auth-box"> | ||||||
|                 <h2 class="section-heading">{% trans "Login"%}</h2> |                 <h2 class="section-heading">{% trans "Login"%}</h2> | ||||||
|                 {% if messages %} |                 {% include  'hosting/includes/_messages.html' %} | ||||||
|                     <ul class="list-unstyled msg-list"> |  | ||||||
|                     {% for message in messages %} |  | ||||||
|                         <li>{{ message }}</li> |  | ||||||
|                     {% endfor %} |  | ||||||
|                     </ul> |  | ||||||
|                 {% endif %} |  | ||||||
|                 <form action="{% url 'hosting:login' %}" method="post" class="form" novalidated> |                 <form action="{% url 'hosting:login' %}" method="post" class="form" novalidated> | ||||||
|                     {% csrf_token %} |                     {% csrf_token %} | ||||||
|                     {% for field in form %} |                     {% for field in form %} | ||||||
|  |  | ||||||
|  | @ -17,10 +17,12 @@ | ||||||
|             <h1 class="dashboard-title-thin"> |             <h1 class="dashboard-title-thin"> | ||||||
|                 <img src="{% static 'hosting/img/billing.svg' %}" class="un-icon">{% blocktrans with page_header_text=page_header_text|default:"Invoice" %}{{page_header_text}}{% endblocktrans %} |                 <img src="{% static 'hosting/img/billing.svg' %}" class="un-icon">{% blocktrans with page_header_text=page_header_text|default:"Invoice" %}{{page_header_text}}{% endblocktrans %} | ||||||
|             </h1> |             </h1> | ||||||
|             <div class="dashboard-container-options"> |             {% if order %} | ||||||
|                 <button type="button" class="btn-plain btn-pdf" data-target="#order-detail{{order.pk}}"><img src="{% static 'hosting/img/icon-pdf.svg' %}" class="svg-img"></button> |                 <div class="dashboard-container-options"> | ||||||
|                 <button type="button" class="btn-plain btn-print"><img src="{% static 'hosting/img/icon-print.svg' %}" class="svg-img"></button> |                     <button type="button" class="btn-plain btn-pdf" data-target="#order-detail{{order.pk}}"><img src="{% static 'hosting/img/icon-pdf.svg' %}" class="svg-img"></button> | ||||||
|             </div> |                     <button type="button" class="btn-plain btn-print"><img src="{% static 'hosting/img/icon-print.svg' %}" class="svg-img"></button> | ||||||
|  |                 </div> | ||||||
|  |             {% endif %} | ||||||
|         </div> |         </div> | ||||||
|         <div class="order-details"> |         <div class="order-details"> | ||||||
|             {% if order %} |             {% if order %} | ||||||
|  | @ -29,7 +31,7 @@ | ||||||
|                 </p> |                 </p> | ||||||
|             {% endif %} |             {% endif %} | ||||||
|             <p> |             <p> | ||||||
|                 <strong>{% trans "Invoice Date" %}:</strong> |                 <strong>{% trans "Date" %}:</strong> | ||||||
|                 <span id="order-created_at"> |                 <span id="order-created_at"> | ||||||
|                     {% if order %} |                     {% if order %} | ||||||
|                         {{order.created_at|date:'Y-m-d H:i'}} |                         {{order.created_at|date:'Y-m-d H:i'}} | ||||||
|  | @ -80,8 +82,7 @@ | ||||||
|                         {{order.last4}}<br> |                         {{order.last4}}<br> | ||||||
|                         {{user.email}} |                         {{user.email}} | ||||||
|                     {% else %} |                     {% else %} | ||||||
|                         {{cc_brand|default:'Card'}} {% trans "ending in" %} **** |                         {{cc_brand|default:_('Credit Card')}} {% trans "ending in" %} ****{{cc_last4}}<br> | ||||||
|                         {{cc_last4}}<br> |  | ||||||
|                         {% if request.user.is_authenticated %} |                         {% if request.user.is_authenticated %} | ||||||
|                             {{request.user.email}} |                             {{request.user.email}} | ||||||
|                         {% else %} |                         {% else %} | ||||||
|  | @ -94,7 +95,12 @@ | ||||||
|             <div> |             <div> | ||||||
|                 <h4>{% trans "Order summary" %}</h4> |                 <h4>{% trans "Order summary" %}</h4> | ||||||
|                 <p> |                 <p> | ||||||
|                     <strong>{% trans "Product" %}:</strong> {{vm.name}} |                     <strong>{% trans "Product" %}:</strong>  | ||||||
|  |                     {% if vm.name %} | ||||||
|  |                         {{ vm.name }} | ||||||
|  |                     {% else %} | ||||||
|  |                         {{ request.session.template.name }} | ||||||
|  |                     {% endif %} | ||||||
|                 </p> |                 </p> | ||||||
|                 <div class="row"> |                 <div class="row"> | ||||||
|                     <div class="col-sm-6"> |                     <div class="col-sm-6"> | ||||||
|  | @ -132,19 +138,21 @@ | ||||||
|             {% endif %} |             {% endif %} | ||||||
|         </div> |         </div> | ||||||
|         {% if not order %} |         {% if not order %} | ||||||
|             <form method="post" id="virtual_machine_create_form"> |             {% block submit_btn %} | ||||||
|                 {% csrf_token %} |                 <form method="post" id="virtual_machine_create_form"> | ||||||
|                 <div class="row"> |                     {% csrf_token %} | ||||||
|                     <div class="col-sm-8"> |                     <div class="row"> | ||||||
|                         <div 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 %}.</div> |                         <div class="col-sm-8"> | ||||||
|  |                             <div 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 %}.</div> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="col-sm-4 order-confirm-btn text-right"> | ||||||
|  |                             <button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal"> | ||||||
|  |                                 {% trans "Place order" %} | ||||||
|  |                             </button> | ||||||
|  |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="col-sm-4 order-confirm-btn text-right"> |                 </form> | ||||||
|                         <button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal"> |             {% endblock submit_btn %} | ||||||
|                             {% trans "Place order" %} |  | ||||||
|                         </button> |  | ||||||
|                     </div> |  | ||||||
|                 </div> |  | ||||||
|             </form> |  | ||||||
|         {% endif %} |         {% endif %} | ||||||
|     {% endif %} |     {% endif %} | ||||||
| </div> | </div> | ||||||
|  | @ -197,8 +205,10 @@ | ||||||
| {%endblock%} | {%endblock%} | ||||||
| 
 | 
 | ||||||
| {% block js_extra %} | {% block js_extra %} | ||||||
|     <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script> |     {% if order %} | ||||||
|     <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script> |         <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script> | ||||||
|     <script src="{% static 'hosting/js/html2pdf.js' %}"></script> |         <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script> | ||||||
|     <script src="{% static 'hosting/js/order.js' %}"></script> |         <script src="{% static 'hosting/js/html2pdf.js' %}"></script> | ||||||
|  |         <script src="{% static 'hosting/js/order.js' %}"></script> | ||||||
|  |     {% endif %} | ||||||
| {% endblock js_extra %} | {% endblock js_extra %} | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
|             <div class="auth-content"> |             <div class="auth-content"> | ||||||
|                 <div class="intro-message auth-box sign-up"> |                 <div class="intro-message auth-box sign-up"> | ||||||
|                     <h2  class="section-heading">{% trans "Resend activation link"%}</h2> |                     <h2  class="section-heading">{% trans "Resend activation link"%}</h2> | ||||||
|  |                     {% include  'hosting/includes/_messages.html' %} | ||||||
|                     <form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate> |                     <form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate> | ||||||
|                         {% csrf_token %} |                         {% csrf_token %} | ||||||
|                         {% for field in form %} |                         {% for field in form %} | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
|             <div class="auth-content"> |             <div class="auth-content"> | ||||||
|                 <div class="intro-message auth-box sign-up"> |                 <div class="intro-message auth-box sign-up"> | ||||||
|                     <h2  class="section-heading">{% trans "Reset your password"%}</h2> |                     <h2  class="section-heading">{% trans "Reset your password"%}</h2> | ||||||
|  |                     {% include  'hosting/includes/_messages.html' %} | ||||||
|                     <form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate> |                     <form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate> | ||||||
|                         {% csrf_token %} |                         {% csrf_token %} | ||||||
|                         {% for field in form %} |                         {% for field in form %} | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ | ||||||
|         <div class="auth-content"> |         <div class="auth-content"> | ||||||
|             <div class="intro-message auth-box sign-up"> |             <div class="intro-message auth-box sign-up"> | ||||||
|                 <h2  class="section-heading">{% trans "Sign up"%}</h2> |                 <h2  class="section-heading">{% trans "Sign up"%}</h2> | ||||||
|  |                 {% include  'hosting/includes/_messages.html' %} | ||||||
|                 <form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate> |                 <form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate> | ||||||
|                     {% csrf_token %} |                     {% csrf_token %} | ||||||
|                     {% for field in form %} |                     {% for field in form %} | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
|     <div class="auth-center"> |     <div class="auth-center"> | ||||||
|             <div class="auth-title"> |             <div class="auth-title"> | ||||||
|                 <h2>{% trans "Your VM hosted in Switzerland"%}</h2> |                 <h2>{% trans "Your VM hosted in Switzerland"%}</h2> | ||||||
|  |                 {% include  'hosting/includes/_messages.html' %} | ||||||
|             </div> |             </div> | ||||||
|             <div class="auth-content"> |             <div class="auth-content"> | ||||||
|                 <div class="intro-message auth-box sign-up"> |                 <div class="intro-message auth-box sign-up"> | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
|                 <p>{% trans 'To create a new virtual machine, click "Create VM"' %} |                 <p>{% trans 'To create a new virtual machine, click "Create VM"' %} | ||||||
|                 {% if show_create_ssh_key_msg %} |                 {% if show_create_ssh_key_msg %} | ||||||
|                      {% url 'hosting:create_ssh_key' as create_ssh_url %} |                      {% url 'hosting:create_ssh_key' as create_ssh_url %} | ||||||
|                      <br/>{% blocktrans %}To access your VM, add your SSH key <a href="{{create_ssh_url}}">here</a>{% endblocktrans %} |                      <br/>{% blocktrans %}To access your VM, <a href="{{create_ssh_url}}">add your SSH key here</a>{% endblocktrans %} | ||||||
|                 {% endif %} |                 {% endif %} | ||||||
|                 </p> |                 </p> | ||||||
|                 <div class="text-right"> |                 <div class="text-right"> | ||||||
|  |  | ||||||
|  | @ -60,8 +60,9 @@ CONNECTION_ERROR = "Your VMs cannot be displayed at the moment due to a \ | ||||||
|                     minutes." |                     minutes." | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class DashboardView(View): | class DashboardView(LoginRequiredMixin, View): | ||||||
|     template_name = "hosting/dashboard.html" |     template_name = "hosting/dashboard.html" | ||||||
|  |     login_url = reverse_lazy('hosting:login') | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = {} |         context = {} | ||||||
|  | @ -80,8 +81,6 @@ class DjangoHostingView(ProcessVMSelectionMixin, View): | ||||||
|         templates = OpenNebulaManager().get_templates() |         templates = OpenNebulaManager().get_templates() | ||||||
|         data = VirtualMachineTemplateSerializer(templates, many=True).data |         data = VirtualMachineTemplateSerializer(templates, many=True).data | ||||||
|         configuration_options = HostingPlan.get_serialized_configs() |         configuration_options = HostingPlan.get_serialized_configs() | ||||||
| 
 |  | ||||||
|         # configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) |  | ||||||
|         context = { |         context = { | ||||||
|             'hosting': HOSTING, |             'hosting': HOSTING, | ||||||
|             'hosting_long': "Django", |             'hosting_long': "Django", | ||||||
|  | @ -134,7 +133,6 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View): | ||||||
| 
 | 
 | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         HOSTING = 'nodejs' |         HOSTING = 'nodejs' | ||||||
|         # configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) |  | ||||||
|         templates = OpenNebulaManager().get_templates() |         templates = OpenNebulaManager().get_templates() | ||||||
|         configuration_options = HostingPlan.get_serialized_configs() |         configuration_options = HostingPlan.get_serialized_configs() | ||||||
| 
 | 
 | ||||||
|  | @ -249,7 +247,8 @@ class SignupValidateView(TemplateView): | ||||||
|                  <br />{go_back} {hurl}.'.format( |                  <br />{go_back} {hurl}.'.format( | ||||||
|             signup_success_message=_( |             signup_success_message=_( | ||||||
|                 'Thank you for signing up. We have sent an email to you. ' |                 'Thank you for signing up. We have sent an email to you. ' | ||||||
|                 'Please follow the instructions in it to activate your account. Once activated, you can login using'), |                 'Please follow the instructions in it to activate your ' | ||||||
|  |                 'account. Once activated, you can login using'), | ||||||
|             go_back=_('Go back to'), |             go_back=_('Go back to'), | ||||||
|             lurl=login_url, |             lurl=login_url, | ||||||
|             hurl=home_url |             hurl=home_url | ||||||
|  | @ -269,7 +268,8 @@ class SignupValidatedView(SignupValidateView): | ||||||
|                     reverse('hosting:login') + '">' + str(_('login')) + '</a>' |                     reverse('hosting:login') + '">' + str(_('login')) + '</a>' | ||||||
|         section_title = _('Account activation') |         section_title = _('Account activation') | ||||||
|         if validated: |         if validated: | ||||||
|             message = '{account_activation_string} <br /> {login_string} {lurl}.'.format( |             message = ('{account_activation_string} <br />' | ||||||
|  |                        ' {login_string} {lurl}.').format( | ||||||
|                 account_activation_string=_( |                 account_activation_string=_( | ||||||
|                     "Your account has been activated."), |                     "Your account has been activated."), | ||||||
|                 login_string=_("You can now"), |                 login_string=_("You can now"), | ||||||
|  | @ -636,10 +636,7 @@ class PaymentVMView(LoginRequiredMixin, FormView): | ||||||
|                 return HttpResponseRedirect( |                 return HttpResponseRedirect( | ||||||
|                     reverse('hosting:payment') + '#payment_error') |                     reverse('hosting:payment') + '#payment_error') | ||||||
| 
 | 
 | ||||||
|             # Create Billing Address |  | ||||||
|             billing_address = form.save() |  | ||||||
|             request.session['billing_address_data'] = billing_address_data |             request.session['billing_address_data'] = billing_address_data | ||||||
|             request.session['billing_address'] = billing_address.id |  | ||||||
|             request.session['token'] = token |             request.session['token'] = token | ||||||
|             request.session['customer'] = customer.id |             request.session['customer'] = customer.id | ||||||
|             return HttpResponseRedirect("{url}?{query_params}".format( |             return HttpResponseRedirect("{url}?{query_params}".format( | ||||||
|  | @ -687,10 +684,12 @@ class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|             try: |             try: | ||||||
|                 vm_detail = VMDetail.objects.get(vm_id=obj.vm_id) |                 vm_detail = VMDetail.objects.get(vm_id=obj.vm_id) | ||||||
|                 context['vm'] = vm_detail.__dict__ |                 context['vm'] = vm_detail.__dict__ | ||||||
|                 context['vm']['name'] = ( |                 context['vm']['name'] = '{}-{}'.format( | ||||||
|                     '{}-{}'.format( |                     context['vm']['configuration'], context['vm']['vm_id']) | ||||||
|                         context['vm']['configuration'], context['vm']['vm_id'] |                 context['vm']['price'] = get_vm_price( | ||||||
|                     ) |                     cpu=context['vm']['cores'], | ||||||
|  |                     disk_size=context['vm']['disk_size'], | ||||||
|  |                     memory=context['vm']['memory'] | ||||||
|                 ) |                 ) | ||||||
|                 context['subscription_end_date'] = vm_detail.end_date() |                 context['subscription_end_date'] = vm_detail.end_date() | ||||||
|             except VMDetail.DoesNotExist: |             except VMDetail.DoesNotExist: | ||||||
|  | @ -755,7 +754,6 @@ class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|         stripe_customer_id = request.session.get('customer') |         stripe_customer_id = request.session.get('customer') | ||||||
|         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() |         customer = StripeCustomer.objects.filter(id=stripe_customer_id).first() | ||||||
|         billing_address_data = request.session.get('billing_address_data') |         billing_address_data = request.session.get('billing_address_data') | ||||||
|         billing_address_id = request.session.get('billing_address') |  | ||||||
|         vm_template_id = template.get('id', 1) |         vm_template_id = template.get('id', 1) | ||||||
| 
 | 
 | ||||||
|         # Make stripe charge to a customer |         # Make stripe charge to a customer | ||||||
|  | @ -773,8 +771,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|         cpu = specs.get('cpu') |         cpu = specs.get('cpu') | ||||||
|         memory = specs.get('memory') |         memory = specs.get('memory') | ||||||
|         disk_size = specs.get('disk_size') |         disk_size = specs.get('disk_size') | ||||||
|         amount_to_be_charged = get_vm_price(cpu=cpu, memory=memory, |         amount_to_be_charged = specs.get('price') | ||||||
|                                             disk_size=disk_size) |  | ||||||
|         plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, |         plan_name = StripeUtils.get_stripe_plan_name(cpu=cpu, | ||||||
|                                                      memory=memory, |                                                      memory=memory, | ||||||
|                                                      disk_size=disk_size) |                                                      disk_size=disk_size) | ||||||
|  | @ -793,12 +790,24 @@ class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|                 'response_object').stripe_plan_id}]) |                 'response_object').stripe_plan_id}]) | ||||||
|         stripe_subscription_obj = subscription_result.get('response_object') |         stripe_subscription_obj = subscription_result.get('response_object') | ||||||
|         # Check if the subscription was approved and is active |         # Check if the subscription was approved and is active | ||||||
|         if stripe_subscription_obj is None or stripe_subscription_obj.status != 'active': |         if (stripe_subscription_obj is None or | ||||||
|  |                 stripe_subscription_obj.status != 'active'): | ||||||
|             msg = subscription_result.get('error') |             msg = subscription_result.get('error') | ||||||
|             messages.add_message(self.request, messages.ERROR, msg, |             messages.add_message(self.request, messages.ERROR, msg, | ||||||
|                                  extra_tags='failed_payment') |                                  extra_tags='failed_payment') | ||||||
|             return HttpResponseRedirect( |             response = { | ||||||
|                 reverse('hosting:payment') + '#payment_error') |                 'status': False, | ||||||
|  |                 'redirect': "{url}#{section}".format( | ||||||
|  |                     url=reverse('hosting:payment'), | ||||||
|  |                     section='payment_error'), | ||||||
|  |                 'msg_title': str(_('Error.')), | ||||||
|  |                 'msg_body': str( | ||||||
|  |                     _('There was a payment related error.' | ||||||
|  |                       ' On close of this popup, you will be redirected back to' | ||||||
|  |                       ' the payment page.')) | ||||||
|  |             } | ||||||
|  |             return HttpResponse(json.dumps(response), | ||||||
|  |                                 content_type="application/json") | ||||||
|         user = { |         user = { | ||||||
|             'name': self.request.user.name, |             'name': self.request.user.name, | ||||||
|             'email': self.request.user.email, |             'email': self.request.user.email, | ||||||
|  | @ -809,8 +818,7 @@ class OrdersHostingDetailView(LoginRequiredMixin, | ||||||
|         } |         } | ||||||
|         create_vm_task.delay(vm_template_id, user, specs, template, |         create_vm_task.delay(vm_template_id, user, specs, template, | ||||||
|                              stripe_customer_id, billing_address_data, |                              stripe_customer_id, billing_address_data, | ||||||
|                              billing_address_id, |                              stripe_subscription_obj.id, card_details_dict) | ||||||
|                              stripe_subscription_obj, card_details_dict) |  | ||||||
| 
 | 
 | ||||||
|         for session_var in ['specs', 'template', 'billing_address', |         for session_var in ['specs', 'template', 'billing_address', | ||||||
|                             'billing_address_data', |                             'billing_address_data', | ||||||
|  | @ -1013,6 +1021,7 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|                 return redirect(reverse('hosting:virtual_machines')) |                 return redirect(reverse('hosting:virtual_machines')) | ||||||
|         elif self.request.is_ajax(): |         elif self.request.is_ajax(): | ||||||
|             return HttpResponse() |             return HttpResponse() | ||||||
|  |         context = None | ||||||
|         try: |         try: | ||||||
|             serializer = VirtualMachineSerializer(vm) |             serializer = VirtualMachineSerializer(vm) | ||||||
|             context = { |             context = { | ||||||
|  | @ -1022,7 +1031,11 @@ class VirtualMachineView(LoginRequiredMixin, View): | ||||||
|             } |             } | ||||||
|         except Exception as ex: |         except Exception as ex: | ||||||
|             logger.debug("Exception generated {}".format(str(ex))) |             logger.debug("Exception generated {}".format(str(ex))) | ||||||
|             pass |             messages.error(self.request, | ||||||
|  |                            _('We could not find the requested VM. Please ' | ||||||
|  |                              'contact Data Center Light Support.') | ||||||
|  |                            ) | ||||||
|  |             return redirect(reverse('hosting:virtual_machines')) | ||||||
| 
 | 
 | ||||||
|         return render(request, self.template_name, context) |         return render(request, self.template_name, context) | ||||||
| 
 | 
 | ||||||
|  | @ -1130,3 +1143,15 @@ class HostingBillDetailView(PermissionRequiredMixin, LoginRequiredMixin, | ||||||
|             bill.total_price += vm['price'] |             bill.total_price += vm['price'] | ||||||
|         context['vms'] = vms |         context['vms'] = vms | ||||||
|         return context |         return context | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def forbidden_view(request, exception=None, reason=''): | ||||||
|  |     """ | ||||||
|  |     Handle 403 error | ||||||
|  |     """ | ||||||
|  |     logger.error(str(exception) if exception else None) | ||||||
|  |     logger.error('Reason = {reason}'.format(reason=reason)) | ||||||
|  |     err_msg = _('There was an error processing your request. Please try ' | ||||||
|  |                 'again.') | ||||||
|  |     messages.add_message(request, messages.ERROR, err_msg) | ||||||
|  |     return HttpResponseRedirect(request.get_full_path()) | ||||||
|  |  | ||||||
|  | @ -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-25 20:11+0000\n" | "POT-Creation-Date: 2017-09-29 20:33+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" | ||||||
|  | @ -771,10 +771,13 @@ msgstr "" | ||||||
| msgid "Country" | msgid "Country" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Street Building" | msgid "Name" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Name" | msgid "Email Address" | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "Street Building" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Email" | msgid "Email" | ||||||
|  | @ -786,9 +789,9 @@ msgstr "Telefon" | ||||||
| msgid "Message" | msgid "Message" | ||||||
| msgstr "Nachricht" | msgstr "Nachricht" | ||||||
| 
 | 
 | ||||||
| msgid "An email with the activation link has been sent to your email" | msgid "An email with the activation link has been sent to you" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Der Link zum Zurücksetzen deines Passwortes wurde an deine E-Mail gesendet" | "Es wurde eine E-Mail mit dem Aktivierungslink an Dich gesendet." | ||||||
| 
 | 
 | ||||||
| msgid "Account Activation" | msgid "Account Activation" | ||||||
| msgstr "Accountaktivierung" | msgstr "Accountaktivierung" | ||||||
|  |  | ||||||
|  | @ -28,28 +28,34 @@ def handleStripeError(f): | ||||||
|             body = e.json_body |             body = e.json_body | ||||||
|             err = body['error'] |             err = body['error'] | ||||||
|             response.update({'error': err['message']}) |             response.update({'error': err['message']}) | ||||||
|  |             logger.error(str(e)) | ||||||
|             return response |             return response | ||||||
|         except stripe.error.RateLimitError as e: |         except stripe.error.RateLimitError as e: | ||||||
|             response.update( |             response.update( | ||||||
|                 {'error': "Too many requests made to the API too quickly"}) |                 {'error': "Too many requests made to the API too quickly"}) | ||||||
|             return response |             return response | ||||||
|         except stripe.error.InvalidRequestError as e: |         except stripe.error.InvalidRequestError as e: | ||||||
|  |             logger.error(str(e)) | ||||||
|             response.update({'error': "Invalid parameters"}) |             response.update({'error': "Invalid parameters"}) | ||||||
|             return response |             return response | ||||||
|         except stripe.error.AuthenticationError as e: |         except stripe.error.AuthenticationError as e: | ||||||
|             # Authentication with Stripe's API failed |             # Authentication with Stripe's API failed | ||||||
|             # (maybe you changed API keys recently) |             # (maybe you changed API keys recently) | ||||||
|  |             logger.error(str(e)) | ||||||
|             response.update({'error': common_message}) |             response.update({'error': common_message}) | ||||||
|             return response |             return response | ||||||
|         except stripe.error.APIConnectionError as e: |         except stripe.error.APIConnectionError as e: | ||||||
|  |             logger.error(str(e)) | ||||||
|             response.update({'error': common_message}) |             response.update({'error': common_message}) | ||||||
|             return response |             return response | ||||||
|         except stripe.error.StripeError as e: |         except stripe.error.StripeError as e: | ||||||
|             # maybe send email |             # maybe send email | ||||||
|  |             logger.error(str(e)) | ||||||
|             response.update({'error': common_message}) |             response.update({'error': common_message}) | ||||||
|             return response |             return response | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             # maybe send email |             # maybe send email | ||||||
|  |             logger.error(str(e)) | ||||||
|             response.update({'error': common_message}) |             response.update({'error': common_message}) | ||||||
|             return response |             return response | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -66,7 +66,7 @@ class LoginViewMixin(FormView): | ||||||
| 
 | 
 | ||||||
| class ResendActivationLinkViewMixin(FormView): | class ResendActivationLinkViewMixin(FormView): | ||||||
|     success_message = _( |     success_message = _( | ||||||
|         "An email with the activation link has been sent to your email") |         "An email with the activation link has been sent to you") | ||||||
| 
 | 
 | ||||||
|     def generate_email_context(self, user): |     def generate_email_context(self, user): | ||||||
|         context = { |         context = { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue