Merged master into whydcl

This commit is contained in:
Mondi Geetha 2017-07-03 23:03:51 +05:30
commit 36976d923e
21 changed files with 554 additions and 324 deletions

View file

@ -1,3 +1,11 @@
1.0.18: 2017-07-02
* [datacenterlight] Introduced the new flow. Landing page -> Payment -> Order confirmation -> Success
* [datacenterlight] Fixed issue showing local time to the user in order confirmation page, vm pages (like ssh keys)
* [hosting] Fixed responsive issue while user signup
* [hosting] Fixed 500 error when user requests for a vm whose id does not belong to him
* [datacenterlight] Refactored partially dcl text and dcl support email to be obtained from env parameters
* [datacenterlight] Updated DE translations
* [hosting] Updated email text for user activation
1.0.17: 2017-06-16 1.0.17: 2017-06-16
* [datacenterlight] Cleanup OrderView useless code * [datacenterlight] Cleanup OrderView useless code
* [datacenterlight] Replaced GiB to GB * [datacenterlight] Replaced GiB to GB
@ -5,7 +13,7 @@
* [datacenterlight] Fixed translations * [datacenterlight] Fixed translations
* [datacenterlight] Added email confirmation feature * [datacenterlight] Added email confirmation feature
* [datacenterlight] Changed logo on datacerlight dashboard * [datacenterlight] Changed logo on datacerlight dashboard
* [datacenterlight] Credit card input disappearance fix * [datacenterlight] Credit card input disappearance fix
1.0.16: 2017-06-15 1.0.16: 2017-06-15
* [datacenterlight] .po file issue with multiple definition fixed * [datacenterlight] .po file issue with multiple definition fixed
* [datacenterlight] Navbar items in dcl user area rearranged * [datacenterlight] Navbar items in dcl user area rearranged

View file

@ -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-06-19 12:22+0530\n" "POT-Creation-Date: 2017-07-02 23:08+0530\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,14 +18,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: templates/datacenterlight/base.html:72
msgid "Please enter your name"
msgstr "Bitte gib Deinen Namen ein"
#: templates/datacenterlight/base.html:73
msgid "Please enter a valid email address"
msgstr "Bitte gib eine gültige E-Mail-Adresse ein"
#: templates/datacenterlight/beta_access.html:13 #: templates/datacenterlight/beta_access.html:13
msgid "Enter name" msgid "Enter name"
msgstr "Name" msgstr "Name"
@ -99,15 +91,18 @@ msgid ""
"datacenterlight account.<br/>\n" "datacenterlight account.<br/>\n"
" %(base_url)s%(activation_link)s\n" " %(base_url)s%(activation_link)s\n"
" " " "
msgstr "\n" msgstr ""
" <a href=\"%(base_url)s%(activation_link)s\">Klicke hier</a> um deinen %(dcl_text)s zu aktivieren.<br/><br/>\n" "\n"
" Oder kopiere den folgenden Link in die Adressleiste deines Browsers und folge dann dem Link um deinen %(dcl_text)s Account zu aktivieren.<br/>\n" " <a href=\"%(base_url)s%(activation_link)s\">Klicke hier</a> "
"um deinen %(dcl_text)s zu aktivieren.<br/><br/>\n"
" Oder kopiere den folgenden Link in die Adressleiste deines "
"Browsers und folge dann dem Link um deinen %(dcl_text)s Account zu "
"aktivieren.<br/>\n"
" %(base_url)s%(activation_link)s\n" " %(base_url)s%(activation_link)s\n"
" " " "
#: templates/datacenterlight/emails/user_activation.html:123 #: templates/datacenterlight/emails/user_activation.html:123
#: templates/datacenterlight/emails/user_activation.txt:11 #: templates/datacenterlight/emails/user_activation.txt:11
#| msgid "Your Name"
msgid "Your" msgid "Your"
msgstr "Dein" msgstr "Dein"
@ -128,8 +123,9 @@ msgstr ""
"\n" "\n"
"Hallo,\n" "Hallo,\n"
"\n" "\n"
"Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst %(base_url)s" "Du kannst deinen %(dcl_text)s Account aktivieren, indem du hier klickst "
"%(activation_link)s\n" "%(base_url)s%(activation_link)s\n"
#: templates/datacenterlight/includes/_footer.html:11 #: templates/datacenterlight/includes/_footer.html:11
#: templates/datacenterlight/includes/_footer.html:31 #: templates/datacenterlight/includes/_footer.html:31
#: templates/datacenterlight/includes/_navbar.html:27 #: templates/datacenterlight/includes/_navbar.html:27
@ -260,44 +256,112 @@ msgstr "MwSt. inklusive"
msgid "Hosted in Switzerland" msgid "Hosted in Switzerland"
msgstr "Standort: Schweiz" msgstr "Standort: Schweiz"
#: templates/datacenterlight/index.html:173 #: templates/datacenterlight/index.html:161
msgid "Please enter a value greater than or equal to 1."
msgstr "Bitte gib einen Wert größer oder gleich 1 ein."
#: templates/datacenterlight/index.html:170
msgid "Please enter a value greater than or equal to 2."
msgstr "Bitte gib einen Wert größer oder gleich 2 ein."
#: templates/datacenterlight/index.html:179
msgid "Please enter a value greater than or equal to 10."
msgstr "Bitte gib einen Wert größer oder gleich 10 ein"
#: templates/datacenterlight/index.html:180
#: templates/datacenterlight/pricing.html:50 #: templates/datacenterlight/pricing.html:50
msgid "GB Storage (SSD)" msgid "GB Storage (SSD)"
msgstr "GB Storage (SSD)" msgstr "GB Storage (SSD)"
#: templates/datacenterlight/index.html:189 #: templates/datacenterlight/index.html:199
msgid "Name" msgid "Name"
msgstr "" msgstr ""
#: templates/datacenterlight/index.html:190 #: templates/datacenterlight/index.html:200
msgid "Your Name" msgid "Your Name"
msgstr "Dein Name" msgstr "Dein Name"
#: templates/datacenterlight/index.html:193 #: templates/datacenterlight/index.html:200
msgid "Please enter your name"
msgstr "Bitte gib Deinen Namen ein"
#: templates/datacenterlight/index.html:214
msgid "Email" msgid "Email"
msgstr "E-Mail-Adresse" msgstr "E-Mail-Adresse"
#: templates/datacenterlight/index.html:194 #: templates/datacenterlight/index.html:215
msgid "Your Email" msgid "Your Email"
msgstr "Deine E-Mail" msgstr "Deine E-Mail"
#: templates/datacenterlight/index.html:197 #: templates/datacenterlight/index.html:215
msgid "Please enter a valid email address"
msgstr "Bitte gib eine gültige E-Mailadresse ein"
#: templates/datacenterlight/index.html:228
#: templates/datacenterlight/pricing.html:79 #: templates/datacenterlight/pricing.html:79
msgid "Order Now!" msgid "Order Now!"
msgstr "Bestelle jetzt!" msgstr "Bestelle jetzt!"
#: templates/datacenterlight/index.html:226 #: templates/datacenterlight/index.html:254
msgid "Switzerland " msgid "Switzerland "
msgstr "Schweiz" msgstr "Schweiz"
#: templates/datacenterlight/index.html:243 #: templates/datacenterlight/index.html:271
msgid "Questions?" msgid "Questions?"
msgstr "Fragen?" msgstr "Fragen?"
#: templates/datacenterlight/index.html:243 #: templates/datacenterlight/index.html:271
msgid "Contact us!" msgid "Contact us!"
msgstr "Kontaktiere uns!" msgstr "Kontaktiere uns!"
#: templates/datacenterlight/order_detail.html:24
msgid "Confirm Order"
msgstr "Bestellung Bestätigen"
#: templates/datacenterlight/order_detail.html:30
msgid "Billed To:"
msgstr "Rechnungsadresse"
#: templates/datacenterlight/order_detail.html:39
msgid "Date"
msgstr "Datum"
#: templates/datacenterlight/order_detail.html:48
msgid "Payment Method:"
msgstr "Bezahlmethode"
#: templates/datacenterlight/order_detail.html:49
msgid "ending"
msgstr "endend in"
#: templates/datacenterlight/order_detail.html:59
msgid "Order summary"
msgstr "Bestellungsübersicht"
#: templates/datacenterlight/order_detail.html:63
msgid "Cores"
msgstr "Prozessorkerne"
#: templates/datacenterlight/order_detail.html:65
msgid "Memory"
msgstr "Arbeitsspeicher"
#: templates/datacenterlight/order_detail.html:67
msgid "Disk space"
msgstr "Festplattenkapazität"
#: templates/datacenterlight/order_detail.html:69
msgid "Configuration"
msgstr "Konfiguration"
#: templates/datacenterlight/order_detail.html:71
msgid "Total"
msgstr ""
#: templates/datacenterlight/order_detail.html:78
msgid "Place order"
msgstr "Bestellen"
#: templates/datacenterlight/pricing.html:9 #: templates/datacenterlight/pricing.html:9
msgid "We are cutting down the costs significantly!" msgid "We are cutting down the costs significantly!"
msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen" msgstr "Wir sorgen dafür, dass die Kosten für Dich signifikant abnehmen"
@ -328,6 +392,14 @@ msgstr ""
msgid "as soon as possible!" msgid "as soon as possible!"
msgstr "" msgstr ""
#: views.py:234
msgid "is not a proper name"
msgstr "ist kein gültiger Name"
#: views.py:241
msgid "is not a proper email"
msgstr "ist keine gültige E-Mailadresse"
#~ msgid "Buy VM" #~ msgid "Buy VM"
#~ msgstr "VM Kaufen" #~ msgstr "VM Kaufen"

View file

@ -7,7 +7,6 @@
font-family: 'Lato-Regular'; font-family: 'Lato-Regular';
src: url('../fonts/Lato/Lato-Regular.ttf'); src: url('../fonts/Lato/Lato-Regular.ttf');
} }
body, body,
html { html {
width: 100%; width: 100%;
@ -189,7 +188,6 @@ h6 {
.nav-language:hover .drop-language{ .nav-language:hover .drop-language{
display: block; display: block;
} }
.intro-header { .intro-header {
height: 100vh; height: 100vh;
text-align: center; text-align: center;
@ -438,7 +436,6 @@ h6 {
} }
.pricing-section .card .description{ .pricing-section .card .description{
padding: 12px; padding: 12px;
border-bottom: 1px solid rgba(128, 128, 128, 0.3);
} }
.pricing-section .card .descriptions{ .pricing-section .card .descriptions{
padding: 10px 30px; padding: 10px 30px;
@ -789,11 +786,10 @@ tech-sub-sec h2 {
} }
.price-calc-section .card .description{ .price-calc-section .card .description{
padding: 12px; padding: 12px;
border-bottom: 1px solid rgba(128, 128, 128, 0.3);
position: relative; position: relative;
display: flex; display: flex;
justify-content: space-around; justify-content: space-around !important;
align-items: center; align-items: center !important;
} }
.price-calc-section .card .description span { .price-calc-section .card .description span {
@ -804,10 +800,10 @@ tech-sub-sec h2 {
width: 30%; width: 30%;
text-align: left; text-align: left;
} }
.price-calc-section .card .description input{ .price-calc-section .card .description .select-number{
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
width: 60px; width: 60px;
} }
.price-calc-section .card .description i{ .price-calc-section .card .description i{
color: #29427A; color: #29427A;
@ -844,8 +840,8 @@ tech-sub-sec h2 {
.price-calc-section .card .check-ip{ .price-calc-section .card .check-ip{
font-size: 18px; font-size: 18px;
} }
.price-calc-section .card .description.input{ .price-calc-section .card .justify-center{
justify-content: center; justify-content: center !important;
} }
.price-calc-section .card .description.input label{ .price-calc-section .card .description.input label{
font-size: 15px; font-size: 15px;
@ -854,10 +850,11 @@ tech-sub-sec h2 {
margin-bottom: 0; margin-bottom: 0;
width: 40px; width: 40px;
} }
.price-calc-section .card .description.input input{ /*Changed class****.price-calc-section .card .description.input input*/
width: 200px; .price-calc-section .card .description input{
font-size: 14px; width: 200px;
text-align: left; font-size: 14px;
text-align: left;
padding: 5px 10px; padding: 5px 10px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #d0d0d0; border: 1px solid #d0d0d0;
@ -869,6 +866,18 @@ tech-sub-sec h2 {
font-size: 17px; font-size: 17px;
margin: 0 8px; margin: 0 8px;
} }
.help-block.with-errors {
text-align: center;
margin: 0;
padding: 0;
}
.has-error .checkbox, .has-error .checkbox-inline, .has-error .control-label, .has-error .help-block, .has-error .radio, .has-error .radio-inline, .has-error.checkbox label, .has-error.checkbox-inline label, .has-error.radio label, .has-error.radio-inline label{
color: #eb4d5c;
}
.form-group {
margin: 0;
border-bottom: 1px solid rgba(128, 128, 128, 0.3);
}
@media(max-width:767px) { @media(max-width:767px) {
.percent-text { .percent-text {
font-size: 50px; font-size: 50px;
@ -1125,7 +1134,7 @@ line-height: 40px;
text-align: center; text-align: center;
} }
.price-calc-section .card .description input { .price-calc-section .card .description .select-number{
font-size: 17px; font-size: 17px;
text-align: center; text-align: center;
width: 60px; width: 60px;

View file

@ -33,6 +33,9 @@
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]--> <![endif]-->
<!-- Google analytics -->
{% include "google_analytics.html" %}
<!-- End Google Analytics -->
</head> </head>
<body> <body>
@ -60,53 +63,5 @@
<script src="{% static 'datacenterlight/js/form.js' %}"></script> <script src="{% static 'datacenterlight/js/form.js' %}"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.5.4/bootstrap-select.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.5.4/bootstrap-select.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.9/validator.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.5.4/bootstrap-select.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.validator.setDefaults({
ignore: []
});
var name_message = "{% trans 'Please enter your name' %}";
var email_message = "{% trans 'Please enter a valid email address' %}";
$('#order_form').validate({
wrapper: 'div',
errorLabelContainer: "#error_message_box",
rules: {
name: {
required: true,
minlength: 3
},
email: {
required: true,
email: true
}
},
messages: {
name: name_message,
email: email_message
},
submitHandler: function (form) {
return true;
}
});
});
// window.onload=function(){
// $('.selectpicker').selectpicker({
// style: 'btn-link',
// windowPadding: 10,
// });
// var hash = window.location.hash.substr(1);
// console.log(hash);
// if (hash == 'requestform'){
// $('#reques-success-message').modal('show');
// }
// };
</script>
</html> </html>

View file

@ -139,7 +139,7 @@
<div class="landing card"> <div class="landing card">
<img class="img-beta" src="{% static 'datacenterlight/img/beta-img.png' %}" alt=""> <img class="img-beta" src="{% static 'datacenterlight/img/beta-img.png' %}" alt="">
<div class="caption"> <div class="caption">
<form id="order_form" method="POST" action=""> <form id="order_form" method="POST" action="" data-toggle="validator" role="form">
{% csrf_token %} {% csrf_token %}
<div class="title"> <div class="title">
<h3>{% trans "VM hosting" %} </h3> <h3>{% trans "VM hosting" %} </h3>
@ -152,28 +152,37 @@
</div> </div>
</div> </div>
<div class="descriptions"> <div class="descriptions">
<div class="description"> <div class="description form-group">
<p>{% trans "Hosted in Switzerland" %}</p> <p>{% trans "Hosted in Switzerland" %}</p>
</div> </div>
<div class="description"> <div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="cpu" aria-hidden="true"></i> <i class="fa fa-minus-circle left" data-minus="cpu" aria-hidden="true"></i>
<input class="input-price" type="number" min="1" max="42" id="coreValue" name="cpu"> <input class="input-price select-number" type="number" min="1" max="42" id="coreValue" name="cpu" data-error="{% trans 'Please enter a value greater than or equal to 1.' %}" required>
<span> Core</span> <span> Core</span>
<i class="fa fa-plus-circle right" data-plus="cpu" aria-hidden="true"></i> <i class="fa fa-plus-circle right" data-plus="cpu" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div> </div>
<div class="description"> <div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="ram" aria-hidden="true"></i> <i class="fa fa-minus-circle left" data-minus="ram" aria-hidden="true"></i>
<input id="ramValue" class="input-price" type="number" min="2" max="200" name="ram"> <input id="ramValue" class="input-price select-number" type="number" min="2" max="200" name="ram" data-error="{% trans 'Please enter a value greater than or equal to 2.' %}" required>
<span> GB RAM</span> <span> GB RAM</span>
<i class="fa fa-plus-circle right" data-plus="ram" aria-hidden="true"></i> <i class="fa fa-plus-circle right" data-plus="ram" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div> </div>
<div class="description"> <div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="storage" aria-hidden="true"></i> <i class="fa fa-minus-circle left" data-minus="storage" aria-hidden="true"></i>
<input id="storageValue" class="input-price" type="number" min="10" max="500" step="10" name="storage"> <input id="storageValue" class="input-price select-number" type="number" min="10" max="500" step="10" name="storage" data-error="{% trans 'Please enter a value greater than or equal to 10.' %}" required>
<span>{% trans "GB Storage (SSD)" %}</span> <span>{% trans "GB Storage (SSD)" %}</span>
<i class="fa fa-plus-circle right" data-plus="storage" aria-hidden="true"></i> <i class="fa fa-plus-circle right" data-plus="storage" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div> </div>
<div class="description select-configuration input"> <div class="description select-configuration input form-group justify-center">
<label for="config">OS</label> <label for="config">OS</label>
<select name="config" id=""> <select name="config" id="">
{% for template in templates %} {% for template in templates %}
@ -185,21 +194,40 @@
<!--<div class="description check-ip"> <!--<div class="description check-ip">
<input type="checkbox" name="ipv6"> Ipv6 Only<br> <input type="checkbox" name="ipv6"> Ipv6 Only<br>
</div>--> </div>-->
<div class="description input"> <div class="form-group">
<label for="name">{% trans "Name"%}</label> <div class="description input justify-center">
<input type="text" name="name" placeholder="{% trans "Your Name" %}"> <label for="name" class="control-label">{% trans "Name"%}</label>
</div> <input type="text" name="name" class="form-control" placeholder="{% trans 'Your Name'%}" data-minlength="3" data-error="{% trans 'Please enter your name' %}" required>
<div class="description input"> </div>
<label for="email">{% trans "Email" %}</label> <div class="help-block with-errors">
<input type="email" name="email" placeholder="{% trans "Your Email" %}"> {% for message in messages %}
</div> {% if 'name' in message.tags %}
<ul class="list-unstyled"><li>
{{ message|safe }}
</li></ul>
{% endif %}
{% endfor %}
</div>
</div>
<div class="form-group">
<div class="description input justify-center">
<label for="email" class="control-label">{% trans "Email"%}</label>
<input name="email" type="email" pattern="^[^@\s]+@([^@\s]+\.)+[^@\s]+$" class="form-control" placeholder="{% trans 'Your Email' %}" data-error="{% trans 'Please enter a valid email address' %}" required>
</div>
<div class="help-block with-errors">
{% for message in messages %}
{% if 'email' in message.tags %}
<ul class="list-unstyled"><li>
{{ message|safe }}
</li></ul>
{% endif %}
{% endfor %}
</div>
</div>
</div> </div>
<input type="submit" class="btn btn-primary" value="{% trans 'Order Now!' %}"></input> <input type="submit" class="btn btn-primary" value="{% trans 'Order Now!' %}"></input>
</form> </form>
</div> </div>
<div>
<div id="error_message_box" class="error-message-box"></div>
</div>
</div> </div>
</div> </div>
@ -250,4 +278,4 @@
</div> </div>
<!-- /.banner --> <!-- /.banner -->
{% endblock %} {% endblock %}

View file

@ -1,7 +1,8 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3 %} {% load staticfiles bootstrap3 %}
{% load i18n %} {% load i18n %}
{% block content %} {% load custom_tags %}
{% block content %}
<div class="order-detail-container"> <div class="order-detail-container">
{% if messages %} {% if messages %}
@ -19,37 +20,38 @@
{% if not error %} {% if not error %}
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-8 col-md-offset-2"> <div class="col-xs-12 col-md-8 col-md-offset-2">
<div class="invoice-title"> <div class="invoice-title">
<h2>{% trans "Confirm Order"%}</h2><h3 class="pull-right">{% trans "Order #"%} {{order.id}}</h3> <h2>{% trans "Confirm Order"%}</h2>
</div> </div>
<hr> <hr>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
<address> <address>
<h3><b>{% trans "Billed To:"%}</b></h3> <h3><b>{% trans "Billed To:"%}</b></h3>
{{user.name}}<br> {% with request.session.billing_address_data as billing_address %}
{{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br> {{request.session.user.name}}<br> {{billing_address|get_value_from_dict:'street_address'}}, {{billing_address|get_value_from_dict:'postal_code'}}<br>
{{order.billing_address.city}}, {{order.billing_address.country}}. {{billing_address|get_value_from_dict:'city'}}, {{billing_address|get_value_from_dict:'country'}}.
</address> {% endwith %}
</div> </address>
</div>
<div class="col-xs-6 text-right"> <div class="col-xs-6 text-right">
<address> <address>
<strong>{% trans "Date"%}:</strong><br> <strong>{% trans "Date"%}:</strong><br>
{{order.created_at}}<br><br> <span id="order-created_at">{% now "Y-m-d H:i" %}</span><br><br>
</address> </address>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
<address> <address>
<strong>{% trans "Payment Method:"%}</strong><br> <strong>{% trans "Payment Method:"%}</strong><br>
{{order.cc_brand}} ending **** {{order.last4}}<br> {{cc_brand}} {% trans "ending" %} **** {{cc_last4}}<br>
{{user.email}} {{request.session.user.email}}
</address> </address>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -57,23 +59,39 @@
<h3><b>{% trans "Order summary"%}</b></h3> <h3><b>{% trans "Order summary"%}</b></h3>
<hr> <hr>
<div class="content"> <div class="content">
<p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cores}}</span></p> {% with request.session.specs as vm %}
<hr> <p><b>{% trans "Cores"%}</b> <span class="pull-right">{{vm.cpu}}</span></p>
<p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p> <hr>
<hr> <p><b>{% trans "Memory"%}</b> <span class="pull-right">{{vm.memory}} GB</span></p>
<p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p> <hr>
<hr> <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4> <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></p></h4>
{% endwith %}
</div> </div>
<br/> <br/>
{% url 'datacenterlight:payment' as payment_url %} <form method="post">
{% if payment_url in request.META.HTTP_REFERER %} {% csrf_token %}
<div class=" content pull-right"> <div class=" content pull-right">
<a href="{{next_url}}" ><button class="btn btn-info">{% trans "Finish Configuration"%}</button></a> <a href="{{next_url}}" ><button class="btn btn-info">{% trans "Place order"%}</button></a>
</div> </div>
{% endif %} </form>
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>
<script type="text/javascript">
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%} {%endblock%}

View file

@ -21,4 +21,14 @@ def change_lang(context, lang=None, *args, **kwargs):
activate(cur_language) activate(cur_language)
return "%s" % url return "%s" % url
@register.filter('get_value_from_dict')
def get_value_from_dict(dict_data, key):
"""
usage example {{ your_dict|get_value_from_dict:your_key }}
"""
if key:
return dict_data.get(key)
else :
return ""

View file

@ -10,7 +10,7 @@ urlpatterns = [
url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'), url(r'^/landing/?$', LandingProgramView.as_view(), name='landing'),
url(r'^/pricing/?$', PricingView.as_view(), name='pricing'), url(r'^/pricing/?$', PricingView.as_view(), name='pricing'),
url(r'^/payment/?$', PaymentOrderView.as_view(), name='payment'), url(r'^/payment/?$', PaymentOrderView.as_view(), name='payment'),
url(r'^/order-confirmation/(?P<pk>\d+)/?$', OrderConfirmationView.as_view(), name='order_confirmation'), url(r'^/order-confirmation/?$', OrderConfirmationView.as_view(), name='order_confirmation'),
url(r'^/order-success/?$', SuccessView.as_view(), name='order_success'), url(r'^/order-success/?$', SuccessView.as_view(), name='order_success'),
url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'), url(r'^/beta_access?$', BetaAccessView.as_view(), name='beta_access'),
] ]

View file

@ -12,7 +12,9 @@ from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.views.decorators.cache import cache_control from django.views.decorators.cache import cache_control
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from utils.forms import BillingAddressForm, UserBillingAddressForm from utils.forms import BillingAddressForm, UserBillingAddressForm
from utils.models import BillingAddress
from membership.models import StripeCustomer from membership.models import StripeCustomer
from hosting.models import HostingOrder, HostingBill from hosting.models import HostingOrder, HostingBill
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
@ -31,9 +33,14 @@ class SuccessView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'specs' not in request.session or 'user' not in request.session: if 'specs' not in request.session or 'user' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:index')) return HttpResponseRedirect(reverse('datacenterlight:index'))
else : elif 'token' not in request.session:
del request.session['specs'] return HttpResponseRedirect(reverse('datacenterlight:payment'))
del request.session['user'] elif 'order_confirmation' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
else:
for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data', 'token', 'customer']:
if session_var in request.session:
del request.session[session_var]
return render(request, self.template_name) return render(request, self.template_name)
class PricingView(TemplateView): class PricingView(TemplateView):
@ -187,15 +194,14 @@ class IndexView(CreateView):
@cache_control(no_cache=True, must_revalidate=True, no_store=True) @cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if 'specs' in request.session : for session_var in ['specs', 'user', 'billing_address_data']:
del request.session['specs'] if session_var in request.session:
if 'user' in request.session : del request.session[session_var]
del request.session['user']
try: try:
manager = OpenNebulaManager() manager = OpenNebulaManager()
templates = manager.get_templates() templates = manager.get_templates()
context = { context = {
'templates': VirtualMachineTemplateSerializer(templates, many=True).data, 'templates': VirtualMachineTemplateSerializer(templates, many=True).data
} }
except: except:
messages.error( request, messages.error( request,
@ -224,14 +230,16 @@ class IndexView(CreateView):
try: try:
name = name_field.clean(name) name = name_field.clean(name)
except ValidationError as err: except ValidationError as err:
messages.add_message(self.request, messages.ERROR, '%(value) is not a proper name.'.format(name)) msg='{} {}.'.format(name, _('is not a proper name'))
return HttpResponseRedirect(reverse('datacenterlight:index')) messages.add_message(self.request, messages.ERROR, msg, extra_tags='name')
return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
try: try:
email = email_field.clean(email) email = email_field.clean(email)
except ValidationError as err: except ValidationError as err:
messages.add_message(self.request, messages.ERROR, '%(value) is not a proper email.'.format(email)) msg='{} {}.'.format(email, _('is not a proper email'))
return HttpResponseRedirect(reverse('datacenterlight:index')) messages.add_message(self.request, messages.ERROR, msg, extra_tags='email')
return HttpResponseRedirect(reverse('datacenterlight:index') + "#order_form")
specs = { specs = {
'cpu': cores, 'cpu': cores,
@ -323,11 +331,27 @@ class WhyDataCenterLightView(IndexView):
class PaymentOrderView(FormView): class PaymentOrderView(FormView):
template_name = 'hosting/payment.html' template_name = 'hosting/payment.html'
form_class = BillingAddressForm form_class = BillingAddressForm
def get_form_kwargs(self):
form_kwargs = super(PaymentOrderView, self).get_form_kwargs()
billing_address_data = self.request.session.get('billing_address_data')
if billing_address_data:
form_kwargs.update({
'initial': {
'street_address': billing_address_data['street_address'],
'city': billing_address_data['city'],
'postal_code': billing_address_data['postal_code'],
'country': billing_address_data['country'],
}
})
return form_kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PaymentOrderView, self).get_context_data(**kwargs) context = super(PaymentOrderView, self).get_context_data(**kwargs)
context.update({ context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY 'stripe_key': settings.STRIPE_API_PUBLIC_KEY,
'site_url': reverse('datacenterlight:index')
}) })
return context return context
@ -342,13 +366,9 @@ class PaymentOrderView(FormView):
if form.is_valid(): if form.is_valid():
# Get billing address data # Get billing address data
billing_address_data = form.cleaned_data billing_address_data = form.cleaned_data
context = self.get_context_data()
template = request.session.get('template')
specs = request.session.get('specs')
user = request.session.get('user')
vm_template_id = template.get('id', 1)
final_price = specs.get('price')
token = form.cleaned_data.get('token') token = form.cleaned_data.get('token')
user = request.session.get('user')
try: try:
custom_user = CustomUser.objects.get(email=user.get('email')) custom_user = CustomUser.objects.get(email=user.get('email'))
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
@ -360,7 +380,6 @@ class PaymentOrderView(FormView):
app='dcl', app='dcl',
base_url=None, send_email=False) base_url=None, send_email=False)
# Get or create stripe customer # Get or create stripe customer
customer = StripeCustomer.get_or_create(email=user.get('email'), customer = StripeCustomer.get_or_create(email=user.get('email'),
token=token) token=token)
@ -370,115 +389,131 @@ class PaymentOrderView(FormView):
# Create Billing Address # Create Billing Address
billing_address = form.save() billing_address = form.save()
request.session['billing_address_data'] = billing_address_data
# Make stripe charge to a customer request.session['billing_address'] = billing_address.id
stripe_utils = StripeUtils() request.session['token'] = token
charge_response = stripe_utils.make_charge(amount=final_price, request.session['customer'] = customer.id
customer=customer.stripe_id) return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
context.update({
'paymentError': charge_response.get('error'),
'form': form
})
return render(request, self.template_name, context)
charge = charge_response.get('response_object')
# Create OpenNebulaManager
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD)
# Create a vm using logged user
vm_id = manager.create_vm(
template_id=vm_template_id,
specs=specs,
vm_name="{email}-{template_name}-{date}".format(
email=user.get('email'),
template_name=template.get('name'),
date=int(datetime.now().strftime("%s")))
)
# Create a Hosting Order
order = HostingOrder.create(
price=final_price,
vm_id=vm_id,
customer=customer,
billing_address=billing_address
)
# Create a Hosting Bill
bill = HostingBill.create(
customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
billing_address_data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(
billing_address_data)
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Associate an order with a stripe payment
order.set_stripe_charge(charge)
# If the Stripe payment was successed, set order status approved
order.set_approved()
vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
context = {
'name': user.get('name'),
'email': user.get('email'),
'cores': specs.get('cpu'),
'memory': specs.get('memory'),
'storage': specs.get('disk_size'),
'price': specs.get('price'),
'template': template.get('name'),
'vm.name': vm['name'],
'vm.id': vm['vm_id'],
'order.id': order.id
}
email_data = {
'subject': "Data Center Light Order from %s" % context['email'],
'from_email': '(Data Center Light) Data Center Light Support <support@datacenterlight.ch>',
'to': ['info@ungleich.ch'],
'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']],
}
email = EmailMessage(**email_data)
email.send()
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation', kwargs={'pk': order.id}))
else: else:
return self.form_invalid(form) return self.form_invalid(form)
class OrderConfirmationView(DetailView): class OrderConfirmationView(DetailView):
template_name = "datacenterlight/order_detail.html" template_name = "datacenterlight/order_detail.html"
payment_template_name = 'hosting/payment.html'
context_object_name = "order" context_object_name = "order"
model = HostingOrder model = HostingOrder
def get_context_data(self, **kwargs):
# Get context @cache_control(no_cache=True, must_revalidate=True, no_store=True)
context = super(DetailView, self).get_context_data(**kwargs) def get(self, request, *args, **kwargs):
obj = self.get_object() if 'specs' not in request.session or 'user' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:index'))
if 'token' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:payment'))
stripe_customer_id = request.session.get('customer')
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
stripe_utils = StripeUtils()
card_details = stripe_utils.get_card_details(customer.stripe_id, request.session.get('token'))
context = {
'site_url': reverse('datacenterlight:index'),
'cc_last4' : card_details.get('response_object').get('last4'),
'cc_brand' : card_details.get('response_object').get('brand')
}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
template = request.session.get('template')
specs = request.session.get('specs')
user = request.session.get('user')
stripe_customer_id = request.session.get('customer')
customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
billing_address_data = request.session.get('billing_address_data')
billing_address_id = request.session.get('billing_address')
billing_address = BillingAddress.objects.filter(id=billing_address_id).first()
token = request.session.get('token')
vm_template_id = template.get('id', 1)
final_price = specs.get('price')
# Make stripe charge to a customer
stripe_utils = StripeUtils()
charge_response = stripe_utils.make_charge(amount=final_price,
customer=customer.stripe_id)
charge = charge_response.get('response_object')
# Check if the payment was approved
if not charge:
context.update({
'paymentError': charge_response.get('error')
# TODO add logic in payment form to autofill data
#'form': form
})
return render(request, self.payment_template_name, context)
charge = charge_response.get('response_object')
# Create OpenNebulaManager
manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME, manager = OpenNebulaManager(email=settings.OPENNEBULA_USERNAME,
password=settings.OPENNEBULA_PASSWORD) password=settings.OPENNEBULA_PASSWORD)
try:
vm = manager.get_vm(obj.vm_id) # Create a vm using oneadmin, also specify the name
context['vm'] = VirtualMachineSerializer(vm).data vm_id = manager.create_vm(
context['next_url'] = reverse('datacenterlight:order_success') template_id=vm_template_id,
except WrongIdError: specs=specs,
messages.error(self.request, vm_name="{email}-{template_name}-{date}".format(
'The VM you are looking for is unavailable at the moment. \ email=user.get('email'),
Please contact Data Center Light support.' template_name=template.get('name'),
) date=int(datetime.now().strftime("%s")))
self.kwargs['error'] = 'WrongIdError' )
context['error'] = 'WrongIdError'
except ConnectionRefusedError: # Create a Hosting Order
messages.error(self.request, order = HostingOrder.create(
'In order to create a VM, you need to create/upload your SSH KEY first.' price=final_price,
) vm_id=vm_id,
return context customer=customer,
billing_address=billing_address
)
# Create a Hosting Bill
bill = HostingBill.create(
customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count():
billing_address_data.update({
'user': customer.user.id
})
billing_address_user_form = UserBillingAddressForm(
billing_address_data)
billing_address_user_form.is_valid()
billing_address_user_form.save()
# Associate an order with a stripe payment
order.set_stripe_charge(charge)
# If the Stripe payment was successed, set order status approved
order.set_approved()
vm = VirtualMachineSerializer(manager.get_vm(vm_id)).data
context = {
'name': user.get('name'),
'email': user.get('email'),
'cores': specs.get('cpu'),
'memory': specs.get('memory'),
'storage': specs.get('disk_size'),
'price': specs.get('price'),
'template': template.get('name'),
'vm.name': vm['name'],
'vm.id': vm['vm_id'],
'order.id': order.id
}
email_data = {
'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
'to': ['info@ungleich.ch'],
'body': "\n".join(["%s=%s" % (k, v) for (k, v) in context.items()]),
'reply_to': [context['email']],
}
email = EmailMessage(**email_data)
email.send()
request.session['order_confirmation'] = True
return HttpResponseRedirect(reverse('datacenterlight:order_success'))

View file

@ -39,27 +39,13 @@
<!-- 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:// -->
<!--[if lt IE 9]> <!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script> <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script> <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]--> <![endif]-->
<script> <!-- Google analytics -->
(function (i, s, o, g, r, a, m) { {% include 'google_analytics.html' %}
i['GoogleAnalyticsObject'] = r; <!-- End Google Analytics -->
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-62285904-2', 'auto');
ga('send', 'pageview');
</script>
</head> </head>
<body> <body>

View file

@ -118,6 +118,7 @@ INSTALLED_APPS = (
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'utils.middleware.MultipleProxyMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
@ -138,6 +139,7 @@ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(PROJECT_DIR, 'cms_templates/'), 'DIRS': [os.path.join(PROJECT_DIR, 'cms_templates/'),
os.path.join(PROJECT_DIR, 'templates'),
os.path.join(PROJECT_DIR, 'cms_templates/djangocms_blog/'), os.path.join(PROJECT_DIR, 'cms_templates/djangocms_blog/'),
os.path.join(PROJECT_DIR, 'membership'), os.path.join(PROJECT_DIR, 'membership'),
os.path.join(PROJECT_DIR, 'hosting/templates/'), os.path.join(PROJECT_DIR, 'hosting/templates/'),
@ -161,6 +163,7 @@ TEMPLATES = [
"django.contrib.messages.context_processors.messages", "django.contrib.messages.context_processors.messages",
'sekizai.context_processors.sekizai', 'sekizai.context_processors.sekizai',
'cms.context_processors.cms_settings', 'cms.context_processors.cms_settings',
'utils.context_processor.google_analytics',
], ],
}, },
}, },
@ -509,3 +512,12 @@ OPENNEBULA_ENDPOINT = env('OPENNEBULA_ENDPOINT')
# dcl email configurations # dcl email configurations
DCL_TEXT = env('DCL_TEXT') DCL_TEXT = env('DCL_TEXT')
DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS') DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS')
# Settings for Google analytics
GOOGLE_ANALYTICS_PROPERTY_IDS = {
'datacenterlight.ch': 'UA-62285904-9',
'digitalglarus.ch': 'UA-62285904-2',
'127.0.0.1:8000': 'localhost',
'dynamicweb-development.ungleich.ch': 'development',
'dynamicweb-staging.ungleich.ch': 'staging'
}

View file

@ -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-06-23 02:28+0530\n" "POT-Creation-Date: 2017-07-01 02:09+0530\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"
@ -26,47 +26,47 @@ msgstr "Dein Account wurde noch nicht aktiviert."
msgid "Paste here your public key" msgid "Paste here your public key"
msgstr "Fügen Sie Ihren public key ein" msgstr "Fügen Sie Ihren public key ein"
#: templates/hosting/base_short.html:67 #: templates/hosting/base_short.html:68
msgid "My Virtual Machines" msgid "My Virtual Machines"
msgstr "Meine virtuellen Maschinen" msgstr "Meine virtuellen Maschinen"
#: templates/hosting/base_short.html:72 templates/hosting/orders.html.py:12 #: templates/hosting/base_short.html:73 templates/hosting/orders.html.py:12
msgid "My Orders" msgid "My Orders"
msgstr "Meine Bestellungen" msgstr "Meine Bestellungen"
#: templates/hosting/base_short.html:81 #: templates/hosting/base_short.html:82
msgid "Keys" msgid "Keys"
msgstr "Schlüssel" msgstr "Schlüssel"
#: templates/hosting/base_short.html:86 #: templates/hosting/base_short.html:87
msgid "Notifications " msgid "Notifications "
msgstr "Benachrichtigungen" msgstr "Benachrichtigungen"
#: templates/hosting/base_short.html:89 #: templates/hosting/base_short.html:90
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
#: templates/hosting/base_short.html:94 #: templates/hosting/base_short.html:95
msgid "How it works" msgid "How it works"
msgstr "So funktioniert es" msgstr "So funktioniert es"
#: templates/hosting/base_short.html:97 #: templates/hosting/base_short.html:98
msgid "Your infrastructure" msgid "Your infrastructure"
msgstr "deine Infrastruktur" msgstr "deine Infrastruktur"
#: templates/hosting/base_short.html:100 #: templates/hosting/base_short.html:101
msgid "Our inftrastructure" msgid "Our inftrastructure"
msgstr "Unsere Infrastruktur" msgstr "Unsere Infrastruktur"
#: templates/hosting/base_short.html:103 #: templates/hosting/base_short.html:104
msgid "Pricing" msgid "Pricing"
msgstr "Preise" msgstr "Preise"
#: templates/hosting/base_short.html:106 #: templates/hosting/base_short.html:107
msgid "Contact" msgid "Contact"
msgstr "Kontakt" msgstr "Kontakt"
#: templates/hosting/base_short.html:109 #: templates/hosting/base_short.html:110
#: templates/hosting/confirm_reset_password.html:38 #: templates/hosting/confirm_reset_password.html:38
#: templates/hosting/login.html:17 templates/hosting/login.html.py:26 #: templates/hosting/login.html:17 templates/hosting/login.html.py:26
#: templates/hosting/reset_password.html:32 templates/hosting/signup.html:30 #: templates/hosting/reset_password.html:32 templates/hosting/signup.html:30
@ -347,11 +347,11 @@ msgstr "Bestellung stornieren"
msgid "Do You want to delete your order?" msgid "Do You want to delete your order?"
msgstr "Willst du deine Bestellung löschen?" msgstr "Willst du deine Bestellung löschen?"
#: templates/hosting/orders.html:63 templates/hosting/user_keys.html.py:62 #: templates/hosting/orders.html:63 templates/hosting/user_keys.html.py:63
msgid "Close" msgid "Close"
msgstr "Schliessen" msgstr "Schliessen"
#: templates/hosting/orders.html:65 templates/hosting/user_keys.html.py:64 #: templates/hosting/orders.html:65 templates/hosting/user_keys.html.py:65
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
@ -359,31 +359,36 @@ msgstr "Löschen"
msgid "Billing Amount" msgid "Billing Amount"
msgstr "Rechnungsbetrag" msgstr "Rechnungsbetrag"
#: templates/hosting/payment.html:35 #: templates/hosting/payment.html:26
#: templates/hosting/virtual_machine_detail.html:98
msgid "Configuration"
msgstr "Konfiguration"
#: templates/hosting/payment.html:38
msgid "Billing Address" msgid "Billing Address"
msgstr "Rechnungsadresse" msgstr "Rechnungsadresse"
#: templates/hosting/payment.html:49 #: templates/hosting/payment.html:52
msgid "Payment Details" msgid "Payment Details"
msgstr "Rechnungsdetails" msgstr "Rechnungsdetails"
#: templates/hosting/payment.html:62 #: templates/hosting/payment.html:65
msgid "Submit Payment" msgid "Submit Payment"
msgstr "Betrag überweisen" msgstr "Betrag überweisen"
#: templates/hosting/payment.html:81 #: templates/hosting/payment.html:84
msgid "CARD NUMBER" msgid "CARD NUMBER"
msgstr "Kreditkartennummer" msgstr "Kreditkartennummer"
#: templates/hosting/payment.html:86 #: templates/hosting/payment.html:89
msgid "Valid Card Number" msgid "Valid Card Number"
msgstr "Gültige Kreditkartennummer" msgstr "Gültige Kreditkartennummer"
#: templates/hosting/payment.html:95 #: templates/hosting/payment.html:98
msgid "EXPIRATION DATE" msgid "EXPIRATION DATE"
msgstr "Ablaufdatum" msgstr "Ablaufdatum"
#: templates/hosting/payment.html:106 #: templates/hosting/payment.html:109
msgid "CV CODE" msgid "CV CODE"
msgstr "CV Code" msgstr "CV Code"
@ -425,13 +430,13 @@ msgstr "Schlüssel hinzufügen"
msgid "Created at" msgid "Created at"
msgstr "Erstellt am" msgstr "Erstellt am"
#: templates/hosting/user_keys.html:42 #: templates/hosting/user_keys.html:43
#, fuzzy #, fuzzy
#| msgid "Delete" #| msgid "Delete"
msgid "Delete Key" msgid "Delete Key"
msgstr "Löschen" msgstr "Löschen"
#: templates/hosting/user_keys.html:55 #: templates/hosting/user_keys.html:56
#, fuzzy #, fuzzy
#| msgid "Do You want do delete your order?" #| msgid "Do You want do delete your order?"
msgid "Do You want to delete this key?" msgid "Do You want to delete this key?"
@ -453,10 +458,6 @@ msgstr "Ip nicht zugewiesen"
msgid "Disk" msgid "Disk"
msgstr "Festplatte" msgstr "Festplatte"
#: templates/hosting/virtual_machine_detail.html:98
msgid "Configuration"
msgstr "Konfiguration"
#: templates/hosting/virtual_machine_detail.html:108 #: templates/hosting/virtual_machine_detail.html:108
msgid "Current pricing" msgid "Current pricing"
msgstr "Aktueller Preis" msgstr "Aktueller Preis"

View file

@ -57,7 +57,7 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand topnav" href="{{ request.session.hosting_url}}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a> <a class="navbar-brand topnav" href="{% if site_url %}{{site_url}}{% else %}{{ request.session.hosting_url}}{% endif %}"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
</div> </div>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<!-- Collect the nav links, forms, and other content for toggling --> <!-- Collect the nav links, forms, and other content for toggling -->
@ -131,6 +131,8 @@
<p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p> <p class="copyright text-muted small">Copyright &copy; ungleich GmbH {% now "Y" %}. All Rights Reserved</p>
</div> </div>
</footer> </footer>
{% else %}
{% include "datacenterlight/includes/_footer.html" %}
{% endif %} {% endif %}
<!-- jQuery --> <!-- jQuery -->
<script src="{% static 'hosting/js/jquery.js' %}"></script> <script src="{% static 'hosting/js/jquery.js' %}"></script>
@ -162,6 +164,12 @@
<!-- Gen SSH Key lib --> <!-- Gen SSH Key lib -->
<script type="text/javascript" src="{% static 'hosting/js/gen-ssh-key.js' %}"></script> <script type="text/javascript" src="{% static 'hosting/js/gen-ssh-key.js' %}"></script>
<!-- Moment -->
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.js"></script>
</body> </body>
</html> </html>

View file

@ -35,7 +35,7 @@
<div class="col-xs-6 text-right"> <div class="col-xs-6 text-right">
<address> <address>
<strong>{% trans "Date"%}:</strong><br> <strong>{% trans "Date"%}:</strong><br>
{{order.created_at}}<br><br> <span id="order-created_at">{{order.created_at|date:'Y-m-d H:i'}}</span><br><br>
<strong>{% trans "Status:"%}</strong><br> <strong>{% trans "Status:"%}</strong><br>
<strong class="{% if order.status == 'Approved' %}text-success <strong class="{% if order.status == 'Approved' %}text-success
{%else%} text-danger {%else%} text-danger
@ -68,7 +68,7 @@
<hr> <hr>
<p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p> <p><b>{% trans "Disk space"%}</b> <span class="pull-right">{{vm.disk_size}} GB</span></p>
<hr> <hr>
<h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4> <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}} CHF</b></p></h4>
</div> </div>
<br/> <br/>
{% url 'hosting:payment' as payment_url %} {% url 'hosting:payment' as payment_url %}
@ -81,4 +81,17 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<script type="text/javascript">
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%} {%endblock%}

