Merge branch 'master' into task/3713/clean_up_css
This commit is contained in:
		
				commit
				
					
						b9c53717e3
					
				
			
		
					 29 changed files with 119 additions and 427 deletions
				
			
		| 
						 | 
					@ -1,3 +1,12 @@
 | 
				
			||||||
 | 
					Next:
 | 
				
			||||||
 | 
					    * #4049: [blog] Replace header background image
 | 
				
			||||||
 | 
					    * #3670: [hosting] Shorten ssh key name
 | 
				
			||||||
 | 
					    * #4046: [hosting] Add sdd_size, hdd_size to VirtualMachineSerializer (No visual change)
 | 
				
			||||||
 | 
					    * bgfix: [hosting] increase invoice pdf resolution
 | 
				
			||||||
 | 
					1.3.2: 2018-01-16
 | 
				
			||||||
 | 
					    * #4000: [all] Replace all ungleich.com with ungleich.ch
 | 
				
			||||||
 | 
					    * #4067: [ungleich] mobile navbar toggle fix
 | 
				
			||||||
 | 
					    * #4103: [dcl] Add "Terms of Service" item to the footer
 | 
				
			||||||
1.3.1: 2017-12-31
 | 
					1.3.1: 2017-12-31
 | 
				
			||||||
    * feature: [all] Load email configurations host, port and use_tls from env
 | 
					    * feature: [all] Load email configurations host, port and use_tls from env
 | 
				
			||||||
    * bugfix:  [all] Use ungleich's smtp as relayhost for sending emails
 | 
					    * bugfix:  [all] Use ungleich's smtp as relayhost for sending emails
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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-12-22 01:00+0530\n"
 | 
					"POT-Creation-Date: 2018-01-15 23:12+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"
 | 
				
			||||||
| 
						 | 
					@ -199,6 +199,9 @@ msgstr "VM bestellen"
 | 
				
			||||||
msgid "Contact"
 | 
					msgid "Contact"
 | 
				
			||||||
msgstr "Kontakt"
 | 
					msgstr "Kontakt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					msgid "Terms of Service"
 | 
				
			||||||
 | 
					msgstr "Nutzungsbedingungen"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
msgid "All Rights Reserved"
 | 
					msgid "All Rights Reserved"
 | 
				
			||||||
msgstr "Alle Rechte vorbehalten"
 | 
					msgstr "Alle Rechte vorbehalten"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,12 @@
 | 
				
			||||||
            <li>
 | 
					            <li>
 | 
				
			||||||
                <a class="url-init" href="{% url 'datacenterlight:index' %}#contact">{% trans "Contact" %}</a>
 | 
					                <a class="url-init" href="{% url 'datacenterlight:index' %}#contact">{% trans "Contact" %}</a>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
 | 
					            {% if request.resolver_match.url_name != "index" %}
 | 
				
			||||||
 | 
					                <li class="footer-menu-divider">⋅</li>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					            <li>
 | 
				
			||||||
 | 
					                <a class="url-init" href="/cms/terms-of-service">{% trans "Terms of Service" %}</a>
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <p class="copyright text-muted small">Copyright © ungleich GmbH {% now "Y" %}. {% trans "All Rights Reserved" %}</p>
 | 
					        <p class="copyright text-muted small">Copyright © ungleich GmbH {% now "Y" %}. {% trans "All Rights Reserved" %}</p>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 141 KiB  | 
