Merged dynamicwebs master into task/3731/cdist_ssh_key_handler
This commit is contained in:
commit
adb75b488c
22 changed files with 642 additions and 166 deletions
|
@ -1,3 +1,8 @@
|
|||
1.1.1: 2017-08-29
|
||||
* #3709: [datacenterlight] Added faq tos cms template
|
||||
* #3657: [datacenterlight] Added a new contact section at landing
|
||||
* #3740: [datacenterlight] Made contact section to send email to info when user submits a message
|
||||
* #3757: [datacenterlight] Added new routes to dcl
|
||||
1.1: 2017-08-24
|
||||
* #3637: [datacenterlight, hosting] Added Stripe error handler
|
||||
* #3695: [hosting] Applied new design for VM list in hosting
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
|
||||
from .models import BetaAccess
|
||||
from .models import BetaAccess, ContactUs
|
||||
|
||||
|
||||
class BetaAccessForm(forms.ModelForm):
|
||||
|
@ -11,6 +11,13 @@ class BetaAccessForm(forms.ModelForm):
|
|||
model = BetaAccess
|
||||
|
||||
|
||||
class ContactForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
fields = ['name', 'email', 'message']
|
||||
model = ContactUs
|
||||
|
||||
|
||||
# class BetaAccessVMForm(forms.ModelForm):
|
||||
# type = forms.CharField(widget=forms.EmailInput())
|
||||
|
||||
|
|
|
@ -82,6 +82,24 @@ msgstr "Bitte gib eine gültige E-Mailadresse ein."
|
|||
msgid "Continue"
|
||||
msgstr "Weiter"
|
||||
|
||||
msgid "Thank you for contacting us."
|
||||
msgstr "Nachricht gesendet."
|
||||
|
||||
msgid "Your message was successfully sent to our team."
|
||||
msgstr "Vielen Dank für Deine Nachricht."
|
||||
|
||||
msgid "Get in touch with us!"
|
||||
msgstr "Sende uns eine Nachricht."
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
msgid "Sorry, there was an unexpected error. Kindly retry."
|
||||
msgstr "Bitte entschuldige, es scheint ein unerwarteter Fehler aufgetreten zu sein. Versuche es doch bitte noch einmal."
|
||||
|
||||
msgid "SUBMIT"
|
||||
msgstr "ABSENDEN"
|
||||
|
||||
msgid "Thank you for your request."
|
||||
msgstr "Vielen Dank für Ihre Anfrage."
|
||||
|
||||
|
@ -234,15 +252,12 @@ msgstr ""
|
|||
msgid "Affordable VM hosting based in Switzerland"
|
||||
msgstr "Bezahlbares VM Hosting in der Schweiz"
|
||||
|
||||
msgid "Contact us"
|
||||
msgstr "Kontaktiere uns"
|
||||
|
||||
msgid "Switzerland "
|
||||
msgstr "Schweiz"
|
||||
|
||||
msgid "Questions?"
|
||||
msgstr "Fragen?"
|
||||
|
||||
msgid "Contact us!"
|
||||
msgstr "Kontaktiere uns!"
|
||||
|
||||
msgid "Confirm Order"
|
||||
msgstr "Bestellung Bestätigen"
|
||||
|
||||
|
@ -412,6 +427,9 @@ msgstr "ist kein gültiger Name"
|
|||
msgid "is not a proper email"
|
||||
msgstr "ist keine gültige E-Mailadresse"
|
||||
|
||||
#~ msgid "Questions?"
|
||||
#~ msgstr "Fragen?"
|
||||
|
||||
#~ msgid "Please enter a value greater than or equal to 1."
|
||||
#~ msgstr "Bitte gib einen Wert größer oder gleich 1 ein."
|
||||
|
||||
|
|
24
datacenterlight/migrations/0007_contactus.py
Normal file
24
datacenterlight/migrations/0007_contactus.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2017-08-19 21:08
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('datacenterlight', '0006_vmtemplate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ContactUs',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=250)),
|
||||
('email', models.CharField(max_length=250)),
|
||||
('message', models.TextField()),
|
||||
],
|
||||
),
|
||||
]
|
23
datacenterlight/migrations/0008_contactus_field.py
Normal file
23
datacenterlight/migrations/0008_contactus_field.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2017-08-23 13:06
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('datacenterlight', '0007_contactus'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='contactus',
|
||||
name='field',
|
||||
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2017, 8, 23, 13, 6, 24, 650869, tzinfo=utc)),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
16
datacenterlight/migrations/0009_merge.py
Normal file
16
datacenterlight/migrations/0009_merge.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2017-08-27 07:55
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('datacenterlight', '0007_contactus'),
|
||||
('datacenterlight', '0008_auto_20170821_2024'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
16
datacenterlight/migrations/0010_merge.py
Normal file
16
datacenterlight/migrations/0010_merge.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2017-08-27 08:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('datacenterlight', '0009_merge'),
|
||||
('datacenterlight', '0008_contactus_field'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
]
|
|
@ -57,7 +57,8 @@ class VMTemplate(models.Model):
|
|||
|
||||
@classmethod
|
||||
def create(cls, name, opennebula_vm_template_id):
|
||||
vm_template = cls(name=name, opennebula_vm_template_id=opennebula_vm_template_id)
|
||||
vm_template = cls(
|
||||
name=name, opennebula_vm_template_id=opennebula_vm_template_id)
|
||||
return vm_template
|
||||
|
||||
|
||||
|
@ -71,3 +72,10 @@ class StripePlan(models.Model):
|
|||
def create(cls, stripe_plan_id):
|
||||
stripe_plan = cls(stripe_plan_id=stripe_plan_id)
|
||||
return stripe_plan
|
||||
|
||||
|
||||
class ContactUs(models.Model):
|
||||
name = models.CharField(max_length=250)
|
||||
email = models.CharField(max_length=250)
|
||||
message = models.TextField()
|
||||
field = models.DateTimeField(auto_now_add=True)
|
||||
|
|
47
datacenterlight/static/datacenterlight/css/cms.css
Normal file
47
datacenterlight/static/datacenterlight/css/cms.css
Normal file
|
@ -0,0 +1,47 @@
|
|||
.dcl-cms_page-full-width {
|
||||
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%);
|
||||
}
|
||||
|
||||
.dcl-cms_page-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;
|
||||
}
|
||||
|
||||
.dcl-cms_page-header::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(90, 116, 175, 0.85);
|
||||
}
|
||||
|
||||
#dcl-cms_page-text {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#dcl-cms_page-text h3 {
|
||||
font-size: 42px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
#dcl-cms_page-text h3 {
|
||||
font-size: 30px;
|
||||
line-height: 40px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -323,9 +323,9 @@ button, input, optgroup, select, textarea {
|
|||
padding-top: 50px;
|
||||
/* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */
|
||||
padding-bottom: 50px;
|
||||
text-align: center;
|
||||
/* text-align: center; */
|
||||
color: #f8f8f8;
|
||||
background: url(../img/banner-bg.jpg) no-repeat center center;
|
||||
background: url(../img/pattern.jpg) no-repeat center center;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
}
|
||||
|
@ -654,74 +654,161 @@ button, input, optgroup, select, textarea {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.full-contact-section {
|
||||
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%);
|
||||
}
|
||||
|
||||
.contact-section {
|
||||
padding: 60px 0;
|
||||
color: #fff;
|
||||
padding: 80px 0;
|
||||
color: rgba(255,255,255,0.9);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
.contact-section .card {
|
||||
text-align: center;
|
||||
width: 350px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
|
||||
padding-bottom: 40px;
|
||||
border-radius: 7px;
|
||||
color: #4c4444;
|
||||
box-sizing: border-box;
|
||||
padding: 45px;
|
||||
margin-top: -115px;
|
||||
.contact-section .modal {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.contact-section .card .social a {
|
||||
color: #29427A;
|
||||
.contact-details {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.contact-section .description{
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.contact-section .social a {
|
||||
color: #fff;
|
||||
font-size: 45px;
|
||||
}
|
||||
|
||||
.contact-section .card .subtitle h3 {
|
||||
font-size: 30px;
|
||||
margin-bottom: 23px;
|
||||
.contact-section .social .fa-facebook {
|
||||
font-size: 40px;
|
||||
background: #fff;
|
||||
border-radius: 100%;
|
||||
color: #425d89;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
top: -2px;
|
||||
position: relative;
|
||||
left: 10px;
|
||||
}
|
||||
.contact-section .social .fa-facebook:before {
|
||||
font-size: 32px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
left: -1px;
|
||||
}
|
||||
|
||||
.contact-section .card .social a:hover {
|
||||
.contact-section .social a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.contact-section .title {
|
||||
margin-right: auto;
|
||||
width: 80%;
|
||||
max-width: 468px;
|
||||
.contact-section .subtitle h3 {
|
||||
font-size: 30px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.contact-section .contact-form-success {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
padding: 0 15px 35px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.contact-section .title h2 {
|
||||
font-size: 65px;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
padding-bottom: 25px;
|
||||
position: relative;
|
||||
text-align: right;
|
||||
/* color: #eee;
|
||||
padding-bottom: 25px;
|
||||
text-align: right; */
|
||||
}
|
||||
|
||||
.contact-section .title h2::before {
|
||||
content: "";
|
||||
.contact-form .form-group {
|
||||
border: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.contact-form .form-group label {
|
||||
letter-spacing: 0.6px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.contact-form .btn {
|
||||
min-width: 140px;
|
||||
background: rgba(23, 23, 23, 0.18);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
border-width: 2px;
|
||||
box-shadow: none;
|
||||
letter-spacing: 2px;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.contact-form .btn.sending {
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
@keyframes sending {
|
||||
0% {content: '.';}
|
||||
50% {content: '..';}
|
||||
100% {content: '...';}
|
||||
}
|
||||
|
||||
.contact-form .btn.sending:after {
|
||||
content: '.';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
height: 7px;
|
||||
width: 70px;
|
||||
right: 0;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
margin-left: 5px;
|
||||
width: 20px;
|
||||
animation: sending 1s linear infinite;
|
||||
}
|
||||
|
||||
.contact-form .btn:hover,
|
||||
.contact-form .btn:focus {
|
||||
background: rgba(23, 23, 23, 0.28);
|
||||
border-color: #fff;
|
||||
box-shadow: none;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.contact-form .form-control {
|
||||
box-shadow: none;
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.contact-form .errorlist {
|
||||
list-style: none;
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
color: rgb(255, 164, 164);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.4px;
|
||||
}
|
||||
|
||||
.contact-form .form-error {
|
||||
background: rgba(255,255,255,0.9);
|
||||
color: #eb4d5c;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.contact-form .has-error label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.contact-form .has-error .form-control {
|
||||
border: 2px solid #e8534b;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.contact-form .subtitle {
|
||||
padding: 22px 0 15px;
|
||||
}
|
||||
|
||||
.contact-form textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
/*Why DCL*/
|
||||
|
||||
|
@ -1311,9 +1398,9 @@ tech-sub-sec h2 {
|
|||
margin: 0 auto;
|
||||
}
|
||||
.contact-section .title h2 {
|
||||
font-size: 35px;
|
||||
font-size: 45px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
/* text-align: center; */
|
||||
margin-top: 35px;
|
||||
}
|
||||
.contact-section .title h2::before {
|
||||
|
|
11
datacenterlight/static/datacenterlight/img/facebook_logo.svg
Normal file
11
datacenterlight/static/datacenterlight/img/facebook_logo.svg
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="57px" height="66px" viewBox="0 0 57 66" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Slice 20</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="contact-us" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<ellipse id="Oval-2" fill="#FFFFFF" cx="28.7865939" cy="33.4691264" rx="19.7865939" ry="19.4691264"></ellipse>
|
||||
<path d="M35.3784886,34.6387051 L30.2336176,34.6387051 L30.2336176,50.2467762 L22.6226844,50.2467762 L22.6226844,34.6387051 L19,34.6387051 L19,29.1194625 L22.6226844,29.1194625 L22.6226844,25.5403791 C22.6226844,22.9849851 24.0459888,19 30.3115248,19 L35.9567996,19.0178699 L35.9567996,24.3762836 L31.8546864,24.3762836 C31.1894789,24.3762836 30.2426069,24.6596489 30.2426069,25.8824599 L30.2426069,29.1194625 L36.0436961,29.1194625 L35.3784886,34.6387051 Z" id="Shape" fill="#5E79AD" fill-rule="nonzero"></path>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -39,7 +39,7 @@
|
|||
_initScroll();
|
||||
_initNavUrl();
|
||||
_initPricing();
|
||||
|
||||
ajaxForms();
|
||||
});
|
||||
|
||||
$(window).resize(function() {
|
||||
|
@ -157,4 +157,27 @@
|
|||
$('#valueTotal').text(numbers * price * 31);
|
||||
}
|
||||
|
||||
function ajaxForms() {
|
||||
$('body').on('submit', '.ajax-form', function(e){
|
||||
e.preventDefault();
|
||||
var $form = $(this);
|
||||
$form.find('[type=submit]').addClass('sending');
|
||||
$.ajax({
|
||||
url: $form.attr('action'),
|
||||
type: $form.attr('method'),
|
||||
data: $form.serialize(),
|
||||
|
||||
success: function(response) {
|
||||
var responseContain = $($form.attr('data-response'));
|
||||
responseContain.html(response);
|
||||
$form.find('[type=submit]').removeClass('sending');
|
||||
},
|
||||
|
||||
error: function() {
|
||||
$form.find('[type=submit]').removeClass('sending');
|
||||
$form.find('.form-error').removeClass('hide');
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
})(jQuery);
|
|
@ -1,4 +1,4 @@
|
|||
{% load staticfiles i18n%}
|
||||
{% load staticfiles i18n cms_tags sekizai_tags %}
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{LANGUAGE_CODE}}">
|
||||
|
@ -33,13 +33,15 @@
|
|||
<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>
|
||||
<![endif]-->
|
||||
{% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %}
|
||||
{% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %}
|
||||
<!-- Google analytics -->
|
||||
{% include "google_analytics.html" %}
|
||||
<!-- End Google Analytics -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{% cms_toolbar %}
|
||||
<!-- Navigation -->
|
||||
{% include "datacenterlight/includes/_navbar.html" %}
|
||||
|
||||
|
|
33
datacenterlight/templates/datacenterlight/cms_page.html
Normal file
33
datacenterlight/templates/datacenterlight/cms_page.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "datacenterlight/base.html" %}
|
||||
{% load staticfiles cms_tags sekizai_tags %}
|
||||
{% block content %}
|
||||
{% addtoblock "css" %}
|
||||
<link href="{% static 'datacenterlight/css/cms.css' %}" media="screen" rel="stylesheet" type="text/css"/>
|
||||
{% endaddtoblock %}
|
||||
|
||||
<div class="dcl-cms_page-full-width">
|
||||
<div class="dcl-cms_page-header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="single-heading">
|
||||
<h2>{% placeholder 'datacenterlight_cms_page_title' %}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-section left" id="dcl-cms_page-text">
|
||||
<div class="space">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% placeholder 'datacenterlight_cms_page_text' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
50
datacenterlight/templates/datacenterlight/contact_form.html
Normal file
50
datacenterlight/templates/datacenterlight/contact_form.html
Normal file
|
@ -0,0 +1,50 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% if success %}
|
||||
<div class="contact-form-success">
|
||||
<div class="subtitle text-center">
|
||||
<h3>{% trans "Thank you for contacting us." %}</h3>
|
||||
</div>
|
||||
<p>
|
||||
{% trans "Your message was successfully sent to our team." %}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col-sm-offset-2 col-sm-10">
|
||||
<div class="subtitle">
|
||||
<h3>{% trans "Get in touch with us!" %}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form class="form-horizontal ajax-form" method="POST" action="{% url 'datacenterlight:contact_us' %}" data-toggle="validator" data-response="#contact-form">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="name">{% trans "Name" %}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="name" class="form-control" data-minlength="3" data-error="{% trans 'Please enter your name.' %}" required>
|
||||
{{contact_form.name.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="email">{% trans "Email" %}</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="email" type="email" pattern="^[^@\s]+@([^@\s]+\.)+[^@\s]+$" class="form-control" data-error="{% trans 'Please enter a valid email address.' %}" required>
|
||||
{{contact_form.email.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="message">{% trans "Message" %}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" name="message" id="message" rows="6" required></textarea>
|
||||
{{contact_form.message.errors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-10 text-right">
|
||||
<div class="form-error hide">{% trans "Sorry, there was an unexpected error. Kindly retry." %}</div>
|
||||
<button type="submit" class="btn btn-default">{% trans "SUBMIT" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
|
@ -1,74 +1,113 @@
|
|||
{% load staticfiles i18n%} {% get_current_language as LANGUAGE_CODE %} {% load custom_tags %}
|
||||
<nav class="navbar navbar-default navbar-fixed-top topnav">
|
||||
<div class="topnav">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<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="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
{% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav" data-url="#home"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav" data-url="#home"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
|
||||
<div class="topnav">
|
||||
<!-- Brand and toggle get grouped for better mobile display -->
|
||||
<div class="navbar-header">
|
||||
<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="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
{% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav" data-url="#home"><img
|
||||
src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav" data-url="#home"><img
|
||||
src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
|
||||
{% else %}
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav"><img
|
||||
src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav"><img
|
||||
src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><!-- Start Navbar collapse-->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
|
||||
<li class="dropdown">
|
||||
<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>
|
||||
<a class="dropdown-toggle url disabled visible-desktop menu-url" data-url="#how"
|
||||
data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Highlights" %}
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="url menu-url" data-url="#your" href="#your">{% trans "Scale out" %}</a></li>
|
||||
<li><a class="url menu-url" data-url="#our" href="#our">{% trans "Reliable and light" %}</a>
|
||||
</li>
|
||||
<li><a class="url menu-url" data-url="#price" href="#price">{% trans "Order VM" %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'datacenterlight:whydatacenterlight' %}">{% trans "Why Data Center Light?" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="url" href="{% url 'datacenterlight:index' %}#contact" data-url="#contact">{% trans "Contact" %}</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoBlack" class="navbar-brand topnav"><img src="{% static 'datacenterlight/img/logo_black.svg' %}"></a>
|
||||
<a href="{% url 'datacenterlight:index' %}" id="logoWhite" class="navbar-brand topnav"><img src="{% static 'datacenterlight/img/logo_white.svg' %}"></a>
|
||||
<li class="dropdown">
|
||||
<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>
|
||||
<a class="dropdown-toggle url disabled visible-desktop menu-url" data-url="#how"
|
||||
data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Highlights" %}
|
||||
<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="url menu-url" data-url="#your"
|
||||
href="{% url 'datacenterlight:whydatacenterlight' %}#your">{% trans "Scale out" %}</a>
|
||||
</li>
|
||||
<li><a class="url menu-url" data-url="#our"
|
||||
href="{% url 'datacenterlight:whydatacenterlight' %}#our">{% trans "Reliable and light" %}
|
||||
</a></li>
|
||||
<li><a class="url menu-url" data-url="#price"
|
||||
href="{% url 'datacenterlight:whydatacenterlight' %}#price">{% trans "Order VM" %}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'datacenterlight:whydatacenterlight' %}">{% trans "Why Data Center Light?" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="url" href="{% url 'datacenterlight:index' %}#contact" data-url="#contact">{% trans "Contact" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><!-- Start Navbar collapse-->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if request.resolver_match.url_name == "index" or request.resolver_match.url_name == "whydatacenterlight" %}
|
||||
<li class="dropdown">
|
||||
<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>
|
||||
<a class="dropdown-toggle url disabled visible-desktop menu-url" data-url="#how" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Highlights" %}<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="url menu-url" data-url="#your" href="#your">{% trans "Scale out" %}</a></li>
|
||||
<li><a class="url menu-url" data-url="#our" href="#our">{% trans "Reliable and light" %}</a></li>
|
||||
<li> <a class="url menu-url" data-url="#price" href="#price">{% trans "Order VM" %}</a></li>
|
||||
<li>
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<a class="on-hover-border" href="{% change_lang 'de' %}">Deutsch <i class="fa fa-globe"
|
||||
aria-hidden="true"></i></a>
|
||||
{% else %}
|
||||
<a class="on-hover-border" href="{% change_lang 'en-us' %}">English <i
|
||||
class="fa fa-globe" aria-hidden="true"></i></a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% comment %}
|
||||
<!-- to be used when more than one option for language -->
|
||||
<li class="nav-language">
|
||||
<div class="dropdown">
|
||||
<div class="dropdown-toggle select-language" data-toggle="dropdown" role="button"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<span>English</span>
|
||||
{% else %}
|
||||
<span>Deutsch</span>
|
||||
{% endif %}
|
||||
<i class="fa fa-globe" aria-hidden="true"></i>
|
||||
</div>
|
||||
<ul class="dropdown-menu drop-language dropdown-menu-right">
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<li><a class="url" href="{% change_lang 'de' %}">Deutsch</a></li>
|
||||
{% else %}
|
||||
<li><a class="url" href="{% change_lang 'en-us' %}">English</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
{% endcomment %}
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'datacenterlight:whydatacenterlight' %}" >{% trans "Why Data Center Light?" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="url" href="{% url 'datacenterlight:index' %}#contact" data-url="#contact" >{% trans "Contact" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li>
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<a class="on-hover-border" href="{% change_lang 'de' %}">Deutsch <i class="fa fa-globe" aria-hidden="true"></i></a>
|
||||
{% else %}
|
||||
<a class="on-hover-border" href="{% change_lang 'en-us' %}">English <i class="fa fa-globe" aria-hidden="true"></i></a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% comment %}
|
||||
<!-- to be used when more than one option for language -->
|
||||
<li class="nav-language">
|
||||
<div class="dropdown">
|
||||
<div class="dropdown-toggle select-language" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<span>English</span>
|
||||
{% else %}
|
||||
<span>Deutsch</span>
|
||||
{% endif %}
|
||||
<i class="fa fa-globe" aria-hidden="true"></i>
|
||||
</div>
|
||||
<ul class="dropdown-menu drop-language dropdown-menu-right">
|
||||
{% if LANGUAGE_CODE == 'en-us'%}
|
||||
<li><a class="url" href="{% change_lang 'de' %}">Deutsch</a></li>
|
||||
{% else %}
|
||||
<li><a class="url" href="{% change_lang 'en-us' %}">English</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
{% endcomment %}
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /.navbar-collapse -->
|
||||
</div>
|
||||
<!-- /.navbar-collapse -->
|
||||
</div>
|
||||
</nav>
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "datacenterlight/base.html" %}
|
||||
{% load staticfiles i18n%}
|
||||
{% load staticfiles i18n %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
@ -149,32 +149,34 @@
|
|||
|
||||
</div>
|
||||
|
||||
<!-- / contact section -->
|
||||
<!-- / contact section -->
|
||||
<div class="full-contact-section">
|
||||
<div class="intro-header-2 contact-section" id="contact">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="card">
|
||||
<div class="col-sm-6">
|
||||
<div class="title">
|
||||
<h2>{% trans "Contact us" %}</h2>
|
||||
</div>
|
||||
<div class="contact-details">
|
||||
<div class="subtitle">
|
||||
<h3>ungleich GmbH </h3>
|
||||
<h3>ungleich GmbH</h3>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p><i class="fa fa-envelope-o"></i> info@datacenterlight.ch</p>
|
||||
<p>info@datacenterlight.ch</p>
|
||||
<p>In der Au 7, Schwanden 8762</p>
|
||||
<p>{% trans "Switzerland " %}</p>
|
||||
</div>
|
||||
<div class="social">
|
||||
<a target="_blank" class="" href="https://twitter.com/datacenterlight"><i class="fa fa-twitter fa-fw"></i></a>
|
||||
<a target="_blank" class="" href="https://github.com/ungleich"><i class="fa fa-github fa-fw"></i></a>
|
||||
<a target="_blank" class="" href="https://www.facebook.com/ungleich.ch/"><i class="fa fa-facebook fa-fw"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="social">
|
||||
<a target="_blank" class="" href="https://twitter.com/datacenterlight"><i class="fa fa-twitter fa-fw"></i></a>
|
||||
<a target="_blank" class="" href="https://github.com/ungleich"><i class="fa fa-github fa-fw"></i></a>
|
||||
<a target="_blank" class="" href="https://www.facebook.com/ungleich.ch/"><i class="fa fa-facebook"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="title">
|
||||
<h2>{% trans "Questions?" %} {% trans "Contact us!" %}</h2>
|
||||
<div class="col-sm-6">
|
||||
<div id="contact-form" class="contact-form">
|
||||
{% include "datacenterlight/contact_form.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,10 +6,8 @@ import stripe
|
|||
from celery.result import AsyncResult
|
||||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
# Create your tests here.
|
||||
from django.test import TestCase, override_settings
|
||||
from model_mommy import mommy
|
||||
|
||||
from datacenterlight.models import VMTemplate
|
||||
from datacenterlight.tasks import create_vm_task
|
||||
from membership.models import StripeCustomer
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import IndexView, BetaProgramView, LandingProgramView, BetaAccessView, PricingView, SuccessView, \
|
||||
PaymentOrderView, OrderConfirmationView, WhyDataCenterLightView
|
||||
|
||||
from .views import IndexView, BetaProgramView, LandingProgramView, \
|
||||
BetaAccessView, PricingView, SuccessView, \
|
||||
PaymentOrderView, OrderConfirmationView, \
|
||||
WhyDataCenterLightView, ContactUsView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', IndexView.as_view(), name='index'),
|
||||
url(r'^whydatacenterlight/?$', WhyDataCenterLightView.as_view(), name='whydatacenterlight'),
|
||||
url(r'^t$', IndexView.as_view(), name='index_t'),
|
||||
url(r'^g$', IndexView.as_view(), name='index_g'),
|
||||
url(r'^f$', IndexView.as_view(), name='index_f'),
|
||||
url(r'^whydatacenterlight/?$', WhyDataCenterLightView.as_view(),
|
||||
name='whydatacenterlight'),
|
||||
url(r'^beta-program/?$', BetaProgramView.as_view(), name='beta'),
|
||||
url(r'^landing/?$', LandingProgramView.as_view(), name='landing'),
|
||||
url(r'^pricing/?$', PricingView.as_view(), name='pricing'),
|
||||
url(r'^payment/?$', PaymentOrderView.as_view(), name='payment'),
|
||||
url(r'^order-confirmation/?$', 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'^beta_access?$', BetaAccessView.as_view(), name='beta_access'),
|
||||
url(r'^contact/?$', ContactUsView.as_view(), name='contact_us'),
|
||||
]
|
||||
|
|
|
@ -1,26 +1,67 @@
|
|||
from django.views.generic import FormView, CreateView, TemplateView, DetailView
|
||||
from django.http import HttpResponseRedirect
|
||||
from .forms import BetaAccessForm
|
||||
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM, VMTemplate
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from utils.mailer import BaseEmail
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import redirect
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import redirect
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from utils.forms import BillingAddressForm
|
||||
from utils.models import BillingAddress
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.views.generic import FormView, CreateView, TemplateView, DetailView
|
||||
|
||||
from datacenterlight.tasks import create_vm_task
|
||||
from hosting.models import HostingOrder
|
||||
from utils.stripe_utils import StripeUtils
|
||||
from membership.models import CustomUser, StripeCustomer
|
||||
from opennebula_api.models import OpenNebulaManager
|
||||
from opennebula_api.serializers import VirtualMachineTemplateSerializer, \
|
||||
VMTemplateSerializer
|
||||
from datacenterlight.tasks import create_vm_task
|
||||
from utils.forms import BillingAddressForm
|
||||
from utils.mailer import BaseEmail
|
||||
from utils.stripe_utils import StripeUtils
|
||||
from utils.tasks import send_plain_email_task
|
||||
from .forms import BetaAccessForm, ContactForm
|
||||
from .models import BetaAccess, BetaAccessVMType, BetaAccessVM, VMTemplate
|
||||
|
||||
|
||||
class ContactUsView(FormView):
|
||||
template_name = "datacenterlight/contact_form.html"
|
||||
form_class = ContactForm
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return HttpResponseRedirect(reverse('datacenterlight:index'))
|
||||
|
||||
def form_invalid(self, form):
|
||||
if self.request.is_ajax():
|
||||
return self.render_to_response(
|
||||
self.get_context_data(contact_form=form))
|
||||
else:
|
||||
return render(self.request,
|
||||
'datacenterlight/index.html',
|
||||
self.get_context_data(contact_form=form))
|
||||
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
email_data = {
|
||||
'subject': "{dcl_text} Message from {sender}".format(
|
||||
dcl_text=settings.DCL_TEXT,
|
||||
sender=form.cleaned_data.get('email')
|
||||
),
|
||||
'from_email': settings.DCL_SUPPORT_FROM_ADDRESS,
|
||||
'to': ['info@ungleich.ch'],
|
||||
'body': "\n".join(
|
||||
["%s=%s" % (k, v) for (k, v) in form.cleaned_data.items()]),
|
||||
'reply_to': [form.cleaned_data.get('email')],
|
||||
}
|
||||
send_plain_email_task.delay(email_data)
|
||||
if self.request.is_ajax():
|
||||
return self.render_to_response(
|
||||
self.get_context_data(success=True, contact_form=form))
|
||||
else:
|
||||
return render(self.request,
|
||||
'datacenterlight/index.html',
|
||||
self.get_context_data(success=True,
|
||||
contact_form=form))
|
||||
|
||||
|
||||
class LandingProgramView(TemplateView):
|
||||
|
@ -315,7 +356,8 @@ class IndexView(CreateView):
|
|||
context = super(IndexView, self).get_context_data(**kwargs)
|
||||
context.update({
|
||||
'base_url': "{0}://{1}".format(self.request.scheme,
|
||||
self.request.get_host())
|
||||
self.request.get_host()),
|
||||
'contact_form': ContactForm
|
||||
})
|
||||
return context
|
||||
|
||||
|
@ -419,7 +461,8 @@ class PaymentOrderView(FormView):
|
|||
token=token)
|
||||
if not customer:
|
||||
form.add_error("__all__", "Invalid credit card")
|
||||
return self.render_to_response(self.get_context_data(form=form))
|
||||
return self.render_to_response(
|
||||
self.get_context_data(form=form))
|
||||
|
||||
# Create Billing Address
|
||||
billing_address = form.save()
|
||||
|
|
|
@ -213,6 +213,8 @@ CMS_TEMPLATES = (
|
|||
# ungleich
|
||||
('blog_ungleich.html', gettext('Blog')),
|
||||
('page.html', gettext('Page')),
|
||||
# dcl
|
||||
('datacenterlight/cms_page.html', gettext('Data Center Light')),
|
||||
)
|
||||
|
||||
DATABASES = {
|
||||
|
|
|
@ -3,12 +3,27 @@ import tempfile
|
|||
from cdist.integration import configure_hosts_simple
|
||||
from celery.utils.log import get_task_logger
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMessage
|
||||
|
||||
from dynamicweb.celery import app
|
||||
|
||||
logger = get_task_logger(__name__)
|
||||
|
||||
|
||||
@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES)
|
||||
def send_plain_email_task(self, email_data):
|
||||
"""
|
||||
This is a generic celery task to be used for sending emails.
|
||||
A celery wrapper task for EmailMessage
|
||||
|
||||
:param self:
|
||||
:param email_data: A dict of all needed email headers
|
||||
:return:
|
||||
"""
|
||||
email = EmailMessage(**email_data)
|
||||
email.send()
|
||||
|
||||
|
||||
@app.task(bind=True, max_retries=settings.CELERY_MAX_RETRIES)
|
||||
def save_ssh_key(self, hosts, keys):
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue