From 9aa732626f0c580fd5034caeeb5a3934d260c1f7 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Sun, 26 Jun 2016 14:54:01 -0500
Subject: [PATCH 1/9] fixed hosting emails

---
 hosting/templates/emails/new_booked_vm.html     | 1 +
 hosting/templates/emails/new_booked_vm.txt      | 1 +
 hosting/templates/emails/vm_charged.html        | 1 +
 hosting/templates/emails/vm_charged.txt         | 1 +
 hosting/templates/emails/vm_status_changed.html | 1 -
 hosting/templates/emails/vm_status_changed.txt  | 1 -
 6 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/hosting/templates/emails/new_booked_vm.html b/hosting/templates/emails/new_booked_vm.html
index 0a3d2742..0f9b4f6e 100644
--- a/hosting/templates/emails/new_booked_vm.html
+++ b/hosting/templates/emails/new_booked_vm.html
@@ -1,3 +1,4 @@
+{% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
diff --git a/hosting/templates/emails/new_booked_vm.txt b/hosting/templates/emails/new_booked_vm.txt
index 0a3d2742..0f9b4f6e 100644
--- a/hosting/templates/emails/new_booked_vm.txt
+++ b/hosting/templates/emails/new_booked_vm.txt
@@ -1,3 +1,4 @@
+{% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
diff --git a/hosting/templates/emails/vm_charged.html b/hosting/templates/emails/vm_charged.html
index b8837645..33568d05 100644
--- a/hosting/templates/emails/vm_charged.html
+++ b/hosting/templates/emails/vm_charged.html
@@ -1,3 +1,4 @@
+{% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
diff --git a/hosting/templates/emails/vm_charged.txt b/hosting/templates/emails/vm_charged.txt
index b8837645..33568d05 100644
--- a/hosting/templates/emails/vm_charged.txt
+++ b/hosting/templates/emails/vm_charged.txt
@@ -1,3 +1,4 @@
+{% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
diff --git a/hosting/templates/emails/vm_status_changed.html b/hosting/templates/emails/vm_status_changed.html
index 691c42a3..c60ba661 100644
--- a/hosting/templates/emails/vm_status_changed.html
+++ b/hosting/templates/emails/vm_status_changed.html
@@ -1,4 +1,3 @@
-
 {% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
diff --git a/hosting/templates/emails/vm_status_changed.txt b/hosting/templates/emails/vm_status_changed.txt
index 691c42a3..c60ba661 100644
--- a/hosting/templates/emails/vm_status_changed.txt
+++ b/hosting/templates/emails/vm_status_changed.txt
@@ -1,4 +1,3 @@
-
 {% load static from staticfiles %}
 <!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">

From e90c5fece035227b2202cb1585a0415e126029a0 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Thu, 30 Jun 2016 01:23:14 -0500
Subject: [PATCH 2/9] Created generic view for vm pricing widget, Added VM
 configuration info on VM detail view, Fixed template bugs. Fixed Blog urls
 bugs

---
 dynamicweb/urls.py                            |  8 ++--
 hosting/mixins.py                             |  7 ++-
 .../templates/hosting/hosting_pricing.html    | 44 +++++++++++++++++++
 .../templates/hosting/includes/_pricing.html  | 26 +++++++----
 .../hosting/virtual_machine_detail.html       |  5 +++
 hosting/urls.py                               |  3 +-
 hosting/views.py                              | 20 +++++++++
 7 files changed, 99 insertions(+), 14 deletions(-)
 create mode 100644 hosting/templates/hosting/hosting_pricing.html

diff --git a/dynamicweb/urls.py b/dynamicweb/urls.py
index a732934e..f0fc25bb 100644
--- a/dynamicweb/urls.py
+++ b/dynamicweb/urls.py
@@ -7,9 +7,10 @@ from django.conf.urls.static import static
 from django.conf import settings
 from hosting.views import RailsHostingView, DjangoHostingView, NodeJSHostingView
 from membership import urls as membership_urls
+from ungleich_page.views import LandingView
 import debug_toolbar
 
-urlpatterns = [
+urlpatterns = [   url(r'^index.html$', LandingView.as_view()),
                   url(r'^hosting/', include('hosting.urls', namespace="hosting")),
                   url(r'^railshosting/', RailsHostingView.as_view(), name="rails.hosting"),
                   url(r'^nodehosting/', NodeJSHostingView.as_view(), name="node.hosting"),
@@ -21,12 +22,13 @@ urlpatterns = [
 
 # note the django CMS URLs included via i18n_patterns
 urlpatterns += i18n_patterns('',
+                             url(r'^/?$', LandingView.as_view()),
                              url(r'^admin/', include(admin.site.urls)),
                              url(r'^digitalglarus/login/', include(membership_urls)),
                              url(r'^digitalglarus/', include('digitalglarus.urls',
                                                              namespace="digitalglarus")),
-                             # url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
-                             url(r'^ungleich_page/',
+                             #url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
+                             url(r'^',
                                  include('ungleich_page.urls', namespace='ungleich_page'),
                                  name='ungleich_page'),
                              url(r'^blog/', include('ungleich.urls', namespace='ungleich')),
diff --git a/hosting/mixins.py b/hosting/mixins.py
index e8a2b7b4..2f8de3a5 100644
--- a/hosting/mixins.py
+++ b/hosting/mixins.py
@@ -1,18 +1,21 @@
 from django.shortcuts import redirect
 from django.core.urlresolvers import reverse
+from .models import VirtualMachinePlan
 
 
 class ProcessVMSelectionMixin(object):
 
     def post(self, request, *args, **kwargs):
+        hosting = request.POST.get('configuration')
+        configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(hosting)
         vm_specs = {
             'cores': request.POST.get('cores'),
             'memory': request.POST.get('memory'),
             'disk_size': request.POST.get('disk_space'),
             'hosting_company': request.POST.get('hosting_company'),
             'location_code': request.POST.get('location_code'),
-            'configuration': request.POST.get('configuration'),
-            'configuration_detail': request.POST.get('configuration_detail'),
+            'configuration': hosting,
+            'configuration_detail': configuration_detail,
             'final_price': request.POST.get('final_price')
         }
         request.session['vm_specs'] = vm_specs
diff --git a/hosting/templates/hosting/hosting_pricing.html b/hosting/templates/hosting/hosting_pricing.html
new file mode 100644
index 00000000..c6ae33d0
--- /dev/null
+++ b/hosting/templates/hosting/hosting_pricing.html
@@ -0,0 +1,44 @@
+{% load staticfiles %}
+<!DOCTYPE html>
+<html>
+<head>
+	<link href="{% static 'hosting/css/pricing.css' %}" rel="stylesheet" />
+	<title>Hosting</title>
+    <!-- Bootstrap Core CSS -->
+    <link href="{% static 'hosting/css/bootstrap.min.css' %}" rel="stylesheet">
+
+    <link href="{% static 'hosting/css/pricing.css' %}" rel="stylesheet">
+
+
+    <!-- Custom CSS -->
+    <link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet">
+
+    <!-- Custom Fonts -->
+    <link href='//fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
+    <link href="{% static 'hosting/font-awesome/css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
+    <link href="//fonts.googleapis.com/css?family=Lato:300,400,700,300italic,400italic,700italic" rel="stylesheet" type="text/css">
+    <link rel="shortcut icon" href="{% static 'hosting/img/favicon.ico' %}" type="image/x-icon" />
+
+</head>
+<body>
+
+	{% include "hosting/includes/_pricing.html" with select_configuration=True%}
+
+
+    <!-- Pricing data -->
+    {% if vm_types %}
+    <script type="text/javascript"> 
+         (function () {window.VMTypesData = "{{vm_types|safe}}";})();
+    </script>
+    {%endif%}
+
+    <!-- Lodash -->
+    <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.11.1/lodash.min.js"></script>
+
+    <!-- jQuery -->
+    <script src="{% static 'hosting/js/jquery.js' %}"></script>
+
+    <!-- Pricing -->
+    <script src="{% static 'hosting/js/pricing.js' %}"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/hosting/templates/hosting/includes/_pricing.html b/hosting/templates/hosting/includes/_pricing.html
index 3a9138b4..92033be8 100644
--- a/hosting/templates/hosting/includes/_pricing.html
+++ b/hosting/templates/hosting/includes/_pricing.html
@@ -24,8 +24,7 @@
                 {% csrf_token %}
                 <input type="hidden" name="hosting_company" value="{{vm.hosting_company}}">
                 <input type="hidden" name="location_code" value="{{vm.location_code}}">
-                <input type="hidden" name="configuration_detail" value="{{configuration_detail}}">
-                <input type="hidden" name="configuration" value="{{hosting}}">
+               
                 
                 
                 <ul class="pricing {% cycle 'p-red' 'p-black' 'p-red' 'p-yel' %}">
@@ -46,13 +45,24 @@
                     </div>
                   </li>
                   <li>
-                    <!-- Single button -->
-                    <div class="btn-group">
-                      <div class="form-group">
-                        <label for="cores">Configuration: </label>
-                        {{configuration_detail}}
+                  <label for="configuration">Configuration: </label>
+                    {% if select_configuration %}
+                        <select class="form-control" name="configuration" id="{{vm.hosting_company}}-configuration" data-vm-type="{{vm.hosting_company}}">
+                        {% for key,value in configuration_options.items   %}
+                            <option  value="{{key}}">{{ value }}</option>
+                        {% endfor %}
+                        </select>
+                    {% else %}
+                      <input type="hidden" name="configuration_detail" value="{{configuration_detail}}">
+                      <input type="hidden" name="configuration" value="{{hosting}}">
+                      <!-- Single button -->
+                      <div class="btn-group">
+                        <div class="form-group">
+                          <label>Configuration: </label>
+                          {{configuration_detail}}
+                        </div>
                       </div>
-                    </div>
+                    {% endif %}
                   </li>
                   <li>
                     <!-- Single button -->
diff --git a/hosting/templates/hosting/virtual_machine_detail.html b/hosting/templates/hosting/virtual_machine_detail.html
index 24ee5d6c..b06bba86 100644
--- a/hosting/templates/hosting/virtual_machine_detail.html
+++ b/hosting/templates/hosting/virtual_machine_detail.html
@@ -89,6 +89,11 @@
 								    </div><!--/row-->    
 								  </div><!--/col-12-->
 								</div><!--/row-->
+								<div class="row">
+									<div class="col-md-12">
+										Configuration: {{virtual_machine.get_configuration_display}}
+									</div>
+								</div>
 
 
 				            </div>
diff --git a/hosting/urls.py b/hosting/urls.py
index 225dd19e..5ceeba97 100644
--- a/hosting/urls.py
+++ b/hosting/urls.py
@@ -4,13 +4,14 @@ from .views import DjangoHostingView, RailsHostingView, PaymentVMView,\
     NodeJSHostingView, LoginView, SignupView, IndexView, \
     OrdersHostingListView, OrdersHostingDetailView, VirtualMachinesPlanListView,\
     VirtualMachineView, GenerateVMSSHKeysView, OrdersHostingDeleteView, NotificationsView, \
-    MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView
+    MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, HostingPricingView
 
 urlpatterns = [
     url(r'index/?$', IndexView.as_view(), name='index'),
     url(r'django/?$', DjangoHostingView.as_view(), name='djangohosting'),
     url(r'nodejs/?$', NodeJSHostingView.as_view(), name='nodejshosting'),
     url(r'rails/?$', RailsHostingView.as_view(), name='railshosting'),
+    url(r'pricing/?$', HostingPricingView.as_view(), name='pricing'),
     url(r'payment/?$', PaymentVMView.as_view(), name='payment'),
     url(r'orders/?$', OrdersHostingListView.as_view(), name='orders'),
     url(r'orders/(?P<pk>\d+)/?$', OrdersHostingDetailView.as_view(), name='orders'),
diff --git a/hosting/views.py b/hosting/views.py
index 09f94ac9..c66068d1 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -99,6 +99,26 @@ class NodeJSHostingView(ProcessVMSelectionMixin, View):
         return render(request, self.template_name, context)
 
 
+class HostingPricingView(ProcessVMSelectionMixin, View):
+    template_name = "hosting/hosting_pricing.html"
+
+    def get_context_data(self, **kwargs):
+        configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
+        context = {
+            'configuration_options': configuration_options,
+            'email': "info@django-hosting.ch",
+            'vm_types': VirtualMachineType.get_serialized_vm_types(),
+        }
+
+        return context
+
+    def get(self, request, *args, **kwargs):
+        request.session['hosting_url'] = reverse('hosting:djangohosting')
+        context = self.get_context_data()
+
+        return render(request, self.template_name, context)
+
+
 class IndexView(View):
     template_name = "hosting/index.html"
 

From 21cd0c21a9260176c74c252e3023d20f05ad0ee9 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Fri, 1 Jul 2016 00:40:39 -0500
Subject: [PATCH 3/9] fixed digitalglarus post detail view on DE

---
 digitalglarus/views.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/digitalglarus/views.py b/digitalglarus/views.py
index 20f81cd9..b4623922 100644
--- a/digitalglarus/views.py
+++ b/digitalglarus/views.py
@@ -80,9 +80,8 @@ def blog(request):
 
 def blog_detail(request, slug):
     # post = Post.objects.filter_by_language(get_language()).filter(slug=slug).first()
-    language = 'en-us' # currently nothing is translated to german so we give then en
 
-    post = Post.objects.translated(language, slug=slug).first()
+    post = Post.objects.translated(get_language(), slug=slug).first()
     context = {
         'post': post,
     }

From 0dc81fff3dfb02de08509f23882de74e92927d99 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Mon, 4 Jul 2016 23:44:15 -0500
Subject: [PATCH 4/9] Fixed duplicated post bug , Added reset password view
 test, Added confirm reset password view test

---
 hosting/models.py     |   3 +-
 hosting/test_views.py | 187 ++++++++++++++++++++++++++++++++++++++++--
 hosting/views.py      |  30 ++++---
 utils/tests.py        |  21 +++++
 4 files changed, 225 insertions(+), 16 deletions(-)

diff --git a/hosting/models.py b/hosting/models.py
index 887f0777..099b7894 100644
--- a/hosting/models.py
+++ b/hosting/models.py
@@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _
 from django.utils.functional import cached_property
 
 
+
 from Crypto.PublicKey import RSA
 from stored_messages.settings import stored_messages_settings
 
@@ -160,7 +161,7 @@ class VirtualMachinePlan(models.Model):
         private_key, public_key = self.generate_RSA()
         self.public_key = public_key
         self.save(update_fields=['public_key'])
-        return private_key
+        return private_key, public_key
 
     def cancel_plan(self):
         self.status = self.CANCELED_STATUS
diff --git a/hosting/test_views.py b/hosting/test_views.py
index b2deb6d7..944cabcb 100644
--- a/hosting/test_views.py
+++ b/hosting/test_views.py
@@ -3,15 +3,20 @@ from django.conf import settings
 from django.test import TestCase, RequestFactory
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import resolve
+from django.contrib.auth.tokens import default_token_generator
+from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
+from django.utils.encoding import force_bytes
+
 
 from model_mommy import mommy
+from stored_messages.models import Inbox
 
 
 from membership.models import CustomUser, StripeCustomer
 from .models import VirtualMachineType, HostingOrder, VirtualMachinePlan
 from .views import DjangoHostingView, RailsHostingView, NodeJSHostingView, LoginView, SignupView, \
     PaymentVMView, OrdersHostingDetailView, OrdersHostingListView, VirtualMachineView, \
-    VirtualMachinesPlanListView
+    VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView
 from utils.tests import BaseTestCase
 
 
@@ -40,9 +45,12 @@ class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
         self.url = reverse('django.hosting')
         self.view = DjangoHostingView()
         self.expected_template = 'hosting/django.html'
+        HOSTING = 'django'
+        configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
         self.expected_context = {
-            'hosting': "django",
+            'hosting': HOSTING,
             'hosting_long': "Django",
+            'configuration_detail': configuration_detail,
             'domain': "django-hosting.ch",
             'google_analytics': "UA-62285904-6",
             'email': "info@django-hosting.ch",
@@ -56,9 +64,12 @@ class RailsHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
         self.url = reverse('rails.hosting')
         self.view = RailsHostingView()
         self.expected_template = 'hosting/rails.html'
+        HOSTING = 'rails'
+        configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
         self.expected_context = {
-            'hosting': "rails",
+            'hosting': HOSTING,
             'hosting_long': "Ruby On Rails",
+            'configuration_detail': configuration_detail,
             'domain': "rails-hosting.ch",
             'google_analytics': "UA-62285904-5",
             'email': "info@rails-hosting.ch",
@@ -72,9 +83,12 @@ class NodeJSHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
         self.url = reverse('node.hosting')
         self.view = NodeJSHostingView()
         self.expected_template = 'hosting/nodejs.html'
+        HOSTING = 'nodejs'
+        configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING)
         self.expected_context = {
-            'hosting': "nodejs",
+            'hosting': HOSTING,
             'hosting_long': "NodeJS",
+            'configuration_detail': configuration_detail,
             'domain': "node-hosting.ch",
             'google_analytics': "UA-62285904-7",
             'email': "info@node-hosting.ch",
@@ -115,6 +129,7 @@ class PaymentVMViewTest(BaseTestCase):
                 'memory': 10,
                 'disk_size': 10000,
                 'price': 22000,
+                'configuration': dict(VirtualMachinePlan.VM_CONFIGURATION).get('django')
             }
         }
 
@@ -153,7 +168,8 @@ class PaymentVMViewTest(BaseTestCase):
             'memory': hosting_order.vm_plan.memory,
             'disk_size': hosting_order.vm_plan.disk_size,
             '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
         }
         self.assertEqual(vm_plan, self.session_data.get('vm_specs'))
 
@@ -172,6 +188,92 @@ class PaymentVMViewTest(BaseTestCase):
                          settings.STRIPE_API_PUBLIC_KEY)
 
 
+class NotificationsViewTest(BaseTestCase):
+
+    def setUp(self):
+        super(NotificationsViewTest, self).setUp()
+
+        self.url = reverse('hosting:notifications')
+        self.expected_template = 'hosting/notifications.html'
+
+        self.inboxes = mommy.make(Inbox, user=self.customer, _quantity=2)
+        self.messages = list(map(lambda x: x.message, self.inboxes))
+
+    def test_get(self):
+
+        # Anonymous user should get redirect to login
+        response = self.client.get(self.url)
+        expected_url = "%s?next=%s" % (reverse('hosting:login'), reverse('hosting:notifications'))
+        self.assertRedirects(response, expected_url=expected_url,
+                             status_code=302, target_status_code=200)
+
+        # Logged user should get the page
+        response = self.customer_client.get(self.url, follow=True)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.context['all_notifications'], self.messages)
+        self.assertTemplateUsed(response, self.expected_template)
+
+
+class MarkAsReadNotificationViewTest(BaseTestCase):
+
+    def setUp(self):
+        super(MarkAsReadNotificationViewTest, self).setUp()
+
+        self.url = reverse('hosting:notifications')
+        self.expected_template = 'hosting/notifications.html'
+
+        self.inbox = mommy.make(Inbox, user=self.customer)
+        self.message = self.inbox.message
+
+        self.url = reverse('hosting:read_notification', kwargs={'pk': self.message.id})
+
+    def test_post(self):
+
+        # Anonymous user should get redirect to login
+        response = self.client.get(self.url)
+        expected_url = "%s?next=%s" % (reverse('hosting:login'),
+                                       reverse('hosting:read_notification',
+                                               kwargs={'pk': self.message.id}))
+        self.assertRedirects(response, expected_url=expected_url,
+                             status_code=302, target_status_code=200)
+
+        # Logged user should mark a message as read
+        response = self.customer_client.post(self.url, follow=True)
+        self.assertEqual(response.status_code, 200)
+        self.assertFalse(Inbox.objects.filter(user=self.customer).exists())
+        self.assertTemplateUsed(response, self.expected_template)
+
+
+class GenerateVMSSHKeysViewTest(BaseTestCase):
+
+    def setUp(self):
+        super(GenerateVMSSHKeysViewTest, self).setUp()
+
+        self.vm = mommy.make(VirtualMachinePlan)
+        self.expected_template = 'hosting/virtual_machine_key.html'
+        self.url = reverse('hosting:virtual_machine_key', kwargs={'pk': self.vm.id})
+
+    def test_get(self):
+
+        # Anonymous user should get redirect to login
+        response = self.client.get(self.url)
+        expected_url = "%s?next=%s" % (reverse('hosting:login'),
+                                       reverse('hosting:virtual_machine_key',
+                                               kwargs={'pk': self.vm.id}))
+        self.assertRedirects(response, expected_url=expected_url,
+                             status_code=302, target_status_code=200)
+
+        # Logged user should get the page
+        response = self.customer_client.get(self.url, follow=True)
+        self.assertEqual(response.status_code, 200)
+        updated_vm = VirtualMachinePlan.objects.get(id=self.vm.id)
+        self.assertEqual(response.context['public_key'].decode("utf-8"), updated_vm.public_key)
+        self.assertTrue(response.context['private_key'] is not None)
+        self.assertEqual(len(response.context['public_key']), 380)
+        self.assertTrue(len(response.context['private_key']) is 1678 or 1674)
+        self.assertTemplateUsed(response, self.expected_template)
+
+
 class VirtualMachineViewTest(BaseTestCase):
 
     def setUp(self):
@@ -357,3 +459,78 @@ class SignupViewTest(TestCase):
         self.user = CustomUser.objects.get(email=self.signup_data.get('email'))
         self.assertEqual(response.context['user'], self.user)
         self.assertEqual(response.status_code, 200)
+
+
+class PasswordResetViewTest(BaseTestCase):
+
+    def setUp(self):
+        super(PasswordResetViewTest, self).setUp()
+
+        self.url = reverse('hosting:reset_password')
+        self.view = PasswordResetView
+        self.expected_template = 'hosting/reset_password.html'
+        self.user = mommy.make('membership.CustomUser')
+        self.password = 'fake_password'
+        self.user.set_password(self.password)
+        self.user.save()
+
+        self.post_data = {
+            'email': self.user.email
+        }
+
+    def test_url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
+    def test_get(self):
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, self.expected_template)
+
+    def test_post(self):
+        response = self.client.post(self.url, data=self.post_data, follow=True)
+        self.assertEqual(response.status_code, 200)
+
+    def test_test_generate_email_context(self):
+        context = self.setup_view(self.view()).\
+            test_generate_email_context(self.user)
+        self.assertEqual(context.get('user'), self.user)
+        self.assertEqual(context.get('site_name'), 'ungleich')
+        self.assertEqual(len(context.get('token')), 24)
+
+
+class PasswordResetConfirmViewTest(BaseTestCase):
+
+    def setUp(self):
+        super(PasswordResetConfirmViewTest, self).setUp()
+
+        self.view = PasswordResetConfirmView
+        self.expected_template = 'hosting/confirm_reset_password.html'
+        self.user = mommy.make('membership.CustomUser')
+        self.password = 'fake_password'
+        self.user.set_password(self.password)
+        self.user.save()
+
+        self.token = default_token_generator.make_token(self.user)
+        self.uid = urlsafe_base64_encode(force_bytes(self.user.pk))
+        self.url = reverse('hosting:reset_password_confirm',
+                           kwargs={'token': self.token, 'uidb64': self.uid})
+
+        self.post_data = {
+            'new_password1': 'new_password',
+            'new_password2': 'new_password'
+        }
+
+    def test_url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
+    def test_get(self):
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, self.expected_template)
+
+    def test_post(self):
+        response = self.client.post(self.url, data=self.post_data, follow=True)
+        self.assertEqual(response.status_code, 200)
+        self.assertTrue(not response.context['form'].errors)
diff --git a/hosting/views.py b/hosting/views.py
index c66068d1..18d8819e 100644
--- a/hosting/views.py
+++ b/hosting/views.py
@@ -195,13 +195,7 @@ class PasswordResetView(FormView):
     success_url = reverse_lazy('hosting:login')
     # form_valid_message = 'Thank you for registering'
 
-    def form_valid(self, form):
-
-        email = form.cleaned_data.get('email')
-        user = CustomUser.objects.get(email=email)
-
-        messages.add_message(self.request, messages.SUCCESS, self.success_message)
-
+    def test_generate_email_context(self, user):
         context = {
             'user': user,
             'token': default_token_generator.make_token(user),
@@ -210,6 +204,16 @@ class PasswordResetView(FormView):
             'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host())
 
         }
+        return context
+
+    def form_valid(self, form):
+
+        email = form.cleaned_data.get('email')
+        user = CustomUser.objects.get(email=email)
+
+        messages.add_message(self.request, messages.SUCCESS, self.success_message)
+
+        context = self.test_generate_email_context(user)
         email_data = {
             'subject': 'Password Reset',
             'to': email,
@@ -246,15 +250,18 @@ class PasswordResetConfirmView(FormView):
                 return self.form_valid(form)
             else:
                 messages.error(request, 'Password reset has not been unsuccessful.')
+                form.add_error(None, 'Password reset has not been unsuccessful.')
                 return self.form_invalid(form)
 
         else:
             messages.error(request, 'The reset password link is no longer valid.')
+            form.add_error(None, 'Password reset has not been unsuccessful.')
             return self.form_invalid(form)
 
 
-class NotificationsView(TemplateView):
+class NotificationsView(LoginRequiredMixin, TemplateView):
     template_name = 'hosting/notifications.html'
+    login_url = reverse_lazy('hosting:login')
 
     def get_context_data(self, **kwargs):
         context = super(NotificationsView, self).get_context_data(**kwargs)
@@ -271,6 +278,7 @@ class NotificationsView(TemplateView):
 class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView):
     model = Message
     success_url = reverse_lazy('hosting:notifications')
+    login_url = reverse_lazy('hosting:login')
     fields = '__all__'
 
     def post(self, *args, **kwargs):
@@ -285,6 +293,7 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView):
     model = VirtualMachinePlan
     template_name = 'hosting/virtual_machine_key.html'
     success_url = reverse_lazy('hosting:orders')
+    login_url = reverse_lazy('hosting:login')
     context_object_name = "virtual_machine"
 
     def get_context_data(self, **kwargs):
@@ -292,9 +301,10 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView):
         context = super(GenerateVMSSHKeysView, self).get_context_data(**kwargs)
         vm = self.get_object()
         if not vm.public_key:
-            private_key = vm.generate_keys()
+            private_key, public_key = vm.generate_keys()
             context.update({
-                'private_key': private_key
+                'private_key': private_key,
+                'public_key': public_key
             })
             return context
         return context
diff --git a/utils/tests.py b/utils/tests.py
index 83b87a85..195fc060 100644
--- a/utils/tests.py
+++ b/utils/tests.py
@@ -1,8 +1,13 @@
 from django.test import TestCase
 from django.test import Client
+from django.http.request import HttpRequest
+
 from model_mommy import mommy
 
 
+
+
+
 class BaseTestCase(TestCase):
     """
     Base class to initialize the test cases
@@ -28,6 +33,11 @@ class BaseTestCase(TestCase):
         self.customer_client = self.get_client(self.customer)
         self.another_customer_client = self.get_client(self.another_customer)
 
+        # Request Object
+        self.request = HttpRequest()
+        self.request.META['SERVER_NAME'] = 'ungleich.com'
+        self.request.META['SERVER_PORT'] = '80'
+
     def get_client(self, user):
         """
         Authenticate a user and return the client
@@ -64,3 +74,14 @@ class BaseTestCase(TestCase):
                 }]
             }
         }
+
+    def setup_view(self, view, *args, **kwargs):
+        """Mimic as_view() returned callable, but returns view instance.
+
+        args and kwargs are the same you would pass to ``reverse()``
+
+        """
+        view.request = self.request
+        view.args = args
+        view.kwargs = kwargs
+        return view

From b34d84657e1b3bd9d34e74ad89ac6123af84fcfe Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Thu, 7 Jul 2016 23:35:50 -0500
Subject: [PATCH 5/9] Added HostingUserLoginForm test, Added
 HostingUserSignupForm test, Added PasswordResetRequestForm Test, Added
 SetPasswordForm test, Created custom 404 page

---
 dynamicweb/settings/base.py                   |   3 +-
 hosting/forms.py                              |   3 +
 hosting/test_forms.py                         | 116 ++++++++++++++++++
 .../static/ungleich_page/css/404.css          |  28 +++++
 .../templates/ungleich_page/404.html          |  28 +++++
 utils/forms.py                                |   1 -
 utils/stripe_utils.py                         |   1 -
 utils/test_forms.py                           |  48 +++++++-
 utils/tests.py                                |   3 -
 9 files changed, 224 insertions(+), 7 deletions(-)
 create mode 100644 hosting/test_forms.py
 create mode 100644 ungleich_page/static/ungleich_page/css/404.css
 create mode 100644 ungleich_page/templates/ungleich_page/404.html

diff --git a/dynamicweb/settings/base.py b/dynamicweb/settings/base.py
index ab2d6763..53a75f3a 100644
--- a/dynamicweb/settings/base.py
+++ b/dynamicweb/settings/base.py
@@ -136,7 +136,8 @@ TEMPLATES = [
                  os.path.join(PROJECT_DIR, 'hosting/templates/'),
                  os.path.join(PROJECT_DIR, 'ungleich/templates/djangocms_blog/'),
                  os.path.join(PROJECT_DIR, 'ungleich/templates/cms/ungleichch'),
-                 os.path.join(PROJECT_DIR, 'ungleich/templates/ungleich')
+                 os.path.join(PROJECT_DIR, 'ungleich/templates/ungleich'),
+                 os.path.join(PROJECT_DIR, 'ungleich_page/templates/ungleich_page')
 
                  ],
         'APP_DIRS': True,
diff --git a/hosting/forms.py b/hosting/forms.py
index 8007b2f4..2a4d67e3 100644
--- a/hosting/forms.py
+++ b/hosting/forms.py
@@ -21,6 +21,9 @@ class HostingOrderAdminForm(forms.ModelForm):
             raise forms.ValidationError("""You can't make a charge over
                                          a canceled virtual machine plan""")
 
+        if not customer:
+            raise forms.ValidationError("""You need select a costumer""")
+
         # Make a charge to the customer
         stripe_utils = StripeUtils()
         charge_response = stripe_utils.make_charge(customer=customer.stripe_id,
diff --git a/hosting/test_forms.py b/hosting/test_forms.py
new file mode 100644
index 00000000..e0f5df30
--- /dev/null
+++ b/hosting/test_forms.py
@@ -0,0 +1,116 @@
+from django.test import TestCase
+
+from unittest import mock
+from model_mommy import mommy
+
+from .forms import HostingOrderAdminForm, HostingUserLoginForm, HostingUserSignupForm
+from .models import VirtualMachinePlan
+
+
+class HostingUserLoginFormTest(TestCase):
+
+    def setUp(self):
+        password = 'user_password'
+        self.user = mommy.make('CustomUser')
+
+        self.user.set_password(password)
+        self.user.save()
+        self.completed_data = {
+            'email': self.user.email,
+            'password': password
+        }
+
+        self.incorrect_data = {
+            'email': 'test',
+        }
+
+    def test_valid_form(self):
+        form = HostingUserLoginForm(data=self.completed_data)
+        self.assertTrue(form.is_valid())
+
+    def test_invalid_form(self):
+        form = HostingUserLoginForm(data=self.incorrect_data)
+        self.assertFalse(form.is_valid())
+
+
+class HostingUserSignupFormTest(TestCase):
+
+    def setUp(self):
+
+        self.completed_data = {
+            'name': 'test name',
+            'email': 'test@ungleich.com',
+            'password': 'test_password',
+            'confirm_password': 'test_password'
+        }
+
+        self.incorrect_data = {
+            'email': 'test',
+        }
+
+    def test_valid_form(self):
+        form = HostingUserSignupForm(data=self.completed_data)
+        self.assertTrue(form.is_valid())
+
+    def test_invalid_form(self):
+        form = HostingUserSignupForm(data=self.incorrect_data)
+        self.assertFalse(form.is_valid())
+
+
+class HostingOrderAdminFormTest(TestCase):
+
+    def setUp(self):
+
+        self.customer = mommy.make('StripeCustomer')
+        self.vm_plan = mommy.make('VirtualMachinePlan')
+        self.vm_canceled_plan = mommy.make('VirtualMachinePlan',
+                                           status=VirtualMachinePlan.CANCELED_STATUS)
+
+        self.mocked_charge = {
+            'amount': 5100,
+            'amount_refunded': 0,
+            'balance_transaction': 'txn_18U99zGjsLAXdRPzUJKkBx3Q',
+            'captured': True,
+            'created': 1467785123,
+            'currency': 'chf',
+            'customer': 'cus_8V61MvJvMd0PhM',
+            'status': 'succeeded'
+        }
+
+        self.completed_data = {
+            'customer': self.customer.id,
+            'vm_plan': self.vm_plan.id,
+        }
+
+        self.incompleted_data = {
+            'vm_plan': self.vm_plan.id,
+            'customer': None
+        }
+
+    @mock.patch('utils.stripe_utils.StripeUtils.make_charge')
+    def test_valid_form(self, stripe_mocked_call):
+        stripe_mocked_call.return_value = {
+            'paid': True,
+            'response_object': self.mocked_charge,
+            'error': None
+        }
+        form = HostingOrderAdminForm(data=self.completed_data)
+        self.assertTrue(form.is_valid())
+
+    @mock.patch('utils.stripe_utils.StripeUtils.make_charge')
+    def test_invalid_form_canceled_vm(self, stripe_mocked_call):
+
+        self.completed_data.update({
+            'vm_plan': self.vm_canceled_plan.id
+        })
+        stripe_mocked_call.return_value = {
+            'paid': True,
+            'response_object': self.mocked_charge,
+            'error': None
+        }
+        form = HostingOrderAdminForm(data=self.completed_data)
+        self.assertFalse(form.is_valid())
+
+    def test_invalid_form(self):
+        form = HostingOrderAdminForm(data=self.incompleted_data)
+        self.assertFalse(form.is_valid())
diff --git a/ungleich_page/static/ungleich_page/css/404.css b/ungleich_page/static/ungleich_page/css/404.css
new file mode 100644
index 00000000..2528973d
--- /dev/null
+++ b/ungleich_page/static/ungleich_page/css/404.css
@@ -0,0 +1,28 @@
+.error {
+  margin: 0 auto;
+  text-align: center;
+}
+
+.error-code {
+  bottom: 60%;
+  color: #2d353c;
+  font-size: 96px;
+  line-height: 100px;
+}
+
+.error-desc {
+  font-size: 12px;
+  color: #647788;
+}
+
+.m-b-10 {
+  margin-bottom: 10px!important;
+}
+
+.m-b-20 {
+  margin-bottom: 20px!important;
+}
+
+.m-t-20 {
+  margin-top: 20px!important;
+}
diff --git a/ungleich_page/templates/ungleich_page/404.html b/ungleich_page/templates/ungleich_page/404.html
new file mode 100644
index 00000000..6b6caf70
--- /dev/null
+++ b/ungleich_page/templates/ungleich_page/404.html
@@ -0,0 +1,28 @@
+{% load staticfiles bootstrap3%}
+
+<!DOCTYPE html>
+<html>
+    <head>
+        <link href="{% static 'ungleich_page/css/404.css' %}" rel="stylesheet">
+        <title>404 | ungleich</title>
+    </head>
+    <body>
+
+        <div class="error">
+            <div class="error-code m-b-10 m-t-20">404 <i class="fa fa-warning"></i></div>
+            <h3 class="font-bold">We couldn't find the page..</h3>
+
+            <div class="error-desc">
+                Sorry, but the page you are looking for was either not found or does not exist. <br/>
+                Try refreshing the page or click the button below to go back to the Homepage.
+                <div>
+                    <a class=" login-detail-panel-button btn" href="http://www.vmware.com/">
+                            <i class="fa fa-arrow-left"></i>
+                            Go back to Homepage                        
+                        </a>
+                </div>
+            </div>
+        </div>
+
+    </body>
+</html>
diff --git a/utils/forms.py b/utils/forms.py
index 7af6f99a..e87d3579 100644
--- a/utils/forms.py
+++ b/utils/forms.py
@@ -48,7 +48,6 @@ class SetPasswordForm(forms.Form):
         return password2
 
 
-
 class BillingAddressForm(forms.ModelForm):
     token = forms.CharField(widget=forms.HiddenInput())
 
diff --git a/utils/stripe_utils.py b/utils/stripe_utils.py
index fb0a328e..eb17ea09 100644
--- a/utils/stripe_utils.py
+++ b/utils/stripe_utils.py
@@ -82,7 +82,6 @@ class StripeUtils(object):
         )
         return customer
 
