Merge remote-tracking branch 'ungleich/master' into task/3704/my_settings

This commit is contained in:
Arvind Tiwari 2017-08-30 16:25:24 +05:30
commit 5105b4583e
17 changed files with 455 additions and 97 deletions

View file

@ -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

View file

@ -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())

View file

@ -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."

View 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()),
],
),
]

View 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,
),
]

View 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 = [
]

View 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 = [
]

View file

@ -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)

View file

@ -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 {

View 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

View file

@ -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);

View 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 %}

View file

@ -1,5 +1,5 @@
{% extends "datacenterlight/base.html" %}
{% load staticfiles i18n%}
{% load staticfiles i18n %}
{% block content %}
@ -154,27 +154,29 @@
<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>
<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>
<a target="_blank" class="" href="https://www.facebook.com/ungleich.ch/"><i class="fa fa-facebook"></i></a>
</div>
</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>

View file

@ -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

View file

@ -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'),
]

View file

@ -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()

20
utils/tasks.py Normal file
View file

@ -0,0 +1,20 @@
from celery.utils.log import get_task_logger
from django.conf import settings
from dynamicweb.celery import app
from django.core.mail import EmailMessage
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()