Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Siarhei Puhach 2017-07-07 17:26:25 +03:00
commit 705948fdb7
36 changed files with 1128 additions and 413 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

@ -20,7 +20,7 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
font-family: 'Lato-Regular', sans-serif; font-family: 'Lato', sans-serif;
font-weight: 300; font-weight: 300;
} }
/*blue light #5A74AF*/ /*blue light #5A74AF*/
@ -108,10 +108,12 @@ h6 {
} }
.navbar-default .navbar-nav>li>a { .navbar-default .navbar-nav>li>a {
cursor: pointer; cursor: pointer;
font-family: 'Lato-Regular', sans-serif;
} }
.navbar-transparent .navbar-nav>li>a { .navbar-transparent .navbar-nav>li>a {
color: #fff; color: #fff;
cursor: pointer; cursor: pointer;
font-family: 'Lato-Regular', sans-serif;
} }
.navbar-transparent .navbar-nav>li>a:hover { .navbar-transparent .navbar-nav>li>a:hover {
color: #fff; color: #fff;
@ -145,11 +147,13 @@ h6 {
} }
.navbar-transparent .nav-language .select-language{ .navbar-transparent .nav-language .select-language{
color: #fff; color: #fff;
font-family: 'Lato-Regular', sans-serif;
} }
.nav-language .select-language span{ .nav-language .select-language span{
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
font-family: 'Lato-Regular', sans-serif;
} }
.nav-language .drop-language{ .nav-language .drop-language{
@ -171,6 +175,7 @@ h6 {
} }
.nav-language .drop-language a{ .nav-language .drop-language a{
cursor: pointer; cursor: pointer;
font-family: 'Lato-Regular', sans-serif;
} }
.navbar-transparent .nav-language .drop-language{ .navbar-transparent .nav-language .drop-language{
background: transparent; background: transparent;
@ -178,6 +183,7 @@ h6 {
} }
.navbar-transparent .nav-language .drop-language a{ .navbar-transparent .nav-language .drop-language a{
color: #fff; color: #fff;
font-family: 'Lato-Regular', sans-serif;
} }
.nav-language:hover .drop-language{ .nav-language:hover .drop-language{
display: block; display: block;
@ -430,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;
@ -445,7 +450,8 @@ h6 {
text-align: left; text-align: left;
} }
.pricing-section .text .section-heading{ .pricing-section .text .section-heading{
font-size: 50px; /*font-size: 50px;*/
font-size: 48px;
line-height: 50px; line-height: 50px;
padding-bottom: 25px; padding-bottom: 25px;
color: #3a3a3a; color: #3a3a3a;
@ -571,6 +577,138 @@ h6 {
width: 70px; width: 70px;
right: 0; right: 0;
} }
/*Why DCL*/
.full-whydcl-sec {
color: #fff;
text-align: center;
background-image: -ms-linear-gradient(right, #29427A 50%, #4F6699 100%);
background-image: -moz-linear-gradient(right, #29427A 50%, #4F6699 100%);
background-image: -o-linear-gradient(right, #29427A 50%, #4F6699 100%);
background-image: -webkit-gradient(linear, right top, left top, color-stop(50, #29427A), color-stop(100, #4F6699));
background-image: -webkit-linear-gradient(right, #29427A 50%, #4F6699 100%);
background-image: linear-gradient(to left, #29427A 50%, #4F6699 100%);
}
.whydcl-header {
padding: 150px 0 150px 0;
text-align: center;
color: #f8f8f8;
background: url(../img/pattern.jpg) no-repeat center center;
background-size: cover;
position: relative;
background-attachment: fixed;
}
.whydcl-header::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(90, 116, 175,0.85);
/*background: rgba(45,70,122,0.8);*/
}
.single-heading h2 {
font-size: 65px;
margin: 0;
padding: 0;
}
#tech_stack {
background: #fff;
}
#tech_stack h3 {
font-size: 42px;
width: 70%;
}
hr.thick-divider {
border-top: 3px solid #eee !important;
}
.space {
padding: 50px 0;
}
tech-sub-sec h2 {
font-size: 45px;
line-height: 60px;
padding-bottom: 25px;
color: #3a3a3a;
letter-spacing: 1px;
}
.logo-wrap {
text-align: center;
min-height: 140px;
padding: 20px 40px 30px 40px;
}
.btm-space{
padding-bottom: 8px;
}
.percent-text {
font-size: 50px;
color: #999;
}
.tech-sub-sec h2 {
font-size: 40px;
line-height: 55px;
}
.space-middle{
padding: 45px 0;
}
.padding-vertical{
padding: 35px 0;
}
.percent-text img {
margin-left:20px;
}
.space-block {
padding: 30px 0;
}
.dropdown-menu {
border: 1px solid #fff;
-webkit-box-shadow: -8px 13px 31px -8px rgba(77,77,77,1);
-moz-box-shadow: -8px 13px 31px -8px rgba(77,77,77,1);
box-shadow: -8px 13px 31px -8px rgba(77,77,77,1);
display: none;
text-align: center;
border-radius: 4px !important;
padding: 5px !important;
}
.dropdown-menu > li > a:focus, .dropdown-menu > li > a:hover {
background: transparent;
text-decoration: underline !important;
}
.logo-wrap .logo-caption {
padding-top: 20px;
display: inline-block;
color: #999 !important;
}
.lead-light {
color: #999 !important;
line-height: 32px !important;
}
.logo-wrap-1 {
padding-top: 50px;
}
.dropdown-menu > li > a {
padding: 1px 10px !important;
}
.dropdown-menu{
left: 0 !important;
min-width: 155px;
text-align: left;
margin-left: 15px;
}
.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover {
background: transparent;
color: #fff;
}
.dropdown-menu > li > a {
font-size: 13px;
font-weight: 300;
font-family: 'Lato-Regular', sans-serif;
}
.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:focus, .navbar-default .navbar-nav > .active > a:hover {
background: #2D457A;
color: #fff;
border-radius: 6px;
}
/*Pricing page*/ /*Pricing page*/
@ -579,6 +717,7 @@ h6 {
background: -webkit-linear-gradient(top, #f0f4f7, #fff) no-repeat; background: -webkit-linear-gradient(top, #f0f4f7, #fff) no-repeat;
background: linear-gradient(to bottom, #f0f4f7, #fff) no-repeat; background: linear-gradient(to bottom, #f0f4f7, #fff) no-repeat;
display: flex; display: flex;
font-family: 'Lato-Regular', sans-serif;
} }
.price-calc-section .text{ .price-calc-section .text{
width: 50%; width: 50%;
@ -634,6 +773,7 @@ h6 {
padding: 15px 40px; padding: 15px 40px;
} }
.price-calc-section .card .title h3{ .price-calc-section .card .title h3{
font-family: 'Lato-Regular', sans-serif;
} }
.price-calc-section .card .price{ .price-calc-section .card .price{
background: #5A74AF; background: #5A74AF;
@ -646,11 +786,10 @@ h6 {
} }
.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 {
@ -661,10 +800,10 @@ h6 {
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;
@ -701,8 +840,8 @@ h6 {
.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;
@ -711,10 +850,11 @@ h6 {
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;
@ -726,7 +866,74 @@ h6 {
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) {
.percent-text {
font-size: 50px;
}
#tech_stack h3 {
font-size: 30px;
line-height: 40px;
width: 100%;
}
.navbar-nav .open .dropdown-menu {
text-align: left;
font-size: 12px;
}
.visible-mobile {
display:block;
}
.visible-desktop {
display:none !important;
}
.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover {
background: transparent;
color: #777 !important;
}
}
@media screen and (min-device-width: 480px) and (max-device-width: 767px) {
.logo-wrap {
width: 50%;
padding: 15px 30px !important;
min-height: 179px;
}
.logo-wrap-1 {
width: 50%;
padding: 15px 30px !importantx;
min-height: 179px;
}
.landscape-xs-6{
width: 50%;
}
.landscape-xs-8{
width: 66.66666667%;
}
.landscape-xs-4{
width: 33.33333333%;
}
}
@media(min-width:768px) {
.visible-mobile {
display:none !important;
}
.visible-desktop {
display:block;
}
}
@media(max-width:990px) { @media(max-width:990px) {
.pricing-section .text { .pricing-section .text {
text-align: center; text-align: center;
@ -742,6 +949,22 @@ h6 {
} }
@media(max-width:768px) { @media(max-width:768px) {
.percent-text {
font-size: 43px;
}
.tech-sub-sec h2 {
font-size: 30px;
line-height: 40px;
}
.single-heading h2 {
font-size: 50px;
}
.logo-wrap {
padding: 10px;
}
.navbar-transparent li a {
color: #777 !important;
}
.intro-message { .intro-message {
padding-bottom: 15%; padding-bottom: 15%;
} }
@ -783,7 +1006,7 @@ h6 {
display: none; display: none;
} }
.navbar-transparent .navbar-nav>li>a { .navbar-transparent .navbar-nav>li>a {
font-size: 15px; font-size: 14px;
color: #777; color: #777;
} }
.nav-language:hover{ .nav-language:hover{
@ -911,7 +1134,7 @@ h6 {
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;
@ -920,6 +1143,12 @@ h6 {
} }
@media(max-width:540px) { @media(max-width:540px) {
.logo-wrap {
padding: 30px;
}
.percent-text {
text-align: center;
}
.pricing-section .card { .pricing-section .card {
width: 90%; width: 90%;
} }
@ -941,6 +1170,14 @@ h6 {
font-size: 15px; font-size: 15px;
margin-left: 0px; margin-left: 0px;
} }
.pull-left.space-middle {
width: 67%;
padding: 20px 0px;
text-align: left;
}
.pull-left.ssdimg {
width: 30%;
}
} }
@ -984,9 +1221,11 @@ h6 {
margin-top: 15px; margin-top: 15px;
} }
} }
@media(min-width:1200px) {
.container-small{
width:980px;
}
}
footer { footer {
padding: 50px 0; padding: 50px 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -53,6 +53,16 @@
/* --------------------------------------------- /* ---------------------------------------------
Nav panel classic Nav panel classic
--------------------------------------------- */ --------------------------------------------- */
if (window.matchMedia("(min-width: 767px)").matches) {
$('ul.nav li.dropdown').hover(function() {
$(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(500);
}, function() {
$(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(500);
});
} else {
/* the viewport is less than 400 pixels wide */
}
function _initScroll(){ function _initScroll(){
@ -66,9 +76,13 @@
if($(window).scrollTop() > 10 ){ if($(window).scrollTop() > 10 ){
$(".navbar").removeClass("navbar-transparent"); $(".navbar").removeClass("navbar-transparent");
$(".navbar-default .btn-link").css("color", "#777"); $(".navbar-default .btn-link").css("color", "#777");
$(".dropdown-menu").removeClass("navbar-transparent");
$(".dropdown-menu > li > a").css("color", "#777");
}else{ }else{
$(".navbar").addClass("navbar-transparent"); $(".navbar").addClass("navbar-transparent");
$(".navbar-default .btn-link").css("color", "#fff"); $(".navbar-default .btn-link").css("color", "#fff");
$(".dropdown-menu").addClass("navbar-transparent");
$(".dropdown-menu > li > a").css("color", "#fff");
} }
} }
function _initNavUrl(){ function _initNavUrl(){

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

@ -1,67 +1,64 @@
{% load staticfiles i18n%} {% load staticfiles i18n%}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% load custom_tags %} {% load custom_tags %}
<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation"> <nav class="navbar navbar-default navbar-fixed-top topnav">
<div class="topnav"> <div class="topnav">
<!-- Brand and toggle get grouped for better mobile display --> <!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header"> <div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
{% if request.resolver_match.url_name == "index" %} {% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
<a id="logoBlack" class="navbar-brand topnav url" data-url="#home"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a> <a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav url" data-url="#home"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
<a id="logoWhite" class="navbar-brand topnav url" data-url="#home"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a> <a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav url" data-url="#home"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
{% else %} {% else %}
<a id="logoBlack" class="navbar-brand topnav url" href="/datacenterlight"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a> <a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav url"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
<a id="logoWhite" class="navbar-brand topnav url" href="/datacenterlight"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a> <a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav url"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
{% endif %} {% endif %}
</div>
<!-- Collect the nav links, forms, and other content for toggling --> </div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><!-- Start Navbar collapse-->
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
{% if request.resolver_match.url_name == "index" %} {% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
<li> <li class="dropdown">
<a class="url" href="javascript:void(0)" data-url="#how" >{% trans "Highlights" %}</a> <a class="dropdown-toggle visible-mobile" href="#" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Highlights" %}<span class="caret"></span></a>
</li> <a class="dropdown-toggle url disabled visible-desktop" href="{% url 'datacenterlight:index' %}#how" data-url="#how" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Highlights" %}<span class="caret"></span></a>
<li> <ul class="dropdown-menu">
<a class="url" href="javascript:void(0)" data-url="#your" >{% trans "Scale out" %}</a> <li><a class="url" href="{% url 'datacenterlight:index' %}#your" data-url="#your" >{% trans "Scale out" %}</a></li>
</li> <li><a class="url" href="{% url 'datacenterlight:index' %}#our" data-url="#our">{% trans "Reliable and light" %}</a></li>
<li> <li> <a class="url" href="{% url 'datacenterlight:index' %}#price" data-url="#price" >{% trans "Order VM" %}</a></li>
<a class="url" href="javascript:void(0)" data-url="#our">{% trans "Reliable and light" %}</a> </ul>
</li> </li>
<li> <li>
<a class="url" href="javascript:void(0)" data-url="#price" >{% trans "Order VM" %}</a> <a class="url" href="{% url 'datacenterlight:index' %}/whydatacenterlight" >{% trans "Why Data Center Light?" %}</a>
</li> </li>
<li> <li>
<a class="url" href="javascript:void(0)" data-url="#contact" >{% trans "Contact" %}</a> <a class="url" href="{% url 'datacenterlight:index' %}#contact" data-url="#contact" >{% trans "Contact" %}</a>
</li> </li>
{% endif %} {% endif %}
<li class="nav-language"> <li class="nav-language">
<div class="select-language"> <div class="select-language">
{% if LANGUAGE_CODE == 'en-us'%} {% if LANGUAGE_CODE == 'en-us'%}
<span>English</span> <span>English</span>
{% else %} {% else %}
<span>Deutsch</span> <span>Deutsch</span>
{% endif %} {% endif %}
<i class="fa fa-globe" aria-hidden="true"></i> <i class="fa fa-globe" aria-hidden="true"></i>
</div> </div>
<div class="drop-language"> <div class="drop-language">
{% if LANGUAGE_CODE == 'en-us'%} {% if LANGUAGE_CODE == 'en-us'%}
<a class="url" href="{% change_lang 'de' %}">Deutsch</a> <a class="url" href="{% change_lang 'de' %}">Deutsch</a>
{% else %} {% else %}
<a class="url" href="{% change_lang 'en-us' %}" >English</a> <a class="url" href="{% change_lang 'en-us' %}" >English</a>
{% endif %} {% endif %}
</div> </div>
</li> </li>
</ul> </ul>
</div><!-- /.navbar-collapse -->
</div>
</div> </div>
<!-- /.navbar-collapse --> </nav>
</div>
<!-- /.container -->
</nav>

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

@ -0,0 +1,254 @@
{% extends "datacenterlight/base.html" %}
{% load staticfiles i18n%}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<!-- Why Data Center Light? -->
<div class="full-whydcl-sec">
<div class="whydcl-header whydcl-section" id="why_dcl">
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="single-heading">
<h2>{% trans "Why Data Center Light?" %}</h2>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="split-section left" id="tech_stack">
<div class="space">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="split-text">
<div class="split-title">
<h2>{% trans "Tech Stack" %}</h2>
</div>
<div class="split-description">
<h3>{% trans "We are seriously open source." %}</h3>
<p class="lead">{% blocktrans %} Our full software stack is open source We don't use anything that isn't open source. <br>Yes, we are that cool. {% endblocktrans %}</p>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive btm-space" src="{% static 'datacenterlight/img/devuan.png' %}" alt="Devuan">
<span class="logo-caption">{% trans "Our services run on" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive" src="{% static 'datacenterlight/img/prometheus.png' %}" alt="Prometheus">
<span class="logo-caption">{% trans "Our monitoring" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive btm-space" src="{% static 'datacenterlight/img/Ceph_Logo.png' %}" alt="Ceph">
<span class="logo-caption">{% trans "Our storage layer" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive" src="{% static 'datacenterlight/img/django.png' %}" alt="Django">
<span class="logo-caption">{% trans "Our web frontend" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive btm-space" src="{% static 'datacenterlight/img/opennebula.png' %}" alt="Opennebula">
<span class="logo-caption">{% trans "Our cloud" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive" src="{% static 'datacenterlight/img/cdistbyungleich.png' %}" alt="Cdist by ungleich">
<span class="logo-caption">{% trans "Our configuration management system" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive" src="{% static 'datacenterlight/img/python-logo.png' %}" alt="Python">
<span class="logo-caption">{% trans "Our awesome juice" %}</span>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-md-6 logo-wrap">
<img class="img-responsive" src="{% static 'datacenterlight/img/tayga.png' %}" alt="Tayga">
<span class="logo-caption">{% trans "Our NAT64 gateway" %}</span>
</div>
</div>
</div>
</div>
</div>
<!-- /.container -->
<hr class="thick-divider"/><!-- Divider -->
<div class=" space">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-4 col-md-5 ">
<div class="col-xs-12 col-sm-12 col-md-6 col-md-6 logo-wrap-1">
<img class="img-responsive" src="{% static 'datacenterlight/img/opennebula.png' %}" alt="Opennebula">
</div>
<div class="col-xs-12 col-sm-12 col-md-6 col-md-6 logo-wrap-1">
<img class="img-responsive" src="{% static 'datacenterlight/img/cdistbyungleich.png' %}" alt="Cdist byu ngleich">
</div>
<div class="col-xs-12 col-sm-12 col-md-6 col-md-6 logo-wrap-1">
<img class="img-responsive" src="{% static 'datacenterlight/img/prometheus.png' %}" alt="Prometheus">
</div>
</div>
<div class="col-xs-12 col-sm-8 col-md-7 text-right">
<div class="tech-sub-sec">
<h2>{% trans "We believe in giving back to the FOSS community." %}</h2>
<p class="lead">{% blocktrans %}Data Center Light is the child of free and open source software (FOSS). <br>We grew up with it, live by it, and believe in it.<br> The more we work on our data center,<br> the more we contribute back to the FOSS community.{% endblocktrans %}</p>
</div>
</div>
</div>
</div>
</div>
<!-- /.container -->
<hr class="thick-divider"/><!-- Divider -->
<div class="space">
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 tech-sub-sec">
<h2>{% trans "We bring the future to you." %}</h2>
</div>
<div class="col-xs-12 col-sm-7 col-md-8 col-lg-8 text-left tech-sub-sec landscape-xs-6">
<p class="lead">{% blocktrans %} Data Center Light uses the most modern technologies out there.<br>
Your VM needs only IPv6. Data Center Light provides<br> transparent two-way IPv6/IPv4 translation.
{% endblocktrans %}</p>
</div>
<div class="col-xs-12 col-sm-5 col-md-4 col-lg-4 percent-text text-right landscape-xs-6">
100% <strong>IPv6</strong>
</div>
</div>
<div class="col-lg-12 space-block"></div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<div class="col-xs-12 col-sm-7 col-md-8 col-lg-8 percent-text landscape-xs-8">
<span class="pull-left space-middle"> 100% <strong>SSD</strong></span> <span class="pull-left ssdimg"><img class="img-responsive" src="{% static 'datacenterlight/img/ssd.jpg' %}" alt="SSD"></span>
</div>
<div class="col-xs-12 col-sm-5 col-md-4 col-lg-4 text-right tech-sub-sec padding-vertical landscape-xs-4">
<div>
<p class="lead">{% blocktrans %} No more spinning metal plates! Data Center Light uses only SSDs. We keep things faster and lighter. {% endblocktrans %}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /.container -->
</div>
<!-- /.content-section-b -->
<div class="content-section-a pricing-section" id="price">
<div class="container">
<!-- Page Features -->
<div class="row text-center">
<div class="col-xs-12 col-md-6 text">
<h2 class="section-heading">{% trans "Starting from only 15CHF per month. Try now." %}</h2>
<p class="lead">{% trans "Actions speak louder than words. Let's do it, try our VM now." %}</p>
</div>
<div class="col-xs-12 col-md-6 hero-feature">
<div class="price-calc-section no-padding">
<div class="landing card">
<img class="img-beta" src="{% static 'datacenterlight/img/beta-img.png' %}" alt="">
<div class="caption">
<form id="order_form" method="POST" action="" data-toggle="validator" role="form">
{% csrf_token %}
<div class="title">
<h3>{% trans "VM hosting" %} </h3>
</div>
<div class="price">
<span id="total">15</span>
<span>CHF/{% trans "month" %}</span>
<div class="price-text">
<p>{% trans "VAT included" %}</p>
</div>
</div>
<div class="descriptions">
<div class="description form-group">
<p>{% trans "Hosted in Switzerland" %}</p>
</div>
<div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="cpu" aria-hidden="true"></i>
<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>
<i class="fa fa-plus-circle right" data-plus="cpu" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="ram" aria-hidden="true"></i>
<input id="ramValue" class="input-price select-number" type="number" min="2" max="200" name="ram" data-error="{% trans 'Please enter a value greater than or equal to 2.' %}" required>
<span> GB RAM</span>
<i class="fa fa-plus-circle right" data-plus="ram" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<div class="description input">
<i class="fa fa-minus-circle left" data-minus="storage" aria-hidden="true"></i>
<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>
<i class="fa fa-plus-circle right" data-plus="storage" aria-hidden="true"></i>
</div>
<div class="help-block with-errors"></div>
</div>
<div class="description select-configuration input form-group justify-center">
<label for="config">OS</label>
<select name="config" id="">
{% for template in templates %}
<option value="{{template.id}}">{{template.name}} </option>
{% endfor %}
</select>
</div>
<input type="hidden" name="total">
<!--<div class="description check-ip">
<input type="checkbox" name="ipv6"> Ipv6 Only<br>
</div>-->
<div class="form-group">
<div class="description input justify-center">
<label for="name" class="control-label">{% trans "Name"%}</label>
<input type="text" name="name" class="form-control" placeholder="{% trans 'Your Name'%}" data-minlength="3" data-error="{% trans 'Please enter your name' %}" required>
</div>
<div class="help-block with-errors">
{% for message in messages %}
{% 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>
<input type="submit" class="btn btn-primary" value="{% trans 'Order Now!' %}"></input>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- End Why Data Center Light? -->
{% endblock %}

View file

@ -20,3 +20,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

@ -1,16 +1,17 @@
from django.conf.urls import url from django.conf.urls import url
from .views import IndexView, BetaProgramView, LandingProgramView, \ from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView, \
BetaAccessView, PricingView, SuccessView, PaymentOrderView, OrderConfirmationView PaymentOrderView, OrderConfirmationView, WhyDataCenterLightView
urlpatterns = [ urlpatterns = [
url(r'^/?$', IndexView.as_view(), name='index'), url(r'^/?$', IndexView.as_view(), name='index'),
url(r'^/whydatacenterlight/?$', WhyDataCenterLightView.as_view(), name='whydatacenterlight'),
url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'), url(r'^/beta-program/?$', BetaProgramView.as_view(), name='beta'),
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,12 +12,14 @@ 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 hosting.models import HostingOrder from utils.models import BillingAddress
from hosting.models import HostingOrder, HostingBill
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
from datetime import datetime from datetime import datetime
from membership.models import CustomUser, StripeCustomer from membership.models import CustomUser, StripeCustomer
from oca.pool import WrongIdError
from opennebula_api.models import OpenNebulaManager from opennebula_api.models import OpenNebulaManager
from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer from opennebula_api.serializers import VirtualMachineTemplateSerializer, VirtualMachineSerializer
@ -32,9 +34,15 @@ 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'))
elif 'token' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:payment'))
elif 'order_confirmation' not in request.session:
return HttpResponseRedirect(reverse('datacenterlight:order_confirmation'))
else: else:
del request.session['specs'] for session_var in ['specs', 'user', 'template', 'billing_address', 'billing_address_data',
del request.session['user'] '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)
@ -68,7 +76,6 @@ class PricingView(TemplateView):
price = request.POST.get('total') price = request.POST.get('total')
template_id = int(request.POST.get('config')) template_id = int(request.POST.get('config'))
manager = OpenNebulaManager() manager = OpenNebulaManager()
template = manager.get_template(template_id) template = manager.get_template(template_id)
@ -189,15 +196,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,
@ -226,14 +232,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,
@ -301,14 +309,53 @@ class IndexView(CreateView):
return super(IndexView, self).form_valid(form) return super(IndexView, self).form_valid(form)
class WhyDataCenterLightView(IndexView):
template_name = "datacenterlight/whydatacenterlight.html"
model = BetaAccess
@cache_control(no_cache=True, must_revalidate=True, no_store=True)
def get(self, request, *args, **kwargs):
try:
manager = OpenNebulaManager()
templates = manager.get_templates()
context = {
'templates': VirtualMachineTemplateSerializer(templates, many=True).data,
}
except:
messages.error(
request,
'We have a temporary problem to connect to our backend. \
Please try again in a few minutes'
)
context = {
'error': 'connection'
}
return render(request, self.template_name, context)
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
@ -323,13 +370,8 @@ 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:
CustomUser.objects.get(email=user.get('email')) CustomUser.objects.get(email=user.get('email'))
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
@ -350,118 +392,130 @@ 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
# not used
# 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): @cache_control(no_cache=True, must_revalidate=True, no_store=True)
# Get context def get(self, request, *args, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs) if 'specs' not in request.session or 'user' not in request.session:
obj = self.get_object() 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()
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 = {}
context.update({
'paymentError': charge_response.get('error')
})
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
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

@ -56,7 +56,7 @@
ga('send', 'pageview'); ga('send', 'pageview');
</script> </script>
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="{% static 'digitalglarus/img/favicon.ico' %}" type="image/x-icon">
<style id="igtranslator-color" type="text/css"></style> <style id="igtranslator-color" type="text/css"></style>
<style type="text/css"> <style type="text/css">

View file

@ -1 +1 @@
# from .base import * from .base import * # flake8: noqa

View file

@ -20,6 +20,11 @@ def env(env_name):
return os.environ.get(env_name) return os.environ.get(env_name)
def bool_env(val):
"""Replaces string based environment values with Python booleans"""
return True if os.environ.get(val, False) == 'True' else False
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.abspath( PROJECT_DIR = os.path.abspath(
@ -120,6 +125,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',
@ -140,6 +146,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/'),
@ -163,6 +170,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',
], ],
}, },
}, },
@ -188,11 +196,7 @@ CMS_TEMPLATES = (
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'app', 'NAME': 'app'
'HOST': 'localhost',
'USER': 'ubuntu',
'PASSWORD': 'Qwerty123',
} }
} }
@ -475,15 +479,6 @@ REGISTRATION_MESSAGE = {'subject': "Validation mail",
STRIPE_API_PRIVATE_KEY = env('STRIPE_API_PRIVATE_KEY') STRIPE_API_PRIVATE_KEY = env('STRIPE_API_PRIVATE_KEY')
STRIPE_API_PUBLIC_KEY = env('STRIPE_API_PUBLIC_KEY') STRIPE_API_PUBLIC_KEY = env('STRIPE_API_PUBLIC_KEY')
DEBUG = True
# not used
# if DEBUG:
# from .local import *
# # else:
# # from .prod import *
ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch' ANONYMOUS_USER_NAME = 'anonymous@ungleich.ch'
GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance' GUARDIAN_GET_INIT_ANONYMOUS_USER = 'membership.models.get_anonymous_user_instance'
@ -518,3 +513,19 @@ 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'
}
DEBUG = bool_env('DEBUG')
if DEBUG:
from .local import * # flake8: noqa
else:
from .prod import * # flake8: noqa

View file

@ -7,6 +7,13 @@ DEBUG = False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
# MANAGERS = ADMINS # MANAGERS = ADMINS
REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='digitalglarus.ungleich.ch', REGISTRATION_MESSAGE['message'] = REGISTRATION_MESSAGE['message'].format(host='digitalglarus.ungleich.ch',

View file

@ -43,12 +43,11 @@ urlpatterns += i18n_patterns('',
url(r'^blog/', include('ungleich.urls', namespace='ungleich')), url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
url(r'^', include('cms.urls')) url(r'^', include('cms.urls'))
) )
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$',
'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += patterns('',
url(r'^media/(?P<path>.*)$',
'django.views.static.serve', {
'document_root': settings.MEDIA_ROOT,
}),
)
urlpatterns += patterns('', url(r'^__debug__/', include(debug_toolbar.urls))) urlpatterns += patterns('', url(r'^__debug__/', include(debug_toolbar.urls)))

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>

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

@ -561,9 +561,8 @@ class PaymentVMView(LoginRequiredMixin, FormView):
) )
# Create a Hosting Bill # Create a Hosting Bill
# variable bill is not used HostingBill.create(
# bill = HostingBill.create( customer=customer, billing_address=billing_address)
# customer=customer, billing_address=billing_address)
# Create Billing Address for User if he does not have one # Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count(): if not customer.user.billing_addresses.count():

View file

@ -85,3 +85,4 @@ coverage==4.3.4
git+https://github.com/ungleich/python-oca.git#egg=python-oca git+https://github.com/ungleich/python-oca.git#egg=python-oca
djangorestframework djangorestframework
flake8==3.3.0 flake8==3.3.0
python-memcached==1.58

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'):