-
     @handleStripeError
     def make_charge(self, amount=None, customer=None):
         amount = int(amount * 100)  # stripe amount unit, in cents
diff --git a/utils/test_forms.py b/utils/test_forms.py
index dc6d9fcc..46285fc5 100644
--- a/utils/test_forms.py
+++ b/utils/test_forms.py
@@ -1,5 +1,51 @@
 from django.test import TestCase
-from .forms import ContactUsForm, BillingAddressForm
+from .forms import ContactUsForm, BillingAddressForm, PasswordResetRequestForm,\
+    SetPasswordForm
+
+from model_mommy import mommy
+
+
+class PasswordResetRequestFormTest(TestCase):
+
+    def setUp(self):
+        self.user = mommy.make('CustomUser')
+        self.completed_data = {
+            'email': self.user.email,
+        }
+
+        self.incorrect_data = {
+            'email': 'test',
+        }
+
+    def test_valid_form(self):
+        form = PasswordResetRequestForm(data=self.completed_data)
+        self.assertTrue(form.is_valid())
+
+    def test_invalid_form(self):
+        form = PasswordResetRequestForm(data=self.incorrect_data)
+        self.assertFalse(form.is_valid())
+
+
+class SetPasswordFormTest(TestCase):
+
+    def setUp(self):
+        # self.user = mommy.make('CustomUser')
+        self.completed_data = {
+            'new_password1': 'new_password',
+            'new_password2': 'new_password',
+        }
+
+        self.incorrect_data = {
+            'email': 'test',
+        }
+
+    def test_valid_form(self):
+        form = SetPasswordForm(data=self.completed_data)
+        self.assertTrue(form.is_valid())
+
+    def test_invalid_form(self):
+        form = SetPasswordForm(data=self.incorrect_data)
+        self.assertFalse(form.is_valid())
 
 
 class ContactUsFormTest(TestCase):