| 
						 | 
					@ -224,7 +224,7 @@ class SignupViewTest(TestCase):
 | 
				
			||||||
        self.view = SignupView
 | 
					        self.view = SignupView
 | 
				
			||||||
        self.signup_data = {
 | 
					        self.signup_data = {
 | 
				
			||||||
            'name': 'ungleich',
 | 
					            'name': 'ungleich',
 | 
				
			||||||
            'email': 'test@ungleich.com',
 | 
					            'email': 'test@ungleich.ch',
 | 
				
			||||||
            'password': 'fake_password',
 | 
					            'password': 'fake_password',
 | 
				
			||||||
            'confirm_password': 'fake_password',
 | 
					            'confirm_password': 'fake_password',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -540,6 +540,8 @@ ONEADMIN_USER_SSH_PUBLIC_KEY = env('ONEADMIN_USER_SSH_PUBLIC_KEY')
 | 
				
			||||||
DCL_TEXT = env('DCL_TEXT')
 | 
					DCL_TEXT = env('DCL_TEXT')
 | 
				
			||||||
DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS')
 | 
					DCL_SUPPORT_FROM_ADDRESS = env('DCL_SUPPORT_FROM_ADDRESS')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DCL_SSH_KEY_NAME_PREFIX = 'dcl-gen-key-'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Settings for Google analytics
 | 
					# Settings for Google analytics
 | 
				
			||||||
GOOGLE_ANALYTICS_PROPERTY_IDS = {
 | 
					GOOGLE_ANALYTICS_PROPERTY_IDS = {
 | 
				
			||||||
    'ungleich.ch': 'UA-62285904-1',
 | 
					    'ungleich.ch': 'UA-62285904-1',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ import subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.auth import authenticate
 | 
					from django.contrib.auth import authenticate
 | 
				
			||||||
from django.utils.translation import ugettext_lazy as _
 | 
					from django.utils.translation import ugettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,8 +16,10 @@ logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generate_ssh_key_name():
 | 
					def generate_ssh_key_name():
 | 
				
			||||||
    return 'dcl-generated-key-' + datetime.datetime.now().strftime(
 | 
					    return '{prefix}{date_time_str}'.format(
 | 
				
			||||||
        '%m%d%y%H%M')
 | 
					        prefix=settings.DCL_SSH_KEY_NAME_PREFIX,
 | 
				
			||||||
 | 
					        date_time_str=datetime.datetime.now().strftime('%m%d%y%H%M%S')
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HostingUserLoginForm(forms.Form):
 | 
					class HostingUserLoginForm(forms.Form):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								hosting/static/hosting/js/html2canvas.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								hosting/static/hosting/js/html2canvas.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
					@ -1,387 +0,0 @@
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @license
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * MIT License
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (c) 2017 Erik Koopmans
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
 * in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
 * furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The above copyright notice and this permission notice shall be included in all
 | 
					 | 
				
			||||||
 * copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
					 | 
				
			||||||
 * SOFTWARE.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Generate a PDF from an HTML element or string using html2canvas and jsPDF.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param {Element|string} source The source element or HTML string.
 | 
					 | 
				
			||||||
 * @param {Object=} opt An object of optional settings: 'margin', 'filename',
 | 
					 | 
				
			||||||
 *    'image' ('type' and 'quality'), and 'html2canvas' / 'jspdf', which are
 | 
					 | 
				
			||||||
 *    sent as settings to their corresponding functions.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
var html2pdf = (function(html2canvas, jsPDF) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ---------- MAIN FUNCTION ---------- */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  var html2pdf = function(source, opt) {
 | 
					 | 
				
			||||||
    // Handle input.
 | 
					 | 
				
			||||||
    opt = objType(opt) === 'object' ? opt : {};
 | 
					 | 
				
			||||||
    var source = html2pdf.parseInput(source, opt);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Determine the PDF page size.
 | 
					 | 
				
			||||||
    var pageSize = jsPDF.getPageSize(opt.jsPDF);
 | 
					 | 
				
			||||||
    pageSize.inner = {
 | 
					 | 
				
			||||||
      width:  pageSize.width - opt.margin[1] - opt.margin[3],
 | 
					 | 
				
			||||||
      height: pageSize.height - opt.margin[0] - opt.margin[2]
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    pageSize.inner.ratio = pageSize.inner.height / pageSize.inner.width;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Copy the source element into a PDF-styled container div.
 | 
					 | 
				
			||||||
    var container = html2pdf.makeContainer(source, pageSize);
 | 
					 | 
				
			||||||
    var overlay = container.parentElement;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Get the locations of all hyperlinks.
 | 
					 | 
				
			||||||
    if (opt.enableLinks) {
 | 
					 | 
				
			||||||
      // Find all anchor tags and get the container's bounds for reference.
 | 
					 | 
				
			||||||
      opt.links = [];
 | 
					 | 
				
			||||||
      var links = container.querySelectorAll('a');
 | 
					 | 
				
			||||||
      var containerRect = unitConvert(container.getBoundingClientRect(), pageSize.k);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Treat each client rect as a separate link (for text-wrapping).
 | 
					 | 
				
			||||||
      Array.prototype.forEach.call(links, function(link) {
 | 
					 | 
				
			||||||
        var clientRects = link.getClientRects();
 | 
					 | 
				
			||||||
        for (var i=0; i<clientRects.length; i++) {
 | 
					 | 
				
			||||||
          var clientRect = unitConvert(clientRects[i], pageSize.k);
 | 
					 | 
				
			||||||
          clientRect.left -= containerRect.left;
 | 
					 | 
				
			||||||
          clientRect.top -= containerRect.top;
 | 
					 | 
				
			||||||
          opt.links.push({ el: link, clientRect: clientRect });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Render the canvas and pass the result to makePDF.
 | 
					 | 
				
			||||||
    var onRendered = opt.html2canvas.onrendered || function() {};
 | 
					 | 
				
			||||||
    opt.html2canvas.onrendered = function(canvas) {
 | 
					 | 
				
			||||||
      onRendered(canvas);
 | 
					 | 
				
			||||||
      document.body.removeChild(overlay);
 | 
					 | 
				
			||||||
      html2pdf.makePDF(canvas, pageSize, opt);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    html2canvas(container, opt.html2canvas);
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  html2pdf.parseInput = function(source, opt) {
 | 
					 | 
				
			||||||
    // Parse the opt object.
 | 
					 | 
				
			||||||
    opt.jsPDF = opt.jsPDF || {};
 | 
					 | 
				
			||||||
    opt.html2canvas = opt.html2canvas || {};
 | 
					 | 
				
			||||||
    opt.filename = opt.filename && objType(opt.filename) === 'string' ? opt.filename : 'file.pdf';
 | 
					 | 
				
			||||||
    opt.enableLinks = opt.hasOwnProperty('enableLinks') ? opt.enableLinks : true;
 | 
					 | 
				
			||||||
    opt.image = opt.image || {};
 | 
					 | 
				
			||||||
    opt.image.type = opt.image.type || 'jpeg';
 | 
					 | 
				
			||||||
    opt.image.quality = opt.image.quality || 0.95;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Parse the margin property of the opt object.
 | 
					 | 
				
			||||||
    switch (objType(opt.margin)) {
 | 
					 | 
				
			||||||
      case 'undefined':
 | 
					 | 
				
			||||||
        opt.margin = 0;
 | 
					 | 
				
			||||||
      case 'number':
 | 
					 | 
				
			||||||
        opt.margin = [opt.margin, opt.margin, opt.margin, opt.margin];
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case 'array':
 | 
					 | 
				
			||||||
        if (opt.margin.length === 2) {
 | 
					 | 
				
			||||||
          opt.margin = [opt.margin[0], opt.margin[1], opt.margin[0], opt.margin[1]];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (opt.margin.length === 4) {
 | 
					 | 
				
			||||||
          break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        throw 'Invalid margin array.';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Parse the source element/string.
 | 
					 | 
				
			||||||
    if (!source) {
 | 
					 | 
				
			||||||
      throw 'Missing source element or string.';
 | 
					 | 
				
			||||||
    } else if (objType(source) === 'string') {
 | 
					 | 
				
			||||||
      source = createElement('div', { innerHTML: source });
 | 
					 | 
				
			||||||
    } else if (objType(source) === 'element') {
 | 
					 | 
				
			||||||
      source = cloneNode(source, opt.html2canvas.javascriptEnabled);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      throw 'Invalid source - please specify an HTML Element or string.';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Return the parsed input (opt is modified in-place, no need to return).
 | 
					 | 
				
			||||||
    return source;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  html2pdf.makeContainer = function(source, pageSize) {
 | 
					 | 
				
			||||||
    // Define the CSS styles for the container and its overlay parent.
 | 
					 | 
				
			||||||
    var overlayCSS = {
 | 
					 | 
				
			||||||
      position: 'fixed', overflow: 'hidden', zIndex: 1000,
 | 
					 | 
				
			||||||
      left: 0, right: 0, bottom: 0, top: 0,
 | 
					 | 
				
			||||||
      backgroundColor: 'rgba(0,0,0,0.8)'
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    var containerCSS = {
 | 
					 | 
				
			||||||
      position: 'absolute', width: pageSize.inner.width + pageSize.unit,
 | 
					 | 
				
			||||||
      left: 0, right: 0, top: 0, height: 'auto', margin: 'auto',
 | 
					 | 
				
			||||||
      backgroundColor: 'white'
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Set the overlay to hidden (could be changed in the future to provide a print preview).
 | 
					 | 
				
			||||||
    overlayCSS.opacity = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Create and attach the elements.
 | 
					 | 
				
			||||||
    var overlay = createElement('div',   { className: 'html2pdf__overlay', style: overlayCSS });
 | 
					 | 
				
			||||||
    var container = createElement('div', { className: 'html2pdf__container', style: containerCSS });
 | 
					 | 
				
			||||||
    container.appendChild(source);
 | 
					 | 
				
			||||||
    overlay.appendChild(container);
 | 
					 | 
				
			||||||
    document.body.appendChild(overlay);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Enable page-breaks.
 | 
					 | 
				
			||||||
    var pageBreaks = source.querySelectorAll('.html2pdf__page-break');
 | 
					 | 
				
			||||||
    var pxPageHeight = pageSize.inner.height * pageSize.k / 72 * 96;
 | 
					 | 
				
			||||||
    Array.prototype.forEach.call(pageBreaks, function(el) {
 | 
					 | 
				
			||||||
      el.style.display = 'block';
 | 
					 | 
				
			||||||
      var clientRect = el.getBoundingClientRect();
 | 
					 | 
				
			||||||
      el.style.height = pxPageHeight - (clientRect.top % pxPageHeight) + 'px';
 | 
					 | 
				
			||||||
    }, this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Return the container.
 | 
					 | 
				
			||||||
    return container;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  html2pdf.makePDF = function(canvas, pageSize, opt) {
 | 
					 | 
				
			||||||
    // Calculate the number of pages.
 | 
					 | 
				
			||||||
    var ctx = canvas.getContext('2d');
 | 
					 | 
				
			||||||
    var pxFullHeight = canvas.height;
 | 
					 | 
				
			||||||
    var pxPageHeight = Math.floor(canvas.width * pageSize.inner.ratio);
 | 
					 | 
				
			||||||
    var nPages = Math.ceil(pxFullHeight / pxPageHeight);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Create a one-page canvas to split up the full image.
 | 
					 | 
				
			||||||
    var pageCanvas = document.createElement('canvas');
 | 
					 | 
				
			||||||
    var pageCtx = pageCanvas.getContext('2d');
 | 
					 | 
				
			||||||
    var pageHeight = pageSize.inner.height;
 | 
					 | 
				
			||||||
    pageCanvas.width = canvas.width;
 | 
					 | 
				
			||||||
    pageCanvas.height = pxPageHeight;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Initialize the PDF.
 | 
					 | 
				
			||||||
    var pdf = new jsPDF(opt.jsPDF);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (var page=0; page<nPages; page++) {
 | 
					 | 
				
			||||||
      // Trim the final page to reduce file size.
 | 
					 | 
				
			||||||
      if (page === nPages-1) {
 | 
					 | 
				
			||||||
        pageCanvas.height = pxFullHeight % pxPageHeight;
 | 
					 | 
				
			||||||
        pageHeight = pageCanvas.height * pageSize.inner.width / pageCanvas.width;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Display the page.
 | 
					 | 
				
			||||||
      var w = pageCanvas.width;
 | 
					 | 
				
			||||||
      var h = pageCanvas.height;
 | 
					 | 
				
			||||||
      pageCtx.fillStyle = 'white';
 | 
					 | 
				
			||||||
      pageCtx.fillRect(0, 0, w, h);
 | 
					 | 
				
			||||||
      pageCtx.drawImage(canvas, 0, page*pxPageHeight, w, h, 0, 0, w, h);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Add the page to the PDF.
 | 
					 | 
				
			||||||
      if (page)  pdf.addPage();
 | 
					 | 
				
			||||||
      var imgData = pageCanvas.toDataURL('image/' + opt.image.type, opt.image.quality);
 | 
					 | 
				
			||||||
      pdf.addImage(imgData, opt.image.type, opt.margin[1], opt.margin[0],
 | 
					 | 
				
			||||||
                   pageSize.inner.width, pageHeight);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Add hyperlinks.
 | 
					 | 
				
			||||||
      if (opt.enableLinks) {
 | 
					 | 
				
			||||||
        var pageTop = page * pageSize.inner.height;
 | 
					 | 
				
			||||||
        opt.links.forEach(function(link) {
 | 
					 | 
				
			||||||
          if (link.clientRect.top > pageTop && link.clientRect.top < pageTop + pageSize.inner.height) {
 | 
					 | 
				
			||||||
            var left = opt.margin[1] + link.clientRect.left;
 | 
					 | 
				
			||||||
            var top = opt.margin[0] + link.clientRect.top - pageTop;
 | 
					 | 
				
			||||||
            pdf.link(left, top, link.clientRect.width, link.clientRect.height, { url: link.el.href });
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Finish the PDF.
 | 
					 | 
				
			||||||
    pdf.save( opt.filename );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* ---------- UTILS ---------- */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Determine the type of a variable/object.
 | 
					 | 
				
			||||||
  var objType = function(obj) {
 | 
					 | 
				
			||||||
    if (typeof obj === 'undefined')                             return 'undefined';
 | 
					 | 
				
			||||||
    else if (typeof obj === 'string' || obj instanceof String)  return 'string';
 | 
					 | 
				
			||||||
    else if (typeof obj === 'number' || obj instanceof Number)  return 'number';
 | 
					 | 
				
			||||||
    else if (!!obj && obj.constructor === Array)                return 'array';
 | 
					 | 
				
			||||||
    else if (obj && obj.nodeType === 1)                         return 'element';
 | 
					 | 
				
			||||||
    else if (typeof obj === 'object')                           return 'object';
 | 
					 | 
				
			||||||
    else                                                        return 'unknown';
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create an HTML element with optional className, innerHTML, and style.
 | 
					 | 
				
			||||||
  var createElement = function(tagName, opt) {
 | 
					 | 
				
			||||||
    var el = document.createElement(tagName);
 | 
					 | 
				
			||||||
    if (opt.className)  el.className = opt.className;
 | 
					 | 
				
			||||||
    if (opt.innerHTML) {
 | 
					 | 
				
			||||||
      el.innerHTML = opt.innerHTML;
 | 
					 | 
				
			||||||
      var scripts = el.getElementsByTagName('script');
 | 
					 | 
				
			||||||
      for (var i = scripts.length; i-- > 0; null) {
 | 
					 | 
				
			||||||
        scripts[i].parentNode.removeChild(scripts[i]);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (var key in opt.style) {
 | 
					 | 
				
			||||||
      el.style[key] = opt.style[key];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return el;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Deep-clone a node and preserve contents/properties.
 | 
					 | 
				
			||||||
  var cloneNode = function(node, javascriptEnabled) {
 | 
					 | 
				
			||||||
    // Recursively clone the node.
 | 
					 | 
				
			||||||
    var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
 | 
					 | 
				
			||||||
    for (var child = node.firstChild; child; child = child.nextSibling) {
 | 
					 | 
				
			||||||
      if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
 | 
					 | 
				
			||||||
        clone.appendChild(cloneNode(child, javascriptEnabled));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (node.nodeType === 1) {
 | 
					 | 
				
			||||||
      // Preserve contents/properties of special nodes.
 | 
					 | 
				
			||||||
      if (node.nodeName === 'CANVAS') {
 | 
					 | 
				
			||||||
        clone.width = node.width;
 | 
					 | 
				
			||||||
        clone.height = node.height;
 | 
					 | 
				
			||||||
        clone.getContext('2d').drawImage(node, 0, 0);
 | 
					 | 
				
			||||||
      } else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
 | 
					 | 
				
			||||||
        clone.value = node.value;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Preserve the node's scroll position when it loads.
 | 
					 | 
				
			||||||
      clone.addEventListener('load', function() {
 | 
					 | 
				
			||||||
        clone.scrollTop = node.scrollTop;
 | 
					 | 
				
			||||||
        clone.scrollLeft = node.scrollLeft;
 | 
					 | 
				
			||||||
      }, true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Return the cloned node.
 | 
					 | 
				
			||||||
    return clone;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Convert units using the conversion value 'k' from jsPDF.
 | 
					 | 
				
			||||||
  var unitConvert = function(obj, k) {
 | 
					 | 
				
			||||||
    var newObj = {};
 | 
					 | 
				
			||||||
    for (var key in obj) {
 | 
					 | 
				
			||||||
      newObj[key] = obj[key] * 72 / 96 / k;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return newObj;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Get dimensions of a PDF page, as determined by jsPDF.
 | 
					 | 
				
			||||||
  jsPDF.getPageSize = function(orientation, unit, format) {
 | 
					 | 
				
			||||||
    // Decode options object
 | 
					 | 
				
			||||||
    if (typeof orientation === 'object') {
 | 
					 | 
				
			||||||
      var options = orientation;
 | 
					 | 
				
			||||||
      orientation = options.orientation;
 | 
					 | 
				
			||||||
      unit = options.unit || unit;
 | 
					 | 
				
			||||||
      format = options.format || format;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Default options
 | 
					 | 
				
			||||||
    unit        = unit || 'mm';
 | 
					 | 
				
			||||||
    format      = format || 'a4';
 | 
					 | 
				
			||||||
    orientation = ('' + (orientation || 'P')).toLowerCase();
 | 
					 | 
				
			||||||
    var format_as_string = ('' + format).toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Size in pt of various paper formats
 | 
					 | 
				
			||||||
    pageFormats = {
 | 
					 | 
				
			||||||
      'a0'  : [2383.94, 3370.39], 'a1'  : [1683.78, 2383.94],
 | 
					 | 
				
			||||||
      'a2'  : [1190.55, 1683.78], 'a3'  : [ 841.89, 1190.55],
 | 
					 | 
				
			||||||
      'a4'  : [ 595.28,  841.89], 'a5'  : [ 419.53,  595.28],
 | 
					 | 
				
			||||||
      'a6'  : [ 297.64,  419.53], 'a7'  : [ 209.76,  297.64],
 | 
					 | 
				
			||||||
      'a8'  : [ 147.40,  209.76], 'a9'  : [ 104.88,  147.40],
 | 
					 | 
				
			||||||
      'a10' : [  73.70,  104.88], 'b0'  : [2834.65, 4008.19],
 | 
					 | 
				
			||||||
      'b1'  : [2004.09, 2834.65], 'b2'  : [1417.32, 2004.09],
 | 
					 | 
				
			||||||
      'b3'  : [1000.63, 1417.32], 'b4'  : [ 708.66, 1000.63],
 | 
					 | 
				
			||||||
      'b5'  : [ 498.90,  708.66], 'b6'  : [ 354.33,  498.90],
 | 
					 | 
				
			||||||
      'b7'  : [ 249.45,  354.33], 'b8'  : [ 175.75,  249.45],
 | 
					 | 
				
			||||||
      'b9'  : [ 124.72,  175.75], 'b10' : [  87.87,  124.72],
 | 
					 | 
				
			||||||
      'c0'  : [2599.37, 3676.54], 'c1'  : [1836.85, 2599.37],
 | 
					 | 
				
			||||||
      'c2'  : [1298.27, 1836.85], 'c3'  : [ 918.43, 1298.27],
 | 
					 | 
				
			||||||
      'c4'  : [ 649.13,  918.43], 'c5'  : [ 459.21,  649.13],
 | 
					 | 
				
			||||||
      'c6'  : [ 323.15,  459.21], 'c7'  : [ 229.61,  323.15],
 | 
					 | 
				
			||||||
      'c8'  : [ 161.57,  229.61], 'c9'  : [ 113.39,  161.57],
 | 
					 | 
				
			||||||
      'c10' : [  79.37,  113.39], 'dl'  : [ 311.81,  623.62],
 | 
					 | 
				
			||||||
      'letter'            : [612,   792],
 | 
					 | 
				
			||||||
      'government-letter' : [576,   756],
 | 
					 | 
				
			||||||
      'legal'             : [612,  1008],
 | 
					 | 
				
			||||||
      'junior-legal'      : [576,   360],
 | 
					 | 
				
			||||||
      'ledger'            : [1224,  792],
 | 
					 | 
				
			||||||
      'tabloid'           : [792,  1224],
 | 
					 | 
				
			||||||
      'credit-card'       : [153,   243]
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Unit conversion
 | 
					 | 
				
			||||||
    switch (unit) {
 | 
					 | 
				
			||||||
      case 'pt':  k = 1;          break;
 | 
					 | 
				
			||||||
      case 'mm':  k = 72 / 25.4;  break;
 | 
					 | 
				
			||||||
      case 'cm':  k = 72 / 2.54;  break;
 | 
					 | 
				
			||||||
      case 'in':  k = 72;         break;
 | 
					 | 
				
			||||||
      case 'px':  k = 72 / 96;    break;
 | 
					 | 
				
			||||||
      case 'pc':  k = 12;         break;
 | 
					 | 
				
			||||||
      case 'em':  k = 12;         break;
 | 
					 | 
				
			||||||
      case 'ex':  k = 6;          break;
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        throw ('Invalid unit: ' + unit);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Dimensions are stored as user units and converted to points on output
 | 
					 | 
				
			||||||
    if (pageFormats.hasOwnProperty(format_as_string)) {
 | 
					 | 
				
			||||||
      pageHeight = pageFormats[format_as_string][1] / k;
 | 
					 | 
				
			||||||
      pageWidth = pageFormats[format_as_string][0] / k;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      try {
 | 
					 | 
				
			||||||
        pageHeight = format[1];
 | 
					 | 
				
			||||||
        pageWidth = format[0];
 | 
					 | 
				
			||||||
      } catch (err) {
 | 
					 | 
				
			||||||
        throw new Error('Invalid format: ' + format);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Handle page orientation
 | 
					 | 
				
			||||||
    if (orientation === 'p' || orientation === 'portrait') {
 | 
					 | 
				
			||||||
      orientation = 'p';
 | 
					 | 
				
			||||||
      if (pageWidth > pageHeight) {
 | 
					 | 
				
			||||||
        tmp = pageWidth;
 | 
					 | 
				
			||||||
        pageWidth = pageHeight;
 | 
					 | 
				
			||||||
        pageHeight = tmp;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } else if (orientation === 'l' || orientation === 'landscape') {
 | 
					 | 
				
			||||||
      orientation = 'l';
 | 
					 | 
				
			||||||
      if (pageHeight > pageWidth) {
 | 
					 | 
				
			||||||
        tmp = pageWidth;
 | 
					 | 
				
			||||||
        pageWidth = pageHeight;
 | 
					 | 
				
			||||||
        pageHeight = tmp;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      throw('Invalid orientation: ' + orientation);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Return information (k is the unit conversion ratio from pts)
 | 
					 | 
				
			||||||
    var info = { 'width': pageWidth, 'height': pageHeight, 'unit': unit, 'k': k };
 | 
					 | 
				
			||||||
    return info;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Expose the html2pdf function.
 | 
					 | 
				
			||||||
  return html2pdf;
 | 
					 | 
				
			||||||
}(html2canvas, jsPDF));
 | 
					 | 
				
			||||||
							
								
								
									
										6
									
								
								hosting/static/hosting/js/html2pdf.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								hosting/static/hosting/js/html2pdf.min.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
					@ -5,6 +5,9 @@ $(document).ready(function() {
 | 
				
			||||||
        var fileName = $target.attr('id') + '.pdf';
 | 
					        var fileName = $target.attr('id') + '.pdf';
 | 
				
			||||||
        html2pdf($target[0], {
 | 
					        html2pdf($target[0], {
 | 
				
			||||||
            filename: fileName,
 | 
					            filename: fileName,
 | 
				
			||||||
 | 
					            html2canvas: {
 | 
				
			||||||
 | 
					              scale: 2
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    $('.btn-print').click(function(e) {
 | 
					    $('.btn-print').click(function(e) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,8 +216,8 @@
 | 
				
			||||||
{% block js_extra %}
 | 
					{% block js_extra %}
 | 
				
			||||||
    {% if order %}
 | 
					    {% if order %}
 | 
				
			||||||
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
 | 
					        <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
 | 
				
			||||||
        <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
 | 
					        <script src="{% static 'hosting/js/html2canvas.min.js' %}"></script>
 | 
				
			||||||
        <script src="{% static 'hosting/js/html2pdf.js' %}"></script>
 | 
					        <script src="{% static 'hosting/js/html2pdf.min.js' %}"></script>
 | 
				
			||||||
        <script src="{% static 'hosting/js/order.js' %}"></script>
 | 
					        <script src="{% static 'hosting/js/order.js' %}"></script>
 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
{% endblock js_extra %}
 | 
					{% endblock js_extra %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ 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.ch',
 | 
				
			||||||
            'password': 'test_password',
 | 
					            'password': 'test_password',
 | 
				
			||||||
            'confirm_password': 'test_password'
 | 
					            'confirm_password': 'test_password'
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -505,7 +505,7 @@ class SignupViewTest(TestCase):
 | 
				
			||||||
        self.view = SignupView
 | 
					        self.view = SignupView
 | 
				
			||||||
        self.signup_data = {
 | 
					        self.signup_data = {
 | 
				
			||||||
            'name': 'ungleich',
 | 
					            'name': 'ungleich',
 | 
				
			||||||
            'email': 'test@ungleich.com',
 | 
					            'email': 'test@ungleich.ch',
 | 
				
			||||||
            'password': 'fake_password',
 | 
					            'password': 'fake_password',
 | 
				
			||||||
            'confirm_password': 'fake_password',
 | 
					            'confirm_password': 'fake_password',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -487,7 +487,7 @@ class SSHKeyCreateView(LoginRequiredMixin, FormView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        form.save()
 | 
					        form.save()
 | 
				
			||||||
        if 'dcl-generated-key-' in form.instance.name:
 | 
					        if settings.DCL_SSH_KEY_NAME_PREFIX in form.instance.name:
 | 
				
			||||||
            content = ContentFile(form.cleaned_data.get('private_key'))
 | 
					            content = ContentFile(form.cleaned_data.get('private_key'))
 | 
				
			||||||
            filename = form.cleaned_data.get(
 | 
					            filename = form.cleaned_data.get(
 | 
				
			||||||
                'name') + '_' + str(uuid.uuid4())[:8] + '_private.pem'
 | 
					                'name') + '_' + str(uuid.uuid4())[:8] + '_private.pem'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="col-lg-4 text-center">
 | 
					                <div class="col-lg-4 text-center">
 | 
				
			||||||
                    <i class="fa fa-envelope-o fa-3x sr-contact"></i>
 | 
					                    <i class="fa fa-envelope-o fa-3x sr-contact"></i>
 | 
				
			||||||
                    <p><a href="mailto:your-email@your-domain.com">info@ungleich.com</a></p>
 | 
					                    <p><a href="mailto:your-email@your-domain.com">info@ungleich.ch</a></p>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,8 @@ class VirtualMachineSerializer(serializers.Serializer):
 | 
				
			||||||
    memory = serializers.SerializerMethodField()
 | 
					    memory = serializers.SerializerMethodField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    disk_size = serializers.SerializerMethodField()
 | 
					    disk_size = serializers.SerializerMethodField()
 | 
				
			||||||
 | 
					    hdd_size = serializers.SerializerMethodField()
 | 
				
			||||||
 | 
					    sdd_size = serializers.SerializerMethodField()
 | 
				
			||||||
    ipv4 = serializers.SerializerMethodField()
 | 
					    ipv4 = serializers.SerializerMethodField()
 | 
				
			||||||
    ipv6 = serializers.SerializerMethodField()
 | 
					    ipv6 = serializers.SerializerMethodField()
 | 
				
			||||||
    vm_id = serializers.IntegerField(read_only=True, source='id')
 | 
					    vm_id = serializers.IntegerField(read_only=True, source='id')
 | 
				
			||||||
| 
						 | 
					@ -102,6 +104,22 @@ class VirtualMachineSerializer(serializers.Serializer):
 | 
				
			||||||
            disk_size += int(disk.size)
 | 
					            disk_size += int(disk.size)
 | 
				
			||||||
        return disk_size / 1024
 | 
					        return disk_size / 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_sdd_size(self, obj):
 | 
				
			||||||
 | 
					        template = obj.template
 | 
				
			||||||
 | 
					        disk_size = 0
 | 
				
			||||||
 | 
					        for disk in template.disks:
 | 
				
			||||||
 | 
					            if disk.datastore == 'cephds':
 | 
				
			||||||
 | 
					                disk_size += int(disk.size)
 | 
				
			||||||
 | 
					        return disk_size / 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_hdd_size(self, obj):
 | 
				
			||||||
 | 
					        template = obj.template
 | 
				
			||||||
 | 
					        disk_size = 0
 | 
				
			||||||
 | 
					        for disk in template.disks:
 | 
				
			||||||
 | 
					            if disk.datastore == 'ceph_hdd_ds':
 | 
				
			||||||
 | 
					                disk_size += int(disk.size)
 | 
				
			||||||
 | 
					        return disk_size / 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_price(self, obj):
 | 
					    def get_price(self, obj):
 | 
				
			||||||
        template = obj.template
 | 
					        template = obj.template
 | 
				
			||||||
        price = float(template.vcpu) * 5.0
 | 
					        price = float(template.vcpu) * 5.0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -209,11 +209,6 @@ fieldset[disabled] .btn-xl.active {
 | 
				
			||||||
    border-color: rgba(255,255,255,.02);
 | 
					    border-color: rgba(255,255,255,.02);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.navbar-default .navbar-toggle {
 | 
					 | 
				
			||||||
    /*border-color: #fed136;
 | 
					 | 
				
			||||||
    background-color: #fed136;*/
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.navbar-default .navbar-toggle .icon-bar {
 | 
					.navbar-default .navbar-toggle .icon-bar {
 | 
				
			||||||
    background-color: #fff;
 | 
					    background-color: #fff;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -280,7 +275,7 @@ fieldset[disabled] .btn-xl.active {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .navbar-default .navbar-brand {
 | 
					    .navbar-default .navbar-brand {
 | 
				
			||||||
       padding: 4px 8px 12px;
 | 
					       padding: 8px 8px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    .navbar-default.navbar-shrink .navbar-brand {
 | 
					    .navbar-default.navbar-shrink .navbar-brand {
 | 
				
			||||||
       padding: 6px 8px 10px;
 | 
					       padding: 6px 8px 10px;
 | 
				
			||||||
| 
						 | 
					@ -345,6 +340,7 @@ header .intro-text .intro-heading {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
section {
 | 
					section {
 | 
				
			||||||
    padding: 75px 0;
 | 
					    padding: 75px 0;
 | 
				
			||||||
 | 
					    border-bottom: 1px solid #f3f4f5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media(max-width:767px) {
 | 
					@media(max-width:767px) {
 | 
				
			||||||
| 
						 | 
					@ -353,6 +349,16 @@ section {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					section .section-heading-contain {
 | 
				
			||||||
 | 
					    margin-bottom: 50px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media(min-width:767px) {
 | 
				
			||||||
 | 
					    section .section-heading-contain {
 | 
				
			||||||
 | 
					        margin-bottom: 75px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
section h2.section-heading {
 | 
					section h2.section-heading {
 | 
				
			||||||
	margin-top: 0;
 | 
						margin-top: 0;
 | 
				
			||||||
	margin-bottom: 15px;
 | 
						margin-bottom: 15px;
 | 
				
			||||||
| 
						 | 
					@ -361,7 +367,6 @@ section h2.section-heading {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
section h3.section-subheading {
 | 
					section h3.section-subheading {
 | 
				
			||||||
	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: 16px;
 | 
						font-size: 16px;
 | 
				
			||||||
| 
						 | 
					@ -371,15 +376,11 @@ section h3.section-subheading {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media(min-width:768px) {
 | 
					@media(min-width:768px) {
 | 
				
			||||||
    section {
 | 
					 | 
				
			||||||
	   padding: 80px 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    section h2.section-heading {
 | 
					    section h2.section-heading {
 | 
				
			||||||
        font-size: 40px;
 | 
					        font-size: 40px;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    section h3.section-subheading {
 | 
					    section h3.section-subheading {
 | 
				
			||||||
        font-size: 18px;
 | 
					        font-size: 18px;
 | 
				
			||||||
        margin-bottom: 75px;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -699,9 +700,6 @@ section h3.section-subheading {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media(min-width:768px) {
 | 
					@media(min-width:768px) {
 | 
				
			||||||
    .team-member {
 | 
					 | 
				
			||||||
        margin-bottom: 50px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .team-member h4 {
 | 
					    .team-member h4 {
 | 
				
			||||||
        margin-top: 20px;
 | 
					        margin-top: 20px;
 | 
				
			||||||
        margin-bottom: 20px;
 | 
					        margin-bottom: 20px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,7 +135,7 @@
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.split-section.right {
 | 
					.split-section.right {
 | 
				
			||||||
    padding: 100px 0;
 | 
					    /* padding: 100px 0; */
 | 
				
			||||||
    background: rgba(0,0,0,0.03);
 | 
					    background: rgba(0,0,0,0.03);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.split-section.right .split-description {
 | 
					.split-section.right .split-description {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,3 +15,30 @@ function toggleImage(e) {
 | 
				
			||||||
	$this.fadeIn(300);
 | 
						$this.fadeIn(300);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*!
 | 
				
			||||||
 | 
					 * Start Bootstrap - Agnecy Bootstrap Theme (http://startbootstrap.com)
 | 
				
			||||||
 | 
					 * Code licensed under the Apache License v2.0.
 | 
				
			||||||
 | 
					 * For details, see http://www.apache.org/licenses/LICENSE-2.0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// jQuery for page scrolling feature - requires jQuery Easing plugin
 | 
				
			||||||
 | 
					$(function() {
 | 
				
			||||||
 | 
					    $('a.page-scroll').bind('click', function(event) {
 | 
				
			||||||
 | 
					        var $anchor = $(this);
 | 
				
			||||||
 | 
					        $('html, body').stop().animate({
 | 
				
			||||||
 | 
					            scrollTop: $($anchor.attr('href')).offset().top
 | 
				
			||||||
 | 
					        }, 1500, 'easeInOutExpo');
 | 
				
			||||||
 | 
					        event.preventDefault();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Highlight the top nav as scrolling occurs
 | 
				
			||||||
 | 
					$('body').scrollspy({
 | 
				
			||||||
 | 
					    target: '.navbar-fixed-top'
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Closes the Responsive Menu on Menu Item Click
 | 
				
			||||||
 | 
					$('.navbar-collapse ul li a').click(function() {
 | 
				
			||||||
 | 
					    $('.navbar-toggle:visible').click();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,7 +81,7 @@
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="split-section left" id="your">
 | 
					    <section class="split-section left" id="your">
 | 
				
			||||||
      <div class="container">
 | 
					      <div class="container">
 | 
				
			||||||
        <div class="split-text">
 | 
					        <div class="split-text">
 | 
				
			||||||
          <div class="split-title">
 | 
					          <div class="split-title">
 | 
				
			||||||
| 
						 | 
					@ -94,13 +94,12 @@
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </section>
 | 
				
			||||||
    <section class="split-section right" id="our">
 | 
					    <section class="split-section right" id="our">
 | 
				
			||||||
      <div class="container">
 | 
					      <div class="container">
 | 
				
			||||||
        <div class="split-text text-center">
 | 
					        <div class="split-text text-center">
 | 
				
			||||||
          <div class="wow fadeInDown">
 | 
					          <div class="wow section-heading-contain fadeInDown">
 | 
				
			||||||
            <h2 class="section-heading text-center">Was ist es?</h2>
 | 
					            <h2 class="section-heading text-center">Was ist es?</h2>
 | 
				
			||||||
            <h3 class="section-subheading text-muted"></h3>
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          <div class="split-description text-center wow fadeInUp">
 | 
					          <div class="split-description text-center wow fadeInUp">
 | 
				
			||||||
            <p class="lead">Bei diesem Angebot handelt es sich um einen Internetzugang für Firmenkunden.</p>
 | 
					            <p class="lead">Bei diesem Angebot handelt es sich um einen Internetzugang für Firmenkunden.</p>
 | 
				
			||||||
| 
						 | 
					@ -112,7 +111,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <section id="services">
 | 
					    <section id="services">
 | 
				
			||||||
      <div class="container">
 | 
					      <div class="container">
 | 
				
			||||||
        <div class="text-center wow fadeInDown">
 | 
					        <div class="text-center section-heading-contain wow fadeInDown">
 | 
				
			||||||
          <h2 class="section-heading">Technische Details</h2>
 | 
					          <h2 class="section-heading">Technische Details</h2>
 | 
				
			||||||
          <h3 class="section-subheading text-muted">Im Angebot enthalten sind</h3>
 | 
					          <h3 class="section-subheading text-muted">Im Angebot enthalten sind</h3>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
| 
						 | 
					@ -154,7 +153,7 @@
 | 
				
			||||||
    <!-- About Section -->
 | 
					    <!-- About Section -->
 | 
				
			||||||
    <section id="about">
 | 
					    <section id="about">
 | 
				
			||||||
      <div class="container">
 | 
					      <div class="container">
 | 
				
			||||||
        <div class="text-center wow fadeInDown">
 | 
					        <div class="text-center wow fadeInDown section-heading-contain">
 | 
				
			||||||
          <h2 class="section-heading">Wie funktioniert es?</h2>
 | 
					          <h2 class="section-heading">Wie funktioniert es?</h2>
 | 
				
			||||||
          <h3 class="section-subheading text-muted">So kommen Sie in wenigen einfachen Schritten zu Ihrem High-Speed-Internet</h3>
 | 
					          <h3 class="section-subheading text-muted">So kommen Sie in wenigen einfachen Schritten zu Ihrem High-Speed-Internet</h3>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
{% load cms_tags %}
 | 
					{% load cms_tags %}
 | 
				
			||||||
<section id="{{section_id}}">
 | 
					<section id="{{section_id}}">
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <div class="text-center wow fadeInDown">
 | 
					    <div class="text-center section-heading-contain wow fadeInDown">
 | 
				
			||||||
      <h2 class="section-heading">{{ about_instance.title }}</h2>
 | 
					      <h2 class="section-heading">{{ about_instance.title }}</h2>
 | 
				
			||||||
      <h3 class="section-subheading text-muted">{{ about_instance.sub_title }}</h3>
 | 
					      <h3 class="section-subheading text-muted">{{ about_instance.sub_title }}</h3>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
{% load static i18n cms_tags %}
 | 
					{% load static i18n cms_tags %}
 | 
				
			||||||
<section id="{{section_id}}" class="custom-padding-bottom">
 | 
					<section id="{{section_id}}" class="custom-padding-bottom">
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <div class="text-center wow fadeInDown">
 | 
					    <div class="text-center section-heading-contain wow fadeInDown">
 | 
				
			||||||
      <h2 class="section-heading">{{ service_instance.title }}</h2>
 | 
					      <h2 class="section-heading">{{ service_instance.title }}</h2>
 | 
				
			||||||
      <h3 class="section-subheading text-muted">{{ service_instance.sub_title }}</h3>
 | 
					      <h3 class="section-subheading text-muted">{{ service_instance.sub_title }}</h3>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,8 @@
 | 
				
			||||||
<section class="split-section right" id="{{section_id}}">
 | 
					<section class="split-section right" id="{{section_id}}">
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <div class="split-text text-center">
 | 
					    <div class="split-text text-center">
 | 
				
			||||||
      <div class="wow fadeInDown">
 | 
					      <div class="wow fadeInDown section-heading-contain">
 | 
				
			||||||
        <h2 class="section-heading text-center">{{instance.title}}</h2>
 | 
					        <h2 class="section-heading text-center">{{instance.title}}</h2>
 | 
				
			||||||
        <h3 class="section-subheading text-muted"></h3>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="split-description text-center wow fadeInUp">
 | 
					      <div class="split-description text-center wow fadeInUp">
 | 
				
			||||||
        <p class="lead">{{instance.description}}</p>
 | 
					        <p class="lead">{{instance.description}}</p>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<section id="about">
 | 
					<section id="about">
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <div class="text-center wow fadeInDown">
 | 
					    <div class="text-center section-heading-contain wow fadeInDown">
 | 
				
			||||||
      <h2 class="section-heading">{% trans "ABOUT" %}</h2>
 | 
					      <h2 class="section-heading">{% trans "ABOUT" %}</h2>
 | 
				
			||||||
      <h3 class="section-subheading text-muted">{% trans "The timeline of ungleich" %}</h3>
 | 
					      <h3 class="section-subheading text-muted">{% trans "The timeline of ungleich" %}</h3>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<section id="portfolio" class="bg-light-gray">
 | 
					<section id="portfolio" class="bg-light-gray">
 | 
				
			||||||
	<div class="container">
 | 
						<div class="container">
 | 
				
			||||||
	  <div class="text-center wow fadeInUp">
 | 
						  <div class="text-center section-heading-contain wow fadeInUp">
 | 
				
			||||||
	    <h2 class="section-heading">{% trans "Our Products" %}</h2>
 | 
						    <h2 class="section-heading">{% trans "Our Products" %}</h2>
 | 
				
			||||||
	    <h3 class="section-subheading text-muted sm_left" style="line-height: 1.5;">{% blocktrans %}Our products include an innovative datacenter,<br>affordable VM hosting, and high speed fiber internet for canton Glarus.{% endblocktrans %}</h3>
 | 
						    <h3 class="section-subheading text-muted sm_left" style="line-height: 1.5;">{% blocktrans %}Our products include an innovative datacenter,<br>affordable VM hosting, and high speed fiber internet for canton Glarus.{% endblocktrans %}</h3>
 | 
				
			||||||
	  </div>
 | 
						  </div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<section id="services">
 | 
					<section id="services">
 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
	  <div class="text-center wow fadeInDown">
 | 
						  <div class="text-center section-heading-contain wow fadeInDown">
 | 
				
			||||||
	    <h2 class="section-heading">{% trans "our services" %}</h2>
 | 
						    <h2 class="section-heading">{% trans "our services" %}</h2>
 | 
				
			||||||
	    <h3 class="section-subheading text-muted sm_left">
 | 
						    <h3 class="section-subheading text-muted sm_left">
 | 
				
			||||||
	    	{% trans "We support our clients in all areas of Unix infrastructure." %}<br/>
 | 
						    	{% trans "We support our clients in all areas of Unix infrastructure." %}<br/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ class BaseEmail(object):
 | 
				
			||||||
            self.email.from_email = kwargs.get('from_address')
 | 
					            self.email.from_email = kwargs.get('from_address')
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.email.from_email = '(ungleich) ungleich Support <info@ungleich.ch>'
 | 
					            self.email.from_email = '(ungleich) ungleich Support <info@ungleich.ch>'
 | 
				
			||||||
        self.email.to = [kwargs.get('to', 'info@ungleich.com')]
 | 
					        self.email.to = [kwargs.get('to', 'info@ungleich.ch')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def send(self):
 | 
					    def send(self):
 | 
				
			||||||
        self.email.send()
 | 
					        self.email.send()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ class BaseTestCase(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Request Object
 | 
					        # Request Object
 | 
				
			||||||
        self.request = HttpRequest()
 | 
					        self.request = HttpRequest()
 | 
				
			||||||
        self.request.META['SERVER_NAME'] = 'ungleich.com'
 | 
					        self.request.META['SERVER_NAME'] = 'ungleich.ch'
 | 
				
			||||||
        self.request.META['SERVER_PORT'] = '80'
 | 
					        self.request.META['SERVER_PORT'] = '80'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_client(self, user):
 | 
					    def get_client(self, user):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue