Merge branch 'master' into task/3774/update_stripe_subscription_on_vm_delete

This commit is contained in:
PCoder 2017-12-12 20:23:25 +01:00
commit 1306dbe46a
158 changed files with 4279 additions and 2015 deletions

View file

@ -1,13 +1,14 @@
language: python language: python
python: python:
- "3.5" - "3.4.2"
- "3.6" # - "3.6"
env: env:
# Set a dummy secret key - DJANGO_SECRET_KEY=0 OPENNEBULA_USERNAME='test' OPENNEBULA_PASSWORD='test' OPENNEBULA_PROTOCOL='http' OPENNEBULA_DOMAIN='test_domain' OPENNEBULA_PORT='2633' OPENNEBULA_ENDPOINT='/RPC2' DCL_TEXT='Data Center Light' CELERY_MAX_RETRIES=0
- DJANGO_SECRET_KEY=0
# install dependencies # install dependencies
install: "pip install -r requirements.txt" install: "pip install -r requirements.txt"
script: script:
- flake8 - flake8
- python manage.py test - python manage.py test -v 3
# - coverage run --source='.' manage.py test dynamicweb -v 3
# - coverage report

View file

@ -1,5 +1,36 @@
Next release: 1.2.13: 2017-12-09
* [cms] Introduce UngleichHeaderBackgroundImageAndTextSliderPlugin that allows to have scrolling images and texts
* [cms] Remove <p> tag for ungleich cms customer item template
1.2.12: 2017-12-09
* #3594: [digitalglarus] Remove white scroll bar on the right in mobile
* #3905: [ungleich] Update ungleich.ch header into a slider
* [all] Enable logging custom modules
1.2.11: 2017-11-30
* [all] TravisCI: Test against python 3.4.2 only
* [ungleich] Remove data-replaced image in ungleich CMS services item plugin template
1.2.10: 2017-11-26
* #3843: [ungleich] Add generic ungleich CMS template
* #3672: [all] Clean existing automated tests
1.2.9: 2017-11-13
* #3848: [ungleich] Optimize ungleich.ch landing page
* #3360: [ungleich] Ungleich.ch landing page animation fix
* #3421: [hosting] Signup form placeholder translations
* #3856: [ungleich] Glasfaser text modified
* bugfix: [blog] Redirect user to ungleich home on ungleich logo click
* #3858: [dcl] Change "affordable vm ..." text to "Ready in 30 seconds ..."
1.2.8: 2017-10-21
* Remove ALLOWED_HOST alplora.ch
* Add ALLOWED_HOST hack4glarus.ch
* Fetch page_title and meta_description dynamically in glasfaser CMS template
1.2.7: 2017-10-20
* Bugfix: [dcl, hosting] Fix Stripe js error in confirm payment page * Bugfix: [dcl, hosting] Fix Stripe js error in confirm payment page
* #3847: [ungleich] change text 'hosting products' -> 'our products'
* #3829: [dcl] Handle landing login fail in payment page itself
* #3794: [dcl, hosting] Update email styles
* #3828: [dcl, hosting] invoice period set to show monthly subscription
* #3838: [hosting] restyle signup/login/password reset/password pages
* Bugfix: [dg] Remove validate email link in the registration email
* Feature: [ungleich_page] Add new glasfaser CMS template
1.2.6: 2017-10-10 1.2.6: 2017-10-10
* Bugfix: [dcl] Refactor and optimize images, links in glasfaser page * Bugfix: [dcl] Refactor and optimize images, links in glasfaser page
* Bugfix: [dcl] Fix email not being sent issue * Bugfix: [dcl] Fix email not being sent issue
@ -8,7 +39,6 @@ Next release:
* Bugfix: [hosting] card details input form alignment fix * Bugfix: [hosting] card details input form alignment fix
* #3823: [hosting] favicon link fixed * #3823: [hosting] favicon link fixed
* #3844: [dcl] Add Glasfaser page for advertisement * #3844: [dcl] Add Glasfaser page for advertisement
1.2.4: 2017-10-02 1.2.4: 2017-10-02
* #3780: [hosting] Store VM details locally * #3780: [hosting] Store VM details locally
* #3764: [hosting] Show cancelled VMs' invoices * #3764: [hosting] Show cancelled VMs' invoices

View file

@ -3,6 +3,10 @@ ungleich
dynamicweb dynamicweb
---------- ----------
.. image:: https://travis-ci.org/ungleich/dynamicweb.svg?branch=master
:target: https://travis-ci.org/ungleich/dynamicweb
Website for ungleich GmbH Website for ungleich GmbH
======= =======

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-10-10 21:35+0530\n" "POT-Creation-Date: 2017-11-13 17:59+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -126,56 +126,57 @@ msgstr ""
msgid "Thank you!" msgid "Thank you!"
msgstr "Vielen Dank!" msgstr "Vielen Dank!"
msgid "Account Activation" msgid "Data Center Light Account Activation"
msgstr "Account Aktivierung" msgstr "Data Center Light Account Aktivierung"
#, python-format #, python-format
msgid "" msgid ""
"\n" "You can activate your Data Center Light account by clicking <a href="
"You can activate your Data Center Light account by <a href=\"%(base_url)s" "\"%(base_url)s%(activation_link)s\" style=\"text-decoration: none; color: "
"%(activation_link)s\">clicking here</a>.<br/>\n" "#4382c8; font-weight: 400;\">here</a>."
msgstr ""
"Klicke <a href=\"%(base_url)s%(activation_link)s\"style=\"text-decoration: "
"none; color: #4382c8; font-weight: 400;\">here</a> um deinen Data Center "
"Light Account zu aktivieren."
msgid ""
"You can also copy and paste the following link into the address bar of your " "You can also copy and paste the following link into the address bar of your "
"browser<br/>\n" "browser to activate your Data Center Light account."
"to activate your Data Center Light account.<br/>\n" msgstr "Kopiere den folgenden Link in die Adressleiste deines Browsers."
"%(base_url)s%(activation_link)s\n"
msgstr ""
"\n"
"<a href=\"%(base_url)s%(activation_link)s\">Klicke hier</a> um deinen Data "
"Center Light Account zu aktivieren oder kopiere den folgenden Link in die "
"Adressleiste deines Browsers.<br/>\n"
"%(base_url)s%(activation_link)s\n"
#, python-format msgid "Your account details are as follows"
msgid "" msgstr "Deine Account Details sind unten aufgelistet"
"Your account details are as follows:<br/><br/>\n"
"Username : Your email address<br/>\n"
"Password : %(account_details)s<br/><br/>\n"
"You can reset your password here:\n"
"%(base_url)s%(reset_password_url)s\n"
msgstr ""
#, python-format msgid "Username"
msgid "" msgstr "Username"
"You can activate your Data Center Light account by clicking here.\n"
"You can also copy and paste the following link into the address bar of your " msgid "Your email address"
"browser\n" msgstr "Deine E-Mail-Adresse"
"to activate your Data Center Light account.\n"
"%(base_url)s%(activation_link)s\n" msgid "Password"
msgstr "" msgstr "Passwort"
"Klicke hier, um deinen Data Center Light Account zu aktivieren oder kopiere "
"den folgenden Link in die Adressleiste deines Browsers.\n" msgid "You can reset your password here"
"%(base_url)s%(activation_link)s\n" msgstr "Du kannst dein Passwort hier zurück setzen"
#, python-format
msgid "" msgid ""
"Your account details are as follows:\n" "You can copy and paste the following link into the address bar of your "
"\n" "browser to activate your Data Center Light account."
"Username : Your email address\n" msgstr "Kopiere den folgenden Link in die Adressleiste deines Browsers."
"Password : %(account_details)s\n"
"\n" msgid "Welcome to Data Center Light!"
"You can reset your password here:\n" msgstr "Willkommen beim Data Center Light!"
"%(base_url)s%(reset_password_url)s\n"
msgstr "" msgid ""
"Thanks for joining us! We provide the most affordable virtual machines from "
"the heart of Switzerland."
msgstr "Bei uns findest Du die günstiges VMs aus der Schweiz."
msgid "Try now, order a VM. VM price starts from only 15CHF per month."
msgstr "Unser Angebot beginnt bei 15 CHF pro Monat. Probier's jetzt aus!"
msgid "ORDER VM"
msgstr "VM BESTELLEN"
msgid "Home" msgid "Home"
msgstr "Home" msgstr "Home"
@ -269,8 +270,12 @@ msgstr ""
"Einfach und bezahlbar: Teste nun unsere virtuellen Maschinen mit " "Einfach und bezahlbar: Teste nun unsere virtuellen Maschinen mit "
"federleichten Preisen." "federleichten Preisen."
msgid "Affordable VM hosting based in Switzerland" msgid ""
msgstr "Bezahlbares VM Hosting in der Schweiz" "Ready in 30 seconds.<br/>Experience the unbeatable speed from Data Center "
"Light."
msgstr ""
"Fertig in 30 Sekunden.<br/>Erlebe die unschlagbare Geschwindigkeit von Data "
"Center Light."
msgid "Contact us" msgid "Contact us"
msgstr "Kontaktiere uns" msgstr "Kontaktiere uns"
@ -512,6 +517,18 @@ msgstr ""
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du " "Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
"auf sie zugreifen kannst." "auf sie zugreifen kannst."
#~ msgid "Affordable VM hosting based in Switzerland"
#~ msgstr "Bezahlbares VM Hosting in der Schweiz"
#~ msgid "Processing..."
#~ msgstr "Abarbeitung..."
#~ msgid "Hold tight, we are processing your request"
#~ msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade"
#~ msgid "Some problem encountered. Please try again later."
#~ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
#~ msgid "Submit" #~ msgid "Submit"
#~ msgstr "Absenden" #~ msgstr "Absenden"
@ -530,15 +547,6 @@ msgstr ""
#~ msgid "Order summary" #~ msgid "Order summary"
#~ msgstr "Bestellungsübersicht" #~ msgstr "Bestellungsübersicht"
#~ msgid "Processing..."
#~ msgstr "Abarbeitung..."
#~ msgid "Hold tight, we are processing your request"
#~ msgstr "Bitte warten - wir verbeiten Deine Anfrage gerade"
#~ msgid "Some problem encountered. Please try again later."
#~ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
#~ msgid "We are cutting down the costs significantly!" #~ 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"
@ -560,9 +568,6 @@ msgstr ""
#~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich " #~ "kontaktiere uns unter support@datacenterlight.ch. Unser Team wird sich "
#~ "umgehend um dein Anliegen kümmern!" #~ "umgehend um dein Anliegen kümmern!"
#~ msgid "Email Address"
#~ msgstr "E-Mail-Adresse"
#~ msgid "is not a proper name" #~ msgid "is not a proper name"
#~ msgstr "ist kein gültiger Name" #~ msgstr "ist kein gültiger Name"

View file

@ -7,7 +7,7 @@
body, body,
html { html {
width: 100%; width: 100%;
height: 100%; min-height: 100%;
} }
body, body,
@ -182,7 +182,11 @@ button, input, optgroup, select, textarea {
.navbar-brand { .navbar-brand {
padding: 10px 15px; padding: 10px 15px;
cursor: pointer; }
@media (max-width: 767px) {
.navbar-brand {
padding: 10px 10px;
}
} }
.navbar-right { .navbar-right {
@ -1544,7 +1548,7 @@ tech-sub-sec h2 {
} }
footer { footer {
padding: 50px 0; padding: 50px 20px;
background-color: #f8f8f8; background-color: #f8f8f8;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View file

@ -5,6 +5,7 @@ from celery.utils.log import get_task_logger
from celery import current_task from celery import current_task
from django.conf import settings from django.conf import settings
from django.core.mail import EmailMessage from django.core.mail import EmailMessage
from django.core.urlresolvers import reverse
from django.utils import translation from django.utils import translation
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -131,9 +132,9 @@ def create_vm_task(self, vm_template_id, user, specs, template,
'storage': specs.get('disk_size'), 'storage': specs.get('disk_size'),
'price': specs.get('price'), 'price': specs.get('price'),
'template': template.get('name'), 'template': template.get('name'),
'vm.name': vm['name'], 'vm_name': vm.get('name'),
'vm.id': vm['vm_id'], 'vm_id': vm['vm_id'],
'order.id': order.id 'order_id': order.id
} }
email_data = { email_data = {
'subject': settings.DCL_TEXT + " Order from %s" % context['email'], 'subject': settings.DCL_TEXT + " Order from %s" % context['email'],
@ -155,13 +156,14 @@ def create_vm_task(self, vm_template_id, user, specs, template,
translation.activate(lang) translation.activate(lang)
# Send notification to the user as soon as VM has been booked # Send notification to the user as soon as VM has been booked
context = { context = {
'vm': vm,
'order': order,
'base_url': "{0}://{1}".format(user.get('request_scheme'), 'base_url': "{0}://{1}".format(user.get('request_scheme'),
user.get('request_host')), user.get('request_host')),
'order_url': reverse('hosting:orders',
kwargs={'pk': order.id}),
'page_header': _( 'page_header': _(
'Your New VM %(vm_name)s at Data Center Light') % { 'Your New VM %(vm_name)s at Data Center Light') % {
'vm_name': vm.get('name')} 'vm_name': vm.get('name')},
'vm_name': vm.get('name')
} }
email_data = { email_data = {
'subject': context.get('page_header'), 'subject': context.get('page_header'),

View file

@ -1,24 +1,58 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.html" %} {% load static i18n %}
{% load static from staticfiles %} <!DOCTYPE html>
{% load i18n %} <html>
{% block email_head %}
{{dcl_text}} {% trans 'Account Activation' %} <head>
{% endblock %} <meta charset="UTF-8">
{% block email_body %} <meta name="viewport" content="width=device-width, initial-scale=1">
{% blocktrans %} <title>{% trans "Data Center Light Account Activation" %}</title>
You can activate your Data Center Light account by <a href="{{base_url}}{{activation_link}}">clicking here</a>.<br/> <link rel="shortcut icon" href="{{ base_url }}{% static 'datacenterlight/img/favicon.ico' %}" type="image/x-icon">
You can also copy and paste the following link into the address bar of your browser<br/> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400">
to activate your Data Center Light account.<br/> </head>
<body style="margin: 0; padding: 20px 0;">
<table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
<tr>
<td>
<img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
</td>
</tr>
<tr>
<td style="padding-top: 15px;">
<h1 style="font-family: Lato, Arial, sans-serif; font-size: 25px; font-weight: 400; margin: 0;">{% trans "Data Center Light Account Activation" %}</h1>
</td>
</tr>
<tr>
<td style="padding-top: 25px; font-size: 16px;">
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 10px; margin-top: 0;">
{% blocktrans %}You can activate your Data Center Light account by clicking <a href="{{base_url}}{{activation_link}}" style="text-decoration: none; color: #4382c8; font-weight: 400;">here</a>.{% endblocktrans %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 10px; margin-top: 0;">
{% blocktrans %}You can also copy and paste the following link into the address bar of your browser to activate your Data Center Light account.{% endblocktrans %}
</p>
<p style="color: #4382c8; line-height: 1.4; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{{base_url}}{{activation_link}} {{base_url}}{{activation_link}}
{% endblocktrans %} </p>
<p>
{% if account_details %} {% if account_details %}
{% url 'hosting:reset_password' as reset_password_url %} {% url 'hosting:reset_password' as reset_password_url %}
<br/><br/> {% trans "Your account details are as follows" %}:
{% blocktrans %}Your account details are as follows:<br/><br/>
Username : Your email address<br/> {% trans "Username" %} : {% trans "Your email address" %}
Password : {{account_details}}<br/><br/> {% trans "Password" %} : {{account_details}}
You can reset your password here:
{% trans "You can reset your password here" %}:
{{base_url}}{{reset_password_url}} {{base_url}}{{reset_password_url}}
{% endblocktrans %}
{% endif %} {% endif %}
{% endblock %} </p>
</td>
</tr>
<tr>
<td style="padding-top: 40px; padding-bottom: 25px;">
<h3 style="font-family: Lato, Arial, sans-serif; margin: 0; font-weight: 400; font-size: 15px;">{% trans "Your Data Center Light Team" %}</h3>
</td>
</tr>
</table>
</body>
</html>

View file

@ -1,21 +1,20 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.txt" %}
{% load i18n %} {% load i18n %}
{% block email_head %}{{dcl_text}} {% trans 'Account Activation' %}{% endblock %}
{% block email_body %} {% trans "Data Center Light Account Activation" %}
{% blocktrans %}You can activate your Data Center Light account by clicking here.
You can also copy and paste the following link into the address bar of your browser {% blocktrans %}You can copy and paste the following link into the address bar of your browser to activate your Data Center Light account.{% endblocktrans %}
to activate your Data Center Light account.
{{base_url}}{{activation_link}} {{base_url}}{{activation_link}}
{% endblocktrans %}
{% if account_details %} {% if account_details %}
{% url 'hosting:reset_password' as reset_password_url %} {% url 'hosting:reset_password' as reset_password_url %}
{% blocktrans %}Your account details are as follows: {% trans "Your account details are as follows" %}:
Username : Your email address {% trans "Username" %} : {% trans "Your email address" %}
Password : {{account_details}} {% trans "Password" %} : {{account_details}}
You can reset your password here: {% trans "You can reset your password here" %}:
{{base_url}}{{reset_password_url}} {{base_url}}{{reset_password_url}}
{% endblocktrans %}
{% endif %} {% endif %}
{% endblock %}
{% trans "Your Data Center Light Team" %}

View file

@ -0,0 +1,48 @@
{% load static i18n %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% trans "Welcome to Data Center Light!" %}</title>
<link rel="shortcut icon" href="{{ base_url }}{% static 'datacenterlight/img/favicon.ico' %}" type="image/x-icon">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400">
</head>
<body style="margin: 0; padding: 20px 0;">
<table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
<tr>
<td>
<img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
</td>
</tr>
<tr>
<td style="padding-top: 15px;">
<h1 style="font-family: Lato, Arial, sans-serif; font-size: 25px; font-weight: 400; margin: 0;">{% trans "Welcome to Data Center Light!" %}</h1>
</td>
</tr>
<tr>
<td style="padding-top: 25px; font-size: 16px;">
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}Thanks for joining us! We provide the most affordable virtual machines from the heart of Switzerland.{% endblocktrans %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}Try now, order a VM. VM price starts from only 15CHF per month.{% endblocktrans %}
</p>
</td>
</tr>
<tr>
<td style="padding-top: 30px;">
<a class="btn" href="{{ base_url }}{% url 'hosting:create_virtual_machine' %}" style="font-family: Lato, Arial, sans-serif; text-decoration: none; background-color: #1596da; color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 30px; padding-right: 30px; letter-spacing: 0.5px; border-radius: 3px; display: inline-block;">{% trans "ORDER VM" %}</a>
</td>
</tr>
<tr>
<td style="padding-top: 40px; padding-bottom: 25px;">
<h3 style="font-family: Lato, Arial, sans-serif; margin: 0; font-weight: 400; font-size: 15px;">{% trans "Your Data Center Light Team" %}</h3>
</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,10 @@
{% load i18n %}
{% trans "Welcome to Data Center Light!" %}
{% blocktrans %}Thanks for joining us! We provide the most affordable virtual machines from the heart of Switzerland.{% endblocktrans %}
{% blocktrans %}Try now, order a VM. VM price starts from only 15CHF per month.{% endblocktrans %}
{{ base_url }}{% url 'hosting:create_virtual_machine' %}
{% trans "Your Data Center Light Team" %}

View file

@ -1,5 +1,6 @@
{% load staticfiles i18n%} {% load staticfiles i18n%}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
<footer> <footer>
<div class="container"> <div class="container">
<ul class="list-inline"> <ul class="list-inline">

View file

@ -130,7 +130,7 @@
<div class="row text-center"> <div class="row text-center">
<div class="col-xs-12 col-md-6 text"> <div class="col-xs-12 col-md-6 text">
<h2 class="section-heading">{% trans "Simple and affordable: Try our virtual machine with featherlight price." %}</h2> <h2 class="section-heading">{% trans "Simple and affordable: Try our virtual machine with featherlight price." %}</h2>
<p class="lead new-lead">{% trans "Affordable VM hosting based in Switzerland" %}</p> <p class="lead new-lead">{% blocktrans %}Ready in 30 seconds.<br/>Experience the unbeatable speed from Data Center Light.{% endblocktrans %}</p>
</div> </div>
<div class="col-xs-12 col-md-6 hero-feature"> <div class="col-xs-12 col-md-6 hero-feature">

View file

@ -25,14 +25,15 @@
<h3>{%trans "Log in" %}</h3> <h3>{%trans "Log in" %}</h3>
<hr class="top-hr"> <hr class="top-hr">
<p style="margin-bottom: 20px;">{% blocktrans %}Already signed up?<br>By logging in you can retrieve saved billing information.{% endblocktrans %}</p> <p style="margin-bottom: 20px;">{% blocktrans %}Already signed up?<br>By logging in you can retrieve saved billing information.{% endblocktrans %}</p>
<form role="form" id="login-form" method="post" action="{% url 'hosting:login' %}" novalidate> <form role="form" id="login-form" method="post" action="" novalidate>
{% for field in login_form %} {% for field in login_form %}
{% csrf_token %} {% csrf_token %}
{% bootstrap_field field show_label=False type='fields'%} {% bootstrap_field field show_label=False type='fields'%}
{% endfor %} {% endfor %}
<p class="text-danger">{{login_form.non_field_errors|striptags}}</p>
<input type='hidden' name='next' value='{{request.path}}'/> <input type='hidden' name='next' value='{{request.path}}'/>
<div class="form-group text-right"> <div class="form-group text-right">
<button type="submit" class="btn btn-wide btn-vm-contact">{% trans "LOGIN" %}</button> <button type="submit" class="btn btn-wide btn-vm-contact" name="login_form">{% trans "LOGIN" %}</button>
</div> </div>
</form> </form>
<p> <p>
@ -58,7 +59,7 @@
{% endfor %} {% endfor %}
<form role="form" id="billing-form" method="post" action="" novalidate> <form role="form" id="billing-form" method="post" action="" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in billing_address_form %}
{% bootstrap_field field show_label=False type='fields'%} {% bootstrap_field field show_label=False type='fields'%}
{% endfor %} {% endfor %}
</form> </form>
@ -153,22 +154,12 @@
{% endif %} {% endif %}
<div id='payment_error'> <div id='payment_error'>
{% for message in messages %} {% for message in messages %}
{% if 'failed_payment' in message.tags or 'make_charge_error' in message.tags %} {% if 'failed_payment' in message.tags or 'make_charge_error' in message.tags or 'error' in message.tags %}
<ul class="list-unstyled"> <ul class="list-unstyled">
<li><p class="card-warning-content card-warning-error">{{ message|safe }}</p></li> <li><p class="card-warning-content card-warning-error">{{ message|safe }}</p></li>
</ul> </ul>
{% elif not form.non_field_errors %}
<p class="card-warning-content">
{% trans "You are not making any payment yet. After placing your order, you will be taken to the Submit Payment Page." %}
</p>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for error in form.non_field_errors %}
<p class="card-warning-content card-warning-error">
{{ error|escape }}
</p>
{% endfor %}
</div> </div>
<div class="text-right"> <div class="text-right">
<button class="btn btn-vm-contact btn-wide" type="submit">{%trans "SUBMIT" %}</button> <button class="btn btn-vm-contact btn-wide" type="submit">{%trans "SUBMIT" %}</button>

View file

@ -31,3 +31,14 @@ def get_value_from_dict(dict_data, key):
return dict_data.get(key) return dict_data.get(key)
else: else:
return "" return ""
@register.filter('multiply')
def multiply(value, arg):
"""
usage: {{ quantity|multiply:price }}
:param value:
:param arg:
:return:
"""
return value*arg

View file

@ -8,6 +8,8 @@ from django.conf import settings
from django.core.management import call_command from django.core.management import call_command
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from model_mommy import mommy from model_mommy import mommy
from unittest import skipIf
from datacenterlight.models import VMTemplate from datacenterlight.models import VMTemplate
from datacenterlight.tasks import create_vm_task from datacenterlight.tasks import create_vm_task
from membership.models import StripeCustomer from membership.models import StripeCustomer
@ -16,6 +18,11 @@ from utils.hosting_utils import get_vm_price
from utils.stripe_utils import StripeUtils from utils.stripe_utils import StripeUtils
@skipIf(
settings.STRIPE_API_PRIVATE_KEY_TEST is None or
settings.STRIPE_API_PRIVATE_KEY_TEST is "",
"""Stripe details unavailable, so skipping CeleryTaskTestCase"""
)
class CeleryTaskTestCase(TestCase): class CeleryTaskTestCase(TestCase):
@override_settings( @override_settings(
task_eager_propagates=True, task_eager_propagates=True,
@ -47,6 +54,11 @@ class CeleryTaskTestCase(TestCase):
# OpenNebula # OpenNebula
call_command('fetchvmtemplates') call_command('fetchvmtemplates')
@skipIf(
settings.OPENNEBULA_DOMAIN is None or settings.OPENNEBULA_DOMAIN is
"test_domain",
"""OpenNebula details unavailable, so skipping test_create_vm_task"""
)
def test_create_vm_task(self): def test_create_vm_task(self):
"""Tests the create vm task for monthly subscription """Tests the create vm task for monthly subscription
@ -110,13 +122,11 @@ class CeleryTaskTestCase(TestCase):
msg = subscription_result.get('error') msg = subscription_result.get('error')
raise Exception("Creating subscription failed: {}".format(msg)) raise Exception("Creating subscription failed: {}".format(msg))
async_task = create_vm_task.delay(vm_template_id, self.user, async_task = create_vm_task.delay(
specs, vm_template_id, self.user, specs, template_data,
template_data, stripe_customer.id, billing_address_data,
stripe_customer.id, stripe_subscription_obj.id, card_details_dict
billing_address_data, )
stripe_subscription_obj.id,
card_details_dict)
new_vm_id = 0 new_vm_id = 0
res = None res = None
for i in range(0, 10): for i in range(0, 10):

View file

@ -345,26 +345,45 @@ class PaymentOrderView(FormView):
else: else:
return BillingAddressFormSignup return BillingAddressFormSignup
def get_form_kwargs(self):
form_kwargs = super(PaymentOrderView, self).get_form_kwargs()
# if user is signed in, get billing address
if self.request.user.is_authenticated():
form_kwargs.update({
'instance': self.request.user.billing_addresses.first()
})
if 'billing_address_data' in self.request.session:
billing_address_data = self.request.session['billing_address_data']
form_kwargs.update({
'initial': billing_address_data
})
return form_kwargs
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)
if 'billing_address_data' in self.request.session:
billing_address_data = self.request.session['billing_address_data']
else:
billing_address_data = {}
if self.request.user.is_authenticated():
if billing_address_data:
billing_address_form = BillingAddressForm(
initial=billing_address_data
)
else:
billing_address_form = BillingAddressForm(
instance=self.request.user.billing_addresses.first()
)
# Get user last order
last_hosting_order = HostingOrder.objects.filter(
customer__user=self.request.user
).last()
# If user has already an hosting order, get the credit card
# data from it
if last_hosting_order:
credit_card_data = last_hosting_order.get_cc_data()
if credit_card_data:
context['credit_card_data'] = credit_card_data
else:
context['credit_card_data'] = None
else:
billing_address_form = BillingAddressFormSignup(
initial=billing_address_data
)
context.update({ context.update({
'stripe_key': settings.STRIPE_API_PUBLIC_KEY, 'stripe_key': settings.STRIPE_API_PUBLIC_KEY,
'site_url': reverse('datacenterlight:index'), 'site_url': reverse('datacenterlight:index'),
'login_form': HostingUserLoginForm() 'login_form': HostingUserLoginForm(prefix='login_form'),
'billing_address_form': billing_address_form
}) })
return context return context
@ -376,9 +395,32 @@ class PaymentOrderView(FormView):
return self.render_to_response(self.get_context_data()) return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
form = self.get_form() if 'login_form' in request.POST:
if form.is_valid(): login_form = HostingUserLoginForm(data=request.POST,
token = form.cleaned_data.get('token') prefix='login_form')
if login_form.is_valid():
email = login_form.cleaned_data.get('email')
password = login_form.cleaned_data.get('password')
auth_user = authenticate(email=email, password=password)
if auth_user:
login(self.request, auth_user)
return HttpResponseRedirect(
reverse('datacenterlight:payment')
)
else:
context = self.get_context_data()
context['login_form'] = login_form
return self.render_to_response(context)
if request.user.is_authenticated():
address_form = BillingAddressForm(
data=request.POST,
)
else:
address_form = BillingAddressFormSignup(
data=request.POST,
)
if address_form.is_valid():
token = address_form.cleaned_data.get('token')
if request.user.is_authenticated(): if request.user.is_authenticated():
this_user = { this_user = {
'email': request.user.email, 'email': request.user.email,
@ -388,8 +430,8 @@ class PaymentOrderView(FormView):
email=this_user.get('email'), email=this_user.get('email'),
token=token) token=token)
else: else:
user_email = form.cleaned_data.get('email') user_email = address_form.cleaned_data.get('email')
user_name = form.cleaned_data.get('name') user_name = address_form.cleaned_data.get('name')
this_user = { this_user = {
'email': user_email, 'email': user_email,
'name': user_name 'name': user_name
@ -422,13 +464,18 @@ class PaymentOrderView(FormView):
token=token, token=token,
customer_name=user_name) customer_name=user_name)
request.session['billing_address_data'] = form.cleaned_data request.session['billing_address_data'] = address_form.cleaned_data
request.session['user'] = this_user request.session['user'] = this_user
# Get or create stripe customer # Get or create stripe customer
if not customer: if not customer:
form.add_error("__all__", "Invalid credit card") address_form.add_error(
"__all__", "Invalid credit card"
)
return self.render_to_response( return self.render_to_response(
self.get_context_data(form=form)) self.get_context_data(
billing_address_form=address_form
)
)
request.session['token'] = token request.session['token'] = token
if type(customer) is StripeCustomer: if type(customer) is StripeCustomer:
request.session['customer'] = customer.stripe_id request.session['customer'] = customer.stripe_id
@ -437,7 +484,9 @@ class PaymentOrderView(FormView):
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('datacenterlight:order_confirmation')) reverse('datacenterlight:order_confirmation'))
else: else:
return self.form_invalid(form) context = self.get_context_data()
context['billing_address_form'] = address_form
return self.render_to_response(context)
class OrderConfirmationView(DetailView): class OrderConfirmationView(DetailView):
@ -548,9 +597,13 @@ class OrderConfirmationView(DetailView):
try: try:
custom_user = CustomUser.objects.get( custom_user = CustomUser.objects.get(
email=user.get('email')) email=user.get('email'))
customer = StripeCustomer.objects.filter( stripe_customer = StripeCustomer.objects.filter(
user_id=custom_user.id).first() user_id=custom_user.id).first()
stripe_customer_id = customer.id if stripe_customer is None:
stripe_customer = StripeCustomer.objects.create(
user=custom_user, stripe_id=stripe_api_cus_id
)
stripe_customer_id = stripe_customer.id
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
logger.debug( logger.debug(
"Customer {} does not exist.".format(user.get('email'))) "Customer {} does not exist.".format(user.get('email')))

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-10-10 21:35+0530\n" "POT-Creation-Date: 2017-11-06 00:24+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"
@ -95,6 +95,9 @@ msgstr "Seite"
msgid "Data Center Light" msgid "Data Center Light"
msgstr "" msgstr ""
msgid "Glasfaser"
msgstr ""
msgid "English" msgid "English"
msgstr "" msgstr ""

View file

@ -964,40 +964,6 @@ section h3.section-comment {
color: #494949; color: #494949;
} }
small-comment {
font-family: "Open Sans", "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif;
margin-bottom: none;
font-transform: none;
font-size:10px;
font-weight:400;
color: #777
}
logo-image {
z-index: 100;
position: absolute;
left: 0;
width: 80px;
height: 80px;
margin-left: 0;
border: 7px solid #f1f1f1;
border-radius: 100%;
text-align: center;
color: #fff;
background-color: #a1cfd7;
}
intro-cap {
margin-bottom: 25px;
text-transform: uppercase;
font-family: 'Raleway', "Helvetica Neue", "Helvetica Neue", Helvetica,Arial,sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #a1cfd7;
}
.intro-small { .intro-small {
font-family: 'Montserrat' ,'Raleway', "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif; font-family: 'Montserrat' ,'Raleway', "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif;
font-size: 20px; font-size: 20px;
@ -1006,26 +972,7 @@ intro-cap {
text-transform: uppercase; text-transform: uppercase;
color: #FFF; color: #FFF;
} }
intro-headline {
margin-bottom: 25px;
text-transform: uppercase;
font-family: 'Raleway', "Helvetica Neue", "Helvetica Neue", Helvetica,Arial,sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 100px;
color:#fff
background-color: #a1cfd7;
}
h6 intro-smallcap {
margin-bottom: 25px;
text-transform: none;
font-family:'Raleway' , Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #a1cfd7;
}
.darkened-container { .darkened-container {
/* Fallback for web browsers that doesn't support RGBa */ /* Fallback for web browsers that doesn't support RGBa */
background: rgb(0, 0, 0); background: rgb(0, 0, 0);

View file

@ -960,40 +960,6 @@ section h3.section-comment {
color: #494949; color: #494949;
} }
small-comment {
font-family: "Open Sans", "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif;
margin-bottom: none;
font-transform: none;
font-size:10px;
font-weight:400;
color: #777
}
logo-image {
z-index: 100;
position: absolute;
left: 0;
width: 80px;
height: 80px;
margin-left: 0;
border: 7px solid #f1f1f1;
border-radius: 100%;
text-align: center;
color: #fff;
background-color: #a1cfd7;
}
intro-cap {
margin-bottom: 25px;
text-transform: uppercase;
font-family: 'Raleway', "Helvetica Neue", "Helvetica Neue", Helvetica,Arial,sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #a1cfd7;
}
.intro-small { .intro-small {
font-family: 'Montserrat' ,'Raleway', "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif; font-family: 'Montserrat' ,'Raleway', "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif;
font-size: 20px; font-size: 20px;
@ -1002,26 +968,7 @@ intro-cap {
text-transform: uppercase; text-transform: uppercase;
color: #FFF; color: #FFF;
} }
intro-headline {
margin-bottom: 25px;
text-transform: uppercase;
font-family: 'Raleway', "Helvetica Neue", "Helvetica Neue", Helvetica,Arial,sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 100px;
color:#fff
background-color: #a1cfd7;
}
h6 intro-smallcap {
margin-bottom: 25px;
text-transform: none;
font-family:'Raleway' , Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #a1cfd7;
}
.darkened-container { .darkened-container {
/* Fallback for web browsers that doesn't support RGBa */ /* Fallback for web browsers that doesn't support RGBa */
background: rgb(0, 0, 0); background: rgb(0, 0, 0);

View file

@ -250,6 +250,7 @@ header.history {
text-align:center; text-align:center;
line-height: 2.5; line-height: 2.5;
color: #fff; color: #fff;
margin-bottom: 100px;
} }
.supporter-intro { .supporter-intro {

View file

@ -1,4 +1,4 @@
#page-top #services .container .row .col-lg-12.text-center .section-heading { #page-top #services .section-heading {
font-style: normal; font-style: normal;
color: #494949; color: #494949;
padding-top: 50px; padding-top: 50px;
@ -10,17 +10,13 @@
.intro-cap { .intro-cap {
font-family: 'Raleway', 'Helvetica Neue', 'Open Sans Bold', Helvetica, Arial, 'Arial Bold', sans-serif; font-family: 'Raleway', 'Helvetica Neue', 'Open Sans Bold', Helvetica, Arial, 'Arial Bold', sans-serif;
font-size: 26px; font-size: 24px;
font-style: normal; font-style: normal;
font-weight: 200; font-weight: 200;
text-transform: uppercase; text-transform: uppercase;
color: #FFF; color: #FFF;
} }
.intro-cap {
font-size: 24px;
}
.intro-smallcap { .intro-smallcap {
font-family: 'Raleway' , "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif; font-family: 'Raleway' , "Open Sans Bold", Helvetica, Arial, "Arial Bold", sans-serif;
font-size: 22px; font-size: 22px;

View file

@ -4,26 +4,19 @@
{% block content %} {% block content %}
<style type="text/css"> <style type="text/css">
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
#timeline{ #timeline{
display: none; display: none;
} }
h2 {font-size: 2em !important;} h2 {font-size: 2em !important;}
} }
</style> </style>
<!-- Header --> <!-- Header -->
<header class="history"> <header class="history">
<div class="container header-history"> <div class="container header-history">
<div class="intro-text"> <div class="intro-text">
<p>
</p>
<div class="intro-headline"> <div class="intro-headline">
<span class="intro-headline"> <span class="intro-headline">
Where great minds work Where great minds work
@ -31,66 +24,72 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</header> </header>
<!-- form section ends--> <!-- form section ends-->
<!-- Services Section --> <!-- Services Section -->
<section id="history"> <section id="history">
<div class="container-fluid"> <div class="container-fluid">
<div class="row-fluid"> <div class="text-center wow fadeInDown">
<div class="col-lg-12 col-md-12 text-center wow fadeInDown">
<span class="glyphicon glyphicon-star glyphicon-inverse"></span> <span class="glyphicon glyphicon-star glyphicon-inverse"></span>
<h2 class="section-heading">the story of Digital Glarus</h2> <h2 class="section-heading">the story of Digital Glarus</h2>
<p class="carousel-text text-center supporter-black"> <p class="carousel-text text-center supporter-black">
In search for a better environment for creativity, ungleich In search for a better environment for creativity, ungleich
arrived at a small village in Glarus. First we were driven by the arrived at a small village in Glarus. First we were driven by the
cheap real estate price, then we were genuinely surprised by the beauty of its nature. People were incredibly friendly as well. Working just became so relaxed and enjoyable in such a beautiful cheap real estate price, then we were genuinely surprised by the
beauty of its nature. People were incredibly friendly as well.
Working just became so relaxed and enjoyable in such a beautiful
surrounding..How come we are the only ones here?! We can't be surrounding..How come we are the only ones here?! We can't be
enjoying this alone, we need to let others know about this great enjoying this alone, we need to let others know about this great
place. That's how it all started... place. That's how it all started...
</p> </p>
<span class="glyphicon glyphicon-heart glyphicon-inverse"></span> <span class="glyphicon glyphicon-heart glyphicon-inverse"></span>
<h2 class="section-heading">we fell in love</h2>
<h2 class="section-heading">we fell in love</h2>
<p class="carousel-text text-center supporter-black"> <p class="carousel-text text-center supporter-black">
We didn't see this coming, but we really fell in love with Glarus. The lakes, the mountains, the mist, the (amazing) snow, We didn't see this coming, but we really fell in love with Glarus.
the fresh air, the stream, the people, the stars...how could we not? And before long, we found an 100 something years old house, The lakes, the mountains, the mist, the (amazing) snow,
the fresh air, the stream, the people, the stars...how could we
not? And before long, we found an 100 something years old house,
formerly a family home, but long time unused, next to a river in formerly a family home, but long time unused, next to a river in
Schwanden. Full of old furniture, the house and the neighborhood Schwanden. Full of old furniture, the house and the neighborhood
was stepping in a time machine. There, we found our first was stepping in a time machine. There, we found our first
coworking space in Glarus.</p> coworking space in Glarus.
</p>
<span class="glyphicon glyphicon-home glyphicon-inverse"></span> <span class="glyphicon glyphicon-home glyphicon-inverse"></span>
<h2 class="section-heading">Our crowdfunding success</h2>
<h2 class="section-heading">Our crowdfunding success</h2>
<p class="carousel-text text-center supporter-black"> <p class="carousel-text text-center supporter-black">
What comes with a very old house? Lots of charm, yes. Great What comes with a very old house? Lots of charm, yes. Great
history, yes. A contract stating that we can park our goats in the history, yes. A contract stating that we can park our goats in the
storage room, yes. And, yes, tons of things to be fixed. We storage room, yes. And, yes, tons of things to be fixed. We
couldn't afford much of renovation-we are a young start up rich couldn't afford much of renovation-we are a young start up rich
with creativity but not much money (yet)-that is why we decided to ask for help. To our surprise, generous people found hope and with creativity but not much money (yet)-that is why we decided to
ask for help. To our surprise, generous people found hope and
inspiration from our project. We got much supports from people we inspiration from our project. We got much supports from people we
know and we don't know. People wrote to us, called us, met us. We know and we don't know. People wrote to us, called us, met us. We
were on the cover of newspaper. We were on TV. We became the talk were on the cover of newspaper. We were on TV. We became the talk
of the town. of the town.
</p> </p>
<div>
<div><iframe class="center-block" frameborder="0" height="330" scrolling="no" src="//www.100-days.net/de/projekt/start-digital-glarus/widget/v2" width="220"></iframe></div> <iframe class="center-block" frameborder="0" height="330" scrolling="no" src="//www.100-days.net/de/projekt/start-digital-glarus/widget/v2" width="220"></iframe>
</div>
<span class="glyphicon glyphicon-road glyphicon-inverse"></span> <span class="glyphicon glyphicon-road glyphicon-inverse"></span>
<h2 class="section-heading text-cente">And the story continues..!</h2> <h2 class="section-heading text-cente">And the story continues..!</h2>
<p class="carousel-text text-center supporter-black"> <p class="carousel-text text-center supporter-black">
With the money we raised from our crowdfunding campaign, we With the money we raised from our crowdfunding campaign, we
started renovating the hourse, ripping floors off and fixing started renovating the hourse, ripping floors off and fixing
walls, giving a fresh coat of paint on old walls. We hired Samuel, walls, giving a fresh coat of paint on old walls. We hired Samuel,
who came to Glarus as a refugee from Eritrea, as our intern to who came to Glarus as a refugee from Eritrea, as our intern to
renovate the house and learn computer science. We opened our door for students to live. Our coworking space is growing slowly but renovate the house and learn computer science. We opened our door
for students to live. Our coworking space is growing slowly but
meaningfully. Our journey only started! meaningfully. Our journey only started!
</p> </p>
<hr class="primary"> <hr class="primary">
</div> </div>
</div> </div>
</div>
</section> </section>
<!-- Half Page Image Background Carousel --> <!-- Half Page Image Background Carousel -->
@ -98,56 +97,55 @@
<div id="timeline"> <div id="timeline">
<iframe frameborder="0" width="100%" height="650" src="//cdn.knightlab.com/libs/timeline3/latest/embed/index.html?source=15clFd1fjnVScVziBlF-X7j5M7V6uNFt9jt9QZVylaYI&amp;font=Default&amp;lang=en&amp;initial_zoom=2&amp;height=650" width="100%"></iframe> <iframe frameborder="0" width="100%" height="650" src="//cdn.knightlab.com/libs/timeline3/latest/embed/index.html?source=15clFd1fjnVScVziBlF-X7j5M7V6uNFt9jt9QZVylaYI&amp;font=Default&amp;lang=en&amp;initial_zoom=2&amp;height=650" width="100%"></iframe>
</div> </div>
</section> </section>
<!-- Supporters --> <!-- Supporters -->
<section id="supporters"> <section id="supporters">
<div class="supporter-bg"> <div class="supporter-bg">
<div class="container"> <div class="container">
<div class="col-lg-12 text-center wow fadeInDown"> <div class="text-center wow fadeInUp">
<h2 class="supporter-headline">Our Supporters</h2> <h2 class="supporter-headline">Our Supporters</h2>
<hr class="primary"> <hr class="primary">
<p class="carousel-text supporter-intro text-muted text-center"> Here are our proud supporters of project Digital Glarus. Thanks to our supporters, the first cowerking space in Glarus <p class="carousel-text supporter-intro text-muted text-center">
is going to have a new look!</p> Here are our proud supporters of project Digital Glarus. Thanks to our supporters,
the first cowerking space in Glarus is going to have a new look!
</p>
<p class="supporter" style="text-transform: uppercase;"> <p class="supporter" style="text-transform: uppercase;">
{% for supporter in supporters %} {% for supporter in supporters %}
{{ supporter.name }} {{ supporter.name }}
<br> <br>
{% endfor %} {% endfor %}
<br> <br>
<a href="{% url 'digitalglarus:supportus' %}" class="btn btn-default btn-primary sr-button">Become a supporter</a> <a href="{% url 'digitalglarus:supportus' %}" class="btn btn-default btn-primary sr-button">Become a supporter</a>
<br> </p>
<br>
<br>
<br>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<section id="contact"> <section id="contact">
<div class="fill"> <div class="fill">
<div class="row" class="wow fadeInDown"> <div class="container">
<div class="col-lg-12 text-center wow fadeInDown"> <div class="wow fadeInUp text-center">
<h2 class="section-heading" style="margin-top: 40px;">Contact Us</h2>
<div class="map-wrap"> <div class="map-wrap">
<iframe style="pointer-events:none;margin-top:20px;" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2721.4267495037207!2d9.070190915609343!3d46.99259307914885!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47852e9322cc1971%3A0xf1558647dfdfaa60!2sIn+der+Au+7%2C+8762+Glarus+S%C3%BCd!5e0!3m2!1sen!2sch!4v1470238006004" width="100%" height="450" frameborder="0" style="border:0"></iframe> <iframe style="margin-top:20px;" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2721.4267495037207!2d9.070190915609343!3d46.99259307914885!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47852e9322cc1971%3A0xf1558647dfdfaa60!2sIn+der+Au+7%2C+8762+Glarus+S%C3%BCd!5e0!3m2!1sen!2sch!4v1470238006004" width="100%" height="450" frameborder="0" style="border:0"></iframe>
</div> </div>
</div>
<div class="row">
<div class="col-md-4 map-title"> <div class="col-md-4 map-title">
Digital Glarus<br> Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland <span class="map-caption">
In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch <br>info@digitalglarus.ch
<br> <br>
(044) 534-66-22 (044) 534-66-22
<p>&nbsp;</p> <br>
</span> </span>
</div>
<p>&nbsp;</p> <p>&nbsp;</p>
</div> </div>
</div> </div>
</div> </div>
</div>
</section> </section>
{% endblock %} {% endblock %}

View file

@ -3,45 +3,12 @@
{% block content %} {% block content %}
<!-- Header -->
<header>
<div class="container">
<div class="intro-text">
<p>
</p>
<div class="intro-headline">
<span class="intro-headline">
Where great minds work
</span>
</div>
</div>
</div>
<div class="container-fluid darkened-container">
<h3 class="intro-small">
Book a date today and dive in</h3>
<a href="{% url 'digitalglarus:booking' %}" class="btn btn-primary">Join now</a>
<!-- <form class="form-inline">
<div class="form-group">
<label class="sr-only" for="exampleInputPassword3">Pick a date</label>
<input type="password" class="form-control" id="exampleInputPassword3" placeholder="Pick a date">
<div class="form-group">
<label class="sr-only" for="exampleInputEmail3">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail3" placeholder="Enter email">
</div>
</div>
<button type="submit" class="btn btn-primary">book a date</button>
</form> -->
</div>
<style type="text/css"> <style type="text/css">
.caption-style-1{ .caption-style-1{
list-style-type: none; list-style-type: none;
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
} }
.caption-style-1 li{ .caption-style-1 li{
@ -53,10 +20,8 @@
.caption-style-1 li:hover .caption{ .caption-style-1 li:hover .caption{
opacity: 1; opacity: 1;
} }
.caption-style-1 img{ .caption-style-1 img{
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
@ -64,7 +29,6 @@
z-index: 4; z-index: 4;
} }
.caption-style-1 .caption{ .caption-style-1 .caption{
cursor: pointer; cursor: pointer;
opacity: 0; opacity: 0;
@ -73,7 +37,6 @@
-o-transition:all 0.45s ease-in-out; -o-transition:all 0.45s ease-in-out;
-ms-transition:all 0.45s ease-in-out; -ms-transition:all 0.45s ease-in-out;
transition:all 0.45s ease-in-out; transition:all 0.45s ease-in-out;
} }
.caption-style-1 .blur{ .caption-style-1 .blur{
background-color: rgba(0,0,0,0.65); background-color: rgba(0,0,0,0.65);
@ -94,8 +57,6 @@
height: 200px; height: 200px;
text-align: center; text-align: center;
top:30px; top:30px;
} }
/** content **/ /** content **/
@ -125,6 +86,8 @@
font-size: 30px; font-size: 30px;
font-weight: 600; font-weight: 600;
padding-top: 50px; padding-top: 50px;
display: flex;
justify-content: center;
} }
.section-top-content span{ .section-top-content span{
font-weight: 300; font-weight: 300;
@ -135,6 +98,7 @@
text-align: right; text-align: right;
} }
.section-top-img { .section-top-img {
max-width: 50%;
padding: 0px; padding: 0px;
} }
@media(max-width:500px) { @media(max-width:500px) {
@ -163,73 +127,112 @@
padding-top: 65px; padding-top: 65px;
} }
} }
@media screen and (min-device-width: 361px) and (max-device-width: 428px) {
.section-top-txt {
padding: 35px 5px 0 0px;
}
.section-top-content {
font-size: 22px;
}
}
</style> </style>
<!-- Header -->
<header>
<div class="container">
<div class="intro-text">
<div class="intro-headline">
<span class="intro-headline">
Where great minds work
</span>
</div>
</div>
</div>
<div class="container-fluid darkened-container">
<h3 class="intro-small">Book a date today and dive in</h3>
<a href="{% url 'digitalglarus:booking' %}" class="btn btn-primary">Join now</a>
{% comment %}
<form class="form-inline">
<div class="form-group">
<label class="sr-only" for="exampleInputPassword3">Pick a date</label>
<input type="password" class="form-control" id="exampleInputPassword3" placeholder="Pick a date">
<div class="form-group">
<label class="sr-only" for="exampleInputEmail3">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail3" placeholder="Enter email">
</div>
</div>
<button type="submit" class="btn btn-primary">book a date</button>
</form>
{% endcomment %}
</div>
</header> </header>
<!-- form section ends--> <!-- form section ends-->
<!-- Services Section --> <!-- Services Section -->
<section id="services"> <section id="services">
<div class="container"> <div class="container">
<div class="row"> <div class="text-center wow fadeInUp section-top-content">
<div class="col-lg-12 text-center wow fadeInDown section-top-content"> <div class="section-top-txt">Partner <span>of</span></div>
<div class="col-lg-3 col-sm-2 col-xs-12"></div> <div class="section-top-img">
<div class="col-lg-6 col-sm-10 col-xs-12"> <a href="https://zurich.impacthub.ch" target="_blank">
<div class="col-lg-5 col-sm-5 col-xs-6 section-top-txt">Partner <span>of</span></div> <img src="{% static 'digitalglarus/img/impacthub_logo.jpg' %}" class="img-responsive" alt="">
<div class="col-lg-7 col-sm-4 col-xs-6 section-top-img"><a href="https://zurich.impacthub.ch" target="_blank"><img src="{% static 'digitalglarus/img/impacthub_logo.jpg' %}" class="img-responsive" alt=""></a></div> </a>
</div> </div>
<div class="col-lg-3 col-sm-12 col-xs-12"></div>
</div> </div>
<div class="col-lg-12 col-xs-12 text-center wow fadeInDown"> <div class="text-center wow fadeInUp">
<h2 class="section-heading">In Digital Glarus you can..</h2> <h2 class="section-heading">In Digital Glarus you can..</h2>
<hr class="primary"> <hr class="primary">
</div> </div>
</div>
<!--dropdown icons--> <!--dropdown icons-->
<div class="row text-center"> <div class="row text-center">
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="0.3s"> <div class="team-member wow fadeInUp" data-wow-delay="0.3s">
<img src="{% static 'digitalglarus/img/services/sleep.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/sleep.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="0.5s"> <div class="team-member wow fadeInUp" data-wow-delay="0.5s">
<img src="{% static 'digitalglarus/img/services/eat.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/eat.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="0.7s"> <div class="team-member wow fadeInUp" data-wow-delay="0.7s">
<img src="{% static 'digitalglarus/img/services/freshenup.svg' %}" class="img-responsive img-toggle cursor-pointer" alt=""> <img src="{% static 'digitalglarus/img/services/freshenup.svg' %}" class="img-responsive img-toggle cursor-pointer" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="0.8s"> <div class="team-member wow fadeInUp" data-wow-delay="0.8s">
<img src="{% static 'digitalglarus/img/services/work.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/work.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
<div class="row text-center" style="margin-left: 0px; margin-right: 0px;"> <div class="row text-center" style="margin-left: 0px; margin-right: 0px;">
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="0.9s"> <div class="team-member wow fadeInUp" data-wow-delay="0.9s">
<img src="{% static 'digitalglarus/img/services/enjoy.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/enjoy.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="1s"> <div class="team-member wow fadeInUp" data-wow-delay="1s">
<img src="{% static 'digitalglarus/img/services/network.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/network.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="1.1s"> <div class="team-member wow fadeInUp" data-wow-delay="1.1s">
<img src="{% static 'digitalglarus/img/services/lightbulb.svg' %}" class="img-responsive img-toggle cursor-pointer" alt=""> <img src="{% static 'digitalglarus/img/services/lightbulb.svg' %}" class="img-responsive img-toggle cursor-pointer" alt="">
</div> </div>
</div> </div>
<div class="col-xs-6 col-sm-3"> <div class="col-xs-6 col-sm-3">
<div class="team-member wow fadeInDown" data-wow-delay="1.2s"> <div class="team-member wow fadeInUp" data-wow-delay="1.2s">
<img src="{% static 'digitalglarus/img/services/beinspired.svg' %}" class="img-responsive img-toggle" alt=""> <img src="{% static 'digitalglarus/img/services/beinspired.svg' %}" class="img-responsive img-toggle" alt="">
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
<!-- start:recommendationSlider --> <!-- start:recommendationSlider -->
<hr class="primary"> <hr class="primary">
<div id="carousel-recommendation-ungleich" class="carousel slide ungleich ungleich-gallery ungleich-gallery-text-carousel" data-ride="carousel" data-interval="false"> <div id="carousel-recommendation-ungleich" class="carousel slide ungleich ungleich-gallery ungleich-gallery-text-carousel" data-ride="carousel" data-interval="false">
@ -284,79 +287,67 @@
</div> </div>
</div> </div>
<!-- end:recommendationSlider --> <!-- end:recommendationSlider -->
</div></section> </section>
<!-- Portfolio Grid Section --> <!-- Portfolio Grid Section -->
<section id="portfolio" class="no-padding"> <section id="portfolio" class="no-padding">
<div class="container-fluid"> <div class="container-fluid">
<!--<div class="row"> <!--<div class="row">
<div class="col-lg-12 text-center wow fadeInDown"> <div class="col-lg-12 text-center wow fadeInUp">
<h2 class="section-heading">here you can</h2> <h2 class="section-heading">here you can</h2>
<h3 class="section-subheading text-muted">Join our community. Inspire and be inspired.</h3> <h3 class="section-subheading text-muted">Join our community. Inspire and be inspired.</h3>
</div>--> </div>-->
</div>
<div class="row no-gutter popup-gallery"> <div class="row no-gutter popup-gallery">
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="0.5s">
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="0.5s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/excursion.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/excursion.png' %}" class="img-responsive inline-block" alt="">
<div class="caption"> <div class="caption">
<div class="blur"></div> <div class="blur"></div>
</div> </div>
</li> </li>
</ul> </ul>
<div class="caption portfolio-caption-white">excursions</div> <div class="caption portfolio-caption-white">excursions</div>
</div> </div>
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="0.8s"> <div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="0.8s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/ski.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/ski.png' %}" class="img-responsive inline-block" alt="">
<div class="caption"> <div class="caption">
<div class="blur"></div> <div class="blur"></div>
</div> </div>
</li> </li>
</ul> </ul>
<div class="caption portfolio-caption-white">enjoy the great outdoors</div> <div class="caption portfolio-caption-white">enjoy the great outdoors</div>
</div> </div>
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="1.1s">
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="1.1s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/concert.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/concert.png' %}" class="img-responsive inline-block" alt="">
<div class="caption"> <div class="caption">
<div class="blur"></div> <div class="blur"></div>
</div> </div>
</li> </li>
</ul> </ul>
<div class="caption portfolio-caption-white">cultural events</div> <div class="caption portfolio-caption-white">cultural events</div>
</div> </div>
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="1.2s"> <div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="1.2s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/inspire.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/inspire.png' %}" class="img-responsive inline-block" alt="">
<div class="caption"> <div class="caption">
<div class="blur"></div> <div class="blur"></div>
</div> </div>
</li> </li>
</ul> </ul>
<div class="caption portfolio-caption-white">be inspired</div> <div class="caption portfolio-caption-white">be inspired</div>
</div> </div>
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="1.3s">
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="1.3s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/workshop.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/workshop.png' %}" class="img-responsive inline-block" alt="">
@ -368,7 +359,7 @@
<div class="caption portfolio-caption-white">workshops</div> <div class="caption portfolio-caption-white">workshops</div>
</div> </div>
<div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInDown text-center" data-wow-delay="1.4s"> <div class="col-lg-4 col-md-4 col-sm-6 portfolio-item wow fadeInUp text-center" data-wow-delay="1.4s">
<ul class="caption-style-1"> <ul class="caption-style-1">
<li> <li>
<img src="{% static 'digitalglarus/img/portfolio/recharge.png' %}" class="img-responsive inline-block" alt=""> <img src="{% static 'digitalglarus/img/portfolio/recharge.png' %}" class="img-responsive inline-block" alt="">
@ -379,15 +370,10 @@
</ul> </ul>
<div class="caption portfolio-caption-white">recharge</div> <div class="caption portfolio-caption-white">recharge</div>
</div> </div>
</div>
</div> </div>
</section> </section>
<!--aside--> <!--aside-->
<aside class="bg-dark"> <aside class="bg-dark">
<div class="container text-center"> <div class="container text-center">
@ -399,6 +385,7 @@
</div> </div>
</div> </div>
</aside> </aside>
<!-- Half Page Image Background Carousel --> <!-- Half Page Image Background Carousel -->
<section id="myCarousel" class="carousel slide"> <section id="myCarousel" class="carousel slide">
<!-- Indicators --> <!-- Indicators -->
@ -446,22 +433,22 @@
<!-- Controls --> <!-- Controls -->
<a class="left carousel-control" href="#myCarousel" data-slide="prev"> <a class="left carousel-control" href="#myCarousel" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span> <span class="glyphicon glyphicon-chevron-left"></span>
</a> </a>
<a class="right carousel-control" href="#myCarousel" data-slide="next"> <a class="right carousel-control" href="#myCarousel" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span> <span class="glyphicon glyphicon-chevron-right"></span>
</a> </a>
</section> </section>
<section id="contact"> <section id="contact">
<div class="fill"> <div class="fill">
<div class="row" class="wow fadeInDown"> <div class="container">
<div class="col-lg-12 text-center wow fadeInDown"> <div class="wow fadeInUp">
<div class="text-center">
<h2 class="section-heading">Contact Us</h2> <h2 class="section-heading">Contact Us</h2>
<div class="map-wrap"> <div class="map-wrap">
<iframe style="pointer-events:none" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2721.4267495037207!2d9.070190915609343!3d46.99259307914885!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47852e9322cc1971%3A0xf1558647dfdfaa60!2sIn+der+Au+7%2C+8762+Glarus+S%C3%BCd!5e0!3m2!1sen!2sch!4v1470238006004" width="100%" height="450" frameborder="0" style="border:0"></iframe></div> <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2721.4267495037207!2d9.070190915609343!3d46.99259307914885!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47852e9322cc1971%3A0xf1558647dfdfaa60!2sIn+der+Au+7%2C+8762+Glarus+S%C3%BCd!5e0!3m2!1sen!2sch!4v1470238006004" width="100%" height="450" frameborder="0" style="border:0"></iframe>
<div class="col-md-4 map-title"> </div>
<div class="map-title">
Digital Glarus<br> Digital Glarus<br>
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland <span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
<br>info@digitalglarus.ch <br>info@digitalglarus.ch
@ -478,10 +465,6 @@
</section> </section>
<!-- <!--
<div class="row"> <div class="row">
<div class="box"> <div class="box">

View file

@ -15,9 +15,11 @@ from membership.models import CustomUser, StripeCustomer
from utils.tests import BaseTestCase from utils.tests import BaseTestCase
from .views import LoginView, SignupView, PasswordResetView, PasswordResetConfirmView,\ from .views import (
LoginView, SignupView, PasswordResetView, PasswordResetConfirmView,
MembershipPricingView, MembershipPaymentView MembershipPricingView, MembershipPaymentView
from .models import MembershipType, MembershipOrder )
from .models import MembershipType
class ContactViewTest(TestCase): class ContactViewTest(TestCase):
@ -41,13 +43,19 @@ class ContactViewTest(TestCase):
class ViewsTest(CMSTestCase): class ViewsTest(CMSTestCase):
def setUp(self): def setUp(self):
self.page1 = create_page('home', 'home_digitalglarus.html', published=True, language='en-us') self.page1 = create_page(
self.page2 = create_page('about', 'about.html', published=True, language='en-us', slug='about') 'home', 'home_digitalglarus.html', published=True,
language='en-us'
)
self.page2 = create_page(
'about', 'about.html', published=True, language='en-us',
slug='about'
)
def test_digitalglarus_templates(self): def test_digitalglarus_templates(self):
res1 = self.client.get('/en-us/') res1 = self.client.get('/en-us/')
self.assertContains(res1, 'Digital Glarus', status_code=200) self.assertContains(res1, 'Digital Glarus', status_code=200)
res2 = self.client.get('/en-us/about/') res2 = self.client.get('/en-us/cms/about/')
self.assertEqual(res2.status_code, 200) self.assertEqual(res2.status_code, 200)
@ -69,7 +77,9 @@ class MembershipPricingViewTest(BaseTestCase):
# Anonymous user should get data # Anonymous user should get data
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['membership_type'], self.membership_type) self.assertEqual(
response.context['membership_type'], self.membership_type
)
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
@ -101,8 +111,10 @@ class MembershipPaymentViewTest(BaseTestCase):
# Anonymous user should get redirect to login # Anonymous user should get redirect to login
response = self.client.get(self.url) response = self.client.get(self.url)
expected_url = "%s?next=%s" % (reverse('digitalglarus:signup'), expected_url = "%s?next=%s" % (
reverse('digitalglarus:membership_payment')) reverse('digitalglarus:signup'),
reverse('digitalglarus:membership_payment')
)
self.assertRedirects(response, expected_url=expected_url, self.assertRedirects(response, expected_url=expected_url,
status_code=302, target_status_code=200) status_code=302, target_status_code=200)
@ -132,19 +144,29 @@ class MembershipPaymentViewTest(BaseTestCase):
} }
response = self.customer_client.post(self.url, self.billing_address) response = self.customer_client.post(self.url, self.billing_address)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTrue(StripeCustomer.objects.filter(user__email=self.customer.email).exists()) self.assertTrue(
stripe_customer = StripeCustomer.objects.get(user__email=self.customer.email) StripeCustomer.objects.filter(
user__email=self.customer.email
).exists()
)
stripe_customer = StripeCustomer.objects.get(
user__email=self.customer.email
)
self.assertEqual(stripe_customer.user, self.customer) self.assertEqual(stripe_customer.user, self.customer)
self.assertTrue(MembershipOrder.objects.filter(customer=stripe_customer).exists()) # self.assertTrue(MembershipOrder.objects.filter(customer=stripe_customer).exists())
membership_order = MembershipOrder.objects.filter(customer=stripe_customer).first() # membership_order = MembershipOrder.objects.filter(
session_data = { # customer=stripe_customer
'membership_price': membership_order.membership.type.first_month_price, # ).first()
'membership_dates': membership_order.membership.type.first_month_formated_range # session_data = {
} # 'membership_price':
self.assertEqual(session_data.get('membership_price'), # membership_order.membership.type.first_month_price,
self.session_data.get('membership_price')) # 'membership_dates':
self.assertEqual(session_data.get('membership_dates'), # membership_order.membership.type.first_month_formated_range
self.session_data.get('membership_dates')) # }
# self.assertEqual(session_data.get('membership_price'),
# self.session_data.get('membership_price'))
# self.assertEqual(session_data.get('membership_dates'),
# self.session_data.get('membership_dates'))
# self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists()) # self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists())
# hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0] # hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0]
@ -212,7 +234,9 @@ class SignupViewTest(TestCase):
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
def test_anonymous_user_can_signup(self): def test_anonymous_user_can_signup(self):
response = self.client.post(self.url, data=self.signup_data, follow=True) response = self.client.post(
self.url, data=self.signup_data, follow=True
)
self.user = CustomUser.objects.get(email=self.signup_data.get('email')) self.user = CustomUser.objects.get(email=self.signup_data.get('email'))
self.assertEqual(response.context['user'], self.user) self.assertEqual(response.context['user'], self.user)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)

View file

@ -218,6 +218,8 @@ CMS_TEMPLATES = (
('page.html', gettext('Page')), ('page.html', gettext('Page')),
# dcl # dcl
('datacenterlight/cms_page.html', gettext('Data Center Light')), ('datacenterlight/cms_page.html', gettext('Data Center Light')),
('ungleich_page/glasfaser_cms_page.html', gettext('Glasfaser')),
('ungleich_page/ungleich_cms_page.html', gettext('ungleich')),
) )
DATABASES = { DATABASES = {
@ -347,8 +349,6 @@ MEDIA_ROOT = os.path.join(PROJECT_DIR, 'media')
MEDIA_URL = APP_ROOT_ENDPOINT + 'media/' MEDIA_URL = APP_ROOT_ENDPOINT + 'media/'
FILE_UPLOAD_PERMISSIONS = 0o644 FILE_UPLOAD_PERMISSIONS = 0o644
META_SITE_PROTOCOL = 'http'
META_USE_SITES = True
MIGRATION_MODULES = { MIGRATION_MODULES = {
'cms': 'cms.migrations', 'cms': 'cms.migrations',
# 'filer': 'filer.migrations_django', # 'filer': 'filer.migrations_django',
@ -359,9 +359,6 @@ MIGRATION_MODULES = {
'djangocms_link': 'djangocms_link.migrations_django', 'djangocms_link': 'djangocms_link.migrations_django',
'djangocms_teaser': 'djangocms_teaser.migrations_django', 'djangocms_teaser': 'djangocms_teaser.migrations_django',
'djangocms_column': 'djangocms_column.migrations_django', 'djangocms_column': 'djangocms_column.migrations_django',
'djangocms_flash': 'djangocms_flash.migrations_django',
'djangocms_googlemap': 'djangocms_googlemap.migrations_django',
'djangocms_inherit': 'djangocms_inherit.migrations_django',
'djangocms_style': 'djangocms_style.migrations_django', 'djangocms_style': 'djangocms_style.migrations_django',
'cmsplugin_filer_image': 'cmsplugin_filer_image.migrations_django', 'cmsplugin_filer_image': 'cmsplugin_filer_image.migrations_django',
'cmsplugin_filer_file': 'cmsplugin_filer_file.migrations_django', 'cmsplugin_filer_file': 'cmsplugin_filer_file.migrations_django',
@ -495,10 +492,9 @@ AUTH_USER_MODEL = 'membership.CustomUser'
STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services" STRIPE_DESCRIPTION_ON_PAYMENT = "Payment for ungleich GmbH services"
# EMAIL MESSAGES # EMAIL MESSAGES
REGISTRATION_MESSAGE = {'subject': "Validation mail", REGISTRATION_MESSAGE = {
'message': 'Thank You for registering for account on Digital Glarus.\n' 'subject': "Digital Glarus registration",
'Please verify Your account under following link ' 'message': 'Thank You for registering for account on Digital Glarus.'
'http://{host}/en-us/digitalglarus/login/validate/{slug}',
} }
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')
@ -577,27 +573,47 @@ if DCL_ERROR_EMAILS_TO is not None:
if 'info@ungleich.ch' not in DCL_ERROR_EMAILS_TO_LIST: if 'info@ungleich.ch' not in DCL_ERROR_EMAILS_TO_LIST:
DCL_ERROR_EMAILS_TO_LIST.append('info@ungleich.ch') DCL_ERROR_EMAILS_TO_LIST.append('info@ungleich.ch')
ENABLE_DEBUG_LOGGING = bool_env('ENABLE_DEBUG_LOGGING') ENABLE_LOGGING = bool_env('ENABLE_LOGGING')
MODULES_TO_LOG = env('MODULES_TO_LOG')
LOG_LEVEL = env('LOG_LEVEL')
if ENABLE_DEBUG_LOGGING: if LOG_LEVEL is None:
LOG_LEVEL = 'DEBUG'
if ENABLE_LOGGING:
loggers_dict = {}
handlers_dict = {}
if MODULES_TO_LOG is None:
# set MODULES_TO_LOG to django, if it is not set
MODULES_TO_LOG = 'django'
modules_to_log_list = MODULES_TO_LOG.split(',')
for custom_module in modules_to_log_list:
logger_item = {
custom_module: {
'handlers': ['custom_file'],
'level': LOG_LEVEL,
'propagate': True
}
}
loggers_dict.update(logger_item)
custom_handler_item = {
'custom_file': {
'level': LOG_LEVEL,
'class': 'logging.FileHandler',
'filename':
"{PROJECT_DIR}/{LEVEL}.log".format(
LEVEL=LOG_LEVEL.lower(),
PROJECT_DIR=PROJECT_DIR
)
}
}
handlers_dict.update(custom_handler_item)
LOGGING = { LOGGING = {
'version': 1, 'version': 1,
'disable_existing_loggers': False, 'disable_existing_loggers': False,
'handlers': { 'handlers': handlers_dict,
'file': { 'loggers': loggers_dict
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': "{PROJECT_DIR}/debug.log".format(
PROJECT_DIR=PROJECT_DIR),
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
} }
TEST_MANAGE_SSH_KEY_PUBKEY = env('TEST_MANAGE_SSH_KEY_PUBKEY') TEST_MANAGE_SSH_KEY_PUBKEY = env('TEST_MANAGE_SSH_KEY_PUBKEY')

View file

@ -31,5 +31,5 @@ ALLOWED_HOSTS = [
".ipv6onlyhosting.com", ".ipv6onlyhosting.com",
".ipv6onlyhosting.net", ".ipv6onlyhosting.net",
".digitalglarus.ch", ".digitalglarus.ch",
".alplora.ch" ".hack4glarus.ch"
] ]

View file

@ -29,6 +29,8 @@ class HostingUserLoginForm(forms.Form):
def clean(self): def clean(self):
email = self.cleaned_data.get('email') email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password') password = self.cleaned_data.get('password')
if self.errors:
return self.cleaned_data
is_auth = authenticate(email=email, password=password) is_auth = authenticate(email=email, password=password)
if not is_auth: if not is_auth:
raise forms.ValidationError( raise forms.ValidationError(
@ -48,15 +50,17 @@ class HostingUserLoginForm(forms.Form):
class HostingUserSignupForm(forms.ModelForm): class HostingUserSignupForm(forms.ModelForm):
confirm_password = forms.CharField(widget=forms.PasswordInput()) confirm_password = forms.CharField(label=_("Confirm Password"),
password = forms.CharField(widget=forms.PasswordInput()) widget=forms.PasswordInput())
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput())
class Meta: class Meta:
model = CustomUser model = CustomUser
fields = ['name', 'email', 'password'] fields = ['name', 'email', 'password']
widgets = { widgets = {
'name': forms.TextInput( 'name': forms.TextInput(
attrs={'placeholder': 'Enter your name or company name'}), attrs={'placeholder': _('Enter your name or company name')}),
} }
def clean_confirm_password(self): def clean_confirm_password(self):

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-10-10 21:35+0530\n" "POT-Creation-Date: 2017-10-26 03:21+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"
@ -27,6 +27,15 @@ msgstr "Dein Account wurde noch nicht aktiviert."
msgid "User does not exist" msgid "User does not exist"
msgstr "Der Benutzer existiert nicht" msgstr "Der Benutzer existiert nicht"
msgid "Confirm Password"
msgstr "Passwort Bestätigung"
msgid "Password"
msgstr "Passwort"
msgid "Enter your name or company name"
msgstr "Gib Deinen Namen oder den Name Deines Unternehmens ein"
msgid "Paste here your public key" msgid "Paste here your public key"
msgstr "Füge Deinen Public Key ein" msgstr "Füge Deinen Public Key ein"
@ -155,9 +164,6 @@ msgstr "Ich möchte einen existierenden SSH-Key nutzen"
msgid "Upload" msgid "Upload"
msgstr "Hochladen" msgstr "Hochladen"
msgid "Your VM hosted in Switzerland"
msgstr "Deine VM in der Schweiz"
msgid "Set your new password" msgid "Set your new password"
msgstr "Setze Dein neues Passwort" msgstr "Setze Dein neues Passwort"
@ -195,101 +201,78 @@ msgid "Support / Contact"
msgstr "Support / Kontakt" msgstr "Support / Kontakt"
#, python-format #, python-format
msgid "" msgid "Your New VM %(vm_name)s"
"You have ordered a new virtual machine!\n" msgstr "Deine Neue VM %(vm_name)s"
"<br/>\n"
"Your order of [%(vm_name)s] has been charged.<br/><br/>\n"
"You can view your invoice by clicking the button below.<br/><br/>\n"
msgstr ""
"Du hast eine neue virtuelle Maschine bestellt!<br/>\n"
"Deine Bestellung von [%(vm_name)s] wurde erhoben.<br/><br/>\n"
"Um die Rechnung zu sehen, klicke auf den Button unten.<br/><br/>\n"
msgid "View Invoice" msgid "You have ordered a new virtual machine!"
msgstr "Zur Rechnung" msgstr "Du hast eine neue virtuelle Maschine bestellt!"
#, python-format #, python-format
msgid "" msgid "Your order of <strong>%(vm_name)s</strong> has been charged."
"You have ordered a new virtual machine!\n" msgstr "Deine Bestellung von <strong>%(vm_name)s</strong> wurde erhoben."
"Your order of [%(vm_name)s] has been charged.\n"
"You can view your invoice here.\n" msgid "You can view your VM detail by clicking the button below."
msgstr "" msgstr "Um die Rechnung zu sehen, klicke auf den Button unten."
"Du hast eine neue virtuelle Maschine bestellt!\n"
"Deine Bestellung von [%(vm_name)s] wurde erhoben.\n" msgid "View Detail"
"Um die Rechnung zu sehen, klicke hier.\n" msgstr "Details anzeigen"
msgid "Your Data Center Light Team"
msgstr "Dein Data Center Light Team"
#, python-format
msgid "Your order of %(vm_name)s has been charged."
msgstr "Deine Bestellung von %(vm_name)s wurde erhoben."
msgid "You can view your VM detail by following the link below."
msgstr "Um die Rechnung zu sehen, klicke auf den Link unten."
msgid "Password Reset" msgid "Password Reset"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
#, python-format msgid "We received a request to reset your password."
msgid "" msgstr "Wir haben eine Anfrage erhalten, um Dein Passwort zurückzusetzen."
"\n"
"You're receiving this email because you requested a password reset for your " msgid "If you didn't make this request you can safely ignore this email."
"user account at %(site_name)s.<br/>\n"
"Please go to the following page and choose a new password: %(base_url)s"
"%(password_reset_url)s<br/>\n"
"If you didn't request a new password, ignore this e-mail.<br/>\n"
"Thank you!\n"
msgstr "" msgstr ""
"\n" "Falls Du kein neues Passwort angefragt hast, kannst Du diese E-mail "
"Du erhälst diese E-Mail da Du Dein Passwort für Deinen Account bei " "ignorieren."
"%(site_name)s zurücksetzen möchtest.<br/>\n"
"Bitte folge diesem Link und wähle ein neues Passwort: %(base_url)s" msgid "Otherwise, click here to reset your password."
"%(password_reset_url)s Solltest Du kein neues Passwort angefordert haben, " msgstr "Andernfalls klicke hier, um Dein Passwort zurückzusetzen."
"dann ignoriere diese E-Mail.<br/>\n"
"Dankeschön!\n" msgid "Thank you!"
msgstr "Dankeschön!"
msgid "Virtual Machine Cancellation"
msgstr "VM Kündigung"
#, python-format #, python-format
msgid "" msgid ""
"You're receiving this email because you requested a password reset for your " "You are receiving this email because your virutal machine <strong>"
"user account at %(site_name)s.\n" "%(vm_name)s</strong> has been cancelled."
"Please go to the following page and choose a new password: %(base_url)s"
"%(password_reset_url)s\n"
"If you didn't request a new password, ignore this e-mail.\n"
"Thank you!\n"
msgstr "" msgstr ""
"Du erhälst diese E-Mail da Du Dein Passwort für Deinen Account bei " "Du erhälst diese E-Mail, da deine virtuelle Maschine <strong>%(vm_name)s</"
"%(site_name)s zurücksetzen möchtest.\n" "strong> gekündigt wurde."
"Bitte folge diesem Link und wähle ein neues Passwort: %(base_url)s"
"%(password_reset_url)s Solltest Du kein neues Passwort angefordert haben, " msgid "You can always order a new VM by clicking the button below."
"dann ignoriere diese E-Mail.\n" msgstr ""
"Dankeschön!\n" "Du kannst einfach eine neue VM bestellen, indem Du den Knopf weiter unten "
"drückst."
msgid "CREATE VM"
msgstr "NEUE VM"
#, python-format #, python-format
msgid "" msgid ""
"You're receiving this mail because your virtual machine [%(vm_name)s] has " "You are receiving this email because your virutal machine %(vm_name)s has "
"been cancelled.<br/>\n" "been cancelled."
"You can see your order status by clicking [my VM page] below.<br/>\n"
"If you want to order a new virtual machine, you can do it by clicking <a "
"href=\"%(base_url)s%(my_virtual_machines_url)s\">this link</a>.<br/>\n"
msgstr "" msgstr ""
"Du erhälst diese E-Mail, Da Deine virtuelle Maschine [%(vm_name)s] gekündigt " "Du erhälst diese E-Mail, da deine virtuelle Maschine %(vm_name)s gekündigt "
"wurde.<br/>\n" "wurde."
"Um Deinen Auftragsstatus zu sehen, klicke auf die [my VM page] unten.<br/>\n"
"Falls Du eine neue virtuelle Maschine bestellen möchtest, kannst Du dies "
"tun, indem Du <a href=\"%(base_url)s%(my_virtual_machines_url)s\">diesen "
"Link klickst</a>.<br/>\n"
msgid "My VM page" msgid "You can always order a new VM by following the link below."
msgstr "Meine VM page"
#, python-format
msgid ""
"You're receiving this mail because your virtual machine [%(vm_name)s] has "
"been cancelled.\n"
"You can see your order status by clicking here\n"
"%(base_url)s%(vm_order_url)s\n"
"If you want to order a new virtual machine, you can do it by clicking this "
"link.\n"
"%(base_url)s%(my_virtual_machines_url)s\n"
msgstr "" msgstr ""
"Du erhälst diese E-Mail, da Deine virtuelle Maschine [%(vm_name)s] gekündigt "
"wurde.\n"
"Um Deinen Auftragsstatus zu sehen, klicke hier.\n"
"%(base_url)s%(vm_order_url)s\n"
"Falls Du eine neue virtuelle Maschine bestellen möchtest, kannst Du dies "
"tun, indem Du diesen Link klickst.\n"
"%(base_url)s%(my_virtual_machines_url)s\n"
msgid "Toggle navigation" msgid "Toggle navigation"
msgstr "Umschalten" msgstr "Umschalten"
@ -300,6 +283,9 @@ msgstr "Dashboard"
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
msgid "Log in"
msgstr "Anmelden"
msgid "Don't have an account yet ?" msgid "Don't have an account yet ?"
msgstr "Besitzt du kein Benutzerkonto?" msgstr "Besitzt du kein Benutzerkonto?"
@ -478,7 +464,7 @@ msgstr "Deine Kreditkartennummer"
msgid "Submit" msgid "Submit"
msgstr "Absenden" msgstr "Absenden"
msgid "Reset your password" msgid "Password reset"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
msgid "UPDATE" msgid "UPDATE"
@ -630,12 +616,6 @@ msgstr ""
"Um auf Deine VM zuzugreifen, <a href=\"%(create_ssh_url)s\">füge Deinen SSH-" "Um auf Deine VM zuzugreifen, <a href=\"%(create_ssh_url)s\">füge Deinen SSH-"
"Key hinzu</a>" "Key hinzu</a>"
msgid "CREATE VM"
msgstr "NEUE VM"
msgid "View Detail"
msgstr "Details anzeigen"
msgid "login" msgid "login"
msgstr "anmelden" msgstr "anmelden"
@ -660,6 +640,9 @@ msgstr "Dein Account wurde aktiviert."
msgid "You can now" msgid "You can now"
msgstr "Du kannst dich nun" msgstr "Du kannst dich nun"
msgid "Welcome to Data Center Light!"
msgstr "Willkommen beim Data Center Light!"
msgid "Sorry. Your request is invalid." msgid "Sorry. Your request is invalid."
msgstr "Entschuldigung, deine Anfrage ist ungültig." msgstr "Entschuldigung, deine Anfrage ist ungültig."
@ -730,14 +713,21 @@ msgstr ""
msgid "Error terminating VM" msgid "Error terminating VM"
msgstr "Fehler beenden VM" msgstr "Fehler beenden VM"
msgid "Virtual Machine Cancellation" #, python-format
msgstr "VM Kündigung" msgid "Virtual Machine %(vm_name)s Cancelled"
msgstr "Virtuelle Maschine %(vm_name)s Kündigung"
msgid "There was an error processing your request. Please try again." msgid "There was an error processing your request. Please try again."
msgstr "" msgstr ""
"Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte versuche es " "Es gab einen Fehler bei der Bearbeitung Deine Anfrage. Bitte versuche es "
"noch einmal." "noch einmal."
#~ msgid "Reset your password"
#~ msgstr "Passwort zurücksetzen"
#~ msgid "My VM page"
#~ msgstr "Meine VM page"
#~ msgid "Invoice Date" #~ msgid "Invoice Date"
#~ msgstr "Rechnung Datum" #~ msgstr "Rechnung Datum"
@ -765,12 +755,27 @@ msgstr ""
#~ msgid "Start VM" #~ msgid "Start VM"
#~ msgstr "VM jetzt starten" #~ msgstr "VM jetzt starten"
#~ msgid "View Invoice"
#~ msgstr "Zur Rechnung"
#~ msgid ""
#~ "You're receiving this mail because your virtual machine [%(vm_name)s] has "
#~ "been cancelled.<br/>\n"
#~ "You can see your order status by clicking [my VM page] below.<br/>\n"
#~ "If you want to order a new virtual machine, you can do it by clicking <a "
#~ "href=\"%(base_url)s%(my_virtual_machines_url)s\">this link</a>.<br/>\n"
#~ msgstr ""
#~ "Du erhälst diese E-Mail, da deine virtuelle Maschine [%(vm_name)s] "
#~ "gekündigt wurde.<br/>\n"
#~ "Um deinen Auftragsstatus zu sehen, klicke auf die [my VM page] unten.<br/"
#~ ">\n"
#~ "Falls du eine neue virtuelle Maschine bestellen möchtest, kannst du dies "
#~ "tun, indem du <a href=\"%(base_url)s%(my_virtual_machines_url)s\">diesen "
#~ "Link klickst</a>.<br/>\n"
#~ msgid "Finish Configuration" #~ msgid "Finish Configuration"
#~ msgstr "Konfiguration beenden" #~ msgstr "Konfiguration beenden"
#~ msgid "Your New VM %(vm_name)s at Data Center Light"
#~ msgstr "Deine neue VM %(vm_name)s bei Data Center Light"
#~ msgid "My Virtual Machines" #~ msgid "My Virtual Machines"
#~ msgstr "Meine virtuellen Maschinen" #~ msgstr "Meine virtuellen Maschinen"
@ -828,9 +833,6 @@ msgstr ""
#~ msgid "Keys" #~ msgid "Keys"
#~ msgstr "Keys" #~ msgstr "Keys"
#~ msgid "Log in"
#~ msgstr "Anmelden"
#~ msgid "You haven been logged out" #~ msgid "You haven been logged out"
#~ msgstr "Du wurdest abgemeldet" #~ msgstr "Du wurdest abgemeldet"

View file

@ -1,7 +1,9 @@
import os import os
import logging import logging
from dateutil.relativedelta import relativedelta
from django.db import models from django.db import models
from django.utils import timezone
from django.utils.functional import cached_property from django.utils.functional import cached_property
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from membership.models import StripeCustomer, CustomUser from membership.models import StripeCustomer, CustomUser
@ -172,3 +174,9 @@ class VMDetail(models.Model):
ipv6 = models.TextField(default='') ipv6 = models.TextField(default='')
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
terminated_at = models.DateTimeField(null=True) terminated_at = models.DateTimeField(null=True)
def end_date(self):
end_date = self.terminated_at if self.terminated_at else timezone.now()
months = relativedelta(end_date, self.created_at).months or 1
end_date = self.created_at + relativedelta(months=months, days=-1)
return end_date

View file

@ -18,7 +18,7 @@
} }
.content-dashboard{ .content-dashboard{
min-height: calc(100vh - 70px); min-height: calc(100vh - 60px);
width: 80%; width: 80%;
margin: 0 auto; margin: 0 auto;
max-width: 1120px; max-width: 1120px;
@ -66,7 +66,9 @@
width: 280px; width: 280px;
} }
.content-dashboard { .content-dashboard {
width: 90%; padding-left: 15px;
padding-right: 15px;
width: 100%;
} }
} }
.btn:focus, .btn:active:focus { .btn:focus, .btn:active:focus {
@ -296,10 +298,6 @@
max-width: 360px; max-width: 360px;
} }
.btn-wide {
min-width: 100px;
}
.caps-link { .caps-link {
font-weight: 600; font-weight: 600;
color: #8da4c0; color: #8da4c0;
@ -376,3 +374,11 @@
color: #999; color: #999;
fill: #999; fill: #999;
} }
.locale_date {
opacity: 0;
}
.locale_date.done{
opacity: 1;
}

View file

@ -17,9 +17,11 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
/*font-family: 'Lato-Regular', sans-serif;*/
font-family: 'Lato', sans-serif; font-family: 'Lato', sans-serif;
/*font-weight: 300;*/ }
.allcaps {
text-transform: uppercase;
} }
.topnav { .topnav {
@ -31,6 +33,11 @@ h6 {
.navbar-brand { .navbar-brand {
padding: 10px 15px; padding: 10px 15px;
} }
@media (max-width: 767px) {
.navbar-brand {
padding: 10px 0;
}
}
.navbar-default { .navbar-default {
background: #fff; background: #fff;
@ -46,7 +53,7 @@ h6 {
.navbar-transparent { .navbar-transparent {
background: transparent; background: transparent;
border: none; border: none;
padding: 20px; padding: 20px 0;
box-shadow: none; box-shadow: none;
} }
@ -72,7 +79,6 @@ h6 {
.navbar-transparent #logoWhite{ .navbar-transparent #logoWhite{
display: block; display: block;
width: 220px; width: 220px;
/* color: #fff; */
} }
.navbar-right .highlights-dropdown .dropdown-menu { .navbar-right .highlights-dropdown .dropdown-menu {
@ -92,16 +98,6 @@ h6 {
border-color: #e7e7e7; border-color: #e7e7e7;
box-shadow: -8px 14px 20px -5px rgba(77, 77, 77, 0.5); box-shadow: -8px 14px 20px -5px rgba(77, 77, 77, 0.5);
} }
/* .navbar-right .highlights-dropdown .dropdown-menu:before {
content: '';
display: block;
height: 1px;
background: #e7e7e7;
position: absolute;
top: -1px;
left: -1px;
right: -1px;
} */
} }
.navbar-right .highlights-dropdown .dropdown-menu > li > a{ .navbar-right .highlights-dropdown .dropdown-menu > li > a{
font-size: 13px; font-size: 13px;
@ -274,16 +270,15 @@ h6 {
/*------Auth section---------*/ /*------Auth section---------*/
.auth-container { .auth-container {
min-height: calc(100vh - 120px); min-height: calc(100vh - 180px);
position: relative; position: relative;
/* flex-grow: 1; */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
} }
.auth-bg { .auth-bg {
background: url(../img/auth-bg-sm.jpg); background: url(../img/pattern.jpg) no-repeat center center;
position: fixed; position: fixed;
left: 0; left: 0;
top: 0; top: 0;
@ -293,7 +288,6 @@ h6 {
background-position: center center; background-position: center center;
background-size: cover; background-size: cover;
background-attachment: fixed; background-attachment: fixed;
} }
.auth-bg::before { .auth-bg::before {
@ -303,7 +297,7 @@ h6 {
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
background: rgba(75, 75, 101, 0.55); background: rgba(90, 116, 175, 0.7);
z-index: 1; z-index: 1;
} }
@ -313,69 +307,38 @@ h6 {
.auth-container .auth-content { .auth-container .auth-content {
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto 15px;
max-width: 390px; max-width: 400px;
padding: 0 15px;
} }
.auth-container .auth-center { .auth-container .auth-content.wide {
/* position: absolute; */ max-width: 480px;
/* left: 50%; */
/* top: 50%; */
/* transform: translate(-50%, -50%); */
/* width: 100%; */
}
.auth-container .auth-title {
margin-bottom: 50px;
}
.auth-container .auth-title h2 {
color: #fff;
font-size: 44px;
text-align: center;
width: 425px;
margin: 0 auto;
margin-bottom: 30px;
position: relative;
}
.auth-container .auth-title h2::after {
content: "";
position: absolute;
bottom: -20px;
background: #fff;
height: 7px;
width: 70px;
left: 50%;
transform: translate(-50%, 0);
} }
.auth-box { .auth-box {
position: relative;
background: #fff; background: #fff;
padding: 0; padding: 40px 20px 20px;
padding-bottom: 30px;
box-sizing: border-box; box-sizing: border-box;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.09), 0 5px 5px rgba(0, 0, 0, 0.23);
border-radius: 4px;
z-index: 10; z-index: 10;
} }
.auth-box .section-heading { .auth-box .section-heading {
color: #5a5a5a; color: #5a5a5a;
padding-top: 30px; font-weight: 300;
padding-bottom: 5px;
text-align: center; text-align: center;
text-transform: uppercase; letter-spacing: 1px;
letter-spacing: 3px; font-size: 36px;
font-size: 20px;
border-radius: 3px 3px 0px 0px; border-radius: 3px 3px 0px 0px;
margin: 0 auto; margin: 0 auto 10px;
} }
.auth-box .form { .auth-box .form {
padding: 20px; padding: 20px;
width: 80%;
margin: 0 auto; margin: 0 auto;
max-width: 360px;
} }
.auth-box .form .red { .auth-box .form .red {
@ -383,27 +346,56 @@ h6 {
} }
.auth-box .form .btn { .auth-box .form .btn {
box-shadow: 0 0px 9px rgba(0, 0, 0, 0.19), 0 3px 5px rgba(0, 0, 0, 0.23); letter-spacing: 2px;
letter-spacing: 3px; font-size: 16px;
font-size: 17px; padding: 6px 12px;
min-width: 140px;
margin-top: 15px;
text-transform: uppercase; text-transform: uppercase;
} }
.auth-box .form .form-control { .auth-box .form .form-control {
height: 44px; height: 48px;
font-size: 16px; font-size: 14px;
padding: 10px 17px;
line-height: 30px;
border-color: #aaa;
}
.auth-box .form .form-control:focus,
.auth-box .form .form-control:active {
box-shadow: none;
border-radius: 0;
}
.auth-box .form-control::-webkit-input-placeholder {
color: #aaa;
}
.auth-box .form-control:-moz-placeholder{
/* Firefox 18- */
color: #aaa;
}
.auth-box .form-control::-moz-placeholder{
/* Firefox 19+ */
color: #aaa;
}
.auth-box .form-control:-ms-input-placeholder {
color: #aaa;
} }
.auth-box .auth-footer { .auth-box .auth-footer {
text-align: center; text-align: center;
padding: 10px; padding: 5px;
} }
.auth-box .auth-footer .text { .auth-box .auth-footer {
color: #777; color: #777;
} }
.auth-box .auth-footer .links a { .auth-box .auth-footer a {
color: #1e94cc; color: #1e94cc;
} }
@ -411,20 +403,11 @@ h6 {
color: #1e94cc; color: #1e94cc;
} }
.auth-box.sign-up {
padding-bottom: 5px;
}
.auth-box.sign-up .form {
padding: 15px 20px 0 20px;
}
.sign-up-message { .sign-up-message {
padding: 25px 30px 25px 30px; padding: 25px 30px 25px 30px;
text-align: center; text-align: center;
font-size: 18px; font-size: 18px;
line-height: 30px; line-height: 30px;
/*font-family: 'Lato' !important;*/
font-weight: 300 !important; font-weight: 300 !important;
} }
@ -458,16 +441,7 @@ h6 {
} }
.auth-box .form { .auth-box .form {
padding: 15px 0px 0 0; padding: 15px 0 15px 0;
}
.auth-box.sign-up .form {
padding: 15px 0px 0 0;
}
.auth-box .form .form-control {
height: 44px;
font-size: 13px;
} }
.auth-container .auth-title { .auth-container .auth-title {
@ -476,7 +450,7 @@ h6 {
} }
.auth-box .msg-list { .auth-box .msg-list {
padding: 15px 25px 5px; padding: 20px 25px 0;
text-align: center; text-align: center;
} }
@ -493,19 +467,14 @@ h6 {
margin-bottom: 50px; margin-bottom: 50px;
} }
.auth-box .form {
width: 90%;
}
.auth-box .section-heading { .auth-box .section-heading {
font-size: 15px; font-size: 32px;
} }
} }
footer { footer {
padding: 20px; padding: 20px 0;
background-color: #f8f8f8; background-color: #f8f8f8;
/* position: absolute */
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -537,7 +506,6 @@ a.unlink:hover {
/***** DCL payment page **********/ /***** DCL payment page **********/
.dcl-order-container { .dcl-order-container {
/*font-family: Lato;*/
font-weight: 300; font-weight: 300;
} }
@ -580,9 +548,7 @@ a.unlink:hover {
} }
.dcl-place-order-text{ .dcl-place-order-text{
/* font-size: 13px; */
color: #808080; color: #808080;
/* margin-bottom: 15px; */
} }
.dcl-order-table-total .tbl-total { .dcl-order-table-total .tbl-total {
@ -610,7 +576,6 @@ a.unlink:hover {
} }
.card-warning-content { .card-warning-content {
/*font-family: Lato;*/
font-weight: 300; font-weight: 300;
border: 1px solid #a1a1a1; border: 1px solid #a1a1a1;
border-radius: 3px; border-radius: 3px;
@ -638,18 +603,6 @@ a.unlink:hover {
right: 0; right: 0;
} }
.brand {
}
.brand #brand-icon {
}
.card-number-element {
}
.card-expiry-element {
}
.card-cvc-element label { .card-cvc-element label {
padding-left: 10px; padding-left: 10px;
} }
@ -735,9 +688,6 @@ a.unlink:hover {
margin-bottom: 30px; margin-bottom: 30px;
} }
.brand {
}
.card-expiry-element { .card-expiry-element {
padding-right: 10px; padding-right: 10px;
} }
@ -802,10 +752,23 @@ a.unlink:hover {
} }
} }
.footer-light {
.footer-light a:hover, .footer-light a:focus, .footer-light a:active { position: relative;
}
.footer-light footer {
background: transparent;
color: #eee;
}
.footer-light a,
.footer-light .text-muted {
color: #ddd; color: #ddd;
} }
.footer-light a:hover, .footer-light a:focus, .footer-light a:active {
color: #fff;
}
.footer-vm p.copyright {
margin-top: 4px;
}
.visible-mobile { .visible-mobile {
display: none !important; display: none !important;

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View file

@ -54,8 +54,7 @@
{% include "hosting/includes/_navbar_user.html" %} {% include "hosting/includes/_navbar_user.html" %}
{% endblock navbar %} {% endblock navbar %}
<div class="{% if request.user.is_authenticated %}content-dashboard{% endif %}">
<div class="content-dashboard">
{% block content %} {% block content %}
{% endblock %} {% endblock %}
</div> </div>

View file

@ -1,6 +1,5 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3%} {% load staticfiles bootstrap3 i18n %}
{% load i18n %}
{% block navbar %} {% block navbar %}
{% include 'hosting/includes/_navbar_transparent.html' %} {% include 'hosting/includes/_navbar_transparent.html' %}
@ -10,12 +9,9 @@
<div class="auth-container"> <div class="auth-container">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center"> <div class="auth-center">
<div class="auth-title">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
</div>
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="auth-box sign-up">
<h2 class="section-heading">{% trans "Set your new password"%}</h2> <h1 class="section-heading">{% trans "Set your new password" %}</h1>
{% if messages %} {% if messages %}
<ul class="list-unstyled msg-list"> <ul class="list-unstyled msg-list">
{% for message in messages %} {% for message in messages %}
@ -28,23 +24,18 @@
{% for field in form %} {% for field in form %}
{% bootstrap_field field show_label=False %} {% bootstrap_field field show_label=False %}
{% endfor %} {% endfor %}
{% buttons %} <div class="text-center">
<button type="submit" class="btn btn-block btn-success"> <button type="submit" class="btn choice-btn">
{% trans "Reset" %} {% trans "Reset" %}
</button> </button>
{% endbuttons %} </div>
</form> </form>
<div class="auth-footer"> <div class="auth-footer">
<div class="text"> <span>{% trans "Already have an account ?" %}</span>&nbsp;
<span>{% trans "Already have an account ?"%}</span>
</div>
<div class="links">
<a class="unlink" href="{% url 'hosting:login' %}">{% trans "Login" %}</a> <a class="unlink" href="{% url 'hosting:login' %}">{% trans "Login" %}</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -1,14 +1,51 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.html" %} {% load static i18n %}
{% load i18n %} <!DOCTYPE html>
{% block email_head %}{{page_header}}{% endblock %} <html>
{% block email_body %}
{% url 'hosting:orders' order.id as order_url %} <head>
{% blocktrans with vm.name as vm_name %}You have ordered a new virtual machine! <meta charset="UTF-8">
<br/> <meta name="viewport" content="width=device-width, initial-scale=1">
Your order of [{{vm_name}}] has been charged.<br/><br/> <title>{% blocktrans %}Your New VM {{vm_name}}{% endblocktrans %}</title>
You can view your invoice by clicking the button below.<br/><br/> <link rel="shortcut icon" href="{{ base_url }}{% static 'datacenterlight/img/favicon.ico' %}" type="image/x-icon">
{% endblocktrans %} <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400">
<div class="button" style="border-collapse: collapse; font-family: 'Lato', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center"> </head>
<a href="{{ base_url }}{{order_url}}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">{% trans 'View Invoice' %}</a>
</div> <body style="margin: 0; padding: 20px 0;">
{% endblock %} <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
<tr>
<td>
<img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
</td>
</tr>
<tr>
<td style="padding-top: 15px;">
<h1 style="font-family: Lato, Arial, sans-serif; font-size: 25px; font-weight: 400; margin: 0;">{% blocktrans %}Your New VM {{ vm_name }}{% endblocktrans %}</h1>
</td>
</tr>
<tr>
<td style="padding-top: 25px; font-size: 16px;">
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}You have ordered a new virtual machine!{% endblocktrans %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}Your order of <strong>{{ vm_name }}</strong> has been charged.{% endblocktrans %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}You can view your VM detail by clicking the button below.{% endblocktrans %}
</p>
</td>
</tr>
<tr>
<td style="padding-top: 30px;">
<a class="btn" href="{{ base_url }}{{ order_url }}" style="font-family: Lato, Arial, sans-serif; text-decoration: none; background-color: #1596da; color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 30px; padding-right: 30px; letter-spacing: 0.5px; border-radius: 3px; display: inline-block; position: relative;">{% trans "View Detail" %}</a>
</td>
</tr>
<tr>
<td style="padding-top: 40px; padding-bottom: 25px;">
<h3 style="font-family: Lato, Arial, sans-serif; margin: 0; font-weight: 400; font-size: 15px;">{% trans "Your Data Center Light Team" %}</h3>
</td>
</tr>
</table>
</body>
</html>

View file

@ -1,11 +1,11 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.txt" %}
{% load i18n %} {% load i18n %}
{% block email_head %}{{page_header}}{% endblock %}
{% block email_body %} {% blocktrans %}Your New VM {{vm_name}}{% endblocktrans %}
{% url 'hosting:orders' order.id as order_url %}
{% blocktrans with vm.name as vm_name %}You have ordered a new virtual machine! {% blocktrans %}You have ordered a new virtual machine!{% endblocktrans %}
Your order of [{{vm_name}}] has been charged. {% blocktrans %}Your order of {{vm_name}} has been charged.{% endblocktrans %}
You can view your invoice here. {% blocktrans %}You can view your VM detail by following the link below.{% endblocktrans %}
{% endblocktrans %}
{{ base_url }}{{ order_url }} {{ base_url }}{{ order_url }}
{% endblock %}
{% trans "Your Data Center Light Team" %}

View file

@ -1,14 +1,52 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.html" %} {% load static i18n %}
{% load i18n %} <!DOCTYPE html>
{% block email_head %} <html>
{% trans 'Password Reset' %}
{% endblock %} <head>
{% block email_body %} <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% trans "Password Reset" %}</title>
<link rel="shortcut icon" href="{{ base_url }}{% static 'datacenterlight/img/favicon.ico' %}" type="image/x-icon">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400">
</head>
<body style="margin: 0; padding: 20px 0;">
<table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
<tr>
<td>
<img src="{{base_url}}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
</td>
</tr>
<tr>
<td style="padding-top: 15px;">
<h1 style="font-family: Lato, Arial, sans-serif; font-size: 25px; font-weight: 400; margin: 0;">{% trans "Password Reset" %}</h1>
</td>
</tr>
<tr>
<td style="padding-top: 25px; font-size: 16px;">
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 10px; margin-top: 0;">
{% trans "We received a request to reset your password." %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 10px; margin-top: 0;">
{% trans "If you didn't make this request you can safely ignore this email." %}
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 10px; margin-top: 0;">
{% trans "Otherwise, click here to reset your password." %}
</p>
<p style="color: #4382c8; line-height: 1.4; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% url 'hosting:reset_password_confirm' uidb64=uid token=token as password_reset_url %} {% url 'hosting:reset_password_confirm' uidb64=uid token=token as password_reset_url %}
{% blocktrans %} {{base_url}}{{ password_reset_url }}
You're receiving this email because you requested a password reset for your user account at {{site_name}}.<br/> </p>
Please go to the following page and choose a new password: {{base_url}}{{ password_reset_url }}<br/> <p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin-bottom: 0; margin-top: 10px;">
If you didn't request a new password, ignore this e-mail.<br/> {% trans "Thank you!" %}
Thank you! </p>
{% endblocktrans %} </td>
{% endblock %} </tr>
<tr>
<td style="padding-top: 40px; padding-bottom: 25px;">
<h3 style="font-family: Lato, Arial, sans-serif; margin: 0; font-weight: 400; font-size: 15px;">{% trans "Your Data Center Light Team" %}</h3>
</td>
</tr>
</table>
</body>
</html>

View file

@ -1,11 +1,14 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.txt" %}
{% load i18n %} {% load i18n %}
{% block email_head %}{% trans 'Password Reset' %}{% endblock %}
{% block email_body %} {% trans "Password Reset" %}
{% trans "We received a request to reset your password." %}
{% trans "If you didn't make this request you can safely ignore this email." %}
{% trans "Otherwise, click here to reset your password." %}
{% url 'hosting:reset_password_confirm' uidb64=uid token=token as password_reset_url %} {% url 'hosting:reset_password_confirm' uidb64=uid token=token as password_reset_url %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{site_name}}. {{base_url}}{{ password_reset_url }}
Please go to the following page and choose a new password: {{base_url}}{{ password_reset_url }}
If you didn't request a new password, ignore this e-mail. {% trans "Thank you!" %}
Thank you!
{% endblocktrans %} {% trans "Your Data Center Light Team" %}
{% endblock %}

View file

@ -1,15 +1,49 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.html" %} {% load static i18n %}
{% load i18n %} <!DOCTYPE html>
{% block email_head %}{{page_header}}{% endblock %} <html>
{% block email_body %}
{% url 'hosting:virtual_machines' as my_virtual_machines_url %} <head>
{% url 'hosting:orders' as vm_orders_url %} <meta charset="UTF-8">
{% blocktrans with vm.name as vm_name %}You're receiving this mail because your virtual machine [{{vm_name}}] has been cancelled.<br/> <meta name="viewport" content="width=device-width, initial-scale=1">
You can see your order status by clicking [my VM page] below.<br/> <title>{% trans "Virtual Machine Cancellation" %}</title>
If you want to order a new virtual machine, you can do it by clicking <a href="{{base_url}}{{my_virtual_machines_url}}">this link</a>.<br/> <link rel="shortcut icon" href="{{ base_url }}{% static 'datacenterlight/img/favicon.ico' %}" type="image/x-icon">
{% endblocktrans %} <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400">
<div class="button" style="border-collapse: collapse; font-family: 'Lato', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center"> </head>
<a href="{{ base_url }}{{vm_orders_url}}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">{% trans 'My VM page' %}</a>
</div> <body style="margin: 0; padding: 20px 0;">
{% endblock %} <table style="width: 100%; border-spacing: 0; border-collapse: collapse; max-width: 560px;">
<tr>
<td>
<img src="{{ base_url }}{% static 'datacenterlight/img/logo_black.png' %}" style="width: 200px; height: 50px;">
</td>
</tr>
<tr>
<td style="padding-top: 15px;">
<h1 style="font-family: Lato, Arial, sans-serif; font-size: 25px; font-weight: 400; margin: 0;">{% trans "Virtual Machine Cancellation" %}</h1>
</td>
</tr>
<tr>
<td style="padding-top: 25px; font-size: 16px;">
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}You are receiving this email because your virutal machine <strong>{{ vm_name }}</strong> has been cancelled.{% endblocktrans %}
</p>
<p style="line-height: 1.75; font-family: Lato, Arial, sans-serif; font-weight: 300; margin: 0;">
{% blocktrans %}You can always order a new VM by clicking the button below.{% endblocktrans %}
</p>
</td>
</tr>
<tr>
<td style="padding-top: 30px;">
<a class="btn" href="{{ base_url }}{% url 'hosting:create_virtual_machine' %}" style="font-family: Lato, Arial, sans-serif; text-decoration: none; background-color: #1596da; color: #fff; padding-top: 10px; padding-bottom: 10px; padding-left: 30px; padding-right: 30px; letter-spacing: 0.5px; border-radius: 3px; display: inline-block; position: relative;">{% trans "CREATE VM" %}</a>
</td>
</tr>
<tr>
<td style="padding-top: 40px; padding-bottom: 25px;">
<h3 style="font-family: Lato, Arial, sans-serif; margin: 0; font-weight: 400; font-size: 15px;">{% trans "Your Data Center Light Team" %}</h3>
</td>
</tr>
</table>
</body>
</html>

View file

@ -1,13 +1,10 @@
{% extends "datacenterlight/emails/base_email_datacenterlight.txt" %}
{% load i18n %} {% load i18n %}
{% block email_head %}{{page_header}}{% endblock %}
{% block email_body %} {% trans "Virtual Machine Cancellation" %}
{% url 'hosting:virtual_machines' as my_virtual_machines_url %}
{% url 'hosting:orders' order.id as vm_order_url %} {% blocktrans %}You are receiving this email because your virutal machine {{vm_name}} has been cancelled.{% endblocktrans %}
{% blocktrans with vm.name as vm_name %}You're receiving this mail because your virtual machine [{{vm_name}}] has been cancelled. {% blocktrans %}You can always order a new VM by following the link below.{% endblocktrans %}
You can see your order status by clicking here
{{base_url}}{{vm_order_url}} {{ base_url }}{% url 'hosting:create_virtual_machine' %}
If you want to order a new virtual machine, you can do it by clicking this link.
{{base_url}}{{my_virtual_machines_url}} {% trans "Your Data Center Light Team" %}
{% endblocktrans %}
{% endblock %}

View file

@ -1,8 +1,7 @@
{% if messages %} {% if messages %}
<ul class="list-unstyled msg-list"> <ul class="list-unstyled msg-list">
{% for message in messages %} {% for message in messages %}
<div <div class="alert {% if message.tags and message.tags == 'error' %} alert-danger {% else %} alert-{{message.tags}} {% endif %}">{{ message|safe }}</div>
class="alert {% if message.tags and message.tags == 'error' %} alert-danger {% else %} alert-{{message.tags}} {% endif %}">{{ message|safe }}</div>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View file

@ -1,6 +1,7 @@
{% load static i18n %} {% load static i18n %}
<nav class="navbar navbar-default topnav navbar-transparent" role="navigation"> <nav class="navbar navbar-default topnav navbar-transparent" role="navigation">
<div class="container">
<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">
@ -8,4 +9,5 @@
</div> </div>
</div> </div>
<!-- /.container --> <!-- /.container -->
</div>
</nav> </nav>

View file

@ -1,6 +1,5 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load i18n %} {% load i18n staticfiles bootstrap3%}
{% load staticfiles bootstrap3%}
{% block navbar %} {% block navbar %}
{% include 'hosting/includes/_navbar_transparent.html' %} {% include 'hosting/includes/_navbar_transparent.html' %}
@ -10,12 +9,9 @@
<div class="auth-container"> <div class="auth-container">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center"> <div class="auth-center">
<div class="auth-title">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
</div>
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box"> <div class="auth-box">
<h2 class="section-heading">{% trans "Login"%}</h2> <h1 class="section-heading allcaps">{% trans "Log in" %}</h1>
{% include 'hosting/includes/_messages.html' %} {% include 'hosting/includes/_messages.html' %}
<form action="{% url 'hosting:login' %}" method="post" class="form" novalidated> <form action="{% url 'hosting:login' %}" method="post" class="form" novalidated>
{% csrf_token %} {% csrf_token %}
@ -23,23 +19,21 @@
{% bootstrap_field field show_label=False type='fields'%} {% bootstrap_field field show_label=False type='fields'%}
{% endfor %} {% endfor %}
<p class="red">{{form.non_field_errors|striptags}}</p> <p class="red">{{form.non_field_errors|striptags}}</p>
{% buttons %} <div class="text-center">
<button type="submit" class="btn btn-block btn-success"> <button type="submit" class="btn choice-btn">
{% trans "Log in" %} {% trans "Log in" %}
</button> </button>
{% endbuttons %} </div>
<input type='hidden' name='next' value='{{request.GET.next}}'/> <input type='hidden' name='next' value='{{request.GET.next}}'/>
</form> </form>
<div class="auth-footer"> <div class="auth-footer">
<div class="text"> <div>
<span>{% trans "Don't have an account yet ? "%}</span> {% trans "Don't have an account yet ?" %}&nbsp;
<a class="" href="{% url 'hosting:signup' %}">{% trans "Sign up" %}</a>
</div> </div>
<div class="links"> <div>
<a class="unlink" href="{% url 'hosting:signup' %}">{% trans "Sign up"%}</a> or <a href="{% url 'hosting:reset_password' %}">{% trans "Forgot your password ?" %}</a><br>
<span class="text"> or </span> or <a href="{% url 'hosting:resend_activation_link' %}">{% trans "Resend activation link" %}</a>
<a class="unlink" href="{% url 'hosting:reset_password' %}">{% trans "Forgot your password ? "%}</a>
<span class="text"> or </span><br/>
<a class="unlink" href="{% url 'hosting:resend_activation_link' %}">{% trans "Resend activation link"%}</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -32,11 +32,11 @@
{% endif %} {% endif %}
<p> <p>
<strong>{% trans "Date" %}:</strong> <strong>{% trans "Date" %}:</strong>
<span id="order-created_at"> <span class="locale_date">
{% if order %} {% if order %}
{{order.created_at|date:'Y-m-d H:i'}} {{order.created_at|date:'Y-m-d h:i a'}}
{% else %} {% else %}
{% now "Y-m-d H:i" %} {% now "Y-m-d h:i a" %}
{% endif %} {% endif %}
</span> </span>
</p> </p>
@ -107,7 +107,9 @@
{% if vm.created_at %} {% if vm.created_at %}
<p> <p>
<span>{% trans "Period" %}: </span> <span>{% trans "Period" %}: </span>
<span>{{ vm.created_at|date:'Y/m/d' }} - {% if vm.terminated_at %}{{ vm.terminated_at|date:'Y/m/d' }}{% else %}{% now 'Y/m/d' %}{% endif %}</span> <span>
<span class="locale_date" data-format="YYYY/MM/DD">{{ vm.created_at|date:'Y-m-d h:i a' }}</span> - <span class="locale_date" data-format="YYYY/MM/DD">{{ subscription_end_date|date:'Y-m-d h:i a' }}</span>
</span>
</p> </p>
{% endif %} {% endif %}
<p> <p>
@ -194,12 +196,16 @@
<script type="text/javascript"> <script type="text/javascript">
{% trans "Some problem encountered. Please try again later." as err_msg %} {% trans "Some problem encountered. Please try again later." as err_msg %}
var create_vm_error_message = '{{err_msg|safe}}'; var create_vm_error_message = '{{err_msg|safe}}';
window.onload = function () { window.onload = function () {
var locale_date = moment.utc(document.getElementById("order-created_at").textContent, 'YYYY-MM-DD HH:mm').toDate(); var locale_dates = document.getElementsByClassName("locale_date");
locale_date = moment(locale_date).format("YYYY-MM-DD h:mm:ss a"); var formats = ['YYYY-MM-DD hh:mm a']
document.getElementById('order-created_at').innerHTML = locale_date; var i;
for (i = 0; i < locale_dates.length; i++) {
var oldDate = moment.utc(locale_dates[i].textContent, formats);
var outputFormat = locale_dates[i].getAttribute('data-format') || oldDate._f;
locale_dates[i].innerHTML = oldDate.local().format(outputFormat);
locale_dates[i].className += ' done';
}
}; };
</script> </script>
{%endblock%} {%endblock%}

View file

@ -1,35 +1,38 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3%} {% load staticfiles bootstrap3 i18n %}
{% load i18n %}
{% block navbar %} {% block navbar %}
{% include 'hosting/includes/_navbar_transparent.html' %} {% include 'hosting/includes/_navbar_transparent.html' %}
{% endblock navbar %} {% endblock navbar %}
{% block content %} {% block content %}
<div class="auth-container"> <div class="auth-container">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center"> <div class="auth-center">
<div class="auth-title"> <div class="auth-content wide">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2> <div class="auth-box sign-up">
</div> <h1 class="section-heading">{% trans "Resend activation link" %}</h1>
<div class="auth-content">
<div class="intro-message auth-box sign-up">
<h2 class="section-heading">{% trans "Resend activation link"%}</h2>
{% include 'hosting/includes/_messages.html' %} {% include 'hosting/includes/_messages.html' %}
<form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate> <form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
{% bootstrap_field field show_label=False %} {% bootstrap_field field show_label=False %}
{% endfor %} {% endfor %}
{% buttons %} <div class="text-center">
<button type="submit" class="btn btn-block btn-success"> <button type="submit" class="btn choice-btn">
{% trans "Submit"%} {% trans "Submit"%}
</button> </button>
{% endbuttons %} </div>
</form> </form>
<div class="auth-footer">
<div>
{% trans "Don't have an account yet ?" %}&nbsp;
<a class="" href="{% url 'hosting:signup' %}">{% trans "Sign up" %}</a>
</div>
<div>
or <a href="{% url 'hosting:reset_password' %}">{% trans "Forgot your password ?" %}</a>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,40 +1,33 @@
{% extends "hosting/base_short.html" %} {% extends "hosting/base_short.html" %}
{% load staticfiles bootstrap3%} {% load i18n staticfiles bootstrap3%}
{% load i18n %}
{% block navbar %} {% block navbar %}
{% include 'hosting/includes/_navbar_transparent.html' %} {% include 'hosting/includes/_navbar_transparent.html' %}
{% endblock navbar %} {% endblock navbar %}
{% block content %} {% block content %}
<div class="auth-container"> <div class="auth-container">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center"> <div class="auth-center">
<div class="auth-title">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
</div>
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="auth-box sign-up">
<h2 class="section-heading">{% trans "Reset your password"%}</h2> <h1 class="section-heading">{% trans "Password reset" %}</h1>
{% include 'hosting/includes/_messages.html' %} {% include 'hosting/includes/_messages.html' %}
<form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate> <form action="{% url 'hosting:reset_password' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
{% bootstrap_field field show_label=False %} {% bootstrap_field field show_label=False %}
{% endfor %} {% endfor %}
{% buttons %} <div class="text-center">
<button type="submit" class="btn btn-block btn-success"> <button type="submit" class="btn choice-btn">
{% trans "Reset" %} {% trans "Reset" %}
</button> </button>
{% endbuttons %} </div>
</form> </form>
<div class="auth-footer"> <div class="auth-footer">
<div class="text"> <div>
<span>{% trans "Already have an account ?"%}</span> <span>{% trans "Already have an account ?" %}</span>&nbsp;
</div> <a href="{% url 'hosting:login' %}">{% trans "Login" %}</a>
<div class="links">
<a class="unlink" href="{% url 'hosting:login' %}">{% trans "Login"%}</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -9,30 +9,25 @@
<div class="auth-container auth-signup"> <div class="auth-container auth-signup">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center "> <div class="auth-center ">
<div class="auth-title">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
</div>
<div class="auth-content"> <div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="auth-box sign-up">
<h2 class="section-heading">{% trans "Sign up"%}</h2> <h1 class="section-heading allcaps">{% trans "Sign up" %}</h1>
{% include 'hosting/includes/_messages.html' %} {% include 'hosting/includes/_messages.html' %}
<form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate> <form action="{% url 'hosting:signup' %}" method="post" class="form" novalidate>
{% csrf_token %} {% csrf_token %}
{% for field in form %} {% for field in form %}
{% bootstrap_field field show_label=False %} {% bootstrap_field field show_label=False %}
{% endfor %} {% endfor %}
{% buttons %} <div class="text-center">
<button type="submit" class="btn btn-block btn-info"> <button type="submit" class="btn choice-btn">
{% trans "Sign up" %} {% trans "Sign up" %}
</button> </button>
{% endbuttons %} </div>
</form> </form>
<div class="auth-footer"> <div class="auth-footer">
<div class="text"> <div>
<span>{% trans "Already have an account ?"%}</span> <span>{% trans "Already have an account ?" %}</span>&nbsp;
</div> <a href="{% url 'hosting:login' %}">{% trans "Login" %}</a>
<div class="links">
<a class="unlink" href="{% url 'hosting:login' %}">{% trans "Login"%}</a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -9,11 +9,7 @@
<div class="auth-container"> <div class="auth-container">
<div class="auth-bg"></div> <div class="auth-bg"></div>
<div class="auth-center"> <div class="auth-center">
<div class="auth-title"> <div class="auth-content wide">
<h2>{% trans "Your VM hosted in Switzerland"%}</h2>
{% include 'hosting/includes/_messages.html' %}
</div>
<div class="auth-content">
<div class="intro-message auth-box sign-up"> <div class="intro-message auth-box sign-up">
<h2 class="section-heading">{{section_title}}</h2> <h2 class="section-heading">{{section_title}}</h2>
<div class="sign-up-message"> <div class="sign-up-message">

View file

@ -1,25 +1,18 @@
from django.test import TestCase from django.test import TestCase
from unittest import mock
from model_mommy import mommy from model_mommy import mommy
from .forms import HostingUserLoginForm, HostingUserSignupForm
from .forms import HostingOrderAdminForm, HostingUserLoginForm, HostingUserSignupForm
from .models import VirtualMachinePlan
class HostingUserLoginFormTest(TestCase): class HostingUserLoginFormTest(TestCase):
def setUp(self): def setUp(self):
password = 'user_password' password = 'user_password'
self.user = mommy.make('CustomUser') self.user = mommy.make('CustomUser', validated=1)
self.user.set_password(password) self.user.set_password(password)
self.user.save() self.user.save()
self.completed_data = { self.completed_data = {
'email': self.user.email, 'email': self.user.email,
'password': password 'password': password
} }
self.incorrect_data = { self.incorrect_data = {
'email': 'test', 'email': 'test',
} }
@ -34,9 +27,7 @@ class HostingUserLoginFormTest(TestCase):
class HostingUserSignupFormTest(TestCase): class HostingUserSignupFormTest(TestCase):
def setUp(self): def setUp(self):
self.completed_data = { self.completed_data = {
'name': 'test name', 'name': 'test name',
'email': 'test@ungleich.com', 'email': 'test@ungleich.com',
@ -58,13 +49,11 @@ class HostingUserSignupFormTest(TestCase):
class HostingOrderAdminFormTest(TestCase): class HostingOrderAdminFormTest(TestCase):
def setUp(self): def setUp(self):
self.customer = mommy.make('StripeCustomer') self.customer = mommy.make('StripeCustomer')
self.vm_plan = mommy.make('VirtualMachinePlan') self.vm_plan = mommy.make('VirtualMachinePlan')
self.vm_canceled_plan = mommy.make('VirtualMachinePlan', # self.vm_canceled_plan = mommy.make('VirtualMachinePlan',
status=VirtualMachinePlan.CANCELED_STATUS) # status=VirtualMachinePlan.CANCELED_STATUS)
self.mocked_charge = { self.mocked_charge = {
'amount': 5100, 'amount': 5100,
@ -87,30 +76,30 @@ class HostingOrderAdminFormTest(TestCase):
'customer': None 'customer': None
} }
@mock.patch('utils.stripe_utils.StripeUtils.make_charge') # @mock.patch('utils.stripe_utils.StripeUtils.make_charge')
def test_valid_form(self, stripe_mocked_call): # def test_valid_form(self, stripe_mocked_call):
stripe_mocked_call.return_value = { # stripe_mocked_call.return_value = {
'paid': True, # 'paid': True,
'response_object': self.mocked_charge, # 'response_object': self.mocked_charge,
'error': None # 'error': None
} # }
form = HostingOrderAdminForm(data=self.completed_data) # form = HostingOrderAdminForm(data=self.completed_data)
self.assertTrue(form.is_valid()) # self.assertTrue(form.is_valid())
@mock.patch('utils.stripe_utils.StripeUtils.make_charge') # @mock.patch('utils.stripe_utils.StripeUtils.make_charge')
def test_invalid_form_canceled_vm(self, stripe_mocked_call): # def test_invalid_form_canceled_vm(self, stripe_mocked_call):
#
self.completed_data.update({ # self.completed_data.update({
'vm_plan': self.vm_canceled_plan.id # 'vm_plan': self.vm_canceled_plan.id
}) # })
stripe_mocked_call.return_value = { # stripe_mocked_call.return_value = {
'paid': True, # 'paid': True,
'response_object': self.mocked_charge, # 'response_object': self.mocked_charge,
'error': None # 'error': None
} # }
form = HostingOrderAdminForm(data=self.completed_data) # form = HostingOrderAdminForm(data=self.completed_data)
self.assertFalse(form.is_valid()) # self.assertFalse(form.is_valid())
#
def test_invalid_form(self): # def test_invalid_form(self):
form = HostingOrderAdminForm(data=self.incompleted_data) # form = HostingOrderAdminForm(data=self.incompleted_data)
self.assertFalse(form.is_valid()) # self.assertFalse(form.is_valid())

View file

@ -1,75 +1,75 @@
from django.test import TestCase # from django.test import TestCase
#
from django.core.management import call_command # from django.core.management import call_command
#
#
from .models import VirtualMachineType # #from .models import VirtualMachineType
#
#
class VirtualMachineTypeModelTest(TestCase): # class VirtualMachineTypeModelTest(TestCase):
#
def setUp(self): # def setUp(self):
self.HETZNER_NUG_NAME = 'hetzner_nug' # self.HETZNER_NUG_NAME = 'hetzner_nug'
self.HETZNER_NAME = 'hetzner' # self.HETZNER_NAME = 'hetzner'
self.HETZNER_RAID6_NAME = 'hetzner_raid6' # self.HETZNER_RAID6_NAME = 'hetzner_raid6'
self.HETZNER_GLUSTERFS_NAME = 'hetzner_glusterfs' # self.HETZNER_GLUSTERFS_NAME = 'hetzner_glusterfs'
self.BERN_NAME = 'bern' # self.BERN_NAME = 'bern'
self.HETZNER_NUG_EXPECTED_PRICE = 79 # self.HETZNER_NUG_EXPECTED_PRICE = 79
self.HETZNER_EXPECTED_PRICE = 180 # self.HETZNER_EXPECTED_PRICE = 180
self.HETZNER_RAID6_EXPECTED_PRICE = 216 # self.HETZNER_RAID6_EXPECTED_PRICE = 216
self.HETZNER_GLUSTERFS_EXPECTED_PRICE = 252 # self.HETZNER_GLUSTERFS_EXPECTED_PRICE = 252
self.BERN_EXPECTED_PRICE = 202 # self.BERN_EXPECTED_PRICE = 202
#
call_command('create_vm_types') # call_command('create_vm_types')
#
def test_calculate_price(self): # def test_calculate_price(self):
#
# hetzner_nug # # hetzner_nug
# # specifications = {
# # 'cores': 2,
# # 'memory': 10,
# # 'disk_size': 100
# # }
# # vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_NUG_NAME)
# # calculated_price = vm_type.calculate_price(specifications)
# # self.assertEqual(calculated_price, self.HETZNER_NUG_EXPECTED_PRICE)
#
# # hetzner
# specifications = { # specifications = {
# 'cores': 2, # 'cores': 2,
# 'memory': 10, # 'memory': 10,
# 'disk_size': 100 # 'disk_size': 100
# } # }
# vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_NUG_NAME) # vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_NAME)
# calculated_price = vm_type.calculate_price(specifications) # calculated_price = vm_type.calculate_price(specifications)
# self.assertEqual(calculated_price, self.HETZNER_NUG_EXPECTED_PRICE) # self.assertEqual(calculated_price, self.HETZNER_EXPECTED_PRICE)
#
# hetzner # # hetzner_raid6
specifications = { # # specifications = {
'cores': 2, # # 'cores': 2,
'memory': 10, # # 'memory': 10,
'disk_size': 100 # # 'disk_size': 100
} # # }
vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_NAME) # # vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_RAID6_NAME)
calculated_price = vm_type.calculate_price(specifications) # # calculated_price = vm_type.calculate_price(specifications)
self.assertEqual(calculated_price, self.HETZNER_EXPECTED_PRICE) # # self.assertEqual(calculated_price, self.HETZNER_RAID6_EXPECTED_PRICE)
#
# hetzner_raid6 # # hetzner_glusterfs
# # specifications = {
# # 'cores': 2,
# # 'memory': 10,
# # 'disk_size': 100
# # }
# # vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_GLUSTERFS_NAME)
# # calculated_price = vm_type.calculate_price(specifications)
# # self.assertEqual(calculated_price, self.HETZNER_GLUSTERFS_EXPECTED_PRICE)
#
# # bern
# specifications = { # specifications = {
# 'cores': 2, # 'cores': 2,
# 'memory': 10, # 'memory': 10,
# 'disk_size': 100 # 'disk_size': 100
# } # }
# vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_RAID6_NAME) # vm_type = VirtualMachineType.objects.get(hosting_company=self.BERN_NAME)
# calculated_price = vm_type.calculate_price(specifications) # calculated_price = vm_type.calculate_price(specifications)
# self.assertEqual(calculated_price, self.HETZNER_RAID6_EXPECTED_PRICE) # self.assertEqual(calculated_price, self.BERN_EXPECTED_PRICE)
# hetzner_glusterfs
# specifications = {
# 'cores': 2,
# 'memory': 10,
# 'disk_size': 100
# }
# vm_type = VirtualMachineType.objects.get(hosting_company=self.HETZNER_GLUSTERFS_NAME)
# calculated_price = vm_type.calculate_price(specifications)
# self.assertEqual(calculated_price, self.HETZNER_GLUSTERFS_EXPECTED_PRICE)
# bern
specifications = {
'cores': 2,
'memory': 10,
'disk_size': 100
}
vm_type = VirtualMachineType.objects.get(hosting_company=self.BERN_NAME)
calculated_price = vm_type.calculate_price(specifications)
self.assertEqual(calculated_price, self.BERN_EXPECTED_PRICE)

View file

@ -1,4 +1,3 @@
from unittest import mock
from django.conf import settings from django.conf import settings
from django.test import TestCase from django.test import TestCase
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -6,21 +5,29 @@ from django.core.urlresolvers import resolve
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from unittest import skipIf
from model_mommy import mommy from model_mommy import mommy
from stored_messages.models import Inbox from stored_messages.models import Inbox
from membership.models import CustomUser, StripeCustomer from membership.models import CustomUser, StripeCustomer
from .models import VirtualMachineType, HostingOrder, VirtualMachinePlan from .models import HostingOrder
from .views import DjangoHostingView, RailsHostingView, NodeJSHostingView, LoginView, SignupView, \ from .views import (
PaymentVMView, OrdersHostingDetailView, OrdersHostingListView, VirtualMachineView, \ DjangoHostingView, RailsHostingView, NodeJSHostingView, LoginView,
VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView, HostingPricingView, \ SignupView, PaymentVMView, OrdersHostingDetailView, OrdersHostingListView,
NotificationsView, MarkAsReadNotificationView, GenerateVMSSHKeysView VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView,
HostingPricingView, NotificationsView, MarkAsReadNotificationView
)
from utils.tests import BaseTestCase from utils.tests import BaseTestCase
@skipIf(
(settings.OPENNEBULA_DOMAIN is None or
settings.OPENNEBULA_DOMAIN == "test_domain"),
"""OpenNebula details unavailable, so skipping
ProcessVMSelectionTestMixin"""
)
class ProcessVMSelectionTestMixin(object): class ProcessVMSelectionTestMixin(object):
def url_resolve_to_view_correctly(self): def url_resolve_to_view_correctly(self):
@ -30,14 +37,15 @@ class ProcessVMSelectionTestMixin(object):
def test_get(self): def test_get(self):
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(self.view.get_context_data(), self.expected_context) # self.assertEqual(self.view.get_context_data(), self.expected_context)
self.assertEqual(response.context['hosting'], self.expected_context['hosting']) self.assertEqual(response.context['hosting'], self.expected_context['hosting'])
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
def test_anonymous_post(self): # def test_anonymous_post(self):
response = self.client.post(self.url) # params = {'vm_template_id': 1, 'configuration': 1}
self.assertRedirects(response, expected_url=reverse('hosting:login'), # response = self.client.post(self.url, params)
status_code=302, target_status_code=200) # self.assertRedirects(response, expected_url=reverse('hosting:login'),
# status_code=302, target_status_code=200)
class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin): class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
@ -47,15 +55,16 @@ class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
self.view = DjangoHostingView() self.view = DjangoHostingView()
self.expected_template = 'hosting/django.html' self.expected_template = 'hosting/django.html'
HOSTING = 'django' HOSTING = 'django'
configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) # configuration_detail = dict(
# VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
self.expected_context = { self.expected_context = {
'hosting': HOSTING, 'hosting': HOSTING,
'hosting_long': "Django", 'hosting_long': "Django",
'configuration_detail': configuration_detail, # 'configuration_detail': configuration_detail,
'domain': "django-hosting.ch", 'domain': "django-hosting.ch",
'google_analytics': "UA-62285904-6", 'google_analytics': "UA-62285904-6",
'email': "info@django-hosting.ch", 'email': "info@django-hosting.ch",
'vm_types': VirtualMachineType.get_serialized_vm_types(), # 'vm_types': VirtualMachineType.get_serialized_vm_types(),
} }
@ -66,15 +75,16 @@ class RailsHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
self.view = RailsHostingView() self.view = RailsHostingView()
self.expected_template = 'hosting/rails.html' self.expected_template = 'hosting/rails.html'
HOSTING = 'rails' HOSTING = 'rails'
configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) # configuration_detail = dict(
# VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
self.expected_context = { self.expected_context = {
'hosting': HOSTING, 'hosting': HOSTING,
'hosting_long': "Ruby On Rails", 'hosting_long': "Ruby On Rails",
'configuration_detail': configuration_detail, # 'configuration_detail': configuration_detail,
'domain': "rails-hosting.ch", 'domain': "rails-hosting.ch",
'google_analytics': "UA-62285904-5", 'google_analytics': "UA-62285904-5",
'email': "info@rails-hosting.ch", 'email': "info@rails-hosting.ch",
'vm_types': VirtualMachineType.get_serialized_vm_types(), # 'vm_types': VirtualMachineType.get_serialized_vm_types(),
} }
@ -85,18 +95,25 @@ class NodeJSHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
self.view = NodeJSHostingView() self.view = NodeJSHostingView()
self.expected_template = 'hosting/nodejs.html' self.expected_template = 'hosting/nodejs.html'
HOSTING = 'nodejs' HOSTING = 'nodejs'
configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) # configuration_detail = dict(
# VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
self.expected_context = { self.expected_context = {
'hosting': HOSTING, 'hosting': HOSTING,
'hosting_long': "NodeJS", 'hosting_long': "NodeJS",
'configuration_detail': configuration_detail, # 'configuration_detail': configuration_detail,
'domain': "node-hosting.ch", 'domain': "node-hosting.ch",
'google_analytics': "UA-62285904-7", 'google_analytics': "UA-62285904-7",
'email': "info@node-hosting.ch", 'email': "info@node-hosting.ch",
'vm_types': VirtualMachineType.get_serialized_vm_types(), # 'vm_types': VirtualMachineType.get_serialized_vm_types(),
} }
@skipIf(
(settings.OPENNEBULA_DOMAIN is None or
settings.OPENNEBULA_DOMAIN == "test_domain"),
"""OpenNebula details unavailable, so skipping
HostingPricingViewTest.test_get"""
)
class HostingPricingViewTest(TestCase): class HostingPricingViewTest(TestCase):
def setUp(self): def setUp(self):
@ -104,11 +121,11 @@ class HostingPricingViewTest(TestCase):
self.view = HostingPricingView() self.view = HostingPricingView()
self.expected_template = 'hosting/hosting_pricing.html' self.expected_template = 'hosting/hosting_pricing.html'
configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION) # configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
self.expected_context = { self.expected_context = {
'configuration_options': configuration_options, # 'configuration_options': configuration_options,
'email': "info@django-hosting.ch", 'email': "info@django-hosting.ch",
'vm_types': VirtualMachineType.get_serialized_vm_types(), # 'vm_types': VirtualMachineType.get_serialized_vm_types(),
} }
def url_resolve_to_view_correctly(self): def url_resolve_to_view_correctly(self):
@ -118,13 +135,13 @@ class HostingPricingViewTest(TestCase):
def test_get(self): def test_get(self):
response = self.client.get(self.url) response = self.client.get(self.url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(self.view.get_context_data(), self.expected_context) # self.assertEqual(self.view.get_context_data(), self.expected_context)
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
def test_anonymous_post(self): # def test_anonymous_post(self):
response = self.client.post(self.url) # response = self.client.post(self.url)
self.assertRedirects(response, expected_url=reverse('hosting:login'), # self.assertRedirects(response, expected_url=reverse('hosting:login'),
status_code=302, target_status_code=200) # status_code=302, target_status_code=200)
class PaymentVMViewTest(BaseTestCase): class PaymentVMViewTest(BaseTestCase):
@ -135,10 +152,10 @@ class PaymentVMViewTest(BaseTestCase):
self.view = PaymentVMView self.view = PaymentVMView
# VM # VM
self.vm = mommy.make(VirtualMachineType, base_price=10000, # self.vm = mommy.make(VirtualMachineType, base_price=10000,
memory_price=100, # memory_price=100,
core_price=1000, # core_price=1000,
disk_size_price=1) # disk_size_price=1)
# post data # post data
self.billing_address = { self.billing_address = {
@ -153,56 +170,56 @@ class PaymentVMViewTest(BaseTestCase):
self.url = reverse('hosting:payment') self.url = reverse('hosting:payment')
# Session data # Session data
self.session_data = { # self.session_data = {
'vm_specs': { # 'vm_specs': {
'hosting_company': self.vm.hosting_company, # 'hosting_company': self.vm.hosting_company,
'cores': 1, # 'cores': 1,
'memory': 10, # 'memory': 10,
'disk_size': 10000, # 'disk_size': 10000,
'price': 22000, # 'price': 22000,
'configuration': dict(VirtualMachinePlan.VM_CONFIGURATION).get('django') # 'configuration': dict(VirtualMachinePlan.VM_CONFIGURATION).get('django')
} # }
} # }
session = self.customer_client.session # session = self.customer_client.session
session.update(self.session_data) # session.update(self.session_data)
session.save() # session.save()
def test_url_resolve_to_view_correctly(self): def test_url_resolve_to_view_correctly(self):
found = resolve(self.url) found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__) self.assertEqual(found.func.__name__, self.view.__name__)
@mock.patch('utils.stripe_utils.StripeUtils.create_customer') # @mock.patch('utils.stripe_utils.StripeUtils.create_customer')
def test_post(self, stripe_mocked_call): # def test_post(self, stripe_mocked_call):
#
# Anonymous user should get redirect to login # # Anonymous user should get redirect to login
response = self.client.post(self.url) # response = self.client.post(self.url)
expected_url = "%s?next=%s" % (reverse('hosting:login'), reverse('hosting:payment')) # expected_url = "%s?next=%s" % (reverse('hosting:login'), reverse('hosting:payment'))
self.assertRedirects(response, expected_url=expected_url, # self.assertRedirects(response, expected_url=expected_url,
status_code=302, target_status_code=200) # status_code=302, target_status_code=200)
#
# Customer user should be able to pay # # Customer user should be able to pay
stripe_mocked_call.return_value = { # stripe_mocked_call.return_value = {
'paid': True, # 'paid': True,
'response_object': self.stripe_mocked_customer, # 'response_object': self.stripe_mocked_customer,
'error': None # 'error': None
} # }
response = self.customer_client.post(self.url, self.billing_address) # response = self.customer_client.post(self.url, self.billing_address)
self.assertEqual(response.status_code, 200) # self.assertEqual(response.status_code, 200)
self.assertTrue(StripeCustomer.objects.filter(user__email=self.customer.email).exists()) # self.assertTrue(StripeCustomer.objects.filter(user__email=self.customer.email).exists())
stripe_customer = StripeCustomer.objects.get(user__email=self.customer.email) # stripe_customer = StripeCustomer.objects.get(user__email=self.customer.email)
self.assertEqual(stripe_customer.user, self.customer) # self.assertEqual(stripe_customer.user, self.customer)
self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists()) # self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists())
hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0] # hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0]
vm_plan = { # vm_plan = {
'cores': hosting_order.vm_plan.cores, # 'cores': hosting_order.vm_plan.cores,
'memory': hosting_order.vm_plan.memory, # 'memory': hosting_order.vm_plan.memory,
'disk_size': hosting_order.vm_plan.disk_size, # 'disk_size': hosting_order.vm_plan.disk_size,
'price': hosting_order.vm_plan.price, # 'price': hosting_order.vm_plan.price,
'hosting_company': hosting_order.vm_plan.vm_type.hosting_company, # 'hosting_company': hosting_order.vm_plan.vm_type.hosting_company,
'configuration': hosting_order.vm_plan.configuration # 'configuration': hosting_order.vm_plan.configuration
} # }
self.assertEqual(vm_plan, self.session_data.get('vm_specs')) # self.assertEqual(vm_plan, self.session_data.get('vm_specs'))
def test_get(self): def test_get(self):
@ -285,73 +302,73 @@ class MarkAsReadNotificationViewTest(BaseTestCase):
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
class GenerateVMSSHKeysViewTest(BaseTestCase): # class GenerateVMSSHKeysViewTest(BaseTestCase):
#
def setUp(self): # def setUp(self):
super(GenerateVMSSHKeysViewTest, self).setUp() # super(GenerateVMSSHKeysViewTest, self).setUp()
#
self.view = GenerateVMSSHKeysView # # self.view = GenerateVMSSHKeysView
self.vm = mommy.make(VirtualMachinePlan) # # self.vm = mommy.make(VirtualMachinePlan)
self.expected_template = 'hosting/virtual_machine_key.html' # self.expected_template = 'hosting/virtual_machine_key.html'
self.url = reverse('hosting:virtual_machine_key', kwargs={'pk': self.vm.id}) # self.url = reverse('hosting:virtual_machine_key', kwargs={'pk': self.vm.id})
#
def test_url_resolve_to_view_correctly(self): # def test_url_resolve_to_view_correctly(self):
found = resolve(self.url) # found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__) # self.assertEqual(found.func.__name__, self.view.__name__)
#
def test_get(self): # def test_get(self):
#
# Anonymous user should get redirect to login # # Anonymous user should get redirect to login
response = self.client.get(self.url) # response = self.client.get(self.url)
expected_url = "%s?next=%s" % (reverse('hosting:login'), # expected_url = "%s?next=%s" % (reverse('hosting:login'),
reverse('hosting:virtual_machine_key', # reverse('hosting:virtual_machine_key',
kwargs={'pk': self.vm.id})) # kwargs={'pk': self.vm.id}))
self.assertRedirects(response, expected_url=expected_url, # self.assertRedirects(response, expected_url=expected_url,
status_code=302, target_status_code=200) # status_code=302, target_status_code=200)
#
# Logged user should get the page # # Logged user should get the page
response = self.customer_client.get(self.url, follow=True) # response = self.customer_client.get(self.url, follow=True)
self.assertEqual(response.status_code, 200) # self.assertEqual(response.status_code, 200)
updated_vm = VirtualMachinePlan.objects.get(id=self.vm.id) # #updated_vm = VirtualMachinePlan.objects.get(id=self.vm.id)
self.assertEqual(response.context['public_key'].decode("utf-8"), updated_vm.public_key) # #self.assertEqual(response.context['public_key'].decode("utf-8"), updated_vm.public_key)
self.assertTrue(response.context['private_key'] is not None) # self.assertTrue(response.context['private_key'] is not None)
self.assertEqual(len(response.context['public_key']), 380) # self.assertEqual(len(response.context['public_key']), 380)
self.assertTrue(len(response.context['private_key']) is 1678 or 1674) # self.assertTrue(len(response.context['private_key']) is 1678 or 1674)
self.assertTemplateUsed(response, self.expected_template) # self.assertTemplateUsed(response, self.expected_template)
class VirtualMachineViewTest(BaseTestCase): # class VirtualMachineViewTest(BaseTestCase):
#
def setUp(self): # def setUp(self):
super(VirtualMachineViewTest, self).setUp() # super(VirtualMachineViewTest, self).setUp()
#
self.stripe_customer = mommy.make(StripeCustomer, user=self.customer) # self.stripe_customer = mommy.make(StripeCustomer, user=self.customer)
self.vm = mommy.make(VirtualMachinePlan) # #self.vm = mommy.make(VirtualMachinePlan)
self.vm.assign_permissions(self.customer) # self.vm.assign_permissions(self.customer)
self.order = mommy.make(HostingOrder, customer=self.stripe_customer, vm_plan=self.vm) # self.order = mommy.make(HostingOrder, customer=self.stripe_customer, vm_plan=self.vm)
self.url = reverse('hosting:virtual_machines', kwargs={'pk': self.vm.id}) # self.url = reverse('hosting:virtual_machines', kwargs={'pk': self.vm.id})
self.view = VirtualMachineView() # self.view = VirtualMachineView()
self.expected_template = 'hosting/virtual_machine_detail.html' # self.expected_template = 'hosting/virtual_machine_detail.html'
#
def url_resolve_to_view_correctly(self): # def url_resolve_to_view_correctly(self):
found = resolve(self.url) # found = resolve(self.url)
self.assertEqual(found.func.__name__, self.view.__name__) # self.assertEqual(found.func.__name__, self.view.__name__)
#
def test_get(self): # def test_get(self):
#
# Anonymous user should get redirect to login # # Anonymous user should get redirect to login
response = self.client.get(self.url) # response = self.client.get(self.url)
expected_url = "%s?next=%s" % (reverse('hosting:login'), # expected_url = "%s?next=%s" % (reverse('hosting:login'),
reverse('hosting:virtual_machines', # reverse('hosting:virtual_machines',
kwargs={'pk': self.vm.id})) # kwargs={'pk': self.vm.id}))
self.assertRedirects(response, expected_url=expected_url, # self.assertRedirects(response, expected_url=expected_url,
status_code=302, target_status_code=200) # status_code=302, target_status_code=200)
#
# Customer should be able to get data # # Customer should be able to get data
response = self.customer_client.get(self.url, follow=True) # response = self.customer_client.get(self.url, follow=True)
self.assertEqual(response.status_code, 200) # self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['virtual_machine'], self.vm) # self.assertEqual(response.context['virtual_machine'], self.vm)
self.assertTemplateUsed(response, self.expected_template) # self.assertTemplateUsed(response, self.expected_template)
class VirtualMachinesPlanListViewTest(BaseTestCase): class VirtualMachinesPlanListViewTest(BaseTestCase):
@ -361,8 +378,8 @@ class VirtualMachinesPlanListViewTest(BaseTestCase):
self.stripe_customer = mommy.make(StripeCustomer, user=self.customer) self.stripe_customer = mommy.make(StripeCustomer, user=self.customer)
mommy.make(HostingOrder, customer=self.stripe_customer, approved=True, _quantity=20) mommy.make(HostingOrder, customer=self.stripe_customer, approved=True, _quantity=20)
_vms = VirtualMachinePlan.objects.all() # _vms = VirtualMachinePlan.objects.all()
self.vms = sorted(_vms, key=lambda vm: vm.id, reverse=True) # self.vms = sorted(_vms, key=lambda vm: vm.id, reverse=True)
self.url = reverse('hosting:virtual_machines') self.url = reverse('hosting:virtual_machines')
self.view = VirtualMachinesPlanListView() self.view = VirtualMachinesPlanListView()
self.expected_template = 'hosting/virtual_machines.html' self.expected_template = 'hosting/virtual_machines.html'
@ -383,7 +400,7 @@ class VirtualMachinesPlanListViewTest(BaseTestCase):
# Customer should be able to get his orders # Customer should be able to get his orders
response = self.customer_client.get(self.url, follow=True) response = self.customer_client.get(self.url, follow=True)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(list(response.context['vms']), self.vms[:10]) # self.assertEqual(list(response.context['vms']), self.vms[:10])
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
@ -456,7 +473,7 @@ class LoginViewTest(TestCase):
self.url = reverse('hosting:login') self.url = reverse('hosting:login')
self.view = LoginView self.view = LoginView
self.expected_template = 'hosting/login.html' self.expected_template = 'hosting/login.html'
self.user = mommy.make('membership.CustomUser') self.user = mommy.make('membership.CustomUser', validated=1)
self.password = 'fake_password' self.password = 'fake_password'
self.user.set_password(self.password) self.user.set_password(self.password)
self.user.save() self.user.save()
@ -505,7 +522,7 @@ class SignupViewTest(TestCase):
def test_anonymous_user_can_signup(self): def test_anonymous_user_can_signup(self):
response = self.client.post(self.url, data=self.signup_data, follow=True) response = self.client.post(self.url, data=self.signup_data, follow=True)
self.user = CustomUser.objects.get(email=self.signup_data.get('email')) self.user = CustomUser.objects.get(email=self.signup_data.get('email'))
self.assertEqual(response.context['user'], self.user) # self.assertEqual(response.context['user'], self.user)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -540,10 +557,11 @@ class PasswordResetViewTest(BaseTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_test_generate_email_context(self): def test_test_generate_email_context(self):
context = self.setup_view(self.view()).\ context = self.setup_view(self.view()).test_generate_email_context(
test_generate_email_context(self.user) self.user
)
self.assertEqual(context.get('user'), self.user) self.assertEqual(context.get('user'), self.user)
self.assertEqual(context.get('site_name'), 'ungleich') self.assertEqual(context.get('site_name'), settings.DCL_TEXT)
self.assertEqual(len(context.get('token')), 24) self.assertEqual(len(context.get('token')), 24)
@ -578,7 +596,9 @@ class PasswordResetConfirmViewTest(BaseTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, self.expected_template) self.assertTemplateUsed(response, self.expected_template)
def test_post(self): # def test_post(self):
response = self.client.post(self.url, data=self.post_data, follow=True) # response = self.client.post(
self.assertEqual(response.status_code, 200) # self.url, data=self.post_data, follow=True
self.assertTrue(not response.context['form'].errors) # )
# self.assertEqual(response.status_code, 200)
# self.assertTrue(not response.context['form'].errors)

View file

@ -268,6 +268,8 @@ class SignupValidatedView(SignupValidateView):
login_url = '<a href="' + \ login_url = '<a href="' + \
reverse('hosting:login') + '">' + str(_('login')) + '</a>' reverse('hosting:login') + '">' + str(_('login')) + '</a>'
section_title = _('Account activation') section_title = _('Account activation')
user = CustomUser.objects.filter(
validation_slug=self.kwargs['validate_slug']).first()
if validated: if validated:
message = ('{account_activation_string} <br />' message = ('{account_activation_string} <br />'
' {login_string} {lurl}.').format( ' {login_string} {lurl}.').format(
@ -275,6 +277,21 @@ class SignupValidatedView(SignupValidateView):
"Your account has been activated."), "Your account has been activated."),
login_string=_("You can now"), login_string=_("You can now"),
lurl=login_url) lurl=login_url)
email_data = {
'subject': _('Welcome to Data Center Light!'),
'to': user.email,
'context': {
'base_url': "{0}://{1}".format(
self.request.scheme,
self.request.get_host()
)
},
'template_name': 'welcome_user',
'template_path': 'datacenterlight/emails/',
'from_address': settings.DCL_SUPPORT_FROM_ADDRESS,
}
email = BaseEmail(**email_data)
email.send()
else: else:
home_url = '<a href="' + \ home_url = '<a href="' + \
reverse('datacenterlight:index') + \ reverse('datacenterlight:index') + \
@ -687,6 +704,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
disk_size=context['vm']['disk_size'], disk_size=context['vm']['disk_size'],
memory=context['vm']['memory'] memory=context['vm']['memory']
) )
context['subscription_end_date'] = vm_detail.end_date()
except VMDetail.DoesNotExist: except VMDetail.DoesNotExist:
try: try:
manager = OpenNebulaManager( manager = OpenNebulaManager(
@ -1049,6 +1067,7 @@ class VirtualMachineView(LoginRequiredMixin, View):
try: try:
vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data vm_data = VirtualMachineSerializer(manager.get_vm(vm.id)).data
vm_name = vm_data.get('name')
except WrongIdError: except WrongIdError:
return redirect(reverse('hosting:virtual_machines')) return redirect(reverse('hosting:virtual_machines'))
@ -1120,10 +1139,11 @@ class VirtualMachineView(LoginRequiredMixin, View):
else: else:
sleep(2) sleep(2)
context = { context = {
'vm': vm_data, 'vm_name': vm_name,
'base_url': "{0}://{1}".format(self.request.scheme, 'base_url': "{0}://{1}".format(self.request.scheme,
self.request.get_host()), self.request.get_host()),
'page_header': _('Virtual Machine Cancellation') 'page_header': _('Virtual Machine %(vm_name)s Cancelled') % {
'vm_name': vm_name}
} }
email_data = { email_data = {
'subject': context['page_header'], 'subject': context['page_header'],

View file

@ -1,29 +1,41 @@
import re # import re
from django.test import TestCase # from django.test import TestCase
from django.core.urlresolvers import reverse # from django.core.urlresolvers import reverse
from django.core import mail # from django.core import mail
class LoginTestCase(TestCase): # class LoginTestCase(TestCase):
def test_login(self): # def test_login(self):
url = reverse('login_glarus') # url = reverse('login_glarus')
res = self.client.post(url, data={'email': 'test@gmail.com', 'password': 'test', 'name': 'test'}) # res = self.client.post(
self.assertContains(res, "You\'re successfully registered!", 1, 200) # url,
self.assertEqual(len(mail.outbox), 1) # data={
# 'email': 'test@gmail.com',
validation_url = re.findall(r"http://.*?(/.*)", mail.outbox[0].body) # 'password': 'test', 'name':
res1 = self.client.get(validation_url[0] + '/') # 'test'}
self.assertContains(res1, "Email verified!", 1, 200) # )
# self.assertContains(res, "You\'re successfully registered!", 1, 200)
res2 = self.client.post(url, data={'email': 'test@gmail.com', 'password': 'test'}) # self.assertEqual(len(mail.outbox), 1)
self.assertEqual(res2.status_code, 302) #
redirect_location = res2.get('Location') # validation_url = re.findall(r"http://.*?(/.*)", mail.outbox[0].body)
# res1 = self.client.get(validation_url[0] + '/')
res3 = self.client.get(redirect_location) # self.assertContains(res1, "Email verified!", 1, 200)
self.assertContains(res3, 'Pick coworking date.', 1, 200) #
# res2 = self.client.post(
# check fail login # url, data={'email': 'test@gmail.com', 'password': 'test'}
# )
res4 = self.client.post(url, data={'email': 'test@gmail.com', 'password': 'falsepassword'}) # self.assertEqual(res2.status_code, 302)
self.assertContains(res4, 'Sorry, that login was invalid.', 1, 200) # redirect_location = res2.get('Location')
#
# res3 = self.client.get(redirect_location)
# self.assertContains(res3, 'Pick coworking date.', 1, 200)
#
# # check fail login
#
# res4 = self.client.post(
# url, data={
# 'email': 'test@gmail.com', 'password': 'falsepassword'
# }
# )
# self.assertContains(res4, 'Sorry, that login was invalid.', 1, 200)

View file

@ -301,12 +301,14 @@ class OpenNebulaManager():
</CONTEXT> </CONTEXT>
</TEMPLATE> </TEMPLATE>
""" """
vm_id = self.client.call(oca.VmTemplate.METHODS['instantiate'], try:
template.id, vm_id = self.client.call(
'', oca.VmTemplate.METHODS['instantiate'], template.id, '', True,
True, vm_specs, False
vm_specs, )
False) except OpenNebulaException as err:
logger.error("OpenNebulaException: {0}".format(err))
return None
self.oneadmin_client.call( self.oneadmin_client.call(
oca.VirtualMachine.METHODS['action'], oca.VirtualMachine.METHODS['action'],

View file

@ -1,13 +1,21 @@
import random import random
import string import string
from django.conf import settings
from django.test import TestCase from django.test import TestCase
from unittest import skipIf
from .models import OpenNebulaManager from .models import OpenNebulaManager
from .serializers import VirtualMachineSerializer from .serializers import VirtualMachineSerializer
from utils.models import CustomUser from utils.models import CustomUser
@skipIf(
settings.OPENNEBULA_DOMAIN is None or
settings.OPENNEBULA_DOMAIN == "test_domain",
"""OpenNebula details unavailable, so skipping
OpenNebulaManagerTestCases"""
)
class OpenNebulaManagerTestCases(TestCase): class OpenNebulaManagerTestCases(TestCase):
"""This class defines the test suite for the opennebula manager model.""" """This class defines the test suite for the opennebula manager model."""
@ -120,13 +128,20 @@ class OpenNebulaManagerTestCases(TestCase):
creating a new vm""" creating a new vm"""
@skipIf(
settings.OPENNEBULA_DOMAIN is None or
settings.OPENNEBULA_DOMAIN == "test_domain",
"""OpenNebula details unavailable, so skipping
VirtualMachineSerializerTestCase"""
)
class VirtualMachineSerializerTestCase(TestCase): class VirtualMachineSerializerTestCase(TestCase):
def setUp(self): def setUp(self):
"""Define the test client and other test variables.""" """Define the test client and other test variables."""
self.manager = OpenNebulaManager(email=None, password=None) self.manager = OpenNebulaManager(email=None, password=None)
def test_serializer_strips_of_public(self): def test_serializer_strips_of_public(self):
""" Test the serialized virtual machine object contains no 'public-'.""" """ Test the serialized virtual machine object contains no
'public-'."""
for vm in self.manager.get_vms(): for vm in self.manager.get_vms():
serialized = VirtualMachineSerializer(vm) serialized = VirtualMachineSerializer(vm)

View file

@ -10,7 +10,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" href="/"> <a class="navbar-brand" href="https://www.ungleich.ch">
<img src="{% static "blog.ungleich.ch/img/logo_white.svg" %}" /> <img src="{% static "blog.ungleich.ch/img/logo_white.svg" %}" />
</a> </a>
</div> </div>

View file

@ -0,0 +1,63 @@
from menus.base import NavigationNode
from menus.menu_pool import menu_pool
from django.utils.translation import ugettext_lazy as _
from cms.menu_bases import CMSAttachMenu
from cms.templatetags.cms_tags import _get_placeholder
from cms.utils.plugins import get_plugins
class GlasfaserMenu(CMSAttachMenu):
name = _("Glasfaser menu")
def get_nodes(self, request):
nodes = []
glasfaser_cms = 'ungleich_page/glasfaser_cms_page.html'
if (request and request.current_page and
request.current_page.get_template() == glasfaser_cms):
template_context = {
"request": request,
}
placeholder_name_list = [
'Top Section', 'Middle Section', 'Glasfaser Services',
'Glasfaser About', 'Contact Section'
]
plugins_list = [
'SectionWithImage', 'UngelichContactUsSection',
'UngelichTextSection', 'Service', 'About'
]
for placeholder_name in placeholder_name_list:
placeholder = _get_placeholder(
request.current_page, request.current_page,
template_context, placeholder_name
)
plugins = get_plugins(
request, placeholder, request.current_page.get_template()
)
for plugin in plugins:
if type(plugin).__name__ in plugins_list:
section_hash = request.build_absolute_uri()
if hasattr(plugin, 'menu_text'):
menu_text = plugin.menu_text
if menu_text.strip() == '':
continue
menu_words = menu_text.split()
if len(menu_words) > 0:
section_hash = '{}#{}'.format(
section_hash,
menu_words[0]
)
else:
continue
newnode = NavigationNode(
menu_text,
url=section_hash,
id="{}-{}".format(
request.current_page.id, plugin.id
)
)
nodes.append(newnode)
return nodes
menu_pool.register_menu(GlasfaserMenu)

View file

@ -0,0 +1,340 @@
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from .models import (
UngelichContactUsSection, UngelichTextSection, Service, ServiceItem,
About, AboutItem, SectionWithImage, UngleichServiceItem, UngleichHeader,
UngleichHeaderItem, UngleichProductItem, UngleichProduct, UngleichCustomer,
UngleichCustomerItem, UngleichHTMLOnly, UngleichSimpleHeader,
UngleichHeaderWithBackgroundImageSlider,
UngleichHeaderWithBackgroundImageSliderItem
)
def get_section_id(plugin_instance, default):
"""
A helper function to get the section id from a given menu text
:param plugin_instance:
:param default: The default section id to return in case a section id
is not found
:return: The section id for the plugin_instance
"""
section_id = default
if hasattr(plugin_instance, 'menu_text'):
menu_words = plugin_instance.menu_text.split()
if len(menu_words) > 0:
section_id = menu_words[0]
return section_id
@plugin_pool.register_plugin
class SectionWithImagePlugin(CMSPluginBase):
model = SectionWithImage
render_template = "ungleich_page/glasfaser/section_with_image.html"
cache = False
def render(self, context, instance, placeholder):
context.update({
'image': instance.image,
'object': instance,
'placeholder': placeholder
})
return context
@plugin_pool.register_plugin
class SectionContact(CMSPluginBase):
model = UngelichContactUsSection
render_template = "ungleich_page/glasfaser/section_contact.html"
cache = False
def render(self, context, instance, placeholder):
context = super(SectionContact, self).render(
context, instance, placeholder
)
context['instance'] = instance
context['section_id'] = get_section_id(instance, 'contact')
return context
@plugin_pool.register_plugin
class SectionTextParagraphDCL(CMSPluginBase):
model = UngelichTextSection
render_template = "ungleich_page/glasfaser/section_text_dcl.html"
cache = False
def render(self, context, instance, placeholder):
context = super(SectionTextParagraphDCL, self).render(
context, instance, placeholder
)
context['instance'] = instance
context['section_id'] = get_section_id(instance, 'your')
return context
@plugin_pool.register_plugin
class SectionTextParagraphGlasfaser(CMSPluginBase):
model = UngelichTextSection
render_template = "ungleich_page/glasfaser/section_text_glasfaser.html"
cache = False
def render(self, context, instance, placeholder):
context = super(SectionTextParagraphGlasfaser, self).render(
context, instance, placeholder
)
context['instance'] = instance
context['section_id'] = get_section_id(instance, 'our')
return context
@plugin_pool.register_plugin
class GlasfaserServicesPlugin(CMSPluginBase):
name = "Glasfaser Services Plugin"
model = Service
render_template = "ungleich_page/glasfaser/section_services.html"
cache = False
allow_children = True
child_classes = ['GlasfaserServicesItemPlugin']
def render(self, context, instance, placeholder):
context['service_instance'] = instance
context['section_id'] = get_section_id(instance, 'services')
return context
@plugin_pool.register_plugin
class GlasfaserServicesItemPlugin(CMSPluginBase):
name = "Glasfaser Service Item Plugin"
model = ServiceItem
render_template = "ungleich_page/glasfaser/_services_item.html"
cache = False
require_parent = True
parent_classes = ['GlasfaserServicesPlugin']
def render(self, context, instance, placeholder):
context = super(GlasfaserServicesItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class GlasfaserAboutPlugin(CMSPluginBase):
name = "Glasfaser About Plugin"
model = About
render_template = "ungleich_page/glasfaser/section_about.html"
cache = False
allow_children = True
child_classes = ['GlasfaserAboutItemPlugin']
def render(self, context, instance, placeholder):
context['about_instance'] = instance
context['section_id'] = get_section_id(instance, 'about')
return context
@plugin_pool.register_plugin
class GlasfaserAboutItemPlugin(CMSPluginBase):
name = "Glasfaser About Item Plugin"
model = AboutItem
render_template = "ungleich_page/glasfaser/_about_item.html"
cache = False
require_parent = True
parent_classes = ['GlasfaserAboutPlugin']
def render(self, context, instance, placeholder):
context = super(GlasfaserAboutItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichServicesPlugin(CMSPluginBase):
name = "ungleich Services Plugin"
model = Service
render_template = "ungleich_page/ungleich/section_services.html"
cache = False
allow_children = True
child_classes = ['UngleichServicesItemPlugin']
def render(self, context, instance, placeholder):
context['service_instance'] = instance
context['section_id'] = get_section_id(instance, 'services')
return context
@plugin_pool.register_plugin
class UngleichServicesItemPlugin(CMSPluginBase):
name = "ungleich Service Item Plugin"
model = UngleichServiceItem
render_template = "ungleich_page/ungleich/_services_item.html"
cache = False
require_parent = True
parent_classes = ['UngleichServicesPlugin']
def render(self, context, instance, placeholder):
context = super(UngleichServicesItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHeaderWithTextAndImagePlugin(CMSPluginBase):
name = "ungleich Header with Text and Image Plugin"
model = UngleichSimpleHeader
render_template = "ungleich_page/ungleich/header.html"
cache = False
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHeaderWithTextAndImageSliderPlugin(CMSPluginBase):
name = "ungleich Header with Text and Image Slider Plugin"
model = UngleichHeader
render_template = "ungleich_page/ungleich/header_with_slider.html"
cache = False
allow_children = True
child_classes = ['UngleichHeaderItemPlugin']
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHeaderItemPlugin(CMSPluginBase):
name = "ungleich Header Item Plugin"
model = UngleichHeaderItem
render_template = "ungleich_page/ungleich/_header_item.html"
cache = False
require_parent = True
parent_classes = ['UngleichHeaderWithTextAndImageSliderPlugin']
def render(self, context, instance, placeholder):
context = super(UngleichHeaderItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHeaderBackgroundImageAndTextSliderPlugin(CMSPluginBase):
name = "ungleich Header with Background and Image Slider Plugin"
model = UngleichHeaderWithBackgroundImageSlider
render_template = (
'ungleich_page/ungleich/header_with_background_image_slider.html'
)
cache = False
allow_children = True
child_classes = ['UngleichHeaderBackgroundImageAndTextItemPlugin']
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHeaderBackgroundImageAndTextItemPlugin(CMSPluginBase):
name = "ungleich Header with Background and Image and Text Item Plugin"
model = UngleichHeaderWithBackgroundImageSliderItem
render_template = (
'ungleich_page/ungleich/_header_with_background_image_slider_item.html'
)
cache = False
require_parent = True
parent_classes = ['UngleichHeaderBackgroundImageAndTextSliderPlugin']
def render(self, context, instance, placeholder):
context = super(
UngleichHeaderBackgroundImageAndTextItemPlugin, self
).render(context, instance, placeholder)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichProductsPlugin(CMSPluginBase):
name = "ungleich Products Plugin"
model = UngleichProduct
render_template = "ungleich_page/ungleich/section_products.html"
cache = False
allow_children = True
child_classes = ['UngleichProductsItemPlugin']
def render(self, context, instance, placeholder):
context['product_instance'] = instance
context['section_id'] = get_section_id(instance, 'products')
return context
@plugin_pool.register_plugin
class UngleichProductsItemPlugin(CMSPluginBase):
name = "ungleich Product Item Plugin"
model = UngleichProductItem
render_template = "ungleich_page/ungleich/_products_item.html"
cache = False
require_parent = True
parent_classes = ['UngleichProductsPlugin']
def render(self, context, instance, placeholder):
context = super(UngleichProductsItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichCustomerSectionPlugin(CMSPluginBase):
name = "ungleich Customer Section Plugin"
model = UngleichCustomer
render_template = "ungleich_page/ungleich/section_customers.html"
cache = False
allow_children = True
child_classes = ['UngleichCustomerItemPlugin']
def render(self, context, instance, placeholder):
context['customer_instance'] = instance
context['section_id'] = get_section_id(instance, 'customer')
return context
@plugin_pool.register_plugin
class UngleichCustomerItemPlugin(CMSPluginBase):
name = "ungleich Customer Item Plugin"
model = UngleichCustomerItem
render_template = "ungleich_page/ungleich/_customer_item.html"
cache = False
require_parent = True
parent_classes = ['UngleichCustomerSectionPlugin']
def render(self, context, instance, placeholder):
context = super(UngleichCustomerItemPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context
@plugin_pool.register_plugin
class UngleichHTMLPlugin(CMSPluginBase):
name = "ungleich HTML Plugin"
model = UngleichHTMLOnly
render_template = "ungleich_page/ungleich/html_block.html"
cache = False
def render(self, context, instance, placeholder):
context = super(UngleichHTMLPlugin, self).render(
context, instance, placeholder
)
context['instance'] = instance
return context

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-10-10 21:35+0530\n" "POT-Creation-Date: 2017-11-26 00:34+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,6 +18,12 @@ 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"
msgid "Glasfaser menu"
msgstr ""
msgid "\"Sorry, we could not find the page you are looking for!\""
msgstr ""
msgid "Toggle navigation" msgid "Toggle navigation"
msgstr "Umschalten" msgstr "Umschalten"
@ -96,6 +102,15 @@ msgstr ""
"ungleich startet das Projekt <a href=\"https://www.alplora.ch/de/\">AlpLora</" "ungleich startet das Projekt <a href=\"https://www.alplora.ch/de/\">AlpLora</"
"a>, mit dem Tiere via LoRaWAN geortet werden können" "a>, mit dem Tiere via LoRaWAN geortet werden können"
msgid "ungleich starts to give basic computer courses for refugees."
msgstr "ungleich bietet einen PC-Grundkurs für Flüchtlinge an."
msgid ""
"ungleich starts computer learning club for locals, \"Digitale Building "
"ungleich.\""
msgstr ""
"ungleich gründet den Verein Digitale Bildung ungleich für Ortsansässige."
msgid "" msgid ""
"ungleich sells <a href=\"https://www.alplora.ch/de/\">Alplora</a> to an IoT " "ungleich sells <a href=\"https://www.alplora.ch/de/\">Alplora</a> to an IoT "
"startup in canton Zürich." "startup in canton Zürich."
@ -145,8 +160,15 @@ msgstr "ungleich Home"
msgid "We Design, Configure &amp; Maintain <br> Your Linux Infrastructure " msgid "We Design, Configure &amp; Maintain <br> Your Linux Infrastructure "
msgstr "Wir designen, erstellen und warten Ihre Linux-Infrastruktur" msgstr "Wir designen, erstellen und warten Ihre Linux-Infrastruktur"
msgid "Hosting Products " msgid "Our Products"
msgstr "Hosting Produkte" msgstr "Unsere Produkte"
msgid ""
"Our products include an innovative datacenter,<br>affordable VM hosting, and "
"high speed fiber internet for canton Glarus."
msgstr ""
"Zu unseren Produkten gehört ein innovatives Rechenzentrum,<br>modernes VM-"
"Hosting und Glasfaser-Internet für den Kanton Glarus."
msgid "Data Center Light" msgid "Data Center Light"
msgstr "" msgstr ""
@ -177,8 +199,8 @@ msgid ""
"We offer high speed fiber internet in Glarus Süd, Glarus and Glarus Nord. " "We offer high speed fiber internet in Glarus Süd, Glarus and Glarus Nord. "
"Experience 100 Mbit/s and see how speed can change everything." "Experience 100 Mbit/s and see how speed can change everything."
msgstr "" msgstr ""
"Wir bieten außerdem Hochgeschwindigkeitsfaser Internet in Glarus Süd, " "Wir bieten außerdem Hochgeschwindigkeitsfaser Internet in Glarus Süd, Glarus "
"Glarus und Glarus Nord. Surfen Sie mit 100 Mbit/s und erleben Sie, wie " "und Glarus Nord. Surfen Sie mit 100 Mbit/s und erleben Sie, wie "
"Geschwindigkeit alles ändern kann." "Geschwindigkeit alles ändern kann."
msgid "our services" msgid "our services"
@ -338,6 +360,9 @@ msgid "If you have any question, just send us an email."
msgstr "" msgstr ""
"Wenn Sie irgendwelche Fragen haben, schicken Sie uns einfach eine E-Mail." "Wenn Sie irgendwelche Fragen haben, schicken Sie uns einfach eine E-Mail."
#~ msgid "Hosting Products "
#~ msgstr "Hosting Produkte"
#~ msgid "HA Hosting" #~ msgid "HA Hosting"
#~ msgstr "HA Hosting" #~ msgstr "HA Hosting"

View file

@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-18 18:23
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
import filer.fields.image
class Migration(migrations.Migration):
initial = True
dependencies = [
('filer', '0004_auto_20160328_1434'),
('cms', '0014_auto_20160404_1908'),
]
operations = [
migrations.CreateModel(
name='Service',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('title', models.CharField(max_length=200)),
('sub_title', models.CharField(max_length=200)),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='ServiceItem',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('title', models.CharField(max_length=200)),
('description', djangocms_text_ckeditor.fields.HTMLField()),
('image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='service_item_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='UngelichContactUsSection',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('email', models.EmailField(max_length=200)),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='UngelichPicture',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('title', models.CharField(max_length=400)),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='UngelichTextSection',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('title', models.CharField(max_length=200)),
('description', djangocms_text_ckeditor.fields.HTMLField()),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='About',
fields=[
('service_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.Service')),
],
options={
'abstract': False,
},
bases=('ungleich_page.service',),
),
migrations.CreateModel(
name='AboutItem',
fields=[
('ungelichpicture_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.UngelichPicture')),
('inverted', models.BooleanField(default=False)),
],
options={
'abstract': False,
},
bases=('ungleich_page.ungelichpicture',),
),
migrations.AddField(
model_name='ungelichpicture',
name='image',
field=filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='image', to='filer.Image'),
),
]

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-18 22:02
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('ungleich_page', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SectionWithImage',
fields=[
('ungelichpicture_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.UngelichPicture')),
('price_tag_url', models.URLField(default='', max_length=300)),
('price_tag_image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='price_tag_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('ungleich_page.ungelichpicture',),
),
]

View file

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-19 10:07
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0002_sectionwithimage'),
]
operations = [
migrations.AddField(
model_name='sectionwithimage',
name='menu_text',
field=models.CharField(default='', max_length=100),
),
migrations.AddField(
model_name='service',
name='menu_text',
field=models.CharField(default='', max_length=100),
),
migrations.AddField(
model_name='ungelichcontactussection',
name='menu_text',
field=models.CharField(default='', max_length=100),
),
migrations.AddField(
model_name='ungelichtextsection',
name='menu_text',
field=models.CharField(default='', max_length=100),
),
]

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-19 11:13
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0003_auto_20171019_1007'),
]
operations = [
migrations.AlterField(
model_name='sectionwithimage',
name='menu_text',
field=models.CharField(blank=True, default='', max_length=100),
),
migrations.AlterField(
model_name='sectionwithimage',
name='price_tag_url',
field=models.URLField(blank=True, default='', max_length=300),
),
migrations.AlterField(
model_name='service',
name='menu_text',
field=models.CharField(blank=True, default='', max_length=100),
),
migrations.AlterField(
model_name='ungelichcontactussection',
name='menu_text',
field=models.CharField(blank=True, default='', max_length=100),
),
migrations.AlterField(
model_name='ungelichtextsection',
name='menu_text',
field=models.CharField(blank=True, default='', max_length=100),
),
]

View file

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-19 15:17
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0004_auto_20171019_1113'),
]
operations = [
migrations.AddField(
model_name='ungelichcontactussection',
name='address',
field=models.CharField(blank=True, default='In der Au 7, Schwanden 8762', max_length=100),
),
migrations.AddField(
model_name='ungelichcontactussection',
name='contact_form_header_text',
field=models.CharField(blank=True, default='Send us a message.', max_length=100),
),
migrations.AddField(
model_name='ungelichcontactussection',
name='contact_text',
field=models.CharField(blank=True, default='Contact', max_length=100),
),
migrations.AddField(
model_name='ungelichcontactussection',
name='country',
field=models.CharField(blank=True, default='Switzerland', max_length=100),
),
migrations.AddField(
model_name='ungelichcontactussection',
name='organization_name',
field=models.CharField(blank=True, default='ungleich GmbH', max_length=100),
),
migrations.AlterField(
model_name='ungelichcontactussection',
name='email',
field=models.EmailField(default='info@ungleich.ch', max_length=200),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-10-20 06:42
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0005_auto_20171019_1517'),
]
operations = [
migrations.AddField(
model_name='aboutitem',
name='link_url',
field=models.URLField(blank=True, default='', max_length=300),
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-17 10:11
from __future__ import unicode_literals
from django.db import migrations
import djangocms_text_ckeditor.fields
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0006_aboutitem_link_url'),
]
operations = [
migrations.AlterField(
model_name='ungelichpicture',
name='title',
field=djangocms_text_ckeditor.fields.HTMLField(),
),
]

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-17 18:49
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('ungleich_page', '0007_auto_20171117_1011'),
]
operations = [
migrations.CreateModel(
name='UngleichServiceItem',
fields=[
('serviceitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.ServiceItem')),
('data_replaced_image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='service_item_data_replaced_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('ungleich_page.serviceitem',),
),
]

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-19 11:28
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('cms', '0014_auto_20160404_1908'),
('ungleich_page', '0008_ungleichserviceitem'),
]
operations = [
migrations.CreateModel(
name='UngleichHeader',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('carousel_data_interval', models.IntegerField(default=5000)),
('background_image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_header_background_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='UngleichHeaderItem',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('description', djangocms_text_ckeditor.fields.HTMLField()),
('image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_header_item_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-19 14:04
from __future__ import unicode_literals
from django.db import migrations
import djangocms_text_ckeditor.fields
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0009_ungleichheader_ungleichheaderitem'),
]
operations = [
migrations.AlterField(
model_name='service',
name='sub_title',
field=djangocms_text_ckeditor.fields.HTMLField(),
),
]

View file

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-21 19:04
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0010_auto_20171119_1404'),
]
operations = [
migrations.CreateModel(
name='UngleichProduct',
fields=[
('service_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.Service')),
('section_class', models.CharField(blank=True, default='', max_length=100)),
],
options={
'abstract': False,
},
bases=('ungleich_page.service',),
),
migrations.CreateModel(
name='UngleichProductItem',
fields=[
('serviceitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.ServiceItem')),
('url', models.URLField(blank=True, default='', max_length=300)),
],
options={
'abstract': False,
},
bases=('ungleich_page.serviceitem',),
),
]

View file

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-23 08:11
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('cms', '0014_auto_20160404_1908'),
('ungleich_page', '0011_ungleichproduct_ungleichproductitem'),
]
operations = [
migrations.CreateModel(
name='UngleichCustomer',
fields=[
('service_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='ungleich_page.Service')),
('section_class', models.CharField(blank=True, default='', max_length=100)),
('carousel_data_interval', models.IntegerField(default=3000)),
('bottom_text', djangocms_text_ckeditor.fields.HTMLField(default='<h3 class="section-subheading text-muted">*ungleich means not equal to (≠) U+2260.</h3>')),
],
options={
'abstract': False,
},
bases=('ungleich_page.service',),
),
migrations.CreateModel(
name='UngleichCustomerItem',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('url', models.URLField(blank=True, default='', max_length=300)),
('description', djangocms_text_ckeditor.fields.HTMLField()),
('image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='customer_item_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-23 11:49
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
class Migration(migrations.Migration):
dependencies = [
('cms', '0014_auto_20160404_1908'),
('ungleich_page', '0012_ungleichcustomer_ungleichcustomeritem'),
]
operations = [
migrations.CreateModel(
name='UngleichHTMLOnly',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('HTML', djangocms_text_ckeditor.fields.HTMLField()),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-24 07:00
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ungleich_page', '0013_ungleichhtmlonly'),
]
operations = [
migrations.AddField(
model_name='ungleichhtmlonly',
name='name',
field=models.CharField(blank=True, default='', max_length=50),
),
]

View file

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-11-24 19:12
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('cms', '0014_auto_20160404_1908'),
('ungleich_page', '0014_ungleichhtmlonly_name'),
]
operations = [
migrations.CreateModel(
name='UngleichSimpleHeader',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('text', djangocms_text_ckeditor.fields.HTMLField()),
('background_image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_simple_header_background_image', to='filer.Image')),
('image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_simple_header_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2017-12-02 07:30
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djangocms_text_ckeditor.fields
import filer.fields.image
class Migration(migrations.Migration):
dependencies = [
('filer', '0004_auto_20160328_1434'),
('cms', '0014_auto_20160404_1908'),
('ungleich_page', '0015_ungleichsimpleheader'),
]
operations = [
migrations.CreateModel(
name='UngleichHeaderWithBackgroundImageSlider',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('carousel_data_interval', models.IntegerField(default=2000)),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.CreateModel(
name='UngleichHeaderWithBackgroundImageSliderItem',
fields=[
('cmsplugin_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
('description', djangocms_text_ckeditor.fields.HTMLField(default='<div class="intro-cap">We Design, Configure &amp; Maintain <br>Your Linux Infrastructure</div><p class="intro_lead">Ruby on Rails, Django, Java, Webserver, Mailserver, any infrastructure that needs to configured, we provide comprehensive solutions. Amazon, rackspace or bare metal servers, we configure for you.</p><p style="text-align: right;"><a class="btn btn-trans" href="">Learn More</a></p>')),
('background_image', filer.fields.image.FilerImageField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ungleich_header_slider_item_image', to='filer.Image')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
]

View file

@ -1,3 +1,191 @@
# from django.db import models from cms.models.pluginmodel import CMSPlugin
from django.db import models
from djangocms_text_ckeditor.fields import HTMLField
from filer.fields.image import FilerImageField
# Create your models here.
class UngelichPicture(CMSPlugin):
image = FilerImageField(
null=True,
blank=True,
related_name="image",
on_delete=models.SET_NULL
)
title = HTMLField()
class SectionWithImage(UngelichPicture):
menu_text = models.CharField(max_length=100, default="", blank=True)
price_tag_image = FilerImageField(
null=True,
blank=True,
related_name="price_tag_image",
on_delete=models.SET_NULL
)
price_tag_url = models.URLField(max_length=300, default="", blank=True)
class UngelichContactUsSection(CMSPlugin):
menu_text = models.CharField(max_length=100, default="", blank=True)
email = models.EmailField(max_length=200, default="info@ungleich.ch")
contact_text = models.CharField(
max_length=100, default="Contact", blank=True
)
organization_name = models.CharField(
max_length=100, default="ungleich GmbH", blank=True
)
address = models.CharField(
max_length=100, default="In der Au 7, Schwanden 8762", blank=True
)
country = models.CharField(
max_length=100, default="Switzerland", blank=True
)
contact_form_header_text = models.CharField(
max_length=100, default="Send us a message.", blank=True
)
class UngelichTextSection(CMSPlugin):
menu_text = models.CharField(max_length=100, default="", blank=True)
title = models.CharField(max_length=200)
description = HTMLField()
class Service(CMSPlugin):
menu_text = models.CharField(max_length=100, default="", blank=True)
title = models.CharField(max_length=200)
sub_title = HTMLField()
def __str__(self):
return self.title
class ServiceItem(CMSPlugin):
image = FilerImageField(
null=True,
blank=True,
related_name="service_item_image",
on_delete=models.SET_NULL
)
title = models.CharField(max_length=200)
description = HTMLField()
def __str__(self):
return self.title
class About(Service):
pass
class AboutItem(UngelichPicture):
inverted = models.BooleanField(default=False)
link_url = models.URLField(max_length=300, default="", blank=True)
def __str__(self):
alignment = "Right" if self.inverted else "Left"
return "{alignment} - {title}".format(
alignment=alignment, title=self.title
)
class UngleichServiceItem(ServiceItem):
data_replaced_image = FilerImageField(
null=True,
blank=True,
related_name="service_item_data_replaced_image",
on_delete=models.SET_NULL
)
class UngleichSimpleHeader(CMSPlugin):
background_image = FilerImageField(
null=True,
blank=True,
related_name="ungleich_simple_header_background_image",
on_delete=models.SET_NULL
)
image = FilerImageField(
null=True,
blank=True,
related_name="ungleich_simple_header_image",
on_delete=models.SET_NULL
)
text = HTMLField()
class UngleichHeader(CMSPlugin):
background_image = FilerImageField(
null=True,
blank=True,
related_name="ungleich_header_background_image",
on_delete=models.SET_NULL
)
carousel_data_interval = models.IntegerField(default=5000)
class UngleichHeaderWithBackgroundImageSliderItem(CMSPlugin):
background_image = FilerImageField(
null=True, blank=True,
related_name="ungleich_header_slider_item_image",
on_delete=models.SET_NULL
)
description = HTMLField(
default='<div class="intro-cap">We Design, Configure &amp; Maintain '
'<br>Your Linux Infrastructure</div><p class="intro_lead">'
'Ruby on Rails, Django, Java, Webserver, Mailserver, any '
'infrastructure that needs to configured, we provide '
'comprehensive solutions. Amazon, rackspace or bare metal '
'servers, we configure for you.</p><p style="text-align: '
'right;"><a class="btn btn-trans" href="">Learn More</a></p>'
)
class UngleichHeaderWithBackgroundImageSlider(CMSPlugin):
carousel_data_interval = models.IntegerField(default=2000)
class UngleichHeaderItem(CMSPlugin):
image = FilerImageField(
null=True,
blank=True,
related_name="ungleich_header_item_image",
on_delete=models.SET_NULL
)
description = HTMLField()
class UngleichProductItem(ServiceItem):
url = models.URLField(max_length=300, default="", blank=True)
class UngleichProduct(Service):
section_class = models.CharField(max_length=100, default="", blank=True)
class UngleichCustomer(Service):
section_class = models.CharField(max_length=100, default="", blank=True)
carousel_data_interval = models.IntegerField(default=3000)
bottom_text = HTMLField(
default='<h3 class="section-subheading text-muted">*ungleich means '
'not equal to (≠) U+2260.</h3>'
)
class UngleichCustomerItem(CMSPlugin):
image = FilerImageField(
null=True,
blank=True,
related_name="customer_item_image",
on_delete=models.SET_NULL
)
url = models.URLField(max_length=300, default="", blank=True)
description = HTMLField()
class UngleichHTMLOnly(CMSPlugin):
name = models.CharField(max_length=50, default="", blank=True)
HTML = HTMLField()
def __str__(self):
return self.name

View file

@ -4,9 +4,21 @@
* For details, see http://www.apache.org/licenses/LICENSE-2.0. * For details, see http://www.apache.org/licenses/LICENSE-2.0.
*/ */
html {
overflow-x: hidden;
}
body { body {
overflow-x: hidden; overflow-x: hidden;
font-family: "Ralesay" , "Helvetica Neue",Helvetica,Arial,sans-serif; font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
.row-eq-height {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
} }
.text-muted { .text-muted {
@ -198,8 +210,8 @@ fieldset[disabled] .btn-xl.active {
} }
.navbar-default .navbar-toggle { .navbar-default .navbar-toggle {
border-color: #fed136; /*border-color: #fed136;
background-color: #fed136; background-color: #fed136;*/
} }
.navbar-default .navbar-toggle .icon-bar { .navbar-default .navbar-toggle .icon-bar {
@ -237,6 +249,10 @@ fieldset[disabled] .btn-xl.active {
background-color: #fec503; background-color: #fec503;
} }
.navbar-default .navbar-brand {
padding: 12px;
}
@media(min-width:768px) { @media(min-width:768px) {
.navbar-default { .navbar-default {
padding: 25px 0; padding: 25px 0;
@ -263,22 +279,19 @@ fieldset[disabled] .btn-xl.active {
background-color: #222; background-color: #222;
} }
.navbar-default.navbar-shrink .navbar-brand { .navbar-default .navbar-brand {
font-size: 1.5em; padding: 8px;
} }
} }
.navbar-default .navbar-brand > img {
height: 100%;
}
header { header {
text-align: center; text-align: center;
color: #fff; color: #fff;
background-attachment: scroll; background: rgba(0,0,0,0.25);
background-image: url(../img/header-bg.jpg);
background-position: center center;
background-repeat: none;
-webkit-background-size: cover;
-moz-background-size: cover;
background-size: cover;
-o-background-size: cover;
} }
header .intro-text { header .intro-text {
@ -328,29 +341,42 @@ header .intro-text .intro-heading {
} }
section { section {
padding: 100px 0; padding: 75px 0;
}
@media(max-width:767px) {
section {
padding: 50px 0;
}
} }
section h2.section-heading { section h2.section-heading {
margin-top: 0; margin-top: 0;
margin-bottom: 15px; margin-bottom: 15px;
font-size: 40px; font-size: 26px;
color: #494949; color: #494949;
} }
section h3.section-subheading { section h3.section-subheading {
margin-bottom: 75px; margin-bottom: 50px;
text-transform: none; text-transform: none;
font-family: 'Raleway', "Helvetica Neue", "Open Sans", "Droid Serif", Helvetica, Arial, sans-serif; font-family: 'Raleway', "Helvetica Neue", "Open Sans", "Droid Serif", Helvetica, Arial, sans-serif;
font-size: 18px; font-size: 16px;
font-weight: 400; font-weight: 400;
color: #494949; color: #494949;
line-height: normal; line-height: 1.4;
} }
@media(min-width:768px) { @media(min-width:768px) {
section { section {
padding: 150px 0; padding: 125px 0;
}
section h2.section-heading {
font-size: 40px;
}
section h3.section-subheading {
font-size: 18px;
margin-bottom: 75px;
} }
} }
@ -414,10 +440,11 @@ section h3.section-subheading {
max-width: 400px; max-width: 400px;
text-align: center; text-align: center;
background-color: #fff; background-color: #fff;
width: 100%;
} }
#portfolio .portfolio-item .portfolio-caption h4 { #portfolio .portfolio-item .portfolio-caption h4 {
margin: 0; margin: 0 0 17px;
text-transform: none; text-transform: none;
color: #494949; color: #494949;
} }
@ -436,7 +463,7 @@ section h3.section-subheading {
display: inline-block display: inline-block
} }
@media(min-width:767px) { @media(min-width:768px) {
#portfolio .portfolio-item { #portfolio .portfolio-item {
margin: 0 0 30px; margin: 0 0 30px;
} }
@ -546,6 +573,10 @@ section h3.section-subheading {
color: inherit; color: inherit;
} }
.timeline .timeline-heading h4 {
margin-bottom: 7px;
}
.timeline .timeline-heading h4.subheading { .timeline .timeline-heading h4.subheading {
text-transform: none; text-transform: none;
} }
@ -561,14 +592,14 @@ section h3.section-subheading {
} }
.timeline>li { .timeline>li {
margin-bottom: 100px; margin-bottom: 75px;
min-height: 100px; min-height: 100px;
} }
.timeline>li .timeline-panel { .timeline>li .timeline-panel {
float: left; float: left;
width: 41%; width: 41%;
padding: 0 20px 20px 30px; padding: 0 20px 20px;
text-align: right; text-align: right;
} }
@ -587,7 +618,7 @@ section h3.section-subheading {
.timeline>li.timeline-inverted>.timeline-panel { .timeline>li.timeline-inverted>.timeline-panel {
float: right; float: right;
padding: 0 30px 20px 20px; padding: 0 20px 20px;
text-align: left; text-align: left;
} }
} }
@ -598,7 +629,7 @@ section h3.section-subheading {
} }
.timeline>li .timeline-panel { .timeline>li .timeline-panel {
padding: 0 20px 20px; padding: 10px 20px 20px;
} }
.timeline>li .timeline-image { .timeline>li .timeline-image {
@ -614,7 +645,7 @@ section h3.section-subheading {
} }
.timeline>li.timeline-inverted>.timeline-panel { .timeline>li.timeline-inverted>.timeline-panel {
padding: 0 20px 20px; padding: 10px 20px 20px;
} }
} }
@ -624,7 +655,7 @@ section h3.section-subheading {
} }
.timeline>li .timeline-panel { .timeline>li .timeline-panel {
padding: 0 20px 20px 100px; padding: 10px 20px 20px 100px;
} }
.timeline>li .timeline-image { .timeline>li .timeline-image {
@ -643,7 +674,7 @@ section h3.section-subheading {
} }
.team-member { .team-member {
margin-bottom: 50px; margin-bottom: 25px;
text-align: center; text-align: center;
} }
@ -653,11 +684,27 @@ section h3.section-subheading {
} }
.team-member h4 { .team-member h4 {
margin-top: 25px; margin-top: 10px;
margin-bottom: 0; margin-bottom: 10px;
text-transform: none; text-transform: none;
} }
@media(max-width:767px) {
.team-member .team-member-caption p {
line-height: 1.5;
}
}
@media(min-width:768px) {
.team-member {
margin-bottom: 50px;
}
.team-member h4 {
margin-top: 20px;
margin-bottom: 20px;
}
}
.team-member p { .team-member p {
margin-top: 0; margin-top: 0;
} }
@ -667,15 +714,33 @@ aside.clients img {
} }
section#contact { section#contact {
background-color: #222; position: relative;
background-image: url(../img/map-image.png); background: rgba(0,0,0,0.75);
background-position: center; }
background-repeat: no-repeat;
section#contact .bg_img {
filter: blur(1px);
}
section#contact a {
color: #79bcf7;
} }
section#contact .section-heading { section#contact .section-heading {
color: #fff; color: #fff;
font-size: 36px; font-size: 32px;
}
@media(max-width:767px) {
aside.clients img {
margin: 20px auto;
}
section#contact .section-heading {
font-size: 26px;
}
section#contact .intro-smallcap {
font-size: 18px;
}
} }
section#contact .form-group { section#contact .form-group {
@ -889,69 +954,32 @@ section h3.section-comment {
color: #494949; color: #494949;
} }
small-comment {
font-family: "Open Sans", "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif;
margin-bottom: none;
font-transform: none;
font-size:10px;
font-weight:400;
color: #777
}
logo-image {
z-index: 100;
position: absolute;
left: 0;
width: 80px;
height: 80px;
margin-left: 0;
border: 7px solid #f1f1f1;
border-radius: 100%;
text-align: center;
color: #fff;
background-color: #fed136;
}
intro-cap {
margin-bottom: 25px;
text-transform: uppercase;
font-family: 'Raleway', "Helvetica Neue", "Helvetica Neue", Helvetica,Arial,sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #fed136;
}
h6 intro-smallcap {
margin-bottom: 25px;
text-transform: none;
font-family:'Raleway' , Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 50px;
color:#fff
background-color: #fed136;
}
.carousel-indicators li.active, .text-carousel .carousel-indicators li.active { .carousel-indicators li.active, .text-carousel .carousel-indicators li.active {
width: 15px;
height: 15px;
border: 0; border: 0;
background-color: #fed136; background-color: #fed136;
} }
@media (min-width: 740px)
@media (min-width: 740px) {
.carousel-inner, .text-carousel .carousel-inner { .carousel-inner, .text-carousel .carousel-inner {
min-height: 225px; min-height: 225px;
} }
}
.carousel-text { .carousel-text {
text-transform : none; text-transform : none;
font-family:'Raleway' , Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif; font-family:'Raleway' , Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
font-size : 20px; font-size : 20px;
font-weight : 100; font-weight : 100;
lign-heignt: 2px;
color : #666; color : #666;
text-align : center; text-align : center;
} }
@media (max-width: 767px) {
.carousel-text {
height: 220px;
overflow: scroll;
}
.carousel-author {
height: 72px;
}
}

View file

@ -0,0 +1,12 @@
.lead, .split-description.wow.fadeInUp p{
font-family: "Raleway" , "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 21px;
color: #3a3a3a;
font-weight: 300 !important;
}
@media(min-width: 768px) {
.custom-padding-bottom{
padding-bottom: 0;
}
}

View file

@ -1,3 +1,17 @@
.btn-trans {
color: #fff;
border: 2px solid #fff;
padding: 4px 18px;
letter-spacing: 0.6px;
}
.btn-trans:focus,
.btn-trans:active,
.btn-trans:hover {
background: #fff;
color: #333;
}
#page-top #services .container .row .col-lg-12.text-center .section-heading { #page-top #services .container .row .col-lg-12.text-center .section-heading {
font-style: normal; font-style: normal;
color: #494949; color: #494949;
@ -7,17 +21,26 @@
color: #494949; color: #494949;
} }
.intro-cap { .header-vh {
height: 30px;
}
.intro-cap-sans-transform p {
font-family: 'Raleway', 'Helvetica Neue', 'Open Sans Bold', Helvetica, Arial, 'Arial Bold', sans-serif; font-family: 'Raleway', 'Helvetica Neue', 'Open Sans Bold', Helvetica, Arial, 'Arial Bold', sans-serif;
font-size: 26px; font-size: 26px;
font-style: normal; font-style: normal;
font-weight: 200; font-weight: 200;
text-transform: uppercase;
color: #FFF; color: #FFF;
} }
.intro-cap { .intro-cap {
margin-top: 25px;
margin-bottom: 15px;
font-family: 'Raleway', 'Helvetica Neue', 'Open Sans Bold', Helvetica, Arial, 'Arial Bold', sans-serif;
font-size: 24px; font-size: 24px;
font-style: normal;
font-weight: 200;
text-transform: uppercase;
color: #FFF;
} }
.intro-smallcap { .intro-smallcap {
@ -79,12 +102,11 @@
#portfolio .portfolio-item .portfolio-caption { #portfolio .portfolio-item .portfolio-caption {
height: 250px; height: 250px;
overflow: hidden; overflow: hidden;
paddding: 10px;
} }
.img-client { .img-client {
margin: 30px auto 30px auto; margin: 30px auto 30px auto;
height: 64px !important; max-height: 64px !important;
} }
.team-member .team-member-caption { .team-member .team-member-caption {
@ -108,6 +130,174 @@
#portfolio .portfolio-item .portfolio-caption { #portfolio .portfolio-item .portfolio-caption {
height: auto; height: auto;
overflow: hidden; overflow: hidden;
paddding: 10px; }
}
@media (max-width: 767px) {
.intro-smallcap.sm_left,
.section-heading.sm_left,
.section-subheading.sm_left {
padding-left: 15px;
padding-right: 15px;
}
}
.header_slider {
height: 95vh;
}
.header_slider > .carousel,
.header_slider > .carousel .carousel-inner,
.header_slider > .carousel .item {
height: 100%;
}
.header_slider .carousel-indicators li.active {
background-color: #ffffff;
}
.header_slider .carousel-control {
display: none;
}
.header_slider .carousel-control .fa {
font-size: 2em;
position: absolute;
top: 50%;
margin-top: -50px;
}
.header_slider > .carousel .item .container {
overflow: auto;
padding: 50px 20px 60px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.header_slider .intro-cap {
text-align: right;
line-height: 1.1;
font-size: 23px;
margin-bottom: 12px;
}
.header_slider .btn-trans {
align-self: flex-end;
z-index: 2;
position: relative;
}
@media (min-width: 768px) {
.header_slider .intro-cap {
font-size: 2.25em;
margin-bottom: 20px;
}
.header_slider .carousel-control {
width: 50px;
display: block;
}
.header_slider .carousel-control .fa-angle-left {
left: 25px;
}
.header_slider .carousel-control .fa-angle-right {
right: 25px;
}
.header_slider .carousel-control .fa {
font-size: 4em;
}
.header_slider > .carousel .item .container {
overflow: auto;
padding: 75px 50px;
}
}
@media (min-width: 992px) {
.header_slider .intro-cap {
font-size: 3.25em;
}
}
.header_slider .intro_lead {
color: #fff;
font-size: 1.55em;
text-align: right;
line-height: 1.4;
margin-bottom: 20px;
}
@media (max-width: 768px) {
.header_slider .intro_lead {
font-size: 1.1em;
margin-bottom: 15px;
}
.header_slider .carousel-indicators li {
margin: 1px 7px;
width: 16px;
height: 16px;
}
.header_slider .carousel-indicators li.active {
margin: 0 7px;
width: 18px;
height: 18px;
}
}
.bg_img {
position: absolute;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
}
.timeline>li .timeline-panel {
display: flex;
flex-direction: column;
min-height: 80px;
align-items: stretch;
justify-content: center;
padding-bottom: 15px;
}
.flex-justify-content-end{
justify-content: flex-end;
}
.flex-justify-content-start{
justify-content: flex-start;
}
.timeline>li.timeline-inverted>.timeline-panel {
padding-bottom: 0;
}
@media (max-width: 767px) {
.sm_left {
text-align: left !important;
}
}
@media (min-width: 768px) and (max-width: 991px) {
.timeline>li .timeline-panel {
min-height: 100px;
}
}
@media (min-width: 992px) {
.timeline>li .timeline-panel {
min-height: 150px;
}
}
@media (min-width: 1200px) {
.timeline>li .timeline-panel {
min-height: 170px;
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View file

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Some files were not shown because too many files have changed in this diff Show more