diff --git a/utils/tests.py b/utils/tests.py
index 195fc060..42831050 100644
--- a/utils/tests.py
+++ b/utils/tests.py
@@ -5,9 +5,6 @@ from django.http.request import HttpRequest
 from model_mommy import mommy
 
 
-
-
-
 class BaseTestCase(TestCase):
     """
     Base class to initialize the test cases

From 228065b1d5be90bc557c0bcc4b6361279e2ac6b8 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Thu, 7 Jul 2016 23:50:02 -0500
Subject: [PATCH 6/9] #hotfix fixing 404 redirect home

---
 ungleich_page/templates/ungleich_page/404.html | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/ungleich_page/templates/ungleich_page/404.html b/ungleich_page/templates/ungleich_page/404.html
index 6b6caf70..bc0dc5ba 100644
--- a/ungleich_page/templates/ungleich_page/404.html
+++ b/ungleich_page/templates/ungleich_page/404.html
@@ -1,5 +1,4 @@
 {% load staticfiles bootstrap3%}
-
 <!DOCTYPE html>
 <html>
     <head>
@@ -16,7 +15,7 @@
                 Sorry, but the page you are looking for was either not found or does not exist. <br/>
                 Try refreshing the page or click the button below to go back to the Homepage.
                 <div>
-                    <a class=" login-detail-panel-button btn" href="http://www.vmware.com/">
+                    <a class=" login-detail-panel-button btn" href="{% url 'ungleich_page:landing' %}">
                             <i class="fa fa-arrow-left"></i>
                             Go back to Homepage                        
                         </a>

From fae5d616e6ee4040f42a1724846a677bb4c0596a Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Thu, 7 Jul 2016 23:52:24 -0500
Subject: [PATCH 7/9] #hotfix fixing 404 style

---
 ungleich_page/templates/ungleich_page/404.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ungleich_page/templates/ungleich_page/404.html b/ungleich_page/templates/ungleich_page/404.html
index bc0dc5ba..2fbac545 100644
--- a/ungleich_page/templates/ungleich_page/404.html
+++ b/ungleich_page/templates/ungleich_page/404.html
@@ -1,4 +1,4 @@
-{% load staticfiles bootstrap3%}
+{% load staticfiles%}
 <!DOCTYPE html>
 <html>
     <head>

From 37287cf2997dd4eb499a0333f92cd6f82421792d Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Sat, 9 Jul 2016 16:04:50 -0500
Subject: [PATCH 8/9] Added HostingPriceView test, - [ ] Added resolving url
 test to few views

---
 hosting/test_views.py | 48 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/hosting/test_views.py b/hosting/test_views.py
index 944cabcb..5e43db88 100644
--- a/hosting/test_views.py
+++ b/hosting/test_views.py
@@ -16,7 +16,8 @@ from membership.models import CustomUser, StripeCustomer
 from .models import VirtualMachineType, HostingOrder, VirtualMachinePlan
 from .views import DjangoHostingView, RailsHostingView, NodeJSHostingView, LoginView, SignupView, \
     PaymentVMView, OrdersHostingDetailView, OrdersHostingListView, VirtualMachineView, \
-    VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView
+    VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView, HostingPricingView, \
+    NotificationsView, MarkAsReadNotificationView, GenerateVMSSHKeysView
 from utils.tests import BaseTestCase
 
 
@@ -96,6 +97,36 @@ class NodeJSHostingViewTest(TestCase, ProcessVMSelectionTestMixin):
         }
 
 
+class HostingPricingViewTest(TestCase):
+
+    def setUp(self):
+        self.url = reverse('hosting:pricing')
+        self.view = HostingPricingView()
+        self.expected_template = 'hosting/hosting_pricing.html'
+
+        configuration_options = dict(VirtualMachinePlan.VM_CONFIGURATION)
+        self.expected_context = {
+            'configuration_options': configuration_options,
+            'email': "info@django-hosting.ch",
+            'vm_types': VirtualMachineType.get_serialized_vm_types(),
+        }
+
+    def url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
+    def get(self):
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(self.view.get_context_data(), self.expected_context)
+        self.assertTemplateUsed(response, self.expected_template)
+
+    def test_anonymous_post(self):
+        response = self.client.post(self.url)
+        self.assertRedirects(response, expected_url=reverse('hosting:login'),
+                             status_code=302, target_status_code=200)
+
+
 class PaymentVMViewTest(BaseTestCase):
 
     def setUp(self):
@@ -193,12 +224,17 @@ class NotificationsViewTest(BaseTestCase):
     def setUp(self):
         super(NotificationsViewTest, self).setUp()
 
+        self.view = NotificationsView
         self.url = reverse('hosting:notifications')
         self.expected_template = 'hosting/notifications.html'
 
         self.inboxes = mommy.make(Inbox, user=self.customer, _quantity=2)
         self.messages = list(map(lambda x: x.message, self.inboxes))
 
+    def test_url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
     def test_get(self):
 
         # Anonymous user should get redirect to login
@@ -219,6 +255,7 @@ class MarkAsReadNotificationViewTest(BaseTestCase):
     def setUp(self):
         super(MarkAsReadNotificationViewTest, self).setUp()
 
+        self.view = MarkAsReadNotificationView
         self.url = reverse('hosting:notifications')
         self.expected_template = 'hosting/notifications.html'
 
@@ -227,6 +264,10 @@ class MarkAsReadNotificationViewTest(BaseTestCase):
 
         self.url = reverse('hosting:read_notification', kwargs={'pk': self.message.id})
 
+    def test_url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
     def test_post(self):
 
         # Anonymous user should get redirect to login
@@ -249,10 +290,15 @@ class GenerateVMSSHKeysViewTest(BaseTestCase):
     def setUp(self):
         super(GenerateVMSSHKeysViewTest, self).setUp()
 
+        self.view = GenerateVMSSHKeysView
         self.vm = mommy.make(VirtualMachinePlan)
         self.expected_template = 'hosting/virtual_machine_key.html'
         self.url = reverse('hosting:virtual_machine_key', kwargs={'pk': self.vm.id})
 
+    def test_url_resolve_to_view_correctly(self):
+        found = resolve(self.url)
+        self.assertEqual(found.func.__name__, self.view.__name__)
+
     def test_get(self):
 
         # Anonymous user should get redirect to login

From 0d6e43de44e4381a29a7209c72f592514c955cb8 Mon Sep 17 00:00:00 2001
From: Levi <levinoelvm@gmail.com>
Date: Sat, 9 Jul 2016 17:21:57 -0500
Subject: [PATCH 9/9] Added ungleich landing translation

---
 ungleich_page/locale/de/LC_MESSAGES/django.mo | Bin 2551 -> 4845 bytes
 ungleich_page/locale/de/LC_MESSAGES/django.po |  67 ++++++++++++------
 .../ungleich_page/includes/_services.html     |   3 +-
 3 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/ungleich_page/locale/de/LC_MESSAGES/django.mo b/ungleich_page/locale/de/LC_MESSAGES/django.mo
index ef04e0dae6d90fec8960faea3dc5846525199f7d..b44e0c322186db93d543c900779a04a0693b89e1 100644
GIT binary patch
literal 4845
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

delta 808
zcmYMy&o5k27{>8;7>3piLtE6Zi-^z&+QdY<5K@Z7LTqIcCSx=m1f2w%X)L5o(=JSi
zg}=hAux?UK8eKH8C{}EwT}X&@Ro~|_oXokOGtQlJ-t!!P8?H){$Hm??qdD|Sb&uII
znZ<+l4Rdf0pW;3~z%#7COAKHz+w2KCsQD23um^)Uh;2A}JO3HW&62jkAeV_Pti^3C
z!{7J{FHjqFdd(hVKel2RnX)g~h^wfLcTn$tMQXEOSbzuk2v5+D|FDSt&ByVo`9m41
z(hzFF0enjuv#14+sFI594{D)Yj;BN_Q1czA1bR`0j3OV4@hHL>9KiRe-+jj#_P0|8
zd6>ha4g;tJ+VLe0Vj-^F&aY#L@7t&Z&ankAQH9j!-}oFkq;+E{_MxsUj7ne$lO+s3
zFi--Us04Pg34b5~xQ(IP9`e*F^}haJbamQ93ul_v&<2XVm|jI!VKsCm$9dfYQSXo&
z4d2~Jq(dk1yQVu=8kwd$)oIjJyrR~%D2den?4RXB(fRqYSkxIwL?R3)67l$=GZLMC
zmwN5{=$~A464SAG^i5>4t2sTKzn+zTQIO|J9r~TrLg8{?Y%Vc%|3>;#aNKhZ^k`5w

diff --git a/ungleich_page/locale/de/LC_MESSAGES/django.po b/ungleich_page/locale/de/LC_MESSAGES/django.po
index a5cb93c7..f8b938ce 100644
--- a/ungleich_page/locale/de/LC_MESSAGES/django.po
+++ b/ungleich_page/locale/de/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-04-15 19:16-0500\n"
+"POT-Creation-Date: 2016-07-09 16:47-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -70,32 +70,32 @@ msgstr "und"
 msgid "the story continues!"
 msgstr "Die Geschichte geht weiter!"
 
-#: templates/ungleich_page/includes/_contact_us.html:14
-#: templates/ungleich_page/includes/_contact_us.html:21 views.py:35
+#: templates/ungleich_page/includes/_contact_us.html:15
+#: templates/ungleich_page/includes/_contact_us.html:28 views.py:36
 msgid "Contact Us"
 msgstr "Kontaktieren Sie uns"
 
-#: templates/ungleich_page/includes/_contact_us.html:16
+#: templates/ungleich_page/includes/_contact_us.html:18
 msgid "Join us at"
 msgstr "Schliessen Sie sich uns an"
 
-#: templates/ungleich_page/includes/_contact_us.html:16
+#: templates/ungleich_page/includes/_contact_us.html:19
 msgid "Digital Glarus"
 msgstr "Digital Glarus"
 
-#: templates/ungleich_page/includes/_contact_us.html:17
+#: templates/ungleich_page/includes/_contact_us.html:20
 msgid "a great co-working space in the middle of Alps!"
 msgstr "ein wunderschöner Co-Working Space mitten in den Alpen"
 
-#: templates/ungleich_page/includes/_contact_us.html:17
+#: templates/ungleich_page/includes/_contact_us.html:21
 msgid "You can contact us at"
 msgstr "Sie können uns kontaktieren unter"
 
-#: templates/ungleich_page/includes/_contact_us.html:20
+#: templates/ungleich_page/includes/_contact_us.html:26
 msgid "or"
 msgstr "oder"
 
-#: templates/ungleich_page/includes/_contact_us.html:50
+#: templates/ungleich_page/includes/_contact_us.html:60
 msgid "Submit"
 msgstr "Absenden"
 
@@ -126,21 +126,24 @@ msgid ""
 "infrastructure is powered by Free and Open Source Software like OpenNebula, "
 "Qemu and GlusterFS."
 msgstr ""
+"Wir offerieren hohe Verfügbarkeit für das Hosting in Deutschland und in der "
+"Schweiz. Unsere Infrastruktur ist unterstützt durch Free and Open  Source "
+"Software wie OpenNebula."
 
 #: templates/ungleich_page/includes/_portfolio.html:24
 msgid "Rails Hosting"
-msgstr ""
+msgstr "Rails Hosting"
 
 #: templates/ungleich_page/includes/_portfolio.html:26
 msgid ""
 "Ready to go live with your Ruby on Rails application? We offer you ready-to-"
 "deploy virtual machines or configure your existing infrastructure for Ruby "
 "on Rails."
-msgstr ""
+msgstr "Sind bereit mit ihrem Ruby on Rails Applikation live zu gehen?"
 
 #: templates/ungleich_page/includes/_portfolio.html:32
 msgid " Configuration as a Service"
-msgstr ""
+msgstr "Konfiguration als Service"
 
 #: templates/ungleich_page/includes/_portfolio.html:34
 msgid ""
@@ -148,11 +151,23 @@ msgid ""
 "experienced team that configure your systems to provide service like DNS, E-"
 "Mail, Databases or Webservers."
 msgstr ""
+"Sie brauchen eine Konfiguration? Mit ungleich haben sie ein erfahrenes Team "
+"gefunden, dass ihnen die Konfiguration von DNS, E-Mail, Datenbanken oder "
+"Webservern für ihr System anbietet"
 
 #: templates/ungleich_page/includes/_services.html:8
 msgid "our services"
 msgstr "Unsere Dienstleistungen"
 
+#: templates/ungleich_page/includes/_services.html:9
+msgid "We support our clients in all areas of Unix infrastructure."
+msgstr ""
+
+#: templates/ungleich_page/includes/_services.html:10
+msgid ""
+"Our top notch configuration management is refreshingly simple and reliable."
+msgstr ""
+
 #: templates/ungleich_page/includes/_services.html:18
 msgid "Hosting"
 msgstr "Hosting"
@@ -162,6 +177,8 @@ msgid ""
 "Ruby on Rails. Java hosting, Django hosting, we make it everything run "
 "smooth and safe."
 msgstr ""
+"Ruby on Rails. Java hosting, Django hosting, wir garantieren einen "
+"reibungslosen Ablauf"
 
 #: templates/ungleich_page/includes/_services.html:28
 msgid "Configuration as a Service"
@@ -173,16 +190,21 @@ msgid ""
 "needs to configured, we provide comprehensive solutions. Amazon, rackspace "
 "or bare metal servers, we configure for you."
 msgstr ""
+"Ruby on Rails, Django, Java, Webserver, Mailserver, jegliche Infrastruktur "
+"welche eine Konfiguration braucht, wir offerieren umfassende Lösungen, "
+"Amazon, Rackspace oder Bare Metal Servers, wir konfigurieren alles."
 
 #: templates/ungleich_page/includes/_services.html:38
 msgid "Linux System Engineering"
-msgstr ""
+msgstr "Linux System Engineering"
 
 #: templates/ungleich_page/includes/_services.html:41
 msgid ""
 "Let your developers develop! We take care of your system administration. "
 "Gentoo, Archlinux, Debian, Ubuntu, and many more."
 msgstr ""
+"Lassen sie ihre Entwickler entwickeln! Wir kümmern uns um ihre "
+"Systemadministration. Gentoo, Archlinux, Debian, Ubuntu und viele mehr."
 
 #: templates/ungleich_page/includes/_team.html:8
 msgid "Why ungleich?*"
@@ -190,7 +212,7 @@ msgstr "Warum ungleich?"
 
 #: templates/ungleich_page/includes/_team.html:9
 msgid "What our customers say"
-msgstr ""
+msgstr "Was unsere Kunden sagen"
 
 #: templates/ungleich_page/includes/_team.html:29
 msgid ""
@@ -249,16 +271,19 @@ msgstr ""
 
 #: templates/ungleich_page/includes/_team.html:95
 msgid "*ungleich means not equal to (≠) U+2260."
-msgstr ""
+msgstr "*ungleich bedeutet nicht gleich wie (≠) U+2260."
 
-#: urls.py:7
-msgid "contact/?$"
-msgstr ""
+#: urls.py:8
+#, fuzzy
+#| msgid "Contact Us"
+msgid "contact/$"
+msgstr "Kontaktieren Sie uns"
 
-#: views.py:25
+#: views.py:26
 msgid "Message Successfully Sent"
 msgstr "Nachricht erfolgreich versendet"
 
-#: views.py:36
+#: views.py:37
 msgid "If you have any question, just send us an email."
-msgstr "Wenn Sie irgendwelche Fragen haben, schicken Sie uns einfach eine E-Mail."
+msgstr ""
+"Wenn Sie irgendwelche Fragen haben, schicken Sie uns einfach eine E-Mail."
diff --git a/ungleich_page/templates/ungleich_page/includes/_services.html b/ungleich_page/templates/ungleich_page/includes/_services.html
index 1d35528a..d07e1336 100644
--- a/ungleich_page/templates/ungleich_page/includes/_services.html
+++ b/ungleich_page/templates/ungleich_page/includes/_services.html
@@ -6,8 +6,7 @@
 		<div class="row">
 		  <div class="col-lg-12 text-center wow fadeInDown">
 		    <h2 class="section-heading">{% trans "our services" %}</h2>
-		    <h3 class="section-subheading text-muted">We support our clients in all areas of Unix infrastructure.<p></p>
-		      Our top notch configuration management is refreshingly simple and reliable."</h3>
+		    <h3 class="section-subheading text-muted">{% trans "" %}</h3>
 		  </div>
 		</div>
 		<div class="row text-center">