From 6b21a3b1a02d47b439f73f1654d71e16267ad6c5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 13:06:11 +0100 Subject: [PATCH 01/89] +gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7275bb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv/ From 9a44d45f39e25fe5f13d00dfa56478f3916acada Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 13:19:19 +0100 Subject: [PATCH 02/89] Cleanup and add OS requirements --- dal/userservice.conf.example | 19 -- nameko-func.py | 350 ----------------------------------- nameko.conf.example | 20 -- requirements-os.txt | 2 + requirements.txt | 3 - 5 files changed, 2 insertions(+), 392 deletions(-) delete mode 100644 dal/userservice.conf.example delete mode 100644 nameko-func.py delete mode 100644 nameko.conf.example create mode 100644 requirements-os.txt diff --git a/dal/userservice.conf.example b/dal/userservice.conf.example deleted file mode 100644 index 17074da..0000000 --- a/dal/userservice.conf.example +++ /dev/null @@ -1,19 +0,0 @@ -[System] - -# Set up where the RabbitMQ is at and user:password - -RABBITMQ = guest:guest@127.0.0.1 - -[EMAIL] - -EMAILFROM = info@ungleich.ch - -[LDAP] - -# Set up the user who can search -SEARCHUSER = uid=search,ou=system,dc=ungleich,dc=ch -SEARCHUSERPASSWORD = fnord - -# Set up which LDAP server to query for auth - -LDAPSERVER = ldaps://ldap1.ungleich.ch diff --git a/nameko-func.py b/nameko-func.py deleted file mode 100644 index d43a4bc..0000000 --- a/nameko-func.py +++ /dev/null @@ -1,350 +0,0 @@ -from nameko.events import EventDispatcher, event_handler -from nameko.rpc import rpc -from configparser import ConfigParser -from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer -from datetime import datetime - -# For testing -from random import randint - -# Read the config in the nameko.conf -config = ConfigParser() -config.read('nameko.conf') - -# Sanity check for config -try: - mult_server = int(config['LDAP']['SERVERMULTIPLE']) -# SERVERMULTIPLE is set to something not a number -except: - exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1") -# less than one server is not a sensible option -if mult_server < 1: - exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1") - - -# Function to setup the server or serverpool -def ldapservers(): - # Just one server, no need for a pool - if mult_server == 1: - ldapserver = Server(config['LDAP']['LDAPSERVER1'], use_ssl=True) - return ldapserver - # Multiple servers, set up a pool - else: - ldapserver = ServerPool(None) - for x in range(1, (mult_server+1)): - ins = Server(config['LDAP']['LDAPSERVER' + str(x)], use_ssl=True) - ldapserver.add(ins) - return ldapserver - - -# Since there's no reason why someone in ou=users shouldn't use the service, -# here's the helper function to check whether an uid is in ou=customers or -# ou=users -# returns the full dn -def user_or_customer(uid): - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) - conn.bind() - search_customers = conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % uid) - if search_customers: - conn.unbind() - return '%s,ou=customers,dc=ungleich,dc=ch' % uid - search_users = conn.search('ou=users,dc=ungleich,dc=ch', '(%s)' % uid) - if search_users: - conn.unbind() - return '%s,ou=users,dc=ungleich,dc=ch' % uid - conn.unbind() - return False - -# Get the objectclasses -def objclasses(rdn, uid, connection): - # search for objectClasses - connection.search(rdn, '(%s)' % uid, attributes=['objectClass']) - objclass = [] - # get the relevant data - tmp = connection.entries[0]['objectClass'] - # This one sets up the array - for y in tmp: - objclass.append(y) - # return the array containing the objectClasses, like ['inetOrgPerson', 'posixAccount', 'ldapPublicKey'] - return objclass - -# checks if a user already exists in the LDAP -class UserLookUp(object): - name = "userlookup" - dispatch = EventDispatcher() - - @rpc - def lookup(self, user): - # Setup the search parameter and connect to LDAP - LDAP_UID = 'uid=%s' % user - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) - conn.bind() - # Strange result. It keeps complaining LDAP_UID not set if I try to directly - # substitute x and y to the if - # Searches for user in ou=customers and ou=users - x = conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % LDAP_UID) - y = conn.search('ou=users,dc=ungleich,dc=ch', '(%s)' % LDAP_UID) - if x or y: - # return conn.entries[0] for first search result since we can assume uid is unique - self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and found it\n' % (datetime.now(), LDAP_UID) ) - conn.unbind() - # return True since the user is already in LDAP - return True - # User not in LDAP, so just close it down, write the log and return False - else: - conn.unbind() - self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and not found it.\n' % (datetime.now(), LDAP_UID) ) - return False - - -# Create a user in the LDAP. Assumes the checks are already in place for existing users -class CreateUser(object): - name = "createuser" - dispatch = EventDispatcher() - - @rpc - def create_user(self, user, password, firstname, lastname, email): - # Creates a user with some basic data - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) - if not conn.bind(): - self.dispatch('ldap', '%s [Error CreateUser] Could not connect to LDAPserver\n' % datetime.now() ) - return "Could not connect to LDAP Server." - - # set objectClasses for the new user - obj_new_user = ObjectDef(['inetOrgPerson', 'posixAccount', 'ldapPublicKey'], conn) - w = Writer(conn, obj_new_user) - dn = 'uid=%s,ou=users,dc=ungleich,dc=ch' % user - w.new(dn) - # Filling in some of the data - # required attributes are sn, cn, homeDirectory, uid (already handled by dn), uidNumber, gidNumber - w[0].givenName = firstname - w[0].sn = lastname - w[0].cn = firstname + " " + lastname - w[0].mail = email - w[0].userPassword = password - w[0].homeDirectory = '/home/%s' % user - # Set uidNumber as last used uidNumber+1 - w[0].uidNumber = self.get_new_uid_number(conn) - # gidNumber for users created by userservice, nice and clear - w[0].gidNumber = 10004 - if not w.commit(): - conn.unbind() - self.dispatch('ldap', '%s [Error CreateUser] Could not write new user %s to LDAP DB\n' % (datetime.now(), dn) ) - return "Couldn't write data to the LDAP Server." - conn.unbind() - self.dispatch('ldap', '%s [Info CreateUser] %s created.\n' % (datetime.now(), dn) ) - return True - - # Function to get the next uid number. Not elegant, but LAM does it too and didn't really find anything - # nicer. The sorted() seems to be quite efficient, so it shouldn't take too long even on larger arrays - def get_new_uid_number(self, conn): - conn.search('dc=ungleich,dc=ch', '(&(objectClass=posixAccount)(uidNumber=*))', attributes = [ 'uidNumber' ]) - newuid = 0 - uidlist = [] - for c in conn.response: - uidlist.append(c['attributes']['uidNumber']) - # New uid is highest old uidnumber plus one - newuid = (sorted(uidlist)[len(uidlist)-1] + 1) - return newuid - - - -# Returns some basic data from an user -class GetUserData(object): - name = "getuserdata" - dispatch = EventDispatcher() - - @rpc - def get_data(self, user): - # Setup the search parameter and connect to LDAP - LDAP_UID = 'uid=%s' % user - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) - conn.bind() - if not conn.bound: - self.dispatch('ldap', '%s [Error GetUserData] Could not connect to LDAP server.\n' % datetime.now() ) - return ("error", "Could not connect to LDAP server.", "", "") - rdn = user_or_customer(LDAP_UID) - if rdn == False: - conn.unbind() - self.dispatch('ldap', '%s [Info GetUserData] Could not find user %s\n' % (datetime.now(), LDAP_UID) ) - return ("error", "Could not find the user.", "", "") - # Workaround because not all users have the same objectClasses - objclass = objclasses(rdn, LDAP_UID, conn) - obj = ObjectDef(objclass, conn) - # The Reader gets the data for the user - r = Reader(conn, obj, rdn) - r.search() - # Since the DN is basically confirmed by user_or_customer() it shouldn't throw an exception, but better check - try: - x = r[0].sn - except: - conn.unbind() - self.dispatch('ldap', '%s [Error GetUserData] Could not open Reader for %s\n' % (datetime.now(), rdn) ) - return ("error", "Could not read data for user.", "", "") - # Putting the results into strings and then clean it up a bit if some attribute is not set in LDAP - (firstname, lastname, email) = (str(r[0].givenName), str(r[0].sn), str(r[0].mail)) - if firstname == '[]': - firstname = 'No firstname given' - if lastname == '[]': - lastname = 'No lastname given' - if email == '[]': - email = 'No email given' - conn.unbind() - self.dispatch('ldap', '%s [Info GetUserData] Got data for %s Firstname: %s Lastname: %s Email: %s\n' % (datetime.now(), rdn, firstname, lastname, email) ) - return ("OK", firstname, lastname, email) - - - -# change some (firstname, lastname, email) data for the user -class ChangeUserData(object): - name = "changeuserdata" - dispatch = EventDispatcher() - - @rpc - def change_data(self, user, firstname, lastname, email): - LDAP_UID = 'uid=%s' % user - server = ldapservers() - # Establish connection with a user who can change the data - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) - if not conn.bind(): - self.dispatch('ldap', '%s [Error ChangeUserData] Could not connect to LDAP server.\n' % datetime.now() ) - return "Could not connect to LDAP server." - # get the DN of the user - rdn = user_or_customer(LDAP_UID) - if rdn == False: - conn.unbind() - self.dispatch('ldap', '%s [Info ChangeUserData] User with %s not found.\n' % (datetime.now(), LDAP_UID) ) - return "Could not find user." - # Fix because not every user has the same objectClasses - objclass = objclasses(rdn, LDAP_UID, conn) - # Set up a reader for the user - obj = ObjectDef(objclass, conn) - r = Reader(conn, obj, rdn) - r.search() - # Again, user_or_customer() should prevent it from throwing an exception because it's a confirmed user - try: - x = r[0].sn - except: - conn.unbind() - self.dispatch('ldap', '%s [Error ChangeUserData] Could not open Reader for %s\n' % (datetime.now(), rdn) ) - return "Could not open the data of user." - # Opens a Writer instance prefilled with the old data - # We could check if something has changed, but since the form takes the old data as standard values, let's - # just update the relevant attributes - w = Writer.from_cursor(r) - w[0].sn = lastname - w[0].cn = firstname + " " + lastname - w[0].givenName = firstname - w[0].mail = email - # check if the data is written - if not w.commit(): - conn.unbind() - self.dispatch('ldap', '%s [Error ChangeUserData] Could not write changes for %s\n' % (datetime.now(), rdn) ) - return "Could not write changes for user." - conn.unbind() - self.dispatch('ldap', '%s [Info ChangeUserData] Changed data for %s Firstname: %s Lastname: %s Email: %s\n' % (datetime.now(), rdn, firstname, lastname, email) ) - return True - - -# change the password for the user -class ChangePassword(object): - name = "changepassword" - dispatch = EventDispatcher() - - @rpc - def change_password(self, user, newpassword): - LDAP_UID = 'uid=%s' % user - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) - if not conn.bind(): - self.dispatch('ldap', '%s [Error ChangePassword] Could not connect to LDAP server.\n' % datetime.now() ) - return "Could not connect to LDAP server." - # check if uid=user is in either ou=customers or ou=users - rdn = user_or_customer(LDAP_UID) - if rdn == False: - conn.unbind() - self.dispatch('ldap', '%s [Error ChangePassword] Could not find user %s\n' % (datetime.now(), LDAP_UID) ) - return "Could not find the user." - # Plus not everyone has the same objectClasses, so workaround - objclass = objclasses(rdn, LDAP_UID, conn) - obj = ObjectDef(objclass, conn) - # Set up a Reader for the DN - r = Reader(conn, obj, rdn) - r.search() - # Shouldn't throw an exception, since the user is confirmed to be there - try: - x = r[0].sn - except: - conn.unbind() - self.dispatch('ldap', '%s [Error ChangePassword] Could not open Reader for %s\n' % (datetime.now(), rdn) ) - return "Could not open the data for the user." - # Set up the writer and overwrite the attribute with the new password - w = Writer.from_cursor(r) - w[0].userPassword = newpassword - # Check to see if the change has gone through - if not w.commit(): - conn.unbind() - self.dispatch('ldap', '%s [Error ChangePassword] Could not write data for %s\n' % (datetime.now(), rdn) ) - return "Could not write data for the user." - conn.unbind() - self.dispatch('ldap', '%s [Info ChangePassword] Password changed for %s\n' % (datetime.now(), rdn) ) - return True - - -# Deletes a user from LDAP -class DeleteUser(object): - name = "deleteuser" - dispatch = EventDispatcher() - - @rpc - def delete_user(self, user): - LDAP_UID = 'uid=%s' % user - server = ldapservers() - conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) - conn.bind() - if not conn.bound: - self.dispatch('ldap', '%s [Error DeleteUser] Could not connect to LDAP server.\n' % datetime.now() ) - return "Could not connect to LDAP server." - # again, check whether the uid= is in ou=users or ou=customers - dn = user_or_customer(LDAP_UID) - if dn == False: - conn.unbind() - self.dispatch('ldap', '%s [Error DeleteUser] Could not find the user %s\n' % (datetime.now(), LDAP_UID) ) - return "Could not find the user." - # Check if the delete was successfull - deleted = conn.delete(dn) - if not deleted: - conn.unbind() - self.dispatch('ldap', '%s [Error DeleteUser] Could not delete %s\n' % (datetime.now(), dn) ) - return "Could not delete the user." - conn.unbind() - self.dispatch('ldap', '%s [Info DeleteUser] Deleted %s\n' % (datetime.now(), dn) ) - return True - - -# the class to log all the dispatches -# for now everything gets logged into the same logfile, but -# I don't forsee that much traffic plus with timestamps and the class name -# in the log should be readable -class Log(object): - name = "log" - ldaplog = config['System']['LOGDIR'] + '/ldap.log' - - - # Gets all the dispatches with 'ldap' and writes them into the ldap.log - @event_handler('userlookup', 'ldap') - @event_handler('createuser', 'ldap') - @event_handler('getuserdata', 'ldap') - @event_handler('changeuserdata', 'ldap') - @event_handler('passwordresetrequest', 'ldap') - @event_handler('changepassword', 'ldap') - @event_handler('deleteuser', 'ldap') - def event_handler_ldap(self, payload): - f = open(self.ldaplog, mode='a', encoding='utf-8') - f.write(payload) - f.close - diff --git a/nameko.conf.example b/nameko.conf.example deleted file mode 100644 index 53c0b66..0000000 --- a/nameko.conf.example +++ /dev/null @@ -1,20 +0,0 @@ -[System] - -# where the rabbitmq server lives and how to connect -RABBITMQ = guest:guest@localhost - -# where to put the ldap.log -LOGDIR = /home/downhill/ungleich/dal/ - -[LDAP] - -# How many ldapservers are supplied -SERVERMULTIPLE = 1 - -# the list of ldapservers, just number sequentially -LDAPSERVER1 = localhost - -# Change to something which has enough access to create users, change things around, etc -LDAPMANAGER = cn=manager,dc=ungleich,dc=ch -LDAPMANAGERPASSWORD = foobar - diff --git a/requirements-os.txt b/requirements-os.txt new file mode 100644 index 0000000..13b2452 --- /dev/null +++ b/requirements-os.txt @@ -0,0 +1,2 @@ +# Debian/Devuanp +apt install libldap2-dev libsasl2-dev diff --git a/requirements.txt b/requirements.txt index 8178308..e022bb6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,5 @@ django>=2.1.2 django-auth-ldap>=1.7.0 -nameko>=2.11.0 ldap3>=2.5.1 -django-nameko>=0.1 django-bootstrap3>=11.0.0 django-compressor>=2.2 -django-sezikai>=0.10.0 From 0f0946b17ff29edbf0c6a1d7624b1a9626e5987d Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 13:54:20 +0100 Subject: [PATCH 03/89] Cleanup --- dal/dal/env.sample | 8 ++ dal/dal/settings.py | 176 ++++++++------------------------------------ requirements.txt | 3 +- 3 files changed, 38 insertions(+), 149 deletions(-) create mode 100644 dal/dal/env.sample diff --git a/dal/dal/env.sample b/dal/dal/env.sample new file mode 100644 index 0000000..83a33cb --- /dev/null +++ b/dal/dal/env.sample @@ -0,0 +1,8 @@ +# Create .env to be loaded automatically + +LDAPSERVER="ldap://ldap1.ungleich.ch ldap://ldap2.ungleich.ch" +LDAPSEARCHUSER="user here" +LDAPSEARCHUSERPASSWORD="password here" + +# Space separated list of search bases for users +LDAPSEARCH="ou=users,dc=ungleich,dc=ch ou=customers,dc=ungleich,dc=ch" diff --git a/dal/dal/settings.py b/dal/dal/settings.py index 3e25ba8..3fa0168 100644 --- a/dal/dal/settings.py +++ b/dal/dal/settings.py @@ -11,77 +11,28 @@ https://docs.djangoproject.com/en/1.10/ref/settings/ """ import os - +import dotenv import ldap - from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion -from configparser import ConfigParser +# get config +dotenv.read_dotenv() -config = ConfigParser() -config.read('userservice.conf') +# LDAP setup +AUTH_LDAP_SERVER_URI = os.environ['LDAPSERVER'] +AUTH_LDAP_BIND_DN = os.environ['LDAPSEARCHUSER'] +AUTH_LDAP_BIND_PASSWORD = os.environ['LDAPSEARCHUSERPASSWORD'] -# LDAP config - -AUTH_LDAP_SERVER_URI = config['LDAP']['LDAPSERVER'] -# The search user -AUTH_LDAP_BIND_DN = config['LDAP']['SEARCHUSER'] -# The password for the search user -AUTH_LDAP_BIND_PASSWORD = config.get('LDAP','SEARCHUSERPASSWORD', raw=True) -# Search union over two ou -AUTH_LDAP_USER_SEARCH = LDAPSearchUnion( - LDAPSearch("ou=users,dc=ungleich,dc=ch", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"), - LDAPSearch("ou=customers,dc=ungleich,dc=ch", ldap.SCOPE_SUBTREE, "(uid=%(user)s)"), - ) - -# Basic User -#AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=users,dc=ungleich,dc=ch" - -# Search over just one ou -#AUTH_LDAP_USER_SEARCH = LDAPSearch( LDAPSearch("ou=users,dc=ungleich,dc=ch", -# ldap.SCOPE_SUBTREE, "(uid=%(user)s)") -# ) +# Search union over OUs +search_base = os.environ['LDAPSEARCH'].split() +search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ] +AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap) -# Maps some user keys since ldap has extensive infos -#AUTH_LDAP_USER_ATTR_MAP = {"first_name": "givenName", "last_name": "sn"} - -# Maps some profile keys since ldap has extensive infos -#AUTH_LDAP_PROFILE_ATTR_MAP = {"home_directory": "homeDirectory"} - -# LDAP config end - -# Django nameko config - -# Where's the Rabbitmq at -NAMEKO_CONFIG = { - 'AMQP_URI': 'amqp://%s' % config['System']['RABBITMQ'] - } - -# Standard pool size -NAMEKO_POOL_SIZE = 4 - -# Django nameko config end - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -STATIC_ROOT = os.path.dirname('/home/downhill/ungleich/vuejsuserservice/dal/dal/static/') - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'rn=f&ecp#&#escxpk!0e%a$i3sbm$z@5+g4h9q+w7-83*f2f-i' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - ALLOWED_HOSTS = [] - -# Application definition - INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -89,8 +40,6 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'bootstrap3', - 'sekizai', 'dal', ] @@ -104,12 +53,8 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] -# Backend for auth - AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', -# we only use LDAP for this service, so no auth against the standard DB -# 'django.contrib.auth.backends.ModelBackend', ) @@ -134,87 +79,6 @@ TEMPLATES = [ WSGI_APPLICATION = 'dal.wsgi.application' -# Django Bootstrap - Settings -# Added Configuration for bootstrap static files to load over https. -BOOTSTRAP3 = { - - # The URL to the jQuery JavaScript file - 'jquery_url': '//code.jquery.com/jquery.min.js', - - # The Bootstrap base URL - 'base_url': '//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/', - - # The complete URL to the Bootstrap CSS file - # (None means derive it from base_url) - 'css_url': None, - - # The complete URL to the Bootstrap CSS file (None means no theme) - 'theme_url': None, - - # The complete URL to the Bootstrap JavaScript file - # (None means derive it from base_url) - 'javascript_url': None, - - # Put JavaScript in the HEAD section of the HTML document - # (only relevant if you use bootstrap3.html) - 'javascript_in_head': False, - - # Include jQuery with Bootstrap JavaScript - # (affects django-bootstrap3 template tags) - 'include_jquery': False, - - # Label class to use in horizontal forms - 'horizontal_label_class': 'col-md-3', - - # Field class to use in horizontal forms - 'horizontal_field_class': 'col-md-9', - - # Set HTML required attribute on required fields - 'set_required': True, - - # Set HTML disabled attribute on disabled fields - 'set_disabled': False, - - # Set placeholder attributes to label if no placeholder is provided - 'set_placeholder': True, - - # Class to indicate required (better to set this in your Django form) - 'required_css_class': '', - - # Class to indicate error (better to set this in your Django form) - 'error_css_class': 'has-error', - - # Class to indicate success, meaning the field has valid input - # (better to set this in your Django form) - 'success_css_class': 'has-success', - - # Renderers (only set these if you have studied the source and understand - # the inner workings) - 'formset_renderers': { - 'default': 'bootstrap3.renderers.FormsetRenderer', - }, - 'form_renderers': { - 'default': 'bootstrap3.renderers.FormRenderer', - }, - 'field_renderers': { - 'default': 'bootstrap3.renderers.FieldRenderer', - 'inline': 'bootstrap3.renderers.InlineFieldRenderer', - }, -} - - - -# Database -# https://docs.djangoproject.com/en/1.10/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } -} - - # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators @@ -252,3 +116,21 @@ USE_TZ = True # https://docs.djangoproject.com/en/1.10/howto/static-files/ STATIC_URL = '/static/' + +############################# To be fixed + +STATIC_ROOT = os.path.dirname('/home/downhill/ungleich/vuejsuserservice/dal/dal/static/') + +# Database +# https://docs.djangoproject.com/en/1.10/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} +SECRET_KEY = 'rn=f&ecp#&#escxpk!0e%a$i3sbm$z@5+g4h9q+w7-83*f2f-i' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True diff --git a/requirements.txt b/requirements.txt index e022bb6..0f502d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ django>=2.1.2 django-auth-ldap>=1.7.0 ldap3>=2.5.1 -django-bootstrap3>=11.0.0 -django-compressor>=2.2 +django-dotenv From a7e6bdeb4275b2d6db48facf1770c7ef3500cecd Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 14:02:37 +0100 Subject: [PATCH 04/89] Make it run again[tm] --- dal/dal/settings.py | 1 - dal/dal/templates/base_short.html | 5 +---- dal/dal/templates/hosting_login.html | 2 +- dal/dal/templates/landing.html | 8 +++---- dal/dal/views.py | 32 ++++++++++++++-------------- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/dal/dal/settings.py b/dal/dal/settings.py index 3fa0168..05abe0f 100644 --- a/dal/dal/settings.py +++ b/dal/dal/settings.py @@ -71,7 +71,6 @@ TEMPLATES = [ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', - 'sekizai.context_processors.sekizai', ], }, }, diff --git a/dal/dal/templates/base_short.html b/dal/dal/templates/base_short.html index 064217d..d2d03e1 100644 --- a/dal/dal/templates/base_short.html +++ b/dal/dal/templates/base_short.html @@ -1,4 +1,4 @@ -{% load staticfiles i18n sekizai_tags %} +{% load staticfiles i18n %} @@ -29,9 +29,6 @@ {% block css_extra %} {% endblock css_extra %} - {% render_block "css" postprocessor "compressor.contrib.sekizai.compress" %} - {% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %} - diff --git a/dal/dal/templates/hosting_login.html b/dal/dal/templates/hosting_login.html index 9545cdd..8a52ae1 100644 --- a/dal/dal/templates/hosting_login.html +++ b/dal/dal/templates/hosting_login.html @@ -1,5 +1,5 @@ {% extends "hosting/base_short.html" %} -{% load i18n staticfiles bootstrap3%} +{% load i18n staticfiles %} {% block navbar %} {% include 'hosting/includes/_navbar_transparent.html' %} diff --git a/dal/dal/templates/landing.html b/dal/dal/templates/landing.html index 3556054..f56d2bb 100644 --- a/dal/dal/templates/landing.html +++ b/dal/dal/templates/landing.html @@ -1,14 +1,14 @@ {% extends "base_short.html" %} -{% load staticfiles bootstrap3 %} +{% load staticfiles %} {% block content %}
@@ -41,5 +41,3 @@ a:link { color: #000000 }
{% endblock %} - - diff --git a/dal/dal/views.py b/dal/dal/views.py index e974cf9..0ece0a1 100644 --- a/dal/dal/views.py +++ b/dal/dal/views.py @@ -1,4 +1,4 @@ -# Imports from django +# Imports from django from django.shortcuts import render from django.views.generic import View from django.contrib.auth import authenticate, login, logout @@ -11,10 +11,10 @@ from django.core.mail import EmailMessage from .models import ResetToken # Imports for the extra stuff not in django -# django_nameko is an extra module, so gets put in here + from base64 import b64encode, b64decode from datetime import datetime -from django_nameko import get_pool + from random import choice, randint import string from configparser import ConfigParser @@ -47,19 +47,19 @@ class PseudoUser(): password = ''.join(choice(string.ascii_letters + string.digits) for _ in range(30)) -# The index page +# The index page # If there's a session open, it will give the user the options he/she/it can do, if not, # it will show a landing page explaining what this is and prompt them to login class Index(View): - + # Basic binary choice, if it is an authenticated user, go straight to the options page, # if not, then show the landing page def get(self, request): if request.user.is_authenticated: return render(request, 'useroptions.html', { 'user': request.user } ) return render(request, 'landing.html') - + # Basically does the same as the GET request, just with trying to login the user beforehand # Shows an errorpage if authentication fails, since just looping to the landing page # would be frustrating @@ -74,7 +74,7 @@ class Index(View): return render(request, 'loginfailed.html') -# Registering a user +# Registering a user class Register(View): @@ -102,11 +102,11 @@ class Register(View): password2 = request.POST.get('password2') # check if the supplied passwords match if password1 != password2: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Your passwords did not match. Please supply the same password twice.' } ) # check for at least a bit of length on the password if len(password1) < 8: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Your password is too short, please use a longer one. At least 8 characters.' } ) email = request.POST.get('email') @@ -164,12 +164,12 @@ class ChangeData(View): # Only logged in users may change data if not request.user.is_authenticated: return render(request, 'mustbeloggedin.html') - + user = str(request.user) firstname = request.POST.get('firstname') lastname = request.POST.get('lastname') email = request.POST.get('email') - + # Some sanity checks for the supplied data if firstname == "": return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter a firstname.' } ) @@ -255,7 +255,7 @@ class ResetPassword(View): # Builds the reset link for the email and puts the token into the database def build_reset_link(self, user, epochutc): - # set up the data + # set up the data host = 'account-staging.ungleich.ch' tokengen = PasswordResetTokenGenerator() # create some noise for use in the tokengenerator @@ -263,7 +263,7 @@ class ResetPassword(View): token = tokengen.make_token(pseudouser) buser = bytes(user, 'utf-8') userpart = b64encode(buser) - # create entry into the database + # create entry into the database newdbentry = ResetToken(user=user, token=token, creation=epochutc) newdbentry.save() # set up the link @@ -353,7 +353,7 @@ class ChangePassword(View): if not request.user.is_authenticated: return render(request, 'mustbeloggedin.html') return render(request, 'changepassword.html', { 'user': request.user } ) - + # Does some checks on the supplied data and changes the password def post(self, request): # Variables for the error page @@ -375,7 +375,7 @@ class ChangePassword(View): password2 = request.POST.get('password2') # Are both passwords from the form the same? if password1 != password2: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, + return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please check if you typed the same password both times for the new password' } ) # Check for password length if len(password1) < 8: @@ -417,7 +417,7 @@ class DeleteAccount(View): check = authenticate(request, username=username, password=pwd) if check is None: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Wrong password for user.' } ) - + # Try to delete the user with get_pool().next() as rpc: result = rpc.deleteuser.delete_user(username) From 8cd904dcdcfee163a1f60540a8995920d3fb05a5 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 15:19:58 +0100 Subject: [PATCH 05/89] Add ldap user create support --- dal/dal/env.sample | 1 + dal/dal/views.py | 174 +++++++++++++--------- nameko-func.py | 350 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 461 insertions(+), 64 deletions(-) create mode 100644 nameko-func.py diff --git a/dal/dal/env.sample b/dal/dal/env.sample index 83a33cb..0e81220 100644 --- a/dal/dal/env.sample +++ b/dal/dal/env.sample @@ -6,3 +6,4 @@ LDAPSEARCHUSERPASSWORD="password here" # Space separated list of search bases for users LDAPSEARCH="ou=users,dc=ungleich,dc=ch ou=customers,dc=ungleich,dc=ch" +LDAPCREATE="ou=customers,dc=ungleich,dc=ch" diff --git a/dal/dal/views.py b/dal/dal/views.py index 0ece0a1..fa2c684 100644 --- a/dal/dal/views.py +++ b/dal/dal/views.py @@ -17,52 +17,91 @@ from datetime import datetime from random import choice, randint import string -from configparser import ConfigParser -config = ConfigParser() -config.read('userservice.conf') +from django.conf import settings +from django_auth_ldap.backend import LDAPBackend +from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer + + -# Check to see if the username is already taken -# Helper function, not to be set up as a view -# Check the LDAP if the user exists def check_user_exists(username): - with get_pool().next() as rpc: - return rpc.userlookup.lookup(username) + user = LDAPBackend().populate_user(username) -# To trick the tokengenerator to work with us, because we don't really -# have the expected user Class since we are reading the user from a form -# We store the tokens and don't have to use the check function, -# some one time data works fine. - -class LastLogin(): - - def replace(self, microsecond=0, tzinfo=None): - return randint(1,100000) - -class PseudoUser(): - # easiest way to handle the check for lastlogin - last_login = LastLogin() - # random alphanumeric strings for primary key and password, just used for token generation - pk = ''.join(choice(string.ascii_letters + string.digits) for _ in range(20)) - password = ''.join(choice(string.ascii_letters + string.digits) for _ in range(30)) + if not user == None: + return True + else: + return False -# The index page -# If there's a session open, it will give the user the options he/she/it can do, if not, -# it will show a landing page explaining what this is and prompt them to login +class LDAP(object): + def __init__(self): + self.server = settings.AUTH_LDAP_SERVER_URI + self.user = settings.AUTH_LDAP_BIND_DN + self.password = settings.AUTH_LDAP_BIND_PASSWORD + + # FIXME: take from settings + self.search = os.environ['LDAPSEARCH'] + + # FIXME: hard coded + self.dn = "uid={{}},{}".format(os.environ['LDAPCREATE']) + + def create_user(self, user, password, firstname, lastname, email): + conn = Connection(self.server, + self.user, + self.password) + + if not conn.bind(): + raise Exception("Could not connect to LDAPserver {}".format(self.server)) + + # set objectClasses for the new user + obj_new_user = ObjectDef(['inetOrgPerson', 'posixAccount', 'ldapPublicKey'], conn) + + w = Writer(conn, obj_new_user) + dn = self.dn.format(user) + w.new(dn) + + # Filling in some of the data + # required attributes are sn, cn, homeDirectory, uid (already handled by dn), uidNumber, gidNumber + + w[0].givenName = firstname + w[0].sn = lastname + w[0].cn = firstname + " " + lastname + w[0].mail = email + w[0].userPassword = password + w[0].homeDirectory = "/home/{}".format(user) + + # Set uidNumber as last used uidNumber+1 + w[0].uidNumber = self.get_new_uid_number(conn) + # gidNumber for users created by userservice, nice and clear + w[0].gidNumber = 10004 + + if not w.commit(): + conn.unbind() + raise Exception("Could not write new user {} to LDAP DB, commit error".format(user)) + + conn.unbind() + + # Function to get the next uid number. Not elegant, but LAM does it too and didn't really find anything + # nicer. The sorted() seems to be quite efficient, so it shouldn't take too long even on larger arrays + def get_new_uid_number(self, conn): + newuid = 0 + uidlist = [] + + for search in self.search.split(): + conn.search(search, '(&(objectClass=posixAccount)(uidNumber=*))', attributes = [ 'uidNumber' ]) + for c in conn.response: + uidlist.append(c['attributes']['uidNumber']) + + # New uid is highest old uidnumber plus one + newuid = (sorted(uidlist)[len(uidlist)-1] + 1) + return newuid class Index(View): - - # Basic binary choice, if it is an authenticated user, go straight to the options page, - # if not, then show the landing page def get(self, request): if request.user.is_authenticated: return render(request, 'useroptions.html', { 'user': request.user } ) return render(request, 'landing.html') - # Basically does the same as the GET request, just with trying to login the user beforehand - # Shows an errorpage if authentication fails, since just looping to the landing page - # would be frustrating def post(self, request): username = request.POST.get('username') password = request.POST.get('password') @@ -73,12 +112,7 @@ class Index(View): return render(request, 'useroptions.html', { 'user': user } ) return render(request, 'loginfailed.html') - -# Registering a user - class Register(View): - - # Someone wants to register, throw up the page for that def get(self, request): return render(request, 'registeruser.html') @@ -91,23 +125,17 @@ class Register(View): username = request.POST.get('username') if username == "" or not username: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please supply a username.' } ) - # Check to see if username is already taken - # isalnum() may be a bit harsh, but is the most logical choice to make sure it's a username we - # can use - if not username.isalnum(): - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Username has to be alphanumeric.' } ) - elif check_user_exists(username): + + if check_user_exists(username): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'User already exists.' } ) password1 = request.POST.get('password1') password2 = request.POST.get('password2') + # check if the supplied passwords match if password1 != password2: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, - 'error': 'Your passwords did not match. Please supply the same password twice.' } ) - # check for at least a bit of length on the password - if len(password1) < 8: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, - 'error': 'Your password is too short, please use a longer one. At least 8 characters.' } ) + return render(request, 'error.html', { 'urlname': urlname, + 'service': service, + 'error': 'Your passwords did not match. Please supply the same password twice.' } ) email = request.POST.get('email') # Is the emailaddress valid? @@ -120,23 +148,23 @@ class Register(View): lastname = request.POST.get('lastname') if firstname == "" or not firstname or lastname == "" or not lastname: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter your firstname and lastname.' } ) - # throw it to nameko to create the user - with get_pool().next() as rpc: - # so nothing strange happens if there are escapable chars - pwd = r'%s' % password1 - result = rpc.createuser.create_user(username, pwd, firstname, lastname, email) - if result == True: - return render(request, 'usercreated.html', { 'user': username } ) - else: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) + # so nothing strange happens if there are escapable chars + pwd = r'%s' % password1 + l = LDAP() + + try: + l.create_user(username, pwd, firstname, lastname, email) + except Exception as e: + return render(request, 'error.html', { 'urlname': urlname, + 'service': service, + 'error': e } ) + + return render(request, 'usercreated.html', { 'user': username } ) -# Change user data for logged in users class ChangeData(View): - - # provide the form for the change request def get(self, request): urlname = 'change_data' @@ -395,7 +423,6 @@ class ChangePassword(View): # Deletes an account class DeleteAccount(View): - # Show the basic form for deleting an account def get(self, request): return render(request, 'deleteaccount.html') @@ -431,7 +458,26 @@ class DeleteAccount(View): # Log out the session class LogOut(View): - def get(self, request): logout(request) return HttpResponse("You have been logged out.", status=200) + + + +# TO be clarified + +# To trick the tokengenerator to work with us, because we don't really +# have the expected user Class since we are reading the user from a form +# We store the tokens and don't have to use the check function, +# some one time data works fine. + +class LastLogin(): + def replace(self, microsecond=0, tzinfo=None): + return randint(1,100000) + +class PseudoUser(): + # easiest way to handle the check for lastlogin + last_login = LastLogin() + # random alphanumeric strings for primary key and password, just used for token generation + pk = ''.join(choice(string.ascii_letters + string.digits) for _ in range(20)) + password = ''.join(choice(string.ascii_letters + string.digits) for _ in range(30)) diff --git a/nameko-func.py b/nameko-func.py new file mode 100644 index 0000000..d43a4bc --- /dev/null +++ b/nameko-func.py @@ -0,0 +1,350 @@ +from nameko.events import EventDispatcher, event_handler +from nameko.rpc import rpc +from configparser import ConfigParser +from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer +from datetime import datetime + +# For testing +from random import randint + +# Read the config in the nameko.conf +config = ConfigParser() +config.read('nameko.conf') + +# Sanity check for config +try: + mult_server = int(config['LDAP']['SERVERMULTIPLE']) +# SERVERMULTIPLE is set to something not a number +except: + exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1") +# less than one server is not a sensible option +if mult_server < 1: + exit("[LDAP] SERVERMULTIPLE has to be an integer >= 1") + + +# Function to setup the server or serverpool +def ldapservers(): + # Just one server, no need for a pool + if mult_server == 1: + ldapserver = Server(config['LDAP']['LDAPSERVER1'], use_ssl=True) + return ldapserver + # Multiple servers, set up a pool + else: + ldapserver = ServerPool(None) + for x in range(1, (mult_server+1)): + ins = Server(config['LDAP']['LDAPSERVER' + str(x)], use_ssl=True) + ldapserver.add(ins) + return ldapserver + + +# Since there's no reason why someone in ou=users shouldn't use the service, +# here's the helper function to check whether an uid is in ou=customers or +# ou=users +# returns the full dn +def user_or_customer(uid): + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) + conn.bind() + search_customers = conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % uid) + if search_customers: + conn.unbind() + return '%s,ou=customers,dc=ungleich,dc=ch' % uid + search_users = conn.search('ou=users,dc=ungleich,dc=ch', '(%s)' % uid) + if search_users: + conn.unbind() + return '%s,ou=users,dc=ungleich,dc=ch' % uid + conn.unbind() + return False + +# Get the objectclasses +def objclasses(rdn, uid, connection): + # search for objectClasses + connection.search(rdn, '(%s)' % uid, attributes=['objectClass']) + objclass = [] + # get the relevant data + tmp = connection.entries[0]['objectClass'] + # This one sets up the array + for y in tmp: + objclass.append(y) + # return the array containing the objectClasses, like ['inetOrgPerson', 'posixAccount', 'ldapPublicKey'] + return objclass + +# checks if a user already exists in the LDAP +class UserLookUp(object): + name = "userlookup" + dispatch = EventDispatcher() + + @rpc + def lookup(self, user): + # Setup the search parameter and connect to LDAP + LDAP_UID = 'uid=%s' % user + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) + conn.bind() + # Strange result. It keeps complaining LDAP_UID not set if I try to directly + # substitute x and y to the if + # Searches for user in ou=customers and ou=users + x = conn.search('ou=customers,dc=ungleich,dc=ch', '(%s)' % LDAP_UID) + y = conn.search('ou=users,dc=ungleich,dc=ch', '(%s)' % LDAP_UID) + if x or y: + # return conn.entries[0] for first search result since we can assume uid is unique + self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and found it\n' % (datetime.now(), LDAP_UID) ) + conn.unbind() + # return True since the user is already in LDAP + return True + # User not in LDAP, so just close it down, write the log and return False + else: + conn.unbind() + self.dispatch('ldap', '%s [Info: UserLookUp] Searched for %s and not found it.\n' % (datetime.now(), LDAP_UID) ) + return False + + +# Create a user in the LDAP. Assumes the checks are already in place for existing users +class CreateUser(object): + name = "createuser" + dispatch = EventDispatcher() + + @rpc + def create_user(self, user, password, firstname, lastname, email): + # Creates a user with some basic data + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP','LDAPMANAGERPASSWORD', raw=True)) + if not conn.bind(): + self.dispatch('ldap', '%s [Error CreateUser] Could not connect to LDAPserver\n' % datetime.now() ) + return "Could not connect to LDAP Server." + + # set objectClasses for the new user + obj_new_user = ObjectDef(['inetOrgPerson', 'posixAccount', 'ldapPublicKey'], conn) + w = Writer(conn, obj_new_user) + dn = 'uid=%s,ou=users,dc=ungleich,dc=ch' % user + w.new(dn) + # Filling in some of the data + # required attributes are sn, cn, homeDirectory, uid (already handled by dn), uidNumber, gidNumber + w[0].givenName = firstname + w[0].sn = lastname + w[0].cn = firstname + " " + lastname + w[0].mail = email + w[0].userPassword = password + w[0].homeDirectory = '/home/%s' % user + # Set uidNumber as last used uidNumber+1 + w[0].uidNumber = self.get_new_uid_number(conn) + # gidNumber for users created by userservice, nice and clear + w[0].gidNumber = 10004 + if not w.commit(): + conn.unbind() + self.dispatch('ldap', '%s [Error CreateUser] Could not write new user %s to LDAP DB\n' % (datetime.now(), dn) ) + return "Couldn't write data to the LDAP Server." + conn.unbind() + self.dispatch('ldap', '%s [Info CreateUser] %s created.\n' % (datetime.now(), dn) ) + return True + + # Function to get the next uid number. Not elegant, but LAM does it too and didn't really find anything + # nicer. The sorted() seems to be quite efficient, so it shouldn't take too long even on larger arrays + def get_new_uid_number(self, conn): + conn.search('dc=ungleich,dc=ch', '(&(objectClass=posixAccount)(uidNumber=*))', attributes = [ 'uidNumber' ]) + newuid = 0 + uidlist = [] + for c in conn.response: + uidlist.append(c['attributes']['uidNumber']) + # New uid is highest old uidnumber plus one + newuid = (sorted(uidlist)[len(uidlist)-1] + 1) + return newuid + + + +# Returns some basic data from an user +class GetUserData(object): + name = "getuserdata" + dispatch = EventDispatcher() + + @rpc + def get_data(self, user): + # Setup the search parameter and connect to LDAP + LDAP_UID = 'uid=%s' % user + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) + conn.bind() + if not conn.bound: + self.dispatch('ldap', '%s [Error GetUserData] Could not connect to LDAP server.\n' % datetime.now() ) + return ("error", "Could not connect to LDAP server.", "", "") + rdn = user_or_customer(LDAP_UID) + if rdn == False: + conn.unbind() + self.dispatch('ldap', '%s [Info GetUserData] Could not find user %s\n' % (datetime.now(), LDAP_UID) ) + return ("error", "Could not find the user.", "", "") + # Workaround because not all users have the same objectClasses + objclass = objclasses(rdn, LDAP_UID, conn) + obj = ObjectDef(objclass, conn) + # The Reader gets the data for the user + r = Reader(conn, obj, rdn) + r.search() + # Since the DN is basically confirmed by user_or_customer() it shouldn't throw an exception, but better check + try: + x = r[0].sn + except: + conn.unbind() + self.dispatch('ldap', '%s [Error GetUserData] Could not open Reader for %s\n' % (datetime.now(), rdn) ) + return ("error", "Could not read data for user.", "", "") + # Putting the results into strings and then clean it up a bit if some attribute is not set in LDAP + (firstname, lastname, email) = (str(r[0].givenName), str(r[0].sn), str(r[0].mail)) + if firstname == '[]': + firstname = 'No firstname given' + if lastname == '[]': + lastname = 'No lastname given' + if email == '[]': + email = 'No email given' + conn.unbind() + self.dispatch('ldap', '%s [Info GetUserData] Got data for %s Firstname: %s Lastname: %s Email: %s\n' % (datetime.now(), rdn, firstname, lastname, email) ) + return ("OK", firstname, lastname, email) + + + +# change some (firstname, lastname, email) data for the user +class ChangeUserData(object): + name = "changeuserdata" + dispatch = EventDispatcher() + + @rpc + def change_data(self, user, firstname, lastname, email): + LDAP_UID = 'uid=%s' % user + server = ldapservers() + # Establish connection with a user who can change the data + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) + if not conn.bind(): + self.dispatch('ldap', '%s [Error ChangeUserData] Could not connect to LDAP server.\n' % datetime.now() ) + return "Could not connect to LDAP server." + # get the DN of the user + rdn = user_or_customer(LDAP_UID) + if rdn == False: + conn.unbind() + self.dispatch('ldap', '%s [Info ChangeUserData] User with %s not found.\n' % (datetime.now(), LDAP_UID) ) + return "Could not find user." + # Fix because not every user has the same objectClasses + objclass = objclasses(rdn, LDAP_UID, conn) + # Set up a reader for the user + obj = ObjectDef(objclass, conn) + r = Reader(conn, obj, rdn) + r.search() + # Again, user_or_customer() should prevent it from throwing an exception because it's a confirmed user + try: + x = r[0].sn + except: + conn.unbind() + self.dispatch('ldap', '%s [Error ChangeUserData] Could not open Reader for %s\n' % (datetime.now(), rdn) ) + return "Could not open the data of user." + # Opens a Writer instance prefilled with the old data + # We could check if something has changed, but since the form takes the old data as standard values, let's + # just update the relevant attributes + w = Writer.from_cursor(r) + w[0].sn = lastname + w[0].cn = firstname + " " + lastname + w[0].givenName = firstname + w[0].mail = email + # check if the data is written + if not w.commit(): + conn.unbind() + self.dispatch('ldap', '%s [Error ChangeUserData] Could not write changes for %s\n' % (datetime.now(), rdn) ) + return "Could not write changes for user." + conn.unbind() + self.dispatch('ldap', '%s [Info ChangeUserData] Changed data for %s Firstname: %s Lastname: %s Email: %s\n' % (datetime.now(), rdn, firstname, lastname, email) ) + return True + + +# change the password for the user +class ChangePassword(object): + name = "changepassword" + dispatch = EventDispatcher() + + @rpc + def change_password(self, user, newpassword): + LDAP_UID = 'uid=%s' % user + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) + if not conn.bind(): + self.dispatch('ldap', '%s [Error ChangePassword] Could not connect to LDAP server.\n' % datetime.now() ) + return "Could not connect to LDAP server." + # check if uid=user is in either ou=customers or ou=users + rdn = user_or_customer(LDAP_UID) + if rdn == False: + conn.unbind() + self.dispatch('ldap', '%s [Error ChangePassword] Could not find user %s\n' % (datetime.now(), LDAP_UID) ) + return "Could not find the user." + # Plus not everyone has the same objectClasses, so workaround + objclass = objclasses(rdn, LDAP_UID, conn) + obj = ObjectDef(objclass, conn) + # Set up a Reader for the DN + r = Reader(conn, obj, rdn) + r.search() + # Shouldn't throw an exception, since the user is confirmed to be there + try: + x = r[0].sn + except: + conn.unbind() + self.dispatch('ldap', '%s [Error ChangePassword] Could not open Reader for %s\n' % (datetime.now(), rdn) ) + return "Could not open the data for the user." + # Set up the writer and overwrite the attribute with the new password + w = Writer.from_cursor(r) + w[0].userPassword = newpassword + # Check to see if the change has gone through + if not w.commit(): + conn.unbind() + self.dispatch('ldap', '%s [Error ChangePassword] Could not write data for %s\n' % (datetime.now(), rdn) ) + return "Could not write data for the user." + conn.unbind() + self.dispatch('ldap', '%s [Info ChangePassword] Password changed for %s\n' % (datetime.now(), rdn) ) + return True + + +# Deletes a user from LDAP +class DeleteUser(object): + name = "deleteuser" + dispatch = EventDispatcher() + + @rpc + def delete_user(self, user): + LDAP_UID = 'uid=%s' % user + server = ldapservers() + conn = Connection(server, config['LDAP']['LDAPMANAGER'], config.get('LDAP', 'LDAPMANAGERPASSWORD', raw=True)) + conn.bind() + if not conn.bound: + self.dispatch('ldap', '%s [Error DeleteUser] Could not connect to LDAP server.\n' % datetime.now() ) + return "Could not connect to LDAP server." + # again, check whether the uid= is in ou=users or ou=customers + dn = user_or_customer(LDAP_UID) + if dn == False: + conn.unbind() + self.dispatch('ldap', '%s [Error DeleteUser] Could not find the user %s\n' % (datetime.now(), LDAP_UID) ) + return "Could not find the user." + # Check if the delete was successfull + deleted = conn.delete(dn) + if not deleted: + conn.unbind() + self.dispatch('ldap', '%s [Error DeleteUser] Could not delete %s\n' % (datetime.now(), dn) ) + return "Could not delete the user." + conn.unbind() + self.dispatch('ldap', '%s [Info DeleteUser] Deleted %s\n' % (datetime.now(), dn) ) + return True + + +# the class to log all the dispatches +# for now everything gets logged into the same logfile, but +# I don't forsee that much traffic plus with timestamps and the class name +# in the log should be readable +class Log(object): + name = "log" + ldaplog = config['System']['LOGDIR'] + '/ldap.log' + + + # Gets all the dispatches with 'ldap' and writes them into the ldap.log + @event_handler('userlookup', 'ldap') + @event_handler('createuser', 'ldap') + @event_handler('getuserdata', 'ldap') + @event_handler('changeuserdata', 'ldap') + @event_handler('passwordresetrequest', 'ldap') + @event_handler('changepassword', 'ldap') + @event_handler('deleteuser', 'ldap') + def event_handler_ldap(self, payload): + f = open(self.ldaplog, mode='a', encoding='utf-8') + f.write(payload) + f.close + From 93677e6ad67222ba7a772aff5c8fdf7d0bf9ad44 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sat, 26 Jan 2019 17:46:06 +0100 Subject: [PATCH 06/89] Try ldap auth using python-ldap --- dal/dal/env.sample | 1 + dal/dal/settings.py | 2 + dal/dal/views.py | 138 ++++++++++++++++++++------------------------ requirements.txt | 6 +- 4 files changed, 69 insertions(+), 78 deletions(-) diff --git a/dal/dal/env.sample b/dal/dal/env.sample index 0e81220..a27b883 100644 --- a/dal/dal/env.sample +++ b/dal/dal/env.sample @@ -4,6 +4,7 @@ LDAPSERVER="ldap://ldap1.ungleich.ch ldap://ldap2.ungleich.ch" LDAPSEARCHUSER="user here" LDAPSEARCHUSERPASSWORD="password here" + # Space separated list of search bases for users LDAPSEARCH="ou=users,dc=ungleich,dc=ch ou=customers,dc=ungleich,dc=ch" LDAPCREATE="ou=customers,dc=ungleich,dc=ch" diff --git a/dal/dal/settings.py b/dal/dal/settings.py index 05abe0f..a284663 100644 --- a/dal/dal/settings.py +++ b/dal/dal/settings.py @@ -28,6 +28,8 @@ search_base = os.environ['LDAPSEARCH'].split() search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ] AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap) +if os.environ['LDAP_USE_TLS']: + AUTH_LDAP_START_TLS=True BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/dal/dal/views.py b/dal/dal/views.py index fa2c684..250cd1a 100644 --- a/dal/dal/views.py +++ b/dal/dal/views.py @@ -18,83 +18,75 @@ from datetime import datetime from random import choice, randint import string +import os + +# Use ldap, like django_auth_backend +import ldap + from django.conf import settings -from django_auth_ldap.backend import LDAPBackend -from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer -def check_user_exists(username): - user = LDAPBackend().populate_user(username) - - if not user == None: - return True - else: - return False - - class LDAP(object): def __init__(self): - self.server = settings.AUTH_LDAP_SERVER_URI + self.uri = settings.AUTH_LDAP_SERVER_URI self.user = settings.AUTH_LDAP_BIND_DN self.password = settings.AUTH_LDAP_BIND_PASSWORD # FIXME: take from settings - self.search = os.environ['LDAPSEARCH'] + self.search_base = os.environ['LDAPSEARCH'] + self.search_scope = ldap.SCOPE_SUBTREE + self.search_filter = "objectClass=inetOrgPerson" # FIXME: hard coded self.dn = "uid={{}},{}".format(os.environ['LDAPCREATE']) + self.gid = "10004" + + self.conn = ldap.initialize(self.uri) + if settings.AUTH_LDAP_START_TLS: + self.conn.start_tls_s() + + print("{} {} {}".format(self.uri, self.user, self.password)) + self.conn.bind_s(self.user, self.password) + + + def check_user_exists(self, username): + result = self.conn.search_s(self.search_base, + self.search_scope, + self.dn.format(username)) + if not len(result) == 0: + return True + else: + return False def create_user(self, user, password, firstname, lastname, email): - conn = Connection(self.server, - self.user, - self.password) - - if not conn.bind(): - raise Exception("Could not connect to LDAPserver {}".format(self.server)) - - # set objectClasses for the new user - obj_new_user = ObjectDef(['inetOrgPerson', 'posixAccount', 'ldapPublicKey'], conn) - - w = Writer(conn, obj_new_user) dn = self.dn.format(user) - w.new(dn) + modlist = { + "objectClass": ["inetOrgPerson", "posixAccount", "ldapPublickey"], + "uid": [user], + "sn": [lastname], + "givenName": [firstname], + "cn": ["{} {}".format(firstname, lastname)], + "displayName": ["{} {}".format(firstname, lastname)], + "uidNumber": ["{}".format(self.get_new_uid_number(conn))], + "gidNumber": [self.gid], + "loginShell": ["/bin/bash"], + "homeDirectory": ["/home/{}".format(user)], + "mail": email, + "userPassword": password + } + result = self.conn.add_s(dn, ldap.modlist.addModlist(modlist)) - # Filling in some of the data - # required attributes are sn, cn, homeDirectory, uid (already handled by dn), uidNumber, gidNumber + def get_new_uid_number(self): + uidlist = [0] - w[0].givenName = firstname - w[0].sn = lastname - w[0].cn = firstname + " " + lastname - w[0].mail = email - w[0].userPassword = password - w[0].homeDirectory = "/home/{}".format(user) + for result in self.conn.search_s(self.search_base, + self.search_scope, + self.search_filter): - # Set uidNumber as last used uidNumber+1 - w[0].uidNumber = self.get_new_uid_number(conn) - # gidNumber for users created by userservice, nice and clear - w[0].gidNumber = 10004 + uidlist.append(int(result[1]['uidNumber'][0])) - if not w.commit(): - conn.unbind() - raise Exception("Could not write new user {} to LDAP DB, commit error".format(user)) - - conn.unbind() - - # Function to get the next uid number. Not elegant, but LAM does it too and didn't really find anything - # nicer. The sorted() seems to be quite efficient, so it shouldn't take too long even on larger arrays - def get_new_uid_number(self, conn): - newuid = 0 - uidlist = [] - - for search in self.search.split(): - conn.search(search, '(&(objectClass=posixAccount)(uidNumber=*))', attributes = [ 'uidNumber' ]) - for c in conn.response: - uidlist.append(c['attributes']['uidNumber']) - - # New uid is highest old uidnumber plus one - newuid = (sorted(uidlist)[len(uidlist)-1] + 1) - return newuid + return sorted(uidlist)[-1] + 1 class Index(View): def get(self, request): @@ -118,36 +110,40 @@ class Register(View): # Someone filled out the register page, do some basic checks and throw it at nameko def post(self, request): - # message for the error template + l = LDAP() + service = 'register an user' - # urlname for 'go back' on the errorpage urlname = 'register' username = request.POST.get('username') + if username == "" or not username: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please supply a username.' } ) - if check_user_exists(username): + + if l.check_user_exists(username): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'User already exists.' } ) + password1 = request.POST.get('password1') password2 = request.POST.get('password2') - - # check if the supplied passwords match if password1 != password2: return render(request, 'error.html', { 'urlname': urlname, 'service': service, - 'error': 'Your passwords did not match. Please supply the same password twice.' } ) + 'error': "Passwords don't match." } ) email = request.POST.get('email') - # Is the emailaddress valid? try: validate_email(email) except ValidationError: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } ) + return render(request, 'error.html', { 'urlname': urlname, + 'service': service, + 'error': 'The supplied email address is invalid.' } ) firstname = request.POST.get('firstname') lastname = request.POST.get('lastname') - if firstname == "" or not firstname or lastname == "" or not lastname: - return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please enter your firstname and lastname.' } ) + if not firstname or not lastname: + return render(request, 'error.html', { 'urlname': urlname, + 'service': service, + 'error': 'Please enter your firstname and lastname.' } ) # so nothing strange happens if there are escapable chars pwd = r'%s' % password1 @@ -163,7 +159,6 @@ class Register(View): return render(request, 'usercreated.html', { 'user': username } ) - class ChangeData(View): # provide the form for the change request def get(self, request): @@ -220,17 +215,10 @@ class ChangeData(View): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } ) -# Resets the password for a user -# Sends email to the user with a link to reset the password - class ResetPassword(View): - - # Presents the form with some information def get(self, request): return render(request, 'resetpassword.html') - # gets the data from confirming the reset request and checks if it was not a misclick - # (by having the user type in his username) def post(self, request): urlname = 'reset_password' service = 'send a password reset request' diff --git a/requirements.txt b/requirements.txt index 0f502d8..0767c8c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -django>=2.1.2 -django-auth-ldap>=1.7.0 -ldap3>=2.5.1 +django +django-auth-ldap +python-ldap django-dotenv From 2fd7bf3041de47f4b0201df876b126b462075219 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 27 Jan 2019 13:00:45 +0100 Subject: [PATCH 07/89] Cleanup, add modlist --- dal/dal/views.py | 53 ++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/dal/dal/views.py b/dal/dal/views.py index 250cd1a..0e8cd19 100644 --- a/dal/dal/views.py +++ b/dal/dal/views.py @@ -22,6 +22,7 @@ import os # Use ldap, like django_auth_backend import ldap +import ldap.modlist as modlist from django.conf import settings @@ -46,36 +47,43 @@ class LDAP(object): if settings.AUTH_LDAP_START_TLS: self.conn.start_tls_s() - print("{} {} {}".format(self.uri, self.user, self.password)) self.conn.bind_s(self.user, self.password) def check_user_exists(self, username): + exists = False + result = self.conn.search_s(self.search_base, self.search_scope, self.dn.format(username)) - if not len(result) == 0: - return True - else: - return False + if len(result) > 0: + exists = True + + return exists def create_user(self, user, password, firstname, lastname, email): dn = self.dn.format(user) - modlist = { - "objectClass": ["inetOrgPerson", "posixAccount", "ldapPublickey"], - "uid": [user], - "sn": [lastname], - "givenName": [firstname], - "cn": ["{} {}".format(firstname, lastname)], - "displayName": ["{} {}".format(firstname, lastname)], - "uidNumber": ["{}".format(self.get_new_uid_number(conn))], - "gidNumber": [self.gid], - "loginShell": ["/bin/bash"], - "homeDirectory": ["/home/{}".format(user)], - "mail": email, - "userPassword": password + attr = { + "objectClass": ["inetOrgPerson".encode("utf-8"), + "posixAccount".encode("utf-8"), + "ldapPublickey".encode("utf-8")], + "uid": [user.encode("utf-8")], + "sn": [lastname.encode("utf-8")], + "givenName": [firstname.encode("utf-8")], + "cn": ["{} {}".format(firstname, lastname).encode("utf-8")], + "displayName": ["{} {}".format(firstname, lastname).encode("utf-8")], + "uidNumber": ["{}".format(self.get_new_uid_number()).encode("utf-8")], + "gidNumber": [self.gid.encode("utf-8")], + "loginShell": ["/bin/bash".encode("utf-8")], + "homeDirectory": ["/home/{}".format(user).encode("utf-8")], + "mail": email.encode("utf-8"), + "userPassword": password.encode("utf-8") } - result = self.conn.add_s(dn, ldap.modlist.addModlist(modlist)) + + ldif = modlist.addModlist(attr) + + print("just before: {} {}".format(dn, ldif)) + return self.conn.add_s(dn, ldif) def get_new_uid_number(self): uidlist = [0] @@ -83,8 +91,8 @@ class LDAP(object): for result in self.conn.search_s(self.search_base, self.search_scope, self.search_filter): - - uidlist.append(int(result[1]['uidNumber'][0])) + if 'uidNumber' in result[1]: + uidlist.append(int(result[1]['uidNumber'][0])) return sorted(uidlist)[-1] + 1 @@ -119,7 +127,6 @@ class Register(View): if username == "" or not username: return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Please supply a username.' } ) - if l.check_user_exists(username): return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'User already exists.' } ) @@ -148,8 +155,6 @@ class Register(View): # so nothing strange happens if there are escapable chars pwd = r'%s' % password1 - l = LDAP() - try: l.create_user(username, pwd, firstname, lastname, email) except Exception as e: From ace2fa6eb98935c373c4c794255b249ce09478c6 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 17:43:06 +0100 Subject: [PATCH 08/89] Move project files to root directory --- dal/{dal => }/__init__.py | 0 .../font-awesome/css/font-awesome.min.css | 4 ---- dal/{dal => }/env.sample | 0 dal/{dal => }/models.py | 0 dal/{dal => }/settings.py | 6 +++--- .../datacenterlight/css/bootstrap-3.3.7.min.css | 0 dal/{dal => }/static/datacenterlight/css/cms.css | 0 dal/{dal => }/static/datacenterlight/css/common.css | 0 .../static/datacenterlight/css/header-slider.css | 0 .../static/datacenterlight/css/hosting.css | 0 .../static/datacenterlight/css/landing-page.css | 0 .../font-awesome/css/font-awesome.min.css | 4 ++++ .../font-awesome/fonts/FontAwesome.otf | Bin .../font-awesome/fonts/fontawesome-webfont.eot | Bin .../font-awesome/fonts/fontawesome-webfont.svg | 0 .../font-awesome/fonts/fontawesome-webfont.ttf | Bin .../font-awesome/fonts/fontawesome-webfont.woff | Bin .../font-awesome/fonts/fontawesome-webfont.woff2 | Bin .../font-awesome/less/bordered-pulled.less | 0 .../datacenterlight/font-awesome/less/core.less | 0 .../font-awesome/less/fixed-width.less | 0 .../font-awesome/less/font-awesome.less | 0 .../datacenterlight/font-awesome/less/icons.less | 0 .../datacenterlight/font-awesome/less/larger.less | 0 .../datacenterlight/font-awesome/less/list.less | 0 .../datacenterlight/font-awesome/less/mixins.less | 0 .../datacenterlight/font-awesome/less/path.less | 0 .../font-awesome/less/rotated-flipped.less | 0 .../datacenterlight/font-awesome/less/spinning.less | 0 .../datacenterlight/font-awesome/less/stacked.less | 0 .../font-awesome/less/variables.less | 0 .../font-awesome/scss/_bordered-pulled.scss | 0 .../datacenterlight/font-awesome/scss/_core.scss | 0 .../font-awesome/scss/_fixed-width.scss | 0 .../datacenterlight/font-awesome/scss/_icons.scss | 0 .../datacenterlight/font-awesome/scss/_larger.scss | 0 .../datacenterlight/font-awesome/scss/_list.scss | 0 .../datacenterlight/font-awesome/scss/_mixins.scss | 0 .../datacenterlight/font-awesome/scss/_path.scss | 0 .../font-awesome/scss/_rotated-flipped.scss | 0 .../font-awesome/scss/_spinning.scss | 0 .../datacenterlight/font-awesome/scss/_stacked.scss | 0 .../font-awesome/scss/_variables.scss | 0 .../font-awesome/scss/font-awesome.scss | 0 .../fonts/Montserrat/Montserrat-Black.ttf | Bin .../fonts/Montserrat/Montserrat-BlackItalic.ttf | Bin .../fonts/Montserrat/Montserrat-Bold.ttf | Bin .../fonts/Montserrat/Montserrat-BoldItalic.ttf | Bin .../fonts/Montserrat/Montserrat-ExtraBold.ttf | Bin .../fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf | Bin .../fonts/Montserrat/Montserrat-ExtraLight.ttf | Bin .../Montserrat/Montserrat-ExtraLightItalic.ttf | Bin .../fonts/Montserrat/Montserrat-Italic.ttf | Bin .../fonts/Montserrat/Montserrat-Light.ttf | Bin .../fonts/Montserrat/Montserrat-LightItalic.ttf | Bin .../fonts/Montserrat/Montserrat-Medium.ttf | Bin .../fonts/Montserrat/Montserrat-MediumItalic.ttf | Bin .../fonts/Montserrat/Montserrat-Regular.ttf | Bin .../fonts/Montserrat/Montserrat-SemiBold.ttf | Bin .../fonts/Montserrat/Montserrat-SemiBoldItalic.ttf | Bin .../fonts/Montserrat/Montserrat-Thin.ttf | Bin .../fonts/Montserrat/Montserrat-ThinItalic.ttf | Bin .../static/datacenterlight/fonts/Montserrat/OFL.txt | 0 .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin .../fonts/glyphicons-halflings-regular.woff2 | Bin .../static/datacenterlight/img/Ceph_Logo.png | Bin .../static/datacenterlight/img/banner-bg copy.jpg | Bin .../static/datacenterlight/img/banner-bg.jpg | Bin dal/{dal => }/static/datacenterlight/img/bg.png | Bin .../static/datacenterlight/img/cdistbyungleich.png | Bin .../static/datacenterlight/img/checkmark.png | Bin .../static/datacenterlight/img/configure.jpg | Bin .../static/datacenterlight/img/datacenterlight.png | Bin .../static/datacenterlight/img/dcl-email-bg.jpg | Bin .../static/datacenterlight/img/deluxeroom.jpg | Bin dal/{dal => }/static/datacenterlight/img/devuan.png | Bin dal/{dal => }/static/datacenterlight/img/django.png | Bin dal/{dal => }/static/datacenterlight/img/dog.png | Bin .../static/datacenterlight/img/economy.jpg | Bin .../static/datacenterlight/img/facebook_logo.svg | 0 .../static/datacenterlight/img/favicon.ico | Bin .../static/datacenterlight/img/header-bg.jpg | Bin dal/{dal => }/static/datacenterlight/img/home.png | Bin dal/{dal => }/static/datacenterlight/img/how.png | Bin dal/{dal => }/static/datacenterlight/img/how1.png | Bin dal/{dal => }/static/datacenterlight/img/how2.png | Bin dal/{dal => }/static/datacenterlight/img/how3.png | Bin dal/{dal => }/static/datacenterlight/img/how4.png | Bin .../static/datacenterlight/img/intro-bg.jpg | Bin dal/{dal => }/static/datacenterlight/img/ipad.png | Bin .../static/datacenterlight/img/loading.gif | Bin .../static/datacenterlight/img/logo_black.png | Bin .../static/datacenterlight/img/logo_black.svg | 0 .../static/datacenterlight/img/logo_white.svg | 0 .../static/datacenterlight/img/opennebula.png | Bin .../static/datacenterlight/img/pattern.jpg | Bin dal/{dal => }/static/datacenterlight/img/phones.png | Bin .../static/datacenterlight/img/presidentialroom.jpg | Bin .../static/datacenterlight/img/prometheus.png | Bin .../static/datacenterlight/img/python-logo.png | Bin dal/{dal => }/static/datacenterlight/img/ssd.jpg | Bin .../static/datacenterlight/img/standardroom.jpg | Bin dal/{dal => }/static/datacenterlight/img/tayga.png | Bin dal/{dal => }/static/datacenterlight/img/ubuntu.png | Bin .../datacenterlight/js/bootstrap-3.3.7.min.js | 0 dal/{dal => }/static/datacenterlight/js/form.js | 0 .../static/datacenterlight/js/jquery-2.2.4.min.js | 0 dal/{dal => }/static/datacenterlight/js/main.js | 0 dal/{dal => }/static/hosting/card-django.png | Bin dal/{dal => }/static/hosting/card-nodejs.png | Bin dal/{dal => }/static/hosting/card-rails.png | Bin dal/{dal => }/static/hosting/css/commons.css | 0 dal/{dal => }/static/hosting/css/dashboard.css | 0 dal/{dal => }/static/hosting/css/landing-page.css | 0 dal/{dal => }/static/hosting/css/nodejshosting.css | 0 dal/{dal => }/static/hosting/css/order.css | 0 dal/{dal => }/static/hosting/css/orders.css | 0 dal/{dal => }/static/hosting/css/payment.css | 0 .../static/hosting/css/price_calculator.css | 0 dal/{dal => }/static/hosting/css/pricing.css | 0 dal/{dal => }/static/hosting/css/user_keys.css | 0 .../static/hosting/css/virtual-machine.css | 0 dal/{dal => }/static/hosting/django-intro-bg.png | Bin .../static/hosting/img/24-hours-support.svg | 0 dal/{dal => }/static/hosting/img/CH_flag.png | Bin dal/{dal => }/static/hosting/img/DE_flag.png | Bin dal/{dal => }/static/hosting/img/ajax-loader.gif | Bin dal/{dal => }/static/hosting/img/auth-bg-sm.jpg | Bin dal/{dal => }/static/hosting/img/auth-bg.jpg | Bin dal/{dal => }/static/hosting/img/banner-bg copy.jpg | Bin dal/{dal => }/static/hosting/img/banner-bg.jpg | Bin dal/{dal => }/static/hosting/img/billing.svg | 0 dal/{dal => }/static/hosting/img/card-django.png | Bin dal/{dal => }/static/hosting/img/card-nodejs.png | Bin dal/{dal => }/static/hosting/img/card-rails.png | Bin dal/{dal => }/static/hosting/img/checkmark.png | Bin dal/{dal => }/static/hosting/img/configure.jpg | Bin dal/{dal => }/static/hosting/img/connected.svg | 0 dal/{dal => }/static/hosting/img/copy.svg | 0 .../static/hosting/img/dashboard_settings.svg | 0 dal/{dal => }/static/hosting/img/delete.svg | 0 dal/{dal => }/static/hosting/img/deluxeroom.jpg | Bin .../static/hosting/img/django-intro-bg.png | Bin dal/{dal => }/static/hosting/img/dog.png | Bin dal/{dal => }/static/hosting/img/economy.jpg | Bin dal/{dal => }/static/hosting/img/favicon.ico | Bin dal/{dal => }/static/hosting/img/g222.png | Bin dal/{dal => }/static/hosting/img/header-bg.jpg | Bin dal/{dal => }/static/hosting/img/home.png | Bin dal/{dal => }/static/hosting/img/how.png | Bin dal/{dal => }/static/hosting/img/how1.png | Bin dal/{dal => }/static/hosting/img/how2.png | Bin dal/{dal => }/static/hosting/img/how4.png | Bin dal/{dal => }/static/hosting/img/icon-pdf.svg | 0 dal/{dal => }/static/hosting/img/icon-print.svg | 0 dal/{dal => }/static/hosting/img/intro-bg.jpg | Bin dal/{dal => }/static/hosting/img/ipad.png | Bin dal/{dal => }/static/hosting/img/key.svg | 0 dal/{dal => }/static/hosting/img/login-bg.jpg | Bin dal/{dal => }/static/hosting/img/logo_black.png | Bin dal/{dal => }/static/hosting/img/logo_black.svg | 0 dal/{dal => }/static/hosting/img/logo_white.svg | 0 .../static/hosting/img/nodejs-intro-bg.png | Bin dal/{dal => }/static/hosting/img/pattern.jpg | Bin .../static/hosting/img/pattern_original.jpg | Bin dal/{dal => }/static/hosting/img/phones.png | Bin dal/{dal => }/static/hosting/img/plusVM.svg | 0 .../static/hosting/img/presidentialroom.jpg | Bin dal/{dal => }/static/hosting/img/rails-intro-bg.png | Bin dal/{dal => }/static/hosting/img/settings.svg | 0 dal/{dal => }/static/hosting/img/shopping-cart.svg | 0 dal/{dal => }/static/hosting/img/signup-bg.png | Bin dal/{dal => }/static/hosting/img/standardroom.jpg | Bin dal/{dal => }/static/hosting/img/ubuntu.png | Bin dal/{dal => }/static/hosting/img/vm.svg | 0 dal/{dal => }/static/hosting/js/createvm.js | 0 dal/{dal => }/static/hosting/js/gen-ssh-key.js | 0 dal/{dal => }/static/hosting/js/html2canvas.min.js | 0 dal/{dal => }/static/hosting/js/html2pdf.min.js | 0 dal/{dal => }/static/hosting/js/initial.js | 0 dal/{dal => }/static/hosting/js/order.js | 0 dal/{dal => }/static/hosting/js/payment.js | 0 dal/{dal => }/static/hosting/js/pricing.js | 0 .../static/hosting/js/virtual_machine_detail.js | 0 dal/{dal => }/static/hosting/nodejs-intro-bg.png | Bin dal/{dal => }/static/hosting/rails-intro-bg.png | Bin dal/{dal => }/templates/base.html | 0 dal/{dal => }/templates/base_short.html | 0 dal/{dal => }/templates/changeddata.html | 0 dal/{dal => }/templates/changedpassword.html | 0 dal/{dal => }/templates/changepassword.html | 0 dal/{dal => }/templates/changeuserdata.html | 0 dal/{dal => }/templates/deleteaccount.html | 0 dal/{dal => }/templates/deleteduser.html | 0 dal/{dal => }/templates/error.html | 0 dal/{dal => }/templates/hosting_login.html | 0 dal/{dal => }/templates/includes/_card_input.html | 0 dal/{dal => }/templates/includes/_contact.html | 0 dal/{dal => }/templates/includes/_footer.html | 0 dal/{dal => }/templates/includes/_header.html | 0 dal/{dal => }/templates/includes/_messages.html | 0 dal/{dal => }/templates/includes/_navbar.html | 0 .../templates/includes/_navbar_transparent.html | 0 dal/{dal => }/templates/includes/_navbar_user.html | 0 .../templates/includes/_our_infrastructure.html | 0 dal/{dal => }/templates/includes/_pricing.html | 0 .../templates/includes/_your_infrastructure.html | 0 dal/{dal => }/templates/landing.html | 0 dal/{dal => }/templates/loginfailed.html | 0 dal/{dal => }/templates/mustbeloggedin.html | 0 dal/{dal => }/templates/registeruser.html | 0 dal/{dal => }/templates/resetpassword.html | 0 dal/{dal => }/templates/resetpasswordnew.html | 0 dal/{dal => }/templates/send_resetrequest.html | 0 dal/{dal => }/templates/usercreated.html | 0 dal/{dal => }/templates/useroptions.html | 0 dal/{dal => }/urls.py | 0 dal/{dal => }/views.py | 0 dal/{dal => }/wsgi.py | 0 dal/manage.py => manage.py | 0 223 files changed, 7 insertions(+), 7 deletions(-) rename dal/{dal => }/__init__.py (100%) delete mode 100644 dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css rename dal/{dal => }/env.sample (100%) rename dal/{dal => }/models.py (100%) rename dal/{dal => }/settings.py (95%) rename dal/{dal => }/static/datacenterlight/css/bootstrap-3.3.7.min.css (100%) rename dal/{dal => }/static/datacenterlight/css/cms.css (100%) rename dal/{dal => }/static/datacenterlight/css/common.css (100%) rename dal/{dal => }/static/datacenterlight/css/header-slider.css (100%) rename dal/{dal => }/static/datacenterlight/css/hosting.css (100%) rename dal/{dal => }/static/datacenterlight/css/landing-page.css (100%) create mode 100644 dal/static/datacenterlight/font-awesome/css/font-awesome.min.css rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/FontAwesome.otf (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/bordered-pulled.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/core.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/fixed-width.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/font-awesome.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/icons.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/larger.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/list.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/mixins.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/path.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/rotated-flipped.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/spinning.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/stacked.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/less/variables.less (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_core.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_fixed-width.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_icons.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_larger.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_list.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_mixins.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_path.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_spinning.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_stacked.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/_variables.scss (100%) rename dal/{dal => }/static/datacenterlight/font-awesome/scss/font-awesome.scss (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/Montserrat/OFL.txt (100%) rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.eot (100%) rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.svg (100%) rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf (100%) rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.woff (100%) rename dal/{dal => }/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 (100%) rename dal/{dal => }/static/datacenterlight/img/Ceph_Logo.png (100%) rename dal/{dal => }/static/datacenterlight/img/banner-bg copy.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/banner-bg.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/bg.png (100%) rename dal/{dal => }/static/datacenterlight/img/cdistbyungleich.png (100%) rename dal/{dal => }/static/datacenterlight/img/checkmark.png (100%) rename dal/{dal => }/static/datacenterlight/img/configure.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/datacenterlight.png (100%) rename dal/{dal => }/static/datacenterlight/img/dcl-email-bg.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/deluxeroom.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/devuan.png (100%) rename dal/{dal => }/static/datacenterlight/img/django.png (100%) rename dal/{dal => }/static/datacenterlight/img/dog.png (100%) rename dal/{dal => }/static/datacenterlight/img/economy.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/facebook_logo.svg (100%) rename dal/{dal => }/static/datacenterlight/img/favicon.ico (100%) rename dal/{dal => }/static/datacenterlight/img/header-bg.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/home.png (100%) rename dal/{dal => }/static/datacenterlight/img/how.png (100%) rename dal/{dal => }/static/datacenterlight/img/how1.png (100%) rename dal/{dal => }/static/datacenterlight/img/how2.png (100%) rename dal/{dal => }/static/datacenterlight/img/how3.png (100%) rename dal/{dal => }/static/datacenterlight/img/how4.png (100%) rename dal/{dal => }/static/datacenterlight/img/intro-bg.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/ipad.png (100%) rename dal/{dal => }/static/datacenterlight/img/loading.gif (100%) rename dal/{dal => }/static/datacenterlight/img/logo_black.png (100%) rename dal/{dal => }/static/datacenterlight/img/logo_black.svg (100%) rename dal/{dal => }/static/datacenterlight/img/logo_white.svg (100%) rename dal/{dal => }/static/datacenterlight/img/opennebula.png (100%) rename dal/{dal => }/static/datacenterlight/img/pattern.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/phones.png (100%) rename dal/{dal => }/static/datacenterlight/img/presidentialroom.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/prometheus.png (100%) rename dal/{dal => }/static/datacenterlight/img/python-logo.png (100%) rename dal/{dal => }/static/datacenterlight/img/ssd.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/standardroom.jpg (100%) rename dal/{dal => }/static/datacenterlight/img/tayga.png (100%) rename dal/{dal => }/static/datacenterlight/img/ubuntu.png (100%) rename dal/{dal => }/static/datacenterlight/js/bootstrap-3.3.7.min.js (100%) rename dal/{dal => }/static/datacenterlight/js/form.js (100%) rename dal/{dal => }/static/datacenterlight/js/jquery-2.2.4.min.js (100%) rename dal/{dal => }/static/datacenterlight/js/main.js (100%) rename dal/{dal => }/static/hosting/card-django.png (100%) rename dal/{dal => }/static/hosting/card-nodejs.png (100%) rename dal/{dal => }/static/hosting/card-rails.png (100%) rename dal/{dal => }/static/hosting/css/commons.css (100%) rename dal/{dal => }/static/hosting/css/dashboard.css (100%) rename dal/{dal => }/static/hosting/css/landing-page.css (100%) rename dal/{dal => }/static/hosting/css/nodejshosting.css (100%) rename dal/{dal => }/static/hosting/css/order.css (100%) rename dal/{dal => }/static/hosting/css/orders.css (100%) rename dal/{dal => }/static/hosting/css/payment.css (100%) rename dal/{dal => }/static/hosting/css/price_calculator.css (100%) rename dal/{dal => }/static/hosting/css/pricing.css (100%) rename dal/{dal => }/static/hosting/css/user_keys.css (100%) rename dal/{dal => }/static/hosting/css/virtual-machine.css (100%) rename dal/{dal => }/static/hosting/django-intro-bg.png (100%) rename dal/{dal => }/static/hosting/img/24-hours-support.svg (100%) rename dal/{dal => }/static/hosting/img/CH_flag.png (100%) rename dal/{dal => }/static/hosting/img/DE_flag.png (100%) rename dal/{dal => }/static/hosting/img/ajax-loader.gif (100%) rename dal/{dal => }/static/hosting/img/auth-bg-sm.jpg (100%) rename dal/{dal => }/static/hosting/img/auth-bg.jpg (100%) rename dal/{dal => }/static/hosting/img/banner-bg copy.jpg (100%) rename dal/{dal => }/static/hosting/img/banner-bg.jpg (100%) rename dal/{dal => }/static/hosting/img/billing.svg (100%) rename dal/{dal => }/static/hosting/img/card-django.png (100%) rename dal/{dal => }/static/hosting/img/card-nodejs.png (100%) rename dal/{dal => }/static/hosting/img/card-rails.png (100%) rename dal/{dal => }/static/hosting/img/checkmark.png (100%) rename dal/{dal => }/static/hosting/img/configure.jpg (100%) rename dal/{dal => }/static/hosting/img/connected.svg (100%) rename dal/{dal => }/static/hosting/img/copy.svg (100%) rename dal/{dal => }/static/hosting/img/dashboard_settings.svg (100%) rename dal/{dal => }/static/hosting/img/delete.svg (100%) rename dal/{dal => }/static/hosting/img/deluxeroom.jpg (100%) rename dal/{dal => }/static/hosting/img/django-intro-bg.png (100%) rename dal/{dal => }/static/hosting/img/dog.png (100%) rename dal/{dal => }/static/hosting/img/economy.jpg (100%) rename dal/{dal => }/static/hosting/img/favicon.ico (100%) rename dal/{dal => }/static/hosting/img/g222.png (100%) rename dal/{dal => }/static/hosting/img/header-bg.jpg (100%) rename dal/{dal => }/static/hosting/img/home.png (100%) rename dal/{dal => }/static/hosting/img/how.png (100%) rename dal/{dal => }/static/hosting/img/how1.png (100%) rename dal/{dal => }/static/hosting/img/how2.png (100%) rename dal/{dal => }/static/hosting/img/how4.png (100%) rename dal/{dal => }/static/hosting/img/icon-pdf.svg (100%) rename dal/{dal => }/static/hosting/img/icon-print.svg (100%) rename dal/{dal => }/static/hosting/img/intro-bg.jpg (100%) rename dal/{dal => }/static/hosting/img/ipad.png (100%) rename dal/{dal => }/static/hosting/img/key.svg (100%) rename dal/{dal => }/static/hosting/img/login-bg.jpg (100%) rename dal/{dal => }/static/hosting/img/logo_black.png (100%) rename dal/{dal => }/static/hosting/img/logo_black.svg (100%) rename dal/{dal => }/static/hosting/img/logo_white.svg (100%) rename dal/{dal => }/static/hosting/img/nodejs-intro-bg.png (100%) rename dal/{dal => }/static/hosting/img/pattern.jpg (100%) rename dal/{dal => }/static/hosting/img/pattern_original.jpg (100%) rename dal/{dal => }/static/hosting/img/phones.png (100%) rename dal/{dal => }/static/hosting/img/plusVM.svg (100%) rename dal/{dal => }/static/hosting/img/presidentialroom.jpg (100%) rename dal/{dal => }/static/hosting/img/rails-intro-bg.png (100%) rename dal/{dal => }/static/hosting/img/settings.svg (100%) rename dal/{dal => }/static/hosting/img/shopping-cart.svg (100%) rename dal/{dal => }/static/hosting/img/signup-bg.png (100%) rename dal/{dal => }/static/hosting/img/standardroom.jpg (100%) rename dal/{dal => }/static/hosting/img/ubuntu.png (100%) rename dal/{dal => }/static/hosting/img/vm.svg (100%) rename dal/{dal => }/static/hosting/js/createvm.js (100%) rename dal/{dal => }/static/hosting/js/gen-ssh-key.js (100%) rename dal/{dal => }/static/hosting/js/html2canvas.min.js (100%) rename dal/{dal => }/static/hosting/js/html2pdf.min.js (100%) rename dal/{dal => }/static/hosting/js/initial.js (100%) rename dal/{dal => }/static/hosting/js/order.js (100%) rename dal/{dal => }/static/hosting/js/payment.js (100%) rename dal/{dal => }/static/hosting/js/pricing.js (100%) rename dal/{dal => }/static/hosting/js/virtual_machine_detail.js (100%) rename dal/{dal => }/static/hosting/nodejs-intro-bg.png (100%) rename dal/{dal => }/static/hosting/rails-intro-bg.png (100%) rename dal/{dal => }/templates/base.html (100%) rename dal/{dal => }/templates/base_short.html (100%) rename dal/{dal => }/templates/changeddata.html (100%) rename dal/{dal => }/templates/changedpassword.html (100%) rename dal/{dal => }/templates/changepassword.html (100%) rename dal/{dal => }/templates/changeuserdata.html (100%) rename dal/{dal => }/templates/deleteaccount.html (100%) rename dal/{dal => }/templates/deleteduser.html (100%) rename dal/{dal => }/templates/error.html (100%) rename dal/{dal => }/templates/hosting_login.html (100%) rename dal/{dal => }/templates/includes/_card_input.html (100%) rename dal/{dal => }/templates/includes/_contact.html (100%) rename dal/{dal => }/templates/includes/_footer.html (100%) rename dal/{dal => }/templates/includes/_header.html (100%) rename dal/{dal => }/templates/includes/_messages.html (100%) rename dal/{dal => }/templates/includes/_navbar.html (100%) rename dal/{dal => }/templates/includes/_navbar_transparent.html (100%) rename dal/{dal => }/templates/includes/_navbar_user.html (100%) rename dal/{dal => }/templates/includes/_our_infrastructure.html (100%) rename dal/{dal => }/templates/includes/_pricing.html (100%) rename dal/{dal => }/templates/includes/_your_infrastructure.html (100%) rename dal/{dal => }/templates/landing.html (100%) rename dal/{dal => }/templates/loginfailed.html (100%) rename dal/{dal => }/templates/mustbeloggedin.html (100%) rename dal/{dal => }/templates/registeruser.html (100%) rename dal/{dal => }/templates/resetpassword.html (100%) rename dal/{dal => }/templates/resetpasswordnew.html (100%) rename dal/{dal => }/templates/send_resetrequest.html (100%) rename dal/{dal => }/templates/usercreated.html (100%) rename dal/{dal => }/templates/useroptions.html (100%) rename dal/{dal => }/urls.py (100%) rename dal/{dal => }/views.py (100%) rename dal/{dal => }/wsgi.py (100%) rename dal/manage.py => manage.py (100%) diff --git a/dal/dal/__init__.py b/dal/__init__.py similarity index 100% rename from dal/dal/__init__.py rename to dal/__init__.py diff --git a/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css b/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css deleted file mode 100644 index 540440c..0000000 --- a/dal/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/dal/dal/env.sample b/dal/env.sample similarity index 100% rename from dal/dal/env.sample rename to dal/env.sample diff --git a/dal/dal/models.py b/dal/models.py similarity index 100% rename from dal/dal/models.py rename to dal/models.py diff --git a/dal/dal/settings.py b/dal/settings.py similarity index 95% rename from dal/dal/settings.py rename to dal/settings.py index a284663..7c30a2a 100644 --- a/dal/dal/settings.py +++ b/dal/settings.py @@ -120,7 +120,7 @@ STATIC_URL = '/static/' ############################# To be fixed -STATIC_ROOT = os.path.dirname('/home/downhill/ungleich/vuejsuserservice/dal/dal/static/') +STATIC_ROOT= os.path.join(BASE_DIR, 'static/') # Database # https://docs.djangoproject.com/en/1.10/ref/settings/#databases @@ -131,7 +131,7 @@ DATABASES = { 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } -SECRET_KEY = 'rn=f&ecp#&#escxpk!0e%a$i3sbm$z@5+g4h9q+w7-83*f2f-i' +SECRET_KEY = os.environ.get('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = os.environ.get('DEBUG', False) diff --git a/dal/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css b/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css similarity index 100% rename from dal/dal/static/datacenterlight/css/bootstrap-3.3.7.min.css rename to dal/static/datacenterlight/css/bootstrap-3.3.7.min.css diff --git a/dal/dal/static/datacenterlight/css/cms.css b/dal/static/datacenterlight/css/cms.css similarity index 100% rename from dal/dal/static/datacenterlight/css/cms.css rename to dal/static/datacenterlight/css/cms.css diff --git a/dal/dal/static/datacenterlight/css/common.css b/dal/static/datacenterlight/css/common.css similarity index 100% rename from dal/dal/static/datacenterlight/css/common.css rename to dal/static/datacenterlight/css/common.css diff --git a/dal/dal/static/datacenterlight/css/header-slider.css b/dal/static/datacenterlight/css/header-slider.css similarity index 100% rename from dal/dal/static/datacenterlight/css/header-slider.css rename to dal/static/datacenterlight/css/header-slider.css diff --git a/dal/dal/static/datacenterlight/css/hosting.css b/dal/static/datacenterlight/css/hosting.css similarity index 100% rename from dal/dal/static/datacenterlight/css/hosting.css rename to dal/static/datacenterlight/css/hosting.css diff --git a/dal/dal/static/datacenterlight/css/landing-page.css b/dal/static/datacenterlight/css/landing-page.css similarity index 100% rename from dal/dal/static/datacenterlight/css/landing-page.css rename to dal/static/datacenterlight/css/landing-page.css diff --git a/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css b/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css new file mode 100644 index 0000000..248ea7a --- /dev/null +++ b/dal/static/datacenterlight/font-awesome/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale} .fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%} .fa-2x{font-size:2em} .fa-3x{font-size:3em} .fa-4x{font-size:4em} .fa-5x{font-size:5em} .fa-fw{width:1.28571429em;text-align:center} .fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none} .fa-ul>li{position:relative} .fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center} .fa-li.fa-lg{left:-1.85714286em} .fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em} .fa-pull-left{float:left} .fa-pull-right{float:right} .fa.fa-pull-left{margin-right:.3em} .fa.fa-pull-right{margin-left:.3em} .pull-right{float:right} .pull-left{float:left} .fa.pull-left{margin-right:.3em} .fa.pull-right{margin-left:.3em} .fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear} .fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)} @-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}} @keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}} .fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)} .fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)} .fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)} .fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)} .fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)} :root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none} .fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle} .fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center} .fa-stack-1x{line-height:inherit} .fa-stack-2x{font-size:2em} .fa-inverse{color:#fff} .fa-glass:before{content:"\f000"} .fa-music:before{content:"\f001"} .fa-search:before{content:"\f002"} .fa-envelope-o:before{content:"\f003"} .fa-heart:before{content:"\f004"} .fa-star:before{content:"\f005"} .fa-star-o:before{content:"\f006"} .fa-user:before{content:"\f007"} .fa-film:before{content:"\f008"} .fa-th-large:before{content:"\f009"} .fa-th:before{content:"\f00a"} .fa-th-list:before{content:"\f00b"} .fa-check:before{content:"\f00c"} .fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"} .fa-search-plus:before{content:"\f00e"} .fa-search-minus:before{content:"\f010"} .fa-power-off:before{content:"\f011"} .fa-signal:before{content:"\f012"} .fa-gear:before,.fa-cog:before{content:"\f013"} .fa-trash-o:before{content:"\f014"} .fa-home:before{content:"\f015"} .fa-file-o:before{content:"\f016"} .fa-clock-o:before{content:"\f017"} .fa-road:before{content:"\f018"} .fa-download:before{content:"\f019"} .fa-arrow-circle-o-down:before{content:"\f01a"} .fa-arrow-circle-o-up:before{content:"\f01b"} .fa-inbox:before{content:"\f01c"} .fa-play-circle-o:before{content:"\f01d"} .fa-rotate-right:before,.fa-repeat:before{content:"\f01e"} .fa-refresh:before{content:"\f021"} .fa-list-alt:before{content:"\f022"} .fa-lock:before{content:"\f023"} .fa-flag:before{content:"\f024"} .fa-headphones:before{content:"\f025"} .fa-volume-off:before{content:"\f026"} .fa-volume-down:before{content:"\f027"} .fa-volume-up:before{content:"\f028"} .fa-qrcode:before{content:"\f029"} .fa-barcode:before{content:"\f02a"} .fa-tag:before{content:"\f02b"} .fa-tags:before{content:"\f02c"} .fa-book:before{content:"\f02d"} .fa-bookmark:before{content:"\f02e"} .fa-print:before{content:"\f02f"} .fa-camera:before{content:"\f030"} .fa-font:before{content:"\f031"} .fa-bold:before{content:"\f032"} .fa-italic:before{content:"\f033"} .fa-text-height:before{content:"\f034"} .fa-text-width:before{content:"\f035"} .fa-align-left:before{content:"\f036"} .fa-align-center:before{content:"\f037"} .fa-align-right:before{content:"\f038"} .fa-align-justify:before{content:"\f039"} .fa-list:before{content:"\f03a"} .fa-dedent:before,.fa-outdent:before{content:"\f03b"} .fa-indent:before{content:"\f03c"} .fa-video-camera:before{content:"\f03d"} .fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"} .fa-pencil:before{content:"\f040"} .fa-map-marker:before{content:"\f041"} .fa-adjust:before{content:"\f042"} .fa-tint:before{content:"\f043"} .fa-edit:before,.fa-pencil-square-o:before{content:"\f044"} .fa-share-square-o:before{content:"\f045"} .fa-check-square-o:before{content:"\f046"} .fa-arrows:before{content:"\f047"} .fa-step-backward:before{content:"\f048"} .fa-fast-backward:before{content:"\f049"} .fa-backward:before{content:"\f04a"} .fa-play:before{content:"\f04b"} .fa-pause:before{content:"\f04c"} .fa-stop:before{content:"\f04d"} .fa-forward:before{content:"\f04e"} .fa-fast-forward:before{content:"\f050"} .fa-step-forward:before{content:"\f051"} .fa-eject:before{content:"\f052"} .fa-chevron-left:before{content:"\f053"} .fa-chevron-right:before{content:"\f054"} .fa-plus-circle:before{content:"\f055"} .fa-minus-circle:before{content:"\f056"} .fa-times-circle:before{content:"\f057"} .fa-check-circle:before{content:"\f058"} .fa-question-circle:before{content:"\f059"} .fa-info-circle:before{content:"\f05a"} .fa-crosshairs:before{content:"\f05b"} .fa-times-circle-o:before{content:"\f05c"} .fa-check-circle-o:before{content:"\f05d"} .fa-ban:before{content:"\f05e"} .fa-arrow-left:before{content:"\f060"} .fa-arrow-right:before{content:"\f061"} .fa-arrow-up:before{content:"\f062"} .fa-arrow-down:before{content:"\f063"} .fa-mail-forward:before,.fa-share:before{content:"\f064"} .fa-expand:before{content:"\f065"} .fa-compress:before{content:"\f066"} .fa-plus:before{content:"\f067"} .fa-minus:before{content:"\f068"} .fa-asterisk:before{content:"\f069"} .fa-exclamation-circle:before{content:"\f06a"} .fa-gift:before{content:"\f06b"} .fa-leaf:before{content:"\f06c"} .fa-fire:before{content:"\f06d"} .fa-eye:before{content:"\f06e"} .fa-eye-slash:before{content:"\f070"} .fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"} .fa-plane:before{content:"\f072"} .fa-calendar:before{content:"\f073"} .fa-random:before{content:"\f074"} .fa-comment:before{content:"\f075"} .fa-magnet:before{content:"\f076"} .fa-chevron-up:before{content:"\f077"} .fa-chevron-down:before{content:"\f078"} .fa-retweet:before{content:"\f079"} .fa-shopping-cart:before{content:"\f07a"} .fa-folder:before{content:"\f07b"} .fa-folder-open:before{content:"\f07c"} .fa-arrows-v:before{content:"\f07d"} .fa-arrows-h:before{content:"\f07e"} .fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"} .fa-twitter-square:before{content:"\f081"} .fa-facebook-square:before{content:"\f082"} .fa-camera-retro:before{content:"\f083"} .fa-key:before{content:"\f084"} .fa-gears:before,.fa-cogs:before{content:"\f085"} .fa-comments:before{content:"\f086"} .fa-thumbs-o-up:before{content:"\f087"} .fa-thumbs-o-down:before{content:"\f088"} .fa-star-half:before{content:"\f089"} .fa-heart-o:before{content:"\f08a"} .fa-sign-out:before{content:"\f08b"} .fa-linkedin-square:before{content:"\f08c"} .fa-thumb-tack:before{content:"\f08d"} .fa-external-link:before{content:"\f08e"} .fa-sign-in:before{content:"\f090"} .fa-trophy:before{content:"\f091"} .fa-github-square:before{content:"\f092"} .fa-upload:before{content:"\f093"} .fa-lemon-o:before{content:"\f094"} .fa-phone:before{content:"\f095"} .fa-square-o:before{content:"\f096"} .fa-bookmark-o:before{content:"\f097"} .fa-phone-square:before{content:"\f098"} .fa-twitter:before{content:"\f099"} .fa-facebook-f:before,.fa-facebook:before{content:"\f09a"} .fa-github:before{content:"\f09b"} .fa-unlock:before{content:"\f09c"} .fa-credit-card:before{content:"\f09d"} .fa-feed:before,.fa-rss:before{content:"\f09e"} .fa-hdd-o:before{content:"\f0a0"} .fa-bullhorn:before{content:"\f0a1"} .fa-bell:before{content:"\f0f3"} .fa-certificate:before{content:"\f0a3"} .fa-hand-o-right:before{content:"\f0a4"} .fa-hand-o-left:before{content:"\f0a5"} .fa-hand-o-up:before{content:"\f0a6"} .fa-hand-o-down:before{content:"\f0a7"} .fa-arrow-circle-left:before{content:"\f0a8"} .fa-arrow-circle-right:before{content:"\f0a9"} .fa-arrow-circle-up:before{content:"\f0aa"} .fa-arrow-circle-down:before{content:"\f0ab"} .fa-globe:before{content:"\f0ac"} .fa-wrench:before{content:"\f0ad"} .fa-tasks:before{content:"\f0ae"} .fa-filter:before{content:"\f0b0"} .fa-briefcase:before{content:"\f0b1"} .fa-arrows-alt:before{content:"\f0b2"} .fa-group:before,.fa-users:before{content:"\f0c0"} .fa-chain:before,.fa-link:before{content:"\f0c1"} .fa-cloud:before{content:"\f0c2"} .fa-flask:before{content:"\f0c3"} .fa-cut:before,.fa-scissors:before{content:"\f0c4"} .fa-copy:before,.fa-files-o:before{content:"\f0c5"} .fa-paperclip:before{content:"\f0c6"} .fa-save:before,.fa-floppy-o:before{content:"\f0c7"} .fa-square:before{content:"\f0c8"} .fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"} .fa-list-ul:before{content:"\f0ca"} .fa-list-ol:before{content:"\f0cb"} .fa-strikethrough:before{content:"\f0cc"} .fa-underline:before{content:"\f0cd"} .fa-table:before{content:"\f0ce"} .fa-magic:before{content:"\f0d0"} .fa-truck:before{content:"\f0d1"} .fa-pinterest:before{content:"\f0d2"} .fa-pinterest-square:before{content:"\f0d3"} .fa-google-plus-square:before{content:"\f0d4"} .fa-google-plus:before{content:"\f0d5"} .fa-money:before{content:"\f0d6"} .fa-caret-down:before{content:"\f0d7"} .fa-caret-up:before{content:"\f0d8"} .fa-caret-left:before{content:"\f0d9"} .fa-caret-right:before{content:"\f0da"} .fa-columns:before{content:"\f0db"} .fa-unsorted:before,.fa-sort:before{content:"\f0dc"} .fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"} .fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"} .fa-envelope:before{content:"\f0e0"} .fa-linkedin:before{content:"\f0e1"} .fa-rotate-left:before,.fa-undo:before{content:"\f0e2"} .fa-legal:before,.fa-gavel:before{content:"\f0e3"} .fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"} .fa-comment-o:before{content:"\f0e5"} .fa-comments-o:before{content:"\f0e6"} .fa-flash:before,.fa-bolt:before{content:"\f0e7"} .fa-sitemap:before{content:"\f0e8"} .fa-umbrella:before{content:"\f0e9"} .fa-paste:before,.fa-clipboard:before{content:"\f0ea"} .fa-lightbulb-o:before{content:"\f0eb"} .fa-exchange:before{content:"\f0ec"} .fa-cloud-download:before{content:"\f0ed"} .fa-cloud-upload:before{content:"\f0ee"} .fa-user-md:before{content:"\f0f0"} .fa-stethoscope:before{content:"\f0f1"} .fa-suitcase:before{content:"\f0f2"} .fa-bell-o:before{content:"\f0a2"} .fa-coffee:before{content:"\f0f4"} .fa-cutlery:before{content:"\f0f5"} .fa-file-text-o:before{content:"\f0f6"} .fa-building-o:before{content:"\f0f7"} .fa-hospital-o:before{content:"\f0f8"} .fa-ambulance:before{content:"\f0f9"} .fa-medkit:before{content:"\f0fa"} .fa-fighter-jet:before{content:"\f0fb"} .fa-beer:before{content:"\f0fc"} .fa-h-square:before{content:"\f0fd"} .fa-plus-square:before{content:"\f0fe"} .fa-angle-double-left:before{content:"\f100"} .fa-angle-double-right:before{content:"\f101"} .fa-angle-double-up:before{content:"\f102"} .fa-angle-double-down:before{content:"\f103"} .fa-angle-left:before{content:"\f104"} .fa-angle-right:before{content:"\f105"} .fa-angle-up:before{content:"\f106"} .fa-angle-down:before{content:"\f107"} .fa-desktop:before{content:"\f108"} .fa-laptop:before{content:"\f109"} .fa-tablet:before{content:"\f10a"} .fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"} .fa-circle-o:before{content:"\f10c"} .fa-quote-left:before{content:"\f10d"} .fa-quote-right:before{content:"\f10e"} .fa-spinner:before{content:"\f110"} .fa-circle:before{content:"\f111"} .fa-mail-reply:before,.fa-reply:before{content:"\f112"} .fa-github-alt:before{content:"\f113"} .fa-folder-o:before{content:"\f114"} .fa-folder-open-o:before{content:"\f115"} .fa-smile-o:before{content:"\f118"} .fa-frown-o:before{content:"\f119"} .fa-meh-o:before{content:"\f11a"} .fa-gamepad:before{content:"\f11b"} .fa-keyboard-o:before{content:"\f11c"} .fa-flag-o:before{content:"\f11d"} .fa-flag-checkered:before{content:"\f11e"} .fa-terminal:before{content:"\f120"} .fa-code:before{content:"\f121"} .fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"} .fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"} .fa-location-arrow:before{content:"\f124"} .fa-crop:before{content:"\f125"} .fa-code-fork:before{content:"\f126"} .fa-unlink:before,.fa-chain-broken:before{content:"\f127"} .fa-question:before{content:"\f128"} .fa-info:before{content:"\f129"} .fa-exclamation:before{content:"\f12a"} .fa-superscript:before{content:"\f12b"} .fa-subscript:before{content:"\f12c"} .fa-eraser:before{content:"\f12d"} .fa-puzzle-piece:before{content:"\f12e"} .fa-microphone:before{content:"\f130"} .fa-microphone-slash:before{content:"\f131"} .fa-shield:before{content:"\f132"} .fa-calendar-o:before{content:"\f133"} .fa-fire-extinguisher:before{content:"\f134"} .fa-rocket:before{content:"\f135"} .fa-maxcdn:before{content:"\f136"} .fa-chevron-circle-left:before{content:"\f137"} .fa-chevron-circle-right:before{content:"\f138"} .fa-chevron-circle-up:before{content:"\f139"} .fa-chevron-circle-down:before{content:"\f13a"} .fa-html5:before{content:"\f13b"} .fa-css3:before{content:"\f13c"} .fa-anchor:before{content:"\f13d"} .fa-unlock-alt:before{content:"\f13e"} .fa-bullseye:before{content:"\f140"} .fa-ellipsis-h:before{content:"\f141"} .fa-ellipsis-v:before{content:"\f142"} .fa-rss-square:before{content:"\f143"} .fa-play-circle:before{content:"\f144"} .fa-ticket:before{content:"\f145"} .fa-minus-square:before{content:"\f146"} .fa-minus-square-o:before{content:"\f147"} .fa-level-up:before{content:"\f148"} .fa-level-down:before{content:"\f149"} .fa-check-square:before{content:"\f14a"} .fa-pencil-square:before{content:"\f14b"} .fa-external-link-square:before{content:"\f14c"} .fa-share-square:before{content:"\f14d"} .fa-compass:before{content:"\f14e"} .fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"} .fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"} .fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"} .fa-euro:before,.fa-eur:before{content:"\f153"} .fa-gbp:before{content:"\f154"} .fa-dollar:before,.fa-usd:before{content:"\f155"} .fa-rupee:before,.fa-inr:before{content:"\f156"} .fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"} .fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"} .fa-won:before,.fa-krw:before{content:"\f159"} .fa-bitcoin:before,.fa-btc:before{content:"\f15a"} .fa-file:before{content:"\f15b"} .fa-file-text:before{content:"\f15c"} .fa-sort-alpha-asc:before{content:"\f15d"} .fa-sort-alpha-desc:before{content:"\f15e"} .fa-sort-amount-asc:before{content:"\f160"} .fa-sort-amount-desc:before{content:"\f161"} .fa-sort-numeric-asc:before{content:"\f162"} .fa-sort-numeric-desc:before{content:"\f163"} .fa-thumbs-up:before{content:"\f164"} .fa-thumbs-down:before{content:"\f165"} .fa-youtube-square:before{content:"\f166"} .fa-youtube:before{content:"\f167"} .fa-xing:before{content:"\f168"} .fa-xing-square:before{content:"\f169"} .fa-youtube-play:before{content:"\f16a"} .fa-dropbox:before{content:"\f16b"} .fa-stack-overflow:before{content:"\f16c"} .fa-instagram:before{content:"\f16d"} .fa-flickr:before{content:"\f16e"} .fa-adn:before{content:"\f170"} .fa-bitbucket:before{content:"\f171"} .fa-bitbucket-square:before{content:"\f172"} .fa-tumblr:before{content:"\f173"} .fa-tumblr-square:before{content:"\f174"} .fa-long-arrow-down:before{content:"\f175"} .fa-long-arrow-up:before{content:"\f176"} .fa-long-arrow-left:before{content:"\f177"} .fa-long-arrow-right:before{content:"\f178"} .fa-apple:before{content:"\f179"} .fa-windows:before{content:"\f17a"} .fa-android:before{content:"\f17b"} .fa-linux:before{content:"\f17c"} .fa-dribbble:before{content:"\f17d"} .fa-skype:before{content:"\f17e"} .fa-foursquare:before{content:"\f180"} .fa-trello:before{content:"\f181"} .fa-female:before{content:"\f182"} .fa-male:before{content:"\f183"} .fa-gittip:before,.fa-gratipay:before{content:"\f184"} .fa-sun-o:before{content:"\f185"} .fa-moon-o:before{content:"\f186"} .fa-archive:before{content:"\f187"} .fa-bug:before{content:"\f188"} .fa-vk:before{content:"\f189"} .fa-weibo:before{content:"\f18a"} .fa-renren:before{content:"\f18b"} .fa-pagelines:before{content:"\f18c"} .fa-stack-exchange:before{content:"\f18d"} .fa-arrow-circle-o-right:before{content:"\f18e"} .fa-arrow-circle-o-left:before{content:"\f190"} .fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"} .fa-dot-circle-o:before{content:"\f192"} .fa-wheelchair:before{content:"\f193"} .fa-vimeo-square:before{content:"\f194"} .fa-turkish-lira:before,.fa-try:before{content:"\f195"} .fa-plus-square-o:before{content:"\f196"} .fa-space-shuttle:before{content:"\f197"} .fa-slack:before{content:"\f198"} .fa-envelope-square:before{content:"\f199"} .fa-wordpress:before{content:"\f19a"} .fa-openid:before{content:"\f19b"} .fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"} .fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"} .fa-yahoo:before{content:"\f19e"} .fa-google:before{content:"\f1a0"} .fa-reddit:before{content:"\f1a1"} .fa-reddit-square:before{content:"\f1a2"} .fa-stumbleupon-circle:before{content:"\f1a3"} .fa-stumbleupon:before{content:"\f1a4"} .fa-delicious:before{content:"\f1a5"} .fa-digg:before{content:"\f1a6"} .fa-pied-piper-pp:before{content:"\f1a7"} .fa-pied-piper-alt:before{content:"\f1a8"} .fa-drupal:before{content:"\f1a9"} .fa-joomla:before{content:"\f1aa"} .fa-language:before{content:"\f1ab"} .fa-fax:before{content:"\f1ac"} .fa-building:before{content:"\f1ad"} .fa-child:before{content:"\f1ae"} .fa-paw:before{content:"\f1b0"} .fa-spoon:before{content:"\f1b1"} .fa-cube:before{content:"\f1b2"} .fa-cubes:before{content:"\f1b3"} .fa-behance:before{content:"\f1b4"} .fa-behance-square:before{content:"\f1b5"} .fa-steam:before{content:"\f1b6"} .fa-steam-square:before{content:"\f1b7"} .fa-recycle:before{content:"\f1b8"} .fa-automobile:before,.fa-car:before{content:"\f1b9"} .fa-cab:before,.fa-taxi:before{content:"\f1ba"} .fa-tree:before{content:"\f1bb"} .fa-spotify:before{content:"\f1bc"} .fa-deviantart:before{content:"\f1bd"} .fa-soundcloud:before{content:"\f1be"} .fa-database:before{content:"\f1c0"} .fa-file-pdf-o:before{content:"\f1c1"} .fa-file-word-o:before{content:"\f1c2"} .fa-file-excel-o:before{content:"\f1c3"} .fa-file-powerpoint-o:before{content:"\f1c4"} .fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"} .fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"} .fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"} .fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"} .fa-file-code-o:before{content:"\f1c9"} .fa-vine:before{content:"\f1ca"} .fa-codepen:before{content:"\f1cb"} .fa-jsfiddle:before{content:"\f1cc"} .fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"} .fa-circle-o-notch:before{content:"\f1ce"} .fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"} .fa-ge:before,.fa-empire:before{content:"\f1d1"} .fa-git-square:before{content:"\f1d2"} .fa-git:before{content:"\f1d3"} .fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"} .fa-tencent-weibo:before{content:"\f1d5"} .fa-qq:before{content:"\f1d6"} .fa-wechat:before,.fa-weixin:before{content:"\f1d7"} .fa-send:before,.fa-paper-plane:before{content:"\f1d8"} .fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"} .fa-history:before{content:"\f1da"} .fa-circle-thin:before{content:"\f1db"} .fa-header:before{content:"\f1dc"} .fa-paragraph:before{content:"\f1dd"} .fa-sliders:before{content:"\f1de"} .fa-share-alt:before{content:"\f1e0"} .fa-share-alt-square:before{content:"\f1e1"} .fa-bomb:before{content:"\f1e2"} .fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"} .fa-tty:before{content:"\f1e4"} .fa-binoculars:before{content:"\f1e5"} .fa-plug:before{content:"\f1e6"} .fa-slideshare:before{content:"\f1e7"} .fa-twitch:before{content:"\f1e8"} .fa-yelp:before{content:"\f1e9"} .fa-newspaper-o:before{content:"\f1ea"} .fa-wifi:before{content:"\f1eb"} .fa-calculator:before{content:"\f1ec"} .fa-paypal:before{content:"\f1ed"} .fa-google-wallet:before{content:"\f1ee"} .fa-cc-visa:before{content:"\f1f0"} .fa-cc-mastercard:before{content:"\f1f1"} .fa-cc-discover:before{content:"\f1f2"} .fa-cc-amex:before{content:"\f1f3"} .fa-cc-paypal:before{content:"\f1f4"} .fa-cc-stripe:before{content:"\f1f5"} .fa-bell-slash:before{content:"\f1f6"} .fa-bell-slash-o:before{content:"\f1f7"} .fa-trash:before{content:"\f1f8"} .fa-copyright:before{content:"\f1f9"} .fa-at:before{content:"\f1fa"} .fa-eyedropper:before{content:"\f1fb"} .fa-paint-brush:before{content:"\f1fc"} .fa-birthday-cake:before{content:"\f1fd"} .fa-area-chart:before{content:"\f1fe"} .fa-pie-chart:before{content:"\f200"} .fa-line-chart:before{content:"\f201"} .fa-lastfm:before{content:"\f202"} .fa-lastfm-square:before{content:"\f203"} .fa-toggle-off:before{content:"\f204"} .fa-toggle-on:before{content:"\f205"} .fa-bicycle:before{content:"\f206"} .fa-bus:before{content:"\f207"} .fa-ioxhost:before{content:"\f208"} .fa-angellist:before{content:"\f209"} .fa-cc:before{content:"\f20a"} .fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"} .fa-meanpath:before{content:"\f20c"} .fa-buysellads:before{content:"\f20d"} .fa-connectdevelop:before{content:"\f20e"} .fa-dashcube:before{content:"\f210"} .fa-forumbee:before{content:"\f211"} .fa-leanpub:before{content:"\f212"} .fa-sellsy:before{content:"\f213"} .fa-shirtsinbulk:before{content:"\f214"} .fa-simplybuilt:before{content:"\f215"} .fa-skyatlas:before{content:"\f216"} .fa-cart-plus:before{content:"\f217"} .fa-cart-arrow-down:before{content:"\f218"} .fa-diamond:before{content:"\f219"} .fa-ship:before{content:"\f21a"} .fa-user-secret:before{content:"\f21b"} .fa-motorcycle:before{content:"\f21c"} .fa-street-view:before{content:"\f21d"} .fa-heartbeat:before{content:"\f21e"} .fa-venus:before{content:"\f221"} .fa-mars:before{content:"\f222"} .fa-mercury:before{content:"\f223"} .fa-intersex:before,.fa-transgender:before{content:"\f224"} .fa-transgender-alt:before{content:"\f225"} .fa-venus-double:before{content:"\f226"} .fa-mars-double:before{content:"\f227"} .fa-venus-mars:before{content:"\f228"} .fa-mars-stroke:before{content:"\f229"} .fa-mars-stroke-v:before{content:"\f22a"} .fa-mars-stroke-h:before{content:"\f22b"} .fa-neuter:before{content:"\f22c"} .fa-genderless:before{content:"\f22d"} .fa-facebook-official:before{content:"\f230"} .fa-pinterest-p:before{content:"\f231"} .fa-whatsapp:before{content:"\f232"} .fa-server:before{content:"\f233"} .fa-user-plus:before{content:"\f234"} .fa-user-times:before{content:"\f235"} .fa-hotel:before,.fa-bed:before{content:"\f236"} .fa-viacoin:before{content:"\f237"} .fa-train:before{content:"\f238"} .fa-subway:before{content:"\f239"} .fa-medium:before{content:"\f23a"} .fa-yc:before,.fa-y-combinator:before{content:"\f23b"} .fa-optin-monster:before{content:"\f23c"} .fa-opencart:before{content:"\f23d"} .fa-expeditedssl:before{content:"\f23e"} .fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"} .fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"} .fa-battery-2:before,.fa-battery-half:before{content:"\f242"} .fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"} .fa-battery-0:before,.fa-battery-empty:before{content:"\f244"} .fa-mouse-pointer:before{content:"\f245"} .fa-i-cursor:before{content:"\f246"} .fa-object-group:before{content:"\f247"} .fa-object-ungroup:before{content:"\f248"} .fa-sticky-note:before{content:"\f249"} .fa-sticky-note-o:before{content:"\f24a"} .fa-cc-jcb:before{content:"\f24b"} .fa-cc-diners-club:before{content:"\f24c"} .fa-clone:before{content:"\f24d"} .fa-balance-scale:before{content:"\f24e"} .fa-hourglass-o:before{content:"\f250"} .fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"} .fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"} .fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"} .fa-hourglass:before{content:"\f254"} .fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"} .fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"} .fa-hand-scissors-o:before{content:"\f257"} .fa-hand-lizard-o:before{content:"\f258"} .fa-hand-spock-o:before{content:"\f259"} .fa-hand-pointer-o:before{content:"\f25a"} .fa-hand-peace-o:before{content:"\f25b"} .fa-trademark:before{content:"\f25c"} .fa-registered:before{content:"\f25d"} .fa-creative-commons:before{content:"\f25e"} .fa-gg:before{content:"\f260"} .fa-gg-circle:before{content:"\f261"} .fa-tripadvisor:before{content:"\f262"} .fa-odnoklassniki:before{content:"\f263"} .fa-odnoklassniki-square:before{content:"\f264"} .fa-get-pocket:before{content:"\f265"} .fa-wikipedia-w:before{content:"\f266"} .fa-safari:before{content:"\f267"} .fa-chrome:before{content:"\f268"} .fa-firefox:before{content:"\f269"} .fa-opera:before{content:"\f26a"} .fa-internet-explorer:before{content:"\f26b"} .fa-tv:before,.fa-television:before{content:"\f26c"} .fa-contao:before{content:"\f26d"} .fa-500px:before{content:"\f26e"} .fa-amazon:before{content:"\f270"} .fa-calendar-plus-o:before{content:"\f271"} .fa-calendar-minus-o:before{content:"\f272"} .fa-calendar-times-o:before{content:"\f273"} .fa-calendar-check-o:before{content:"\f274"} .fa-industry:before{content:"\f275"} .fa-map-pin:before{content:"\f276"} .fa-map-signs:before{content:"\f277"} .fa-map-o:before{content:"\f278"} .fa-map:before{content:"\f279"} .fa-commenting:before{content:"\f27a"} .fa-commenting-o:before{content:"\f27b"} .fa-houzz:before{content:"\f27c"} .fa-vimeo:before{content:"\f27d"} .fa-black-tie:before{content:"\f27e"} .fa-fonticons:before{content:"\f280"} .fa-reddit-alien:before{content:"\f281"} .fa-edge:before{content:"\f282"} .fa-credit-card-alt:before{content:"\f283"} .fa-codiepie:before{content:"\f284"} .fa-modx:before{content:"\f285"} .fa-fort-awesome:before{content:"\f286"} .fa-usb:before{content:"\f287"} .fa-product-hunt:before{content:"\f288"} .fa-mixcloud:before{content:"\f289"} .fa-scribd:before{content:"\f28a"} .fa-pause-circle:before{content:"\f28b"} .fa-pause-circle-o:before{content:"\f28c"} .fa-stop-circle:before{content:"\f28d"} .fa-stop-circle-o:before{content:"\f28e"} .fa-shopping-bag:before{content:"\f290"} .fa-shopping-basket:before{content:"\f291"} .fa-hashtag:before{content:"\f292"} .fa-bluetooth:before{content:"\f293"} .fa-bluetooth-b:before{content:"\f294"} .fa-percent:before{content:"\f295"} .fa-gitlab:before{content:"\f296"} .fa-wpbeginner:before{content:"\f297"} .fa-wpforms:before{content:"\f298"} .fa-envira:before{content:"\f299"} .fa-universal-access:before{content:"\f29a"} .fa-wheelchair-alt:before{content:"\f29b"} .fa-question-circle-o:before{content:"\f29c"} .fa-blind:before{content:"\f29d"} .fa-audio-description:before{content:"\f29e"} .fa-volume-control-phone:before{content:"\f2a0"} .fa-braille:before{content:"\f2a1"} .fa-assistive-listening-systems:before{content:"\f2a2"} .fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"} .fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"} .fa-glide:before{content:"\f2a5"} .fa-glide-g:before{content:"\f2a6"} .fa-signing:before,.fa-sign-language:before{content:"\f2a7"} .fa-low-vision:before{content:"\f2a8"} .fa-viadeo:before{content:"\f2a9"} .fa-viadeo-square:before{content:"\f2aa"} .fa-snapchat:before{content:"\f2ab"} .fa-snapchat-ghost:before{content:"\f2ac"} .fa-snapchat-square:before{content:"\f2ad"} .fa-pied-piper:before{content:"\f2ae"} .fa-first-order:before{content:"\f2b0"} .fa-yoast:before{content:"\f2b1"} .fa-themeisle:before{content:"\f2b2"} .fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"} .fa-fa:before,.fa-font-awesome:before{content:"\f2b4"} .fa-handshake-o:before{content:"\f2b5"} .fa-envelope-open:before{content:"\f2b6"} .fa-envelope-open-o:before{content:"\f2b7"} .fa-linode:before{content:"\f2b8"} .fa-address-book:before{content:"\f2b9"} .fa-address-book-o:before{content:"\f2ba"} .fa-vcard:before,.fa-address-card:before{content:"\f2bb"} .fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"} .fa-user-circle:before{content:"\f2bd"} .fa-user-circle-o:before{content:"\f2be"} .fa-user-o:before{content:"\f2c0"} .fa-id-badge:before{content:"\f2c1"} .fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"} .fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"} .fa-quora:before{content:"\f2c4"} .fa-free-code-camp:before{content:"\f2c5"} .fa-telegram:before{content:"\f2c6"} .fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"} .fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"} .fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"} .fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"} .fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"} .fa-shower:before{content:"\f2cc"} .fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"} .fa-podcast:before{content:"\f2ce"} .fa-window-maximize:before{content:"\f2d0"} .fa-window-minimize:before{content:"\f2d1"} .fa-window-restore:before{content:"\f2d2"} .fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"} .fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"} .fa-bandcamp:before{content:"\f2d5"} .fa-grav:before{content:"\f2d6"} .fa-etsy:before{content:"\f2d7"} .fa-imdb:before{content:"\f2d8"} .fa-ravelry:before{content:"\f2d9"} .fa-eercast:before{content:"\f2da"} .fa-microchip:before{content:"\f2db"} .fa-snowflake-o:before{content:"\f2dc"} .fa-superpowers:before{content:"\f2dd"} .fa-wpexplorer:before{content:"\f2de"} .fa-meetup:before{content:"\f2e0"} .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0} .sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf b/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf rename to dal/static/datacenterlight/font-awesome/fonts/FontAwesome.otf diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.eot diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.svg diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.ttf diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff diff --git a/dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 b/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 rename to dal/static/datacenterlight/font-awesome/fonts/fontawesome-webfont.woff2 diff --git a/dal/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less b/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/bordered-pulled.less rename to dal/static/datacenterlight/font-awesome/less/bordered-pulled.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/core.less b/dal/static/datacenterlight/font-awesome/less/core.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/core.less rename to dal/static/datacenterlight/font-awesome/less/core.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/fixed-width.less b/dal/static/datacenterlight/font-awesome/less/fixed-width.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/fixed-width.less rename to dal/static/datacenterlight/font-awesome/less/fixed-width.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/font-awesome.less b/dal/static/datacenterlight/font-awesome/less/font-awesome.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/font-awesome.less rename to dal/static/datacenterlight/font-awesome/less/font-awesome.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/icons.less b/dal/static/datacenterlight/font-awesome/less/icons.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/icons.less rename to dal/static/datacenterlight/font-awesome/less/icons.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/larger.less b/dal/static/datacenterlight/font-awesome/less/larger.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/larger.less rename to dal/static/datacenterlight/font-awesome/less/larger.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/list.less b/dal/static/datacenterlight/font-awesome/less/list.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/list.less rename to dal/static/datacenterlight/font-awesome/less/list.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/mixins.less b/dal/static/datacenterlight/font-awesome/less/mixins.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/mixins.less rename to dal/static/datacenterlight/font-awesome/less/mixins.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/path.less b/dal/static/datacenterlight/font-awesome/less/path.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/path.less rename to dal/static/datacenterlight/font-awesome/less/path.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less b/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/rotated-flipped.less rename to dal/static/datacenterlight/font-awesome/less/rotated-flipped.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/spinning.less b/dal/static/datacenterlight/font-awesome/less/spinning.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/spinning.less rename to dal/static/datacenterlight/font-awesome/less/spinning.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/stacked.less b/dal/static/datacenterlight/font-awesome/less/stacked.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/stacked.less rename to dal/static/datacenterlight/font-awesome/less/stacked.less diff --git a/dal/dal/static/datacenterlight/font-awesome/less/variables.less b/dal/static/datacenterlight/font-awesome/less/variables.less similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/less/variables.less rename to dal/static/datacenterlight/font-awesome/less/variables.less diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss b/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss rename to dal/static/datacenterlight/font-awesome/scss/_bordered-pulled.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_core.scss b/dal/static/datacenterlight/font-awesome/scss/_core.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_core.scss rename to dal/static/datacenterlight/font-awesome/scss/_core.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss b/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss rename to dal/static/datacenterlight/font-awesome/scss/_fixed-width.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_icons.scss b/dal/static/datacenterlight/font-awesome/scss/_icons.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_icons.scss rename to dal/static/datacenterlight/font-awesome/scss/_icons.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_larger.scss b/dal/static/datacenterlight/font-awesome/scss/_larger.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_larger.scss rename to dal/static/datacenterlight/font-awesome/scss/_larger.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_list.scss b/dal/static/datacenterlight/font-awesome/scss/_list.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_list.scss rename to dal/static/datacenterlight/font-awesome/scss/_list.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_mixins.scss b/dal/static/datacenterlight/font-awesome/scss/_mixins.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_mixins.scss rename to dal/static/datacenterlight/font-awesome/scss/_mixins.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_path.scss b/dal/static/datacenterlight/font-awesome/scss/_path.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_path.scss rename to dal/static/datacenterlight/font-awesome/scss/_path.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss b/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss rename to dal/static/datacenterlight/font-awesome/scss/_rotated-flipped.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_spinning.scss b/dal/static/datacenterlight/font-awesome/scss/_spinning.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_spinning.scss rename to dal/static/datacenterlight/font-awesome/scss/_spinning.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_stacked.scss b/dal/static/datacenterlight/font-awesome/scss/_stacked.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_stacked.scss rename to dal/static/datacenterlight/font-awesome/scss/_stacked.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/_variables.scss b/dal/static/datacenterlight/font-awesome/scss/_variables.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/_variables.scss rename to dal/static/datacenterlight/font-awesome/scss/_variables.scss diff --git a/dal/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss b/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss similarity index 100% rename from dal/dal/static/datacenterlight/font-awesome/scss/font-awesome.scss rename to dal/static/datacenterlight/font-awesome/scss/font-awesome.scss diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Black.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-BlackItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Bold.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-BoldItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBold.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLight.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Italic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Light.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-LightItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Medium.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-MediumItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Regular.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBold.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-Thin.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf b/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf rename to dal/static/datacenterlight/fonts/Montserrat/Montserrat-ThinItalic.ttf diff --git a/dal/dal/static/datacenterlight/fonts/Montserrat/OFL.txt b/dal/static/datacenterlight/fonts/Montserrat/OFL.txt similarity index 100% rename from dal/dal/static/datacenterlight/fonts/Montserrat/OFL.txt rename to dal/static/datacenterlight/fonts/Montserrat/OFL.txt diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.eot diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.svg diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.ttf diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff diff --git a/dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 b/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 similarity index 100% rename from dal/dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 rename to dal/static/datacenterlight/fonts/glyphicons-halflings-regular.woff2 diff --git a/dal/dal/static/datacenterlight/img/Ceph_Logo.png b/dal/static/datacenterlight/img/Ceph_Logo.png similarity index 100% rename from dal/dal/static/datacenterlight/img/Ceph_Logo.png rename to dal/static/datacenterlight/img/Ceph_Logo.png diff --git a/dal/dal/static/datacenterlight/img/banner-bg copy.jpg b/dal/static/datacenterlight/img/banner-bg copy.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/banner-bg copy.jpg rename to dal/static/datacenterlight/img/banner-bg copy.jpg diff --git a/dal/dal/static/datacenterlight/img/banner-bg.jpg b/dal/static/datacenterlight/img/banner-bg.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/banner-bg.jpg rename to dal/static/datacenterlight/img/banner-bg.jpg diff --git a/dal/dal/static/datacenterlight/img/bg.png b/dal/static/datacenterlight/img/bg.png similarity index 100% rename from dal/dal/static/datacenterlight/img/bg.png rename to dal/static/datacenterlight/img/bg.png diff --git a/dal/dal/static/datacenterlight/img/cdistbyungleich.png b/dal/static/datacenterlight/img/cdistbyungleich.png similarity index 100% rename from dal/dal/static/datacenterlight/img/cdistbyungleich.png rename to dal/static/datacenterlight/img/cdistbyungleich.png diff --git a/dal/dal/static/datacenterlight/img/checkmark.png b/dal/static/datacenterlight/img/checkmark.png similarity index 100% rename from dal/dal/static/datacenterlight/img/checkmark.png rename to dal/static/datacenterlight/img/checkmark.png diff --git a/dal/dal/static/datacenterlight/img/configure.jpg b/dal/static/datacenterlight/img/configure.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/configure.jpg rename to dal/static/datacenterlight/img/configure.jpg diff --git a/dal/dal/static/datacenterlight/img/datacenterlight.png b/dal/static/datacenterlight/img/datacenterlight.png similarity index 100% rename from dal/dal/static/datacenterlight/img/datacenterlight.png rename to dal/static/datacenterlight/img/datacenterlight.png diff --git a/dal/dal/static/datacenterlight/img/dcl-email-bg.jpg b/dal/static/datacenterlight/img/dcl-email-bg.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/dcl-email-bg.jpg rename to dal/static/datacenterlight/img/dcl-email-bg.jpg diff --git a/dal/dal/static/datacenterlight/img/deluxeroom.jpg b/dal/static/datacenterlight/img/deluxeroom.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/deluxeroom.jpg rename to dal/static/datacenterlight/img/deluxeroom.jpg diff --git a/dal/dal/static/datacenterlight/img/devuan.png b/dal/static/datacenterlight/img/devuan.png similarity index 100% rename from dal/dal/static/datacenterlight/img/devuan.png rename to dal/static/datacenterlight/img/devuan.png diff --git a/dal/dal/static/datacenterlight/img/django.png b/dal/static/datacenterlight/img/django.png similarity index 100% rename from dal/dal/static/datacenterlight/img/django.png rename to dal/static/datacenterlight/img/django.png diff --git a/dal/dal/static/datacenterlight/img/dog.png b/dal/static/datacenterlight/img/dog.png similarity index 100% rename from dal/dal/static/datacenterlight/img/dog.png rename to dal/static/datacenterlight/img/dog.png diff --git a/dal/dal/static/datacenterlight/img/economy.jpg b/dal/static/datacenterlight/img/economy.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/economy.jpg rename to dal/static/datacenterlight/img/economy.jpg diff --git a/dal/dal/static/datacenterlight/img/facebook_logo.svg b/dal/static/datacenterlight/img/facebook_logo.svg similarity index 100% rename from dal/dal/static/datacenterlight/img/facebook_logo.svg rename to dal/static/datacenterlight/img/facebook_logo.svg diff --git a/dal/dal/static/datacenterlight/img/favicon.ico b/dal/static/datacenterlight/img/favicon.ico similarity index 100% rename from dal/dal/static/datacenterlight/img/favicon.ico rename to dal/static/datacenterlight/img/favicon.ico diff --git a/dal/dal/static/datacenterlight/img/header-bg.jpg b/dal/static/datacenterlight/img/header-bg.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/header-bg.jpg rename to dal/static/datacenterlight/img/header-bg.jpg diff --git a/dal/dal/static/datacenterlight/img/home.png b/dal/static/datacenterlight/img/home.png similarity index 100% rename from dal/dal/static/datacenterlight/img/home.png rename to dal/static/datacenterlight/img/home.png diff --git a/dal/dal/static/datacenterlight/img/how.png b/dal/static/datacenterlight/img/how.png similarity index 100% rename from dal/dal/static/datacenterlight/img/how.png rename to dal/static/datacenterlight/img/how.png diff --git a/dal/dal/static/datacenterlight/img/how1.png b/dal/static/datacenterlight/img/how1.png similarity index 100% rename from dal/dal/static/datacenterlight/img/how1.png rename to dal/static/datacenterlight/img/how1.png diff --git a/dal/dal/static/datacenterlight/img/how2.png b/dal/static/datacenterlight/img/how2.png similarity index 100% rename from dal/dal/static/datacenterlight/img/how2.png rename to dal/static/datacenterlight/img/how2.png diff --git a/dal/dal/static/datacenterlight/img/how3.png b/dal/static/datacenterlight/img/how3.png similarity index 100% rename from dal/dal/static/datacenterlight/img/how3.png rename to dal/static/datacenterlight/img/how3.png diff --git a/dal/dal/static/datacenterlight/img/how4.png b/dal/static/datacenterlight/img/how4.png similarity index 100% rename from dal/dal/static/datacenterlight/img/how4.png rename to dal/static/datacenterlight/img/how4.png diff --git a/dal/dal/static/datacenterlight/img/intro-bg.jpg b/dal/static/datacenterlight/img/intro-bg.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/intro-bg.jpg rename to dal/static/datacenterlight/img/intro-bg.jpg diff --git a/dal/dal/static/datacenterlight/img/ipad.png b/dal/static/datacenterlight/img/ipad.png similarity index 100% rename from dal/dal/static/datacenterlight/img/ipad.png rename to dal/static/datacenterlight/img/ipad.png diff --git a/dal/dal/static/datacenterlight/img/loading.gif b/dal/static/datacenterlight/img/loading.gif similarity index 100% rename from dal/dal/static/datacenterlight/img/loading.gif rename to dal/static/datacenterlight/img/loading.gif diff --git a/dal/dal/static/datacenterlight/img/logo_black.png b/dal/static/datacenterlight/img/logo_black.png similarity index 100% rename from dal/dal/static/datacenterlight/img/logo_black.png rename to dal/static/datacenterlight/img/logo_black.png diff --git a/dal/dal/static/datacenterlight/img/logo_black.svg b/dal/static/datacenterlight/img/logo_black.svg similarity index 100% rename from dal/dal/static/datacenterlight/img/logo_black.svg rename to dal/static/datacenterlight/img/logo_black.svg diff --git a/dal/dal/static/datacenterlight/img/logo_white.svg b/dal/static/datacenterlight/img/logo_white.svg similarity index 100% rename from dal/dal/static/datacenterlight/img/logo_white.svg rename to dal/static/datacenterlight/img/logo_white.svg diff --git a/dal/dal/static/datacenterlight/img/opennebula.png b/dal/static/datacenterlight/img/opennebula.png similarity index 100% rename from dal/dal/static/datacenterlight/img/opennebula.png rename to dal/static/datacenterlight/img/opennebula.png diff --git a/dal/dal/static/datacenterlight/img/pattern.jpg b/dal/static/datacenterlight/img/pattern.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/pattern.jpg rename to dal/static/datacenterlight/img/pattern.jpg diff --git a/dal/dal/static/datacenterlight/img/phones.png b/dal/static/datacenterlight/img/phones.png similarity index 100% rename from dal/dal/static/datacenterlight/img/phones.png rename to dal/static/datacenterlight/img/phones.png diff --git a/dal/dal/static/datacenterlight/img/presidentialroom.jpg b/dal/static/datacenterlight/img/presidentialroom.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/presidentialroom.jpg rename to dal/static/datacenterlight/img/presidentialroom.jpg diff --git a/dal/dal/static/datacenterlight/img/prometheus.png b/dal/static/datacenterlight/img/prometheus.png similarity index 100% rename from dal/dal/static/datacenterlight/img/prometheus.png rename to dal/static/datacenterlight/img/prometheus.png diff --git a/dal/dal/static/datacenterlight/img/python-logo.png b/dal/static/datacenterlight/img/python-logo.png similarity index 100% rename from dal/dal/static/datacenterlight/img/python-logo.png rename to dal/static/datacenterlight/img/python-logo.png diff --git a/dal/dal/static/datacenterlight/img/ssd.jpg b/dal/static/datacenterlight/img/ssd.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/ssd.jpg rename to dal/static/datacenterlight/img/ssd.jpg diff --git a/dal/dal/static/datacenterlight/img/standardroom.jpg b/dal/static/datacenterlight/img/standardroom.jpg similarity index 100% rename from dal/dal/static/datacenterlight/img/standardroom.jpg rename to dal/static/datacenterlight/img/standardroom.jpg diff --git a/dal/dal/static/datacenterlight/img/tayga.png b/dal/static/datacenterlight/img/tayga.png similarity index 100% rename from dal/dal/static/datacenterlight/img/tayga.png rename to dal/static/datacenterlight/img/tayga.png diff --git a/dal/dal/static/datacenterlight/img/ubuntu.png b/dal/static/datacenterlight/img/ubuntu.png similarity index 100% rename from dal/dal/static/datacenterlight/img/ubuntu.png rename to dal/static/datacenterlight/img/ubuntu.png diff --git a/dal/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js b/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js similarity index 100% rename from dal/dal/static/datacenterlight/js/bootstrap-3.3.7.min.js rename to dal/static/datacenterlight/js/bootstrap-3.3.7.min.js diff --git a/dal/dal/static/datacenterlight/js/form.js b/dal/static/datacenterlight/js/form.js similarity index 100% rename from dal/dal/static/datacenterlight/js/form.js rename to dal/static/datacenterlight/js/form.js diff --git a/dal/dal/static/datacenterlight/js/jquery-2.2.4.min.js b/dal/static/datacenterlight/js/jquery-2.2.4.min.js similarity index 100% rename from dal/dal/static/datacenterlight/js/jquery-2.2.4.min.js rename to dal/static/datacenterlight/js/jquery-2.2.4.min.js diff --git a/dal/dal/static/datacenterlight/js/main.js b/dal/static/datacenterlight/js/main.js similarity index 100% rename from dal/dal/static/datacenterlight/js/main.js rename to dal/static/datacenterlight/js/main.js diff --git a/dal/dal/static/hosting/card-django.png b/dal/static/hosting/card-django.png similarity index 100% rename from dal/dal/static/hosting/card-django.png rename to dal/static/hosting/card-django.png diff --git a/dal/dal/static/hosting/card-nodejs.png b/dal/static/hosting/card-nodejs.png similarity index 100% rename from dal/dal/static/hosting/card-nodejs.png rename to dal/static/hosting/card-nodejs.png diff --git a/dal/dal/static/hosting/card-rails.png b/dal/static/hosting/card-rails.png similarity index 100% rename from dal/dal/static/hosting/card-rails.png rename to dal/static/hosting/card-rails.png diff --git a/dal/dal/static/hosting/css/commons.css b/dal/static/hosting/css/commons.css similarity index 100% rename from dal/dal/static/hosting/css/commons.css rename to dal/static/hosting/css/commons.css diff --git a/dal/dal/static/hosting/css/dashboard.css b/dal/static/hosting/css/dashboard.css similarity index 100% rename from dal/dal/static/hosting/css/dashboard.css rename to dal/static/hosting/css/dashboard.css diff --git a/dal/dal/static/hosting/css/landing-page.css b/dal/static/hosting/css/landing-page.css similarity index 100% rename from dal/dal/static/hosting/css/landing-page.css rename to dal/static/hosting/css/landing-page.css diff --git a/dal/dal/static/hosting/css/nodejshosting.css b/dal/static/hosting/css/nodejshosting.css similarity index 100% rename from dal/dal/static/hosting/css/nodejshosting.css rename to dal/static/hosting/css/nodejshosting.css diff --git a/dal/dal/static/hosting/css/order.css b/dal/static/hosting/css/order.css similarity index 100% rename from dal/dal/static/hosting/css/order.css rename to dal/static/hosting/css/order.css diff --git a/dal/dal/static/hosting/css/orders.css b/dal/static/hosting/css/orders.css similarity index 100% rename from dal/dal/static/hosting/css/orders.css rename to dal/static/hosting/css/orders.css diff --git a/dal/dal/static/hosting/css/payment.css b/dal/static/hosting/css/payment.css similarity index 100% rename from dal/dal/static/hosting/css/payment.css rename to dal/static/hosting/css/payment.css diff --git a/dal/dal/static/hosting/css/price_calculator.css b/dal/static/hosting/css/price_calculator.css similarity index 100% rename from dal/dal/static/hosting/css/price_calculator.css rename to dal/static/hosting/css/price_calculator.css diff --git a/dal/dal/static/hosting/css/pricing.css b/dal/static/hosting/css/pricing.css similarity index 100% rename from dal/dal/static/hosting/css/pricing.css rename to dal/static/hosting/css/pricing.css diff --git a/dal/dal/static/hosting/css/user_keys.css b/dal/static/hosting/css/user_keys.css similarity index 100% rename from dal/dal/static/hosting/css/user_keys.css rename to dal/static/hosting/css/user_keys.css diff --git a/dal/dal/static/hosting/css/virtual-machine.css b/dal/static/hosting/css/virtual-machine.css similarity index 100% rename from dal/dal/static/hosting/css/virtual-machine.css rename to dal/static/hosting/css/virtual-machine.css diff --git a/dal/dal/static/hosting/django-intro-bg.png b/dal/static/hosting/django-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/django-intro-bg.png rename to dal/static/hosting/django-intro-bg.png diff --git a/dal/dal/static/hosting/img/24-hours-support.svg b/dal/static/hosting/img/24-hours-support.svg similarity index 100% rename from dal/dal/static/hosting/img/24-hours-support.svg rename to dal/static/hosting/img/24-hours-support.svg diff --git a/dal/dal/static/hosting/img/CH_flag.png b/dal/static/hosting/img/CH_flag.png similarity index 100% rename from dal/dal/static/hosting/img/CH_flag.png rename to dal/static/hosting/img/CH_flag.png diff --git a/dal/dal/static/hosting/img/DE_flag.png b/dal/static/hosting/img/DE_flag.png similarity index 100% rename from dal/dal/static/hosting/img/DE_flag.png rename to dal/static/hosting/img/DE_flag.png diff --git a/dal/dal/static/hosting/img/ajax-loader.gif b/dal/static/hosting/img/ajax-loader.gif similarity index 100% rename from dal/dal/static/hosting/img/ajax-loader.gif rename to dal/static/hosting/img/ajax-loader.gif diff --git a/dal/dal/static/hosting/img/auth-bg-sm.jpg b/dal/static/hosting/img/auth-bg-sm.jpg similarity index 100% rename from dal/dal/static/hosting/img/auth-bg-sm.jpg rename to dal/static/hosting/img/auth-bg-sm.jpg diff --git a/dal/dal/static/hosting/img/auth-bg.jpg b/dal/static/hosting/img/auth-bg.jpg similarity index 100% rename from dal/dal/static/hosting/img/auth-bg.jpg rename to dal/static/hosting/img/auth-bg.jpg diff --git a/dal/dal/static/hosting/img/banner-bg copy.jpg b/dal/static/hosting/img/banner-bg copy.jpg similarity index 100% rename from dal/dal/static/hosting/img/banner-bg copy.jpg rename to dal/static/hosting/img/banner-bg copy.jpg diff --git a/dal/dal/static/hosting/img/banner-bg.jpg b/dal/static/hosting/img/banner-bg.jpg similarity index 100% rename from dal/dal/static/hosting/img/banner-bg.jpg rename to dal/static/hosting/img/banner-bg.jpg diff --git a/dal/dal/static/hosting/img/billing.svg b/dal/static/hosting/img/billing.svg similarity index 100% rename from dal/dal/static/hosting/img/billing.svg rename to dal/static/hosting/img/billing.svg diff --git a/dal/dal/static/hosting/img/card-django.png b/dal/static/hosting/img/card-django.png similarity index 100% rename from dal/dal/static/hosting/img/card-django.png rename to dal/static/hosting/img/card-django.png diff --git a/dal/dal/static/hosting/img/card-nodejs.png b/dal/static/hosting/img/card-nodejs.png similarity index 100% rename from dal/dal/static/hosting/img/card-nodejs.png rename to dal/static/hosting/img/card-nodejs.png diff --git a/dal/dal/static/hosting/img/card-rails.png b/dal/static/hosting/img/card-rails.png similarity index 100% rename from dal/dal/static/hosting/img/card-rails.png rename to dal/static/hosting/img/card-rails.png diff --git a/dal/dal/static/hosting/img/checkmark.png b/dal/static/hosting/img/checkmark.png similarity index 100% rename from dal/dal/static/hosting/img/checkmark.png rename to dal/static/hosting/img/checkmark.png diff --git a/dal/dal/static/hosting/img/configure.jpg b/dal/static/hosting/img/configure.jpg similarity index 100% rename from dal/dal/static/hosting/img/configure.jpg rename to dal/static/hosting/img/configure.jpg diff --git a/dal/dal/static/hosting/img/connected.svg b/dal/static/hosting/img/connected.svg similarity index 100% rename from dal/dal/static/hosting/img/connected.svg rename to dal/static/hosting/img/connected.svg diff --git a/dal/dal/static/hosting/img/copy.svg b/dal/static/hosting/img/copy.svg similarity index 100% rename from dal/dal/static/hosting/img/copy.svg rename to dal/static/hosting/img/copy.svg diff --git a/dal/dal/static/hosting/img/dashboard_settings.svg b/dal/static/hosting/img/dashboard_settings.svg similarity index 100% rename from dal/dal/static/hosting/img/dashboard_settings.svg rename to dal/static/hosting/img/dashboard_settings.svg diff --git a/dal/dal/static/hosting/img/delete.svg b/dal/static/hosting/img/delete.svg similarity index 100% rename from dal/dal/static/hosting/img/delete.svg rename to dal/static/hosting/img/delete.svg diff --git a/dal/dal/static/hosting/img/deluxeroom.jpg b/dal/static/hosting/img/deluxeroom.jpg similarity index 100% rename from dal/dal/static/hosting/img/deluxeroom.jpg rename to dal/static/hosting/img/deluxeroom.jpg diff --git a/dal/dal/static/hosting/img/django-intro-bg.png b/dal/static/hosting/img/django-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/img/django-intro-bg.png rename to dal/static/hosting/img/django-intro-bg.png diff --git a/dal/dal/static/hosting/img/dog.png b/dal/static/hosting/img/dog.png similarity index 100% rename from dal/dal/static/hosting/img/dog.png rename to dal/static/hosting/img/dog.png diff --git a/dal/dal/static/hosting/img/economy.jpg b/dal/static/hosting/img/economy.jpg similarity index 100% rename from dal/dal/static/hosting/img/economy.jpg rename to dal/static/hosting/img/economy.jpg diff --git a/dal/dal/static/hosting/img/favicon.ico b/dal/static/hosting/img/favicon.ico similarity index 100% rename from dal/dal/static/hosting/img/favicon.ico rename to dal/static/hosting/img/favicon.ico diff --git a/dal/dal/static/hosting/img/g222.png b/dal/static/hosting/img/g222.png similarity index 100% rename from dal/dal/static/hosting/img/g222.png rename to dal/static/hosting/img/g222.png diff --git a/dal/dal/static/hosting/img/header-bg.jpg b/dal/static/hosting/img/header-bg.jpg similarity index 100% rename from dal/dal/static/hosting/img/header-bg.jpg rename to dal/static/hosting/img/header-bg.jpg diff --git a/dal/dal/static/hosting/img/home.png b/dal/static/hosting/img/home.png similarity index 100% rename from dal/dal/static/hosting/img/home.png rename to dal/static/hosting/img/home.png diff --git a/dal/dal/static/hosting/img/how.png b/dal/static/hosting/img/how.png similarity index 100% rename from dal/dal/static/hosting/img/how.png rename to dal/static/hosting/img/how.png diff --git a/dal/dal/static/hosting/img/how1.png b/dal/static/hosting/img/how1.png similarity index 100% rename from dal/dal/static/hosting/img/how1.png rename to dal/static/hosting/img/how1.png diff --git a/dal/dal/static/hosting/img/how2.png b/dal/static/hosting/img/how2.png similarity index 100% rename from dal/dal/static/hosting/img/how2.png rename to dal/static/hosting/img/how2.png diff --git a/dal/dal/static/hosting/img/how4.png b/dal/static/hosting/img/how4.png similarity index 100% rename from dal/dal/static/hosting/img/how4.png rename to dal/static/hosting/img/how4.png diff --git a/dal/dal/static/hosting/img/icon-pdf.svg b/dal/static/hosting/img/icon-pdf.svg similarity index 100% rename from dal/dal/static/hosting/img/icon-pdf.svg rename to dal/static/hosting/img/icon-pdf.svg diff --git a/dal/dal/static/hosting/img/icon-print.svg b/dal/static/hosting/img/icon-print.svg similarity index 100% rename from dal/dal/static/hosting/img/icon-print.svg rename to dal/static/hosting/img/icon-print.svg diff --git a/dal/dal/static/hosting/img/intro-bg.jpg b/dal/static/hosting/img/intro-bg.jpg similarity index 100% rename from dal/dal/static/hosting/img/intro-bg.jpg rename to dal/static/hosting/img/intro-bg.jpg diff --git a/dal/dal/static/hosting/img/ipad.png b/dal/static/hosting/img/ipad.png similarity index 100% rename from dal/dal/static/hosting/img/ipad.png rename to dal/static/hosting/img/ipad.png diff --git a/dal/dal/static/hosting/img/key.svg b/dal/static/hosting/img/key.svg similarity index 100% rename from dal/dal/static/hosting/img/key.svg rename to dal/static/hosting/img/key.svg diff --git a/dal/dal/static/hosting/img/login-bg.jpg b/dal/static/hosting/img/login-bg.jpg similarity index 100% rename from dal/dal/static/hosting/img/login-bg.jpg rename to dal/static/hosting/img/login-bg.jpg diff --git a/dal/dal/static/hosting/img/logo_black.png b/dal/static/hosting/img/logo_black.png similarity index 100% rename from dal/dal/static/hosting/img/logo_black.png rename to dal/static/hosting/img/logo_black.png diff --git a/dal/dal/static/hosting/img/logo_black.svg b/dal/static/hosting/img/logo_black.svg similarity index 100% rename from dal/dal/static/hosting/img/logo_black.svg rename to dal/static/hosting/img/logo_black.svg diff --git a/dal/dal/static/hosting/img/logo_white.svg b/dal/static/hosting/img/logo_white.svg similarity index 100% rename from dal/dal/static/hosting/img/logo_white.svg rename to dal/static/hosting/img/logo_white.svg diff --git a/dal/dal/static/hosting/img/nodejs-intro-bg.png b/dal/static/hosting/img/nodejs-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/img/nodejs-intro-bg.png rename to dal/static/hosting/img/nodejs-intro-bg.png diff --git a/dal/dal/static/hosting/img/pattern.jpg b/dal/static/hosting/img/pattern.jpg similarity index 100% rename from dal/dal/static/hosting/img/pattern.jpg rename to dal/static/hosting/img/pattern.jpg diff --git a/dal/dal/static/hosting/img/pattern_original.jpg b/dal/static/hosting/img/pattern_original.jpg similarity index 100% rename from dal/dal/static/hosting/img/pattern_original.jpg rename to dal/static/hosting/img/pattern_original.jpg diff --git a/dal/dal/static/hosting/img/phones.png b/dal/static/hosting/img/phones.png similarity index 100% rename from dal/dal/static/hosting/img/phones.png rename to dal/static/hosting/img/phones.png diff --git a/dal/dal/static/hosting/img/plusVM.svg b/dal/static/hosting/img/plusVM.svg similarity index 100% rename from dal/dal/static/hosting/img/plusVM.svg rename to dal/static/hosting/img/plusVM.svg diff --git a/dal/dal/static/hosting/img/presidentialroom.jpg b/dal/static/hosting/img/presidentialroom.jpg similarity index 100% rename from dal/dal/static/hosting/img/presidentialroom.jpg rename to dal/static/hosting/img/presidentialroom.jpg diff --git a/dal/dal/static/hosting/img/rails-intro-bg.png b/dal/static/hosting/img/rails-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/img/rails-intro-bg.png rename to dal/static/hosting/img/rails-intro-bg.png diff --git a/dal/dal/static/hosting/img/settings.svg b/dal/static/hosting/img/settings.svg similarity index 100% rename from dal/dal/static/hosting/img/settings.svg rename to dal/static/hosting/img/settings.svg diff --git a/dal/dal/static/hosting/img/shopping-cart.svg b/dal/static/hosting/img/shopping-cart.svg similarity index 100% rename from dal/dal/static/hosting/img/shopping-cart.svg rename to dal/static/hosting/img/shopping-cart.svg diff --git a/dal/dal/static/hosting/img/signup-bg.png b/dal/static/hosting/img/signup-bg.png similarity index 100% rename from dal/dal/static/hosting/img/signup-bg.png rename to dal/static/hosting/img/signup-bg.png diff --git a/dal/dal/static/hosting/img/standardroom.jpg b/dal/static/hosting/img/standardroom.jpg similarity index 100% rename from dal/dal/static/hosting/img/standardroom.jpg rename to dal/static/hosting/img/standardroom.jpg diff --git a/dal/dal/static/hosting/img/ubuntu.png b/dal/static/hosting/img/ubuntu.png similarity index 100% rename from dal/dal/static/hosting/img/ubuntu.png rename to dal/static/hosting/img/ubuntu.png diff --git a/dal/dal/static/hosting/img/vm.svg b/dal/static/hosting/img/vm.svg similarity index 100% rename from dal/dal/static/hosting/img/vm.svg rename to dal/static/hosting/img/vm.svg diff --git a/dal/dal/static/hosting/js/createvm.js b/dal/static/hosting/js/createvm.js similarity index 100% rename from dal/dal/static/hosting/js/createvm.js rename to dal/static/hosting/js/createvm.js diff --git a/dal/dal/static/hosting/js/gen-ssh-key.js b/dal/static/hosting/js/gen-ssh-key.js similarity index 100% rename from dal/dal/static/hosting/js/gen-ssh-key.js rename to dal/static/hosting/js/gen-ssh-key.js diff --git a/dal/dal/static/hosting/js/html2canvas.min.js b/dal/static/hosting/js/html2canvas.min.js similarity index 100% rename from dal/dal/static/hosting/js/html2canvas.min.js rename to dal/static/hosting/js/html2canvas.min.js diff --git a/dal/dal/static/hosting/js/html2pdf.min.js b/dal/static/hosting/js/html2pdf.min.js similarity index 100% rename from dal/dal/static/hosting/js/html2pdf.min.js rename to dal/static/hosting/js/html2pdf.min.js diff --git a/dal/dal/static/hosting/js/initial.js b/dal/static/hosting/js/initial.js similarity index 100% rename from dal/dal/static/hosting/js/initial.js rename to dal/static/hosting/js/initial.js diff --git a/dal/dal/static/hosting/js/order.js b/dal/static/hosting/js/order.js similarity index 100% rename from dal/dal/static/hosting/js/order.js rename to dal/static/hosting/js/order.js diff --git a/dal/dal/static/hosting/js/payment.js b/dal/static/hosting/js/payment.js similarity index 100% rename from dal/dal/static/hosting/js/payment.js rename to dal/static/hosting/js/payment.js diff --git a/dal/dal/static/hosting/js/pricing.js b/dal/static/hosting/js/pricing.js similarity index 100% rename from dal/dal/static/hosting/js/pricing.js rename to dal/static/hosting/js/pricing.js diff --git a/dal/dal/static/hosting/js/virtual_machine_detail.js b/dal/static/hosting/js/virtual_machine_detail.js similarity index 100% rename from dal/dal/static/hosting/js/virtual_machine_detail.js rename to dal/static/hosting/js/virtual_machine_detail.js diff --git a/dal/dal/static/hosting/nodejs-intro-bg.png b/dal/static/hosting/nodejs-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/nodejs-intro-bg.png rename to dal/static/hosting/nodejs-intro-bg.png diff --git a/dal/dal/static/hosting/rails-intro-bg.png b/dal/static/hosting/rails-intro-bg.png similarity index 100% rename from dal/dal/static/hosting/rails-intro-bg.png rename to dal/static/hosting/rails-intro-bg.png diff --git a/dal/dal/templates/base.html b/dal/templates/base.html similarity index 100% rename from dal/dal/templates/base.html rename to dal/templates/base.html diff --git a/dal/dal/templates/base_short.html b/dal/templates/base_short.html similarity index 100% rename from dal/dal/templates/base_short.html rename to dal/templates/base_short.html diff --git a/dal/dal/templates/changeddata.html b/dal/templates/changeddata.html similarity index 100% rename from dal/dal/templates/changeddata.html rename to dal/templates/changeddata.html diff --git a/dal/dal/templates/changedpassword.html b/dal/templates/changedpassword.html similarity index 100% rename from dal/dal/templates/changedpassword.html rename to dal/templates/changedpassword.html diff --git a/dal/dal/templates/changepassword.html b/dal/templates/changepassword.html similarity index 100% rename from dal/dal/templates/changepassword.html rename to dal/templates/changepassword.html diff --git a/dal/dal/templates/changeuserdata.html b/dal/templates/changeuserdata.html similarity index 100% rename from dal/dal/templates/changeuserdata.html rename to dal/templates/changeuserdata.html diff --git a/dal/dal/templates/deleteaccount.html b/dal/templates/deleteaccount.html similarity index 100% rename from dal/dal/templates/deleteaccount.html rename to dal/templates/deleteaccount.html diff --git a/dal/dal/templates/deleteduser.html b/dal/templates/deleteduser.html similarity index 100% rename from dal/dal/templates/deleteduser.html rename to dal/templates/deleteduser.html diff --git a/dal/dal/templates/error.html b/dal/templates/error.html similarity index 100% rename from dal/dal/templates/error.html rename to dal/templates/error.html diff --git a/dal/dal/templates/hosting_login.html b/dal/templates/hosting_login.html similarity index 100% rename from dal/dal/templates/hosting_login.html rename to dal/templates/hosting_login.html diff --git a/dal/dal/templates/includes/_card_input.html b/dal/templates/includes/_card_input.html similarity index 100% rename from dal/dal/templates/includes/_card_input.html rename to dal/templates/includes/_card_input.html diff --git a/dal/dal/templates/includes/_contact.html b/dal/templates/includes/_contact.html similarity index 100% rename from dal/dal/templates/includes/_contact.html rename to dal/templates/includes/_contact.html diff --git a/dal/dal/templates/includes/_footer.html b/dal/templates/includes/_footer.html similarity index 100% rename from dal/dal/templates/includes/_footer.html rename to dal/templates/includes/_footer.html diff --git a/dal/dal/templates/includes/_header.html b/dal/templates/includes/_header.html similarity index 100% rename from dal/dal/templates/includes/_header.html rename to dal/templates/includes/_header.html diff --git a/dal/dal/templates/includes/_messages.html b/dal/templates/includes/_messages.html similarity index 100% rename from dal/dal/templates/includes/_messages.html rename to dal/templates/includes/_messages.html diff --git a/dal/dal/templates/includes/_navbar.html b/dal/templates/includes/_navbar.html similarity index 100% rename from dal/dal/templates/includes/_navbar.html rename to dal/templates/includes/_navbar.html diff --git a/dal/dal/templates/includes/_navbar_transparent.html b/dal/templates/includes/_navbar_transparent.html similarity index 100% rename from dal/dal/templates/includes/_navbar_transparent.html rename to dal/templates/includes/_navbar_transparent.html diff --git a/dal/dal/templates/includes/_navbar_user.html b/dal/templates/includes/_navbar_user.html similarity index 100% rename from dal/dal/templates/includes/_navbar_user.html rename to dal/templates/includes/_navbar_user.html diff --git a/dal/dal/templates/includes/_our_infrastructure.html b/dal/templates/includes/_our_infrastructure.html similarity index 100% rename from dal/dal/templates/includes/_our_infrastructure.html rename to dal/templates/includes/_our_infrastructure.html diff --git a/dal/dal/templates/includes/_pricing.html b/dal/templates/includes/_pricing.html similarity index 100% rename from dal/dal/templates/includes/_pricing.html rename to dal/templates/includes/_pricing.html diff --git a/dal/dal/templates/includes/_your_infrastructure.html b/dal/templates/includes/_your_infrastructure.html similarity index 100% rename from dal/dal/templates/includes/_your_infrastructure.html rename to dal/templates/includes/_your_infrastructure.html diff --git a/dal/dal/templates/landing.html b/dal/templates/landing.html similarity index 100% rename from dal/dal/templates/landing.html rename to dal/templates/landing.html diff --git a/dal/dal/templates/loginfailed.html b/dal/templates/loginfailed.html similarity index 100% rename from dal/dal/templates/loginfailed.html rename to dal/templates/loginfailed.html diff --git a/dal/dal/templates/mustbeloggedin.html b/dal/templates/mustbeloggedin.html similarity index 100% rename from dal/dal/templates/mustbeloggedin.html rename to dal/templates/mustbeloggedin.html diff --git a/dal/dal/templates/registeruser.html b/dal/templates/registeruser.html similarity index 100% rename from dal/dal/templates/registeruser.html rename to dal/templates/registeruser.html diff --git a/dal/dal/templates/resetpassword.html b/dal/templates/resetpassword.html similarity index 100% rename from dal/dal/templates/resetpassword.html rename to dal/templates/resetpassword.html diff --git a/dal/dal/templates/resetpasswordnew.html b/dal/templates/resetpasswordnew.html similarity index 100% rename from dal/dal/templates/resetpasswordnew.html rename to dal/templates/resetpasswordnew.html diff --git a/dal/dal/templates/send_resetrequest.html b/dal/templates/send_resetrequest.html similarity index 100% rename from dal/dal/templates/send_resetrequest.html rename to dal/templates/send_resetrequest.html diff --git a/dal/dal/templates/usercreated.html b/dal/templates/usercreated.html similarity index 100% rename from dal/dal/templates/usercreated.html rename to dal/templates/usercreated.html diff --git a/dal/dal/templates/useroptions.html b/dal/templates/useroptions.html similarity index 100% rename from dal/dal/templates/useroptions.html rename to dal/templates/useroptions.html diff --git a/dal/dal/urls.py b/dal/urls.py similarity index 100% rename from dal/dal/urls.py rename to dal/urls.py diff --git a/dal/dal/views.py b/dal/views.py similarity index 100% rename from dal/dal/views.py rename to dal/views.py diff --git a/dal/dal/wsgi.py b/dal/wsgi.py similarity index 100% rename from dal/dal/wsgi.py rename to dal/wsgi.py diff --git a/dal/manage.py b/manage.py similarity index 100% rename from dal/manage.py rename to manage.py From 1673d6e03ba37396e946f037acb23b65ee591c48 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 17:44:17 +0100 Subject: [PATCH 09/89] Update .gitignore --- .gitignore | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.gitignore b/.gitignore index f7275bb..712a31c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,41 @@ +*.log +db.sqlite3 +*.pyc +*.DS_Store +build/ +*.egg_info +#editors && utilites. +*.swp +*~ +__pycache__/ +.ropeproject/ +#django +local_settings.py + +!.keep +media/ +!media/keep +/CACHE/ +/static/ + +\#*# +.\#* +*~ + +secret-key + +node_modules/ +*.db +ungleich.db +*~* + +secret-key + +*.psd + +.idea/ + +.env +*.mo + venv/ From 8b61db8dee1902ae116954bf505ae5da7156aef2 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 17:57:48 +0100 Subject: [PATCH 10/89] Simplify getting LDAP_USE_TLS --- dal/settings.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dal/settings.py b/dal/settings.py index 7c30a2a..ee96962 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -28,8 +28,7 @@ search_base = os.environ['LDAPSEARCH'].split() search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ] AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap) -if os.environ['LDAP_USE_TLS']: - AUTH_LDAP_START_TLS=True +AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) From 5ec63d8536d2c0786d9a4558b62f1aa7636fd4d2 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 18:08:36 +0100 Subject: [PATCH 11/89] Get ALLOWED_HOSTS and DEBUG from .env --- dal/settings.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dal/settings.py b/dal/settings.py index ee96962..9fd3169 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -32,7 +32,9 @@ AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost') + +DEBUG = os.environ.get('DEBUG', False) INSTALLED_APPS = [ 'django.contrib.admin', @@ -131,6 +133,3 @@ DATABASES = { } } SECRET_KEY = os.environ.get('SECRET_KEY') - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = os.environ.get('DEBUG', False) From 876567f9337fd476d3b9d8e0163b8b88eb1735d5 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 18:20:56 +0100 Subject: [PATCH 12/89] Correct the way we get ALLOWED_HOSTS --- dal/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dal/settings.py b/dal/settings.py index 9fd3169..8b467c2 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -32,10 +32,10 @@ AUTH_LDAP_START_TLS = os.environ.get('LDAP_USE_TLS', False) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost') - DEBUG = os.environ.get('DEBUG', False) +ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(",") + INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', From c4c990a98d80ccdbf6b67bcedfdbae3770e4d0e5 Mon Sep 17 00:00:00 2001 From: PCoder Date: Sun, 17 Feb 2019 18:25:12 +0100 Subject: [PATCH 13/89] More correction --- dal/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dal/settings.py b/dal/settings.py index 8b467c2..2aa808d 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -34,7 +34,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) DEBUG = os.environ.get('DEBUG', False) -ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost').split(",") +ALLOWED_HOSTS = (os.environ.get('ALLOWED_HOSTS', 'localhost')).split(",") INSTALLED_APPS = [ 'django.contrib.admin', From 467af3422c4a003018e98ece457c1bc5addda77a Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 18 Feb 2019 22:01:07 +0100 Subject: [PATCH 14/89] Update django bootstrap and filter requirements --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 0767c8c..f6d34b1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ django django-auth-ldap python-ldap django-dotenv +django-bootstrap3 +django-filter==2.1.0 \ No newline at end of file From c571cf5c1d6cfb05e819afcf71a5f91a7492350b Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 18 Feb 2019 22:01:42 +0100 Subject: [PATCH 15/89] Add bootstrap3 to INSTALLED_APPS --- dal/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dal/settings.py b/dal/settings.py index 2aa808d..1cc50c3 100644 --- a/dal/settings.py +++ b/dal/settings.py @@ -43,6 +43,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'bootstrap3', 'dal', ] From dab31aa8537c476f908be92e2ddffedaf01ed8eb Mon Sep 17 00:00:00 2001 From: PCoder Date: Mon, 18 Feb 2019 22:03:51 +0100 Subject: [PATCH 16/89] Remove unwanted code / refactor code --- dal/templates/includes/_footer.html | 32 -------- .../includes/_navbar_transparent.html | 1 - dal/templates/landing.html | 73 +++++++++---------- 3 files changed, 35 insertions(+), 71 deletions(-) diff --git a/dal/templates/includes/_footer.html b/dal/templates/includes/_footer.html index e61ed59..800f7dc 100644 --- a/dal/templates/includes/_footer.html +++ b/dal/templates/includes/_footer.html @@ -1,41 +1,9 @@ {% load i18n %} - - -