View file

@ -24,7 +24,7 @@
{% for order in orders %} {% for order in orders %}
<tr> <tr>
<td scope="row">{{ order.id }}</td> <td scope="row">{{ order.id }}</td>
<td>{{ order.created_at }}</td> <td>{{ order.created_at | date:"M d, Y" }}</td>
<td>{{ order.price }} CHF</td> <td>{{ order.price }} CHF</td>
<td>{% if order.approved %} <td>{% if order.approved %}
<span class="text-success strong">{% trans "Approved"%}</span> <span class="text-success strong">{% trans "Approved"%}</span>

View file

@ -22,6 +22,9 @@
<hr> <hr>
<p><b>{%trans "Disk space"%}</b> <span <p><b>{%trans "Disk space"%}</b> <span
class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</span></p> class="pull-right">{{request.session.specs.disk_size|floatformat}} GB</span></p>
<hr>
<p><b>{%trans "Configuration"%}</b> <span
class="pull-right">{{request.session.template.name}}</span></p>
<hr> <hr>
<h4>Total<p <h4>Total<p
class="pull-right"><b>{{request.session.specs.price }} CHF</b></p></h4> class="pull-right"><b>{{request.session.specs.price }} CHF</b></p></h4>

View file

@ -32,7 +32,8 @@
{% for user_key in keys %} {% for user_key in keys %}
<tr> <tr>
<td scope="row">{{user_key.name}}</td> <td scope="row">{{user_key.name}}</td>
<td>{{user_key.created_at}}</td>
<td><span id="ssh-created_at-{{user_key.id}}">{{user_key.created_at|date:'Y-m-d H:i' }}</span></td>
<td> <td>
<span class="h3 label label-success"><strong>Active</strong></span> <span class="h3 label label-success"><strong>Active</strong></span>
</td> </td>
@ -92,5 +93,21 @@
</script> </script>
{% endif %} {% endif %}
<script type="text/javascript">
window.onload = function () {
{% for user_key in keys %}
// var locale_date = new Date(document.getElementById("ssh-created_at-{{user_key.id}}").textContent).toISOString();
var locale_date = moment.utc(document.getElementById("ssh-created_at-{{user_key.id}}").textContent,'YYYY-MM-DD HH:mm').toDate();
locale_date = moment(locale_date).format("YYYY-MM-DD h:mm:ss a");
document.getElementById('ssh-created_at-{{user_key.id}}').innerHTML = locale_date;
{% endfor %}
};
</script>
{%endblock%} {%endblock%}

View file

@ -0,0 +1,13 @@
{% if GOOGLE_ANALYTICS_PROPERTY_ID %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', '{{ GOOGLE_ANALYTICS_PROPERTY_ID }}', 'auto');
ga('send', 'pageview');
</script>
{% else %}
<!-- Empty analytics -->
{% endif %}

View file

@ -0,0 +1,15 @@
from django.conf import settings
def google_analytics(request):
"""
Use the variables returned in this function to
render your Google Analytics tracking code template.
"""
host = request.get_host()
ga_prop_id = getattr(settings, 'GOOGLE_ANALYTICS_PROPERTY_IDS', False).get(host)
if not settings.DEBUG and ga_prop_id:
return {
'GOOGLE_ANALYTICS_PROPERTY_ID': ga_prop_id
}
return {}

17
utils/middleware.py Normal file
View file

@ -0,0 +1,17 @@
class MultipleProxyMiddleware(object):
FORWARDED_FOR_FIELDS = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_HOST',
'HTTP_X_FORWARDED_SERVER',
]
def process_request(self, request):
"""
Rewrites the proxy headers so that only the most
recent proxy is used.
"""
for field in self.FORWARDED_FOR_FIELDS:
if field in request.META:
if ',' in request.META[field]:
parts = request.META[field].split(',')
request.META[field] = parts[-1].strip()

View file

@ -77,6 +77,16 @@ class StripeUtils(object):
} }
return new_card_data return new_card_data
@handleStripeError
def get_card_details(self, customer_id, token):
customer = stripe.Customer.retrieve(customer_id)
credit_card_raw_data = customer.sources.data.pop()
card_details = {
'last4': credit_card_raw_data.last4,
'brand': credit_card_raw_data.brand
}
return card_details
def check_customer(self, id, user, token): def check_customer(self, id, user, token):
customers = self.stripe.Customer.all() customers = self.stripe.Customer.all()
if not customers.get('data'): if not customers.get('data'):