diff --git a/.gitignore b/.gitignore
index f7275bb..38b9c32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,42 @@
+*.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/
+dal/ldap_max_uid_file
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/models.py b/dal/dal/models.py
deleted file mode 100644
index 7dee319..0000000
--- a/dal/dal/models.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from django.db import models
-
-# Basic DB to correlate tokens, users and creation time
-
-class ResetToken(models.Model):
-
- # users wouldn't use usernames >100 chars
- user = models.CharField(max_length=100)
- # Not so sure about tokens, better make it big
- # should be <100, but big usernames make bigger tokens
- # if I read that correctly
- token = models.CharField(max_length=255)
- # creation time in epoch (UTC)
- # BigInt just so we are save for the next few decades ;)
- creation = models.BigIntegerField()
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/templates/includes/_footer.html b/dal/dal/templates/includes/_footer.html
deleted file mode 100644
index e61ed59..0000000
--- a/dal/dal/templates/includes/_footer.html
+++ /dev/null
@@ -1,44 +0,0 @@
-{% load i18n %}
-
-
-
-
diff --git a/dal/dal/templates/landing.html b/dal/dal/templates/landing.html
deleted file mode 100644
index f56d2bb..0000000
--- a/dal/dal/templates/landing.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% extends "base_short.html" %}
-{% load staticfiles %}
-
-
-{% block content %}
-
-
-
-
-
-
-
-
Login
- {% include 'includes/_messages.html' %}
-
-
-
-
-
-
-
-{% endblock %}
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/forms.py b/dal/forms.py
new file mode 100644
index 0000000..d4bc028
--- /dev/null
+++ b/dal/forms.py
@@ -0,0 +1,31 @@
+from django import forms
+from django.contrib.auth import authenticate
+from django.utils.translation import ugettext_lazy as _
+
+
+class LoginForm(forms.Form):
+ email = forms.CharField(widget=forms.TextInput())
+ password = forms.CharField(widget=forms.PasswordInput())
+
+ class Meta:
+ fields = ['email', 'password']
+
+ def clean(self):
+ email = self.cleaned_data.get('email')
+ password = self.cleaned_data.get('password')
+ if self.errors:
+ return self.cleaned_data
+ is_auth = authenticate(username=email, password=password)
+ if not is_auth:
+ raise forms.ValidationError(
+ _("Your username and/or password were incorrect.")
+ )
+ # elif is_auth.validated == 0:
+ # raise forms.ValidationError(
+ # _("Your account is not activated yet.")
+ # )
+ return self.cleaned_data
+
+ def clean_email(self):
+ email = self.cleaned_data.get('email')
+ return email
diff --git a/dal/migrations/0001_initial.py b/dal/migrations/0001_initial.py
new file mode 100644
index 0000000..936a832
--- /dev/null
+++ b/dal/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.1.7 on 2019-02-24 17:35
+
+import dal.models
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ResetToken',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('user', models.CharField(max_length=100)),
+ ('token', models.CharField(max_length=255)),
+ ('creation', models.BigIntegerField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='UserAccountValidationDetail',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('validated', models.IntegerField(choices=[(0, 'Not validated'), (1, 'Validated')], default=0)),
+ ('validation_slug', models.CharField(db_index=True, default=dal.models.get_validation_slug, max_length=50, unique=True)),
+ ('date_validation_started', models.DateTimeField(auto_now_add=True)),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ ]
diff --git a/dal/migrations/__init__.py b/dal/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dal/models.py b/dal/models.py
new file mode 100644
index 0000000..676b103
--- /dev/null
+++ b/dal/models.py
@@ -0,0 +1,32 @@
+from django.db import models
+from django.contrib.auth.hashers import make_password
+from django.contrib.auth.models import User
+
+# Basic DB to correlate tokens, users and creation time
+
+class ResetToken(models.Model):
+
+ # users wouldn't use usernames >100 chars
+ user = models.CharField(max_length=100)
+ # Not so sure about tokens, better make it big
+ # should be <100, but big usernames make bigger tokens
+ # if I read that correctly
+ token = models.CharField(max_length=255)
+ # creation time in epoch (UTC)
+ # BigInt just so we are save for the next few decades ;)
+ creation = models.BigIntegerField()
+
+
+def get_validation_slug():
+ return make_password(None)
+
+
+class UserAccountValidationDetail(models.Model):
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
+ VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated'))
+ validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0)
+ validation_slug = models.CharField(
+ db_index=True, unique=True, max_length=50,
+ default=get_validation_slug
+ )
+ date_validation_started = models.DateTimeField(auto_now_add=True)
diff --git a/dal/dal/settings.py b/dal/settings.py
similarity index 52%
rename from dal/dal/settings.py
rename to dal/settings.py
index a284663..a302eac 100644
--- a/dal/dal/settings.py
+++ b/dal/settings.py
@@ -11,29 +11,50 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
"""
import os
-import dotenv
+from decouple import config, Csv
import ldap
from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
-# get config
-dotenv.read_dotenv()
-
# LDAP setup
-AUTH_LDAP_SERVER_URI = os.environ['LDAPSERVER']
-AUTH_LDAP_BIND_DN = os.environ['LDAPSEARCHUSER']
-AUTH_LDAP_BIND_PASSWORD = os.environ['LDAPSEARCHUSERPASSWORD']
+LDAP_SERVER = config('LDAP_SERVER')
+AUTH_LDAP_SERVER_URI = config('LDAPSERVER')
+
+LDAP_ADMIN_DN = config('LDAP_ADMIN_DN')
+LDAP_ADMIN_PASSWORD = config('LDAP_ADMIN_PASSWORD')
+AUTH_LDAP_BIND_DN = LDAP_ADMIN_DN
+AUTH_LDAP_BIND_PASSWORD = LDAP_ADMIN_PASSWORD
+AUTH_LDAP_SERVER = AUTH_LDAP_SERVER_URI
+
+LDAP_CUSTOMER_DN = config('LDAP_CUSTOMER_DN')
+LDAP_USERS_DN = config('LDAP_USERS_DN')
+LDAP_CUSTOMER_GROUP_ID = config('LDAP_CUSTOMER_GROUP_ID', cast=int)
+
+LDAP_MAX_UID_FILE_PATH = config(
+ 'LDAP_MAX_UID_FILE_PATH',
+ default=os.path.join(os.path.abspath(
+ os.path.dirname(__file__)), 'ldap_max_uid_file'
+ )
+)
+LDAP_DEFAULT_START_UID = config('LDAP_DEFAULT_START_UID', cast=int)
# Search union over OUs
-search_base = os.environ['LDAPSEARCH'].split()
+search_base = config('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 = config('LDAP_USE_TLS', default=False, cast=bool)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-ALLOWED_HOSTS = []
+DEBUG = config('DEBUG', default=False, cast=bool)
+
+EMAIL_FROM_ADDRESS = config('EMAIL_FROM_ADDRESS')
+
+EMAIL_HOST = config("EMAIL_HOST", default="localhost")
+EMAIL_PORT = config("EMAIL_PORT", default=25, cast=int)
+EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=True, cast=bool)
+
+ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
INSTALLED_APPS = [
'django.contrib.admin',
@@ -42,6 +63,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'bootstrap3',
'dal',
]
@@ -120,7 +142,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 +153,58 @@ 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 = config('SECRET_KEY')
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
+AUTH_LDAP_USER_ATTR_MAP = {
+ "first_name": "givenName",
+ "last_name": "sn",
+ "email": "mail"
+}
+
+ENTIRE_SEARCH_BASE = config("ENTIRE_SEARCH_BASE")
+
+LOGGING = {
+ 'disable_existing_loggers': False,
+ 'version': 1,
+ 'formatters': {
+ 'standard': {
+ 'format': '%(asctime)s %(levelname)s %(name)s %(funcName)s %(lineno)d: %(message)s'
+ }
+ },
+ 'handlers': {
+ 'default': {
+ 'level': 'DEBUG',
+ 'class': 'logging.handlers.RotatingFileHandler',
+ 'filename': 'logs/debug.log',
+ 'maxBytes': 1024*1024*5,
+ 'backupCount': 10,
+ 'formatter': 'standard',
+ },
+ 'console': {
+ 'class': 'logging.StreamHandler',
+ },
+ },
+}
+
+if config('ENABLE_DEBUG_LOG', default=False, cast=bool):
+ loggers_dict = {}
+ modules_to_log_list = config(
+ 'MODULES_TO_LOG', default='django', cast=Csv()
+ )
+ for custom_module in modules_to_log_list:
+ logger_item = {
+ custom_module: {
+ 'handlers': ['default'],
+ 'level': 'INFO',
+ 'propagate': True
+ }
+ }
+ loggers_dict.update(logger_item)
+
+ LOGGING['loggers'] = loggers_dict
+
+ if 'ldap3' in modules_to_log_list:
+ from ldap3.utils.log import (
+ set_library_log_detail_level, OFF, BASIC, NETWORK, EXTENDED
+ )
+ set_library_log_detail_level(BASIC)
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/templates/includes/_footer.html b/dal/templates/includes/_footer.html
new file mode 100644
index 0000000..800f7dc
--- /dev/null
+++ b/dal/templates/includes/_footer.html
@@ -0,0 +1,12 @@
+{% load i18n %}
+
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 94%
rename from dal/dal/templates/includes/_navbar_transparent.html
rename to dal/templates/includes/_navbar_transparent.html
index e413ace..1af4bcb 100644
--- a/dal/dal/templates/includes/_navbar_transparent.html
+++ b/dal/templates/includes/_navbar_transparent.html
@@ -2,7 +2,6 @@
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/templates/landing.html b/dal/templates/landing.html
new file mode 100644
index 0000000..741fd74
--- /dev/null
+++ b/dal/templates/landing.html
@@ -0,0 +1,38 @@
+{% extends "base_short.html" %}
+{% load i18n staticfiles bootstrap3 %}
+
+
+{% block content %}
+
+
+
+
+
+
{% trans "Log in" %}
+ {% include 'includes/_messages.html' %}
+
+
+
+
+
+
+{% endblock %}
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/ungleich_ldap.py b/dal/ungleich_ldap.py
new file mode 100644
index 0000000..74f102f
--- /dev/null
+++ b/dal/ungleich_ldap.py
@@ -0,0 +1,282 @@
+import base64
+import hashlib
+import random
+
+import ldap3
+from django.conf import settings
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class LdapManager:
+ __instance = None
+ def __new__(cls):
+ if LdapManager.__instance is None:
+ LdapManager.__instance = object.__new__(cls)
+ return LdapManager.__instance
+
+ def __init__(self):
+ """
+ Initialize the LDAP subsystem.
+ """
+ self.rng = random.SystemRandom()
+ self.server = ldap3.Server(settings.AUTH_LDAP_SERVER)
+
+
+ def get_admin_conn(self):
+ """
+ Return a bound :class:`ldap3.Connection` instance which has write
+ permissions on the dn in which the user accounts reside.
+ """
+ conn = self.get_conn(user=settings.LDAP_ADMIN_DN,
+ password=settings.LDAP_ADMIN_PASSWORD,
+ raise_exceptions=True)
+ conn.bind()
+ return conn
+
+
+ def get_conn(self, **kwargs):
+ """
+ Return an unbound :class:`ldap3.Connection` which talks to the configured
+ LDAP server.
+
+ The *kwargs* are passed to the constructor of :class:`ldap3.Connection` and
+ can be used to set *user*, *password* and other useful arguments.
+ """
+ return ldap3.Connection(self.server, **kwargs)
+
+
+ def _ssha_password(self, password):
+ """
+ Apply the SSHA password hashing scheme to the given *password*.
+ *password* must be a :class:`bytes` object, containing the utf-8
+ encoded password.
+
+ Return a :class:`bytes` object containing ``ascii``-compatible data
+ which can be used as LDAP value, e.g. after armoring it once more using
+ base64 or decoding it to unicode from ``ascii``.
+ """
+ SALT_BYTES = 15
+
+ sha1 = hashlib.sha1()
+ salt = self.rng.getrandbits(SALT_BYTES * 8).to_bytes(SALT_BYTES,
+ "little")
+ sha1.update(password)
+ sha1.update(salt)
+
+ digest = sha1.digest()
+ passwd = b"{SSHA}" + base64.b64encode(digest + salt)
+ return passwd
+
+
+ def create_user(self, user, password, firstname, lastname, email):
+ conn = self.get_admin_conn()
+ uidNumber = self._get_max_uid() + 1
+ logger.debug("uidNumber={uidNumber}".format(uidNumber=uidNumber))
+ user_exists = True
+ while user_exists:
+ user_exists, _ = self.check_user_exists(
+ "",
+ '(&(objectClass=inetOrgPerson)(objectClass=posixAccount)'
+ '(objectClass=top)(uidNumber={uidNumber}))'.format(
+ uidNumber=uidNumber
+ )
+ )
+ if user_exists:
+ logger.debug(
+ "{uid} exists. Trying next.".format(uid=uidNumber)
+ )
+ uidNumber += 1
+ logger.debug("{uid} does not exist. Using it".format(uid=uidNumber))
+ self._set_max_uid(uidNumber)
+ try:
+ conn.add(
+ ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=user),
+ ["inetOrgPerson", "posixAccount", "ldapPublickey"],
+ {
+ "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": [str(uidNumber)],
+ "gidNumber": [str(settings.LDAP_CUSTOMER_GROUP_ID)],
+ "loginShell": ["/bin/bash"],
+ "homeDirectory": ["/home/{}".format(user).encode("utf-8")],
+ "mail": email.encode("utf-8"),
+ "userPassword": [self._ssha_password(
+ password.encode("utf-8")
+ )]
+ }
+ )
+ logger.debug('Created user %s %s' % (user.encode('utf-8'),
+ uidNumber))
+ except Exception as ex:
+ logger.debug('Could not create user %s' % user.encode('utf-8'))
+ logger.error("Exception: " + str(ex))
+ raise Exception(ex)
+ finally:
+ conn.unbind()
+
+
+ def change_password(self, uid, new_password):
+ """
+ Changes the password of the user identified by user_dn
+
+ :param uid: str The uid that identifies the user
+ :param new_password: str The new password string
+ :return: True if password was changed successfully False otherwise
+ """
+ conn = self.get_admin_conn()
+
+ # Make sure the user exists first to change his/her details
+ user_exists, entries = self.check_user_exists(
+ uid=uid,
+ search_base=settings.ENTIRE_SEARCH_BASE
+ )
+ return_val = False
+ if user_exists:
+ try:
+ return_val = conn.modify(
+ entries[0].entry_dn,
+ {
+ "userpassword": (
+ ldap3.MODIFY_REPLACE,
+ [self._ssha_password(new_password.encode("utf-8"))]
+ )
+ }
+ )
+ except Exception as ex:
+ logger.error("Exception: " + str(ex))
+ else:
+ logger.error("User {} not found".format(uid))
+
+ conn.unbind()
+ return return_val
+
+ def change_user_details(self, uid, details):
+ """
+ Updates the user details as per given values in kwargs of the user
+ identified by user_dn.
+
+ Assumes that all attributes passed in kwargs are valid.
+
+ :param uid: str The uid that identifies the user
+ :param details: dict A dictionary containing the new values
+ :return: True if user details were updated successfully False otherwise
+ """
+ conn = self.get_admin_conn()
+
+ # Make sure the user exists first to change his/her details
+ user_exists, entries = self.check_user_exists(
+ uid=uid,
+ search_base=settings.ENTIRE_SEARCH_BASE
+ )
+
+ return_val = False
+ if user_exists:
+ details_dict = {k: (ldap3.MODIFY_REPLACE, [v.encode("utf-8")]) for
+ k, v in details.items()}
+ try:
+ return_val = conn.modify(entries[0].entry_dn, details_dict)
+ msg = "success"
+ except Exception as ex:
+ msg = str(ex)
+ logger.error("Exception: " + msg)
+ finally:
+ conn.unbind()
+ else:
+ msg = "User {} not found".format(uid)
+ logger.error(msg)
+ conn.unbind()
+ return return_val, msg
+
+ def check_user_exists(self, uid, search_filter="", attributes=None,
+ search_base=settings.LDAP_CUSTOMER_DN):
+ """
+ Check if the user with the given uid exists in the customer group.
+
+ :param uid: str representing the user
+ :param search_filter: str representing the filter condition to find
+ users. If its empty, the search finds the user with
+ the given uid.
+ :param attributes: list A list of str representing all the attributes
+ to be obtained in the result entries
+ :param search_base: str
+ :return: tuple (bool, [ldap3.abstract.entry.Entry ..])
+ A bool indicating if the user exists
+ A list of all entries obtained in the search
+ """
+ conn = self.get_admin_conn()
+ entries = []
+ try:
+ result = conn.search(
+ search_base=search_base,
+ search_filter=search_filter if len(search_filter)> 0 else
+ '(uid={uid})'.format(uid=uid),
+ attributes=attributes
+ )
+ entries = conn.entries
+ finally:
+ conn.unbind()
+ return result, entries
+
+ def delete_user(self, uid):
+ """
+ Deletes the user with the given uid from ldap
+
+ :param uid: str representing the user
+ :return: True if the delete was successful False otherwise
+ """
+ conn = self.get_admin_conn()
+ try:
+ return_val = conn.delete(
+ ("uid={uid}," + settings.LDAP_CUSTOMER_DN).format(uid=uid),
+ )
+ msg = "success"
+ except Exception as ex:
+ msg = str(ex)
+ logger.error("Exception: " + msg)
+ return_val = False
+ finally:
+ conn.unbind()
+ return return_val, msg
+
+ def _set_max_uid(self, max_uid):
+ """
+ a utility function to save max_uid value to a file
+
+ :param max_uid: an integer representing the max uid
+ :return:
+ """
+ with open(settings.LDAP_MAX_UID_FILE_PATH, 'w+') as handler:
+ handler.write(str(max_uid))
+
+ def _get_max_uid(self):
+ """
+ A utility function to read the max uid value that was previously set
+
+ :return: An integer representing the max uid value that was previously
+ set
+ """
+ try:
+ with open(settings.LDAP_MAX_UID_FILE_PATH, 'r+') as handler:
+ try:
+ return_value = int(handler.read())
+ except ValueError as ve:
+ logger.error(
+ "Error reading int value from {}. {}"
+ "Returning default value {} instead".format(
+ settings.LDAP_MAX_UID_PATH,
+ str(ve),
+ settings.LDAP_DEFAULT_START_UID
+ )
+ )
+ return_value = settings.LDAP_DEFAULT_START_UID
+ return return_value
+ except FileNotFoundError as fnfe:
+ logger.error("File not found : " + str(fnfe))
+ return_value = settings.LDAP_DEFAULT_START_UID
+ logger.error("So, returning UID={}".format(return_value))
+ return return_value
diff --git a/dal/dal/urls.py b/dal/urls.py
similarity index 94%
rename from dal/dal/urls.py
rename to dal/urls.py
index 10875b6..b5f4a3a 100644
--- a/dal/dal/urls.py
+++ b/dal/urls.py
@@ -16,5 +16,5 @@ urlpatterns = [
path('logout/', LogOut.as_view(), name="logout"),
path('reset///', ResetRequest.as_view()),
path('reset/', ResetRequest.as_view(), name="reset"),
- path('', Index.as_view(), name="index"),
-]
+ path('', Index.as_view(), name="login_index"),
+]
\ No newline at end of file
diff --git a/dal/dal/views.py b/dal/views.py
similarity index 62%
rename from dal/dal/views.py
rename to dal/views.py
index 0e8cd19..5d643d2 100644
--- a/dal/dal/views.py
+++ b/dal/views.py
@@ -1,14 +1,16 @@
# Imports from django
from django.shortcuts import render
-from django.views.generic import View
+from django.views.generic import View, FormView
from django.contrib.auth import authenticate, login, logout
-from django.contrib.auth.models import User
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import HttpResponse
from django.core.validators import validate_email, ValidationError
from django.urls import reverse_lazy
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.core.mail import EmailMessage
+from django.views.decorators.cache import cache_control
from .models import ResetToken
+from .forms import LoginForm
+from .ungleich_ldap import LdapManager
# Imports for the extra stuff not in django
@@ -18,99 +20,31 @@ from datetime import datetime
from random import choice, randint
import string
-import os
-
-# Use ldap, like django_auth_backend
-import ldap
-import ldap.modlist as modlist
-
from django.conf import settings
+from django.contrib.auth.mixins import LoginRequiredMixin
+class Index(FormView):
+ template_name = "landing.html"
+ form_class = LoginForm
+ success_url = 'useroptions.html'
-class LDAP(object):
- def __init__(self):
- 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_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()
-
- 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 len(result) > 0:
- exists = True
-
- return exists
-
- def create_user(self, user, password, firstname, lastname, email):
- dn = self.dn.format(user)
- 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")
- }
-
- 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]
-
- for result in self.conn.search_s(self.search_base,
- self.search_scope,
- self.search_filter):
- if 'uidNumber' in result[1]:
- uidlist.append(int(result[1]['uidNumber'][0]))
-
- return sorted(uidlist)[-1] + 1
-
-class Index(View):
- def get(self, request):
- if request.user.is_authenticated:
- return render(request, 'useroptions.html', { 'user': request.user } )
- return render(request, 'landing.html')
-
- def post(self, request):
- username = request.POST.get('username')
- password = request.POST.get('password')
- pwd = r'%s' % password
- user = authenticate(request, username=username, password=pwd)
+ def form_valid(self, form):
+ email = form.cleaned_data.get('email')
+ password = form.cleaned_data.get('password')
+ user = authenticate(username=email, password=password)
if user is not None:
- login(request, user)
- return render(request, 'useroptions.html', { 'user': user } )
- return render(request, 'loginfailed.html')
+ login(self.request, user)
+ return render(self.request, 'useroptions.html', { 'user': user } )
+ return render(self.request, 'loginfailed.html')
+
+ @cache_control(no_cache=True, must_revalidate=True, no_store=True)
+ def get(self, request, *args, **kwargs):
+ if self.request.user.is_authenticated:
+ return render(self.request, 'useroptions.html',
+ { 'user': self.request.user.username } )
+ return super(Index, self).get(request, *args, **kwargs)
+
class Register(View):
def get(self, request):
@@ -118,8 +52,6 @@ class Register(View):
# Someone filled out the register page, do some basic checks and throw it at nameko
def post(self, request):
- l = LDAP()
-
service = 'register an user'
urlname = 'register'
username = request.POST.get('username')
@@ -127,9 +59,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.' } )
-
password1 = request.POST.get('password1')
password2 = request.POST.get('password2')
if password1 != password2:
@@ -156,7 +85,10 @@ class Register(View):
pwd = r'%s' % password1
try:
- l.create_user(username, pwd, firstname, lastname, email)
+ ldap_manager = LdapManager()
+ ldap_manager.create_user(
+ username, pwd, firstname, lastname, email
+ )
except Exception as e:
return render(request, 'error.html', { 'urlname': urlname,
'service': service,
@@ -164,24 +96,37 @@ class Register(View):
return render(request, 'usercreated.html', { 'user': username } )
-class ChangeData(View):
+class ChangeData(LoginRequiredMixin, View):
+ login_url = reverse_lazy('login_index')
# provide the form for the change request
def get(self, request):
urlname = 'change_data'
service = 'get default data for logged in user'
- if not request.user.is_authenticated:
- return render(request, 'mustbeloggedin.html')
+
user = request.user
- login(request, user)
- # get basic data (firstname, lastname, email)
- with get_pool().next() as rpc:
- (state, firstname, lastname, email) = rpc.getuserdata.get_data(str(request.user))
- # If it throws an error, the errormessage gets put into firstname.. not great naming, but works best this way
- if state == "error":
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': firstname } )
- # The template puts the old data as standard in the fields
+ ldap_manager = LdapManager()
+ user_exists, entries = ldap_manager.check_user_exists(
+ uid=user.username,
+ attributes=['uid', 'givenName', 'sn', 'mail'],
+ search_base=settings.ENTIRE_SEARCH_BASE
+ )
+
+ if user_exists:
+ return render(
+ request,
+ 'changeuserdata.html',
+ { 'user': user.username,
+ 'firstname': entries[0].givenName
+ if entries[0].givenName.value is not None else '',
+ 'lastname': entries[0].sn
+ if entries[0].sn.value is not None else '',
+ 'email': entries[0].mail
+ if entries[0].mail.value is not None else ''}
+ )
else:
- return render(request, 'changeuserdata.html', { 'user': str(request.user), 'firstname': firstname, 'lastname': lastname, 'email': email } )
+ return render(request, 'error.html',
+ {'urlname': urlname, 'service': service,
+ 'error': request.user.username})
# get the change request
def post(self, request):
@@ -189,11 +134,6 @@ class ChangeData(View):
service = 'change user data'
urlname = 'change_data'
- # 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')
@@ -209,15 +149,19 @@ class ChangeData(View):
validate_email(email)
except ValidationError:
return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The supplied email address is invalid.' } )
- # Trying to change the data
- with get_pool().next() as rpc:
- result = rpc.changeuserdata.change_data(user, firstname, lastname, email)
+
+ ldap_manager = LdapManager()
+ result, msg = ldap_manager.change_user_details(
+ uid=request.user.username,
+ details={"givenName": firstname, "sn": lastname, "mail": email}
+ )
+
# Data change worked
- if result == True:
- return render(request, 'changeddata.html', { 'user': user, 'firstname': firstname, 'lastname': lastname, 'email': email } )
+ if result:
+ return render(request, 'changeddata.html', { 'user': request.user.username, 'firstname': firstname, 'lastname': lastname, 'email': email } )
# Data change did not work, display error
else:
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
+ return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': msg } )
class ResetPassword(View):
@@ -229,32 +173,57 @@ class ResetPassword(View):
service = 'send a password reset request'
user = request.POST.get('user')
# First, check if the user exists
- if not check_user_exists(user):
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'The user does not exist.' } )
- # user exists, so try to get email
- with get_pool().next() as rpc:
- (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)
- # Either error with the datalookup or no email provided
- if state == "error" or email == 'No email given' or not email:
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unable to retrieve email address for user.' } )
- # Try to send the email out
- emailsend = self.email(user, email)
- # Email got sent out
- if emailsend == True:
- return render(request, 'send_resetrequest.html', { 'user': user } )
- # Error while trying to send email
+ ldap_manager = LdapManager()
+ user_exists, entries = ldap_manager.check_user_exists(
+ uid=user,
+ search_base=settings.ENTIRE_SEARCH_BASE,
+ attributes=['uid', 'givenName', 'sn', 'mail']
+ )
+ if user_exists:
+ # user exists, so try to get email
+ # with get_pool().next() as rpc:
+ # (state, tmp1, tmp2, email) = rpc.getuserdata.get_data(user)
+ # Either error with the datalookup or no email provided
+ email = entries[0].mail.value
+ if email is None:
+ return render(
+ request, 'error.html',
+ {'urlname': urlname, 'service': service,
+ 'error': 'Unable to retrieve email address for user.'}
+ )
+
+ base_url = "{0}://{1}".format(self.request.scheme,
+ self.request.get_host())
+ # Try to send the email out
+ emailsend = self.email(user, email, base_url)
+ # Email got sent out
+ if emailsend == True:
+ return render(
+ request, 'send_resetrequest.html', {'user': user}
+ )
+ # Error while trying to send email
+ else:
+ return render(
+ request, 'error.html',
+ {'urlname': urlname, 'service': service,
+ 'error': emailsend}
+ )
else:
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': emailsend } )
+ return render(
+ request, 'error.html',
+ { 'urlname': urlname, 'service': service,
+ 'error': 'The user does not exist.' }
+ )
# Sends an email to the user with the 24h active link for a password reset
- def email(self, user, email):
+ def email(self, user, email, base_url):
# getting epoch for the time now in UTC to spare us headache with timezones
creationtime = int(datetime.utcnow().timestamp())
# Construct the data for the email
- email_from = 'Userservice at ungleich <%s>' % config['EMAIL']['EMAILFROM']
+ email_from = settings.EMAIL_FROM_ADDRESS
to = ['%s <%s>' % (user, email)]
subject = 'Password reset request for %s' % user
- link = self.build_reset_link(user, creationtime)
+ link = self.build_reset_link(user, creationtime, base_url)
body = 'This is an automated email which was triggered by a reset request for the user %s. Please do not reply to this email.\n' % user
body += 'If you received this email in error, please disregard it. If you get multiple emails like this, please contact us to look into potential abuse.\n'
body += 'To reset your password, please follow the link below:\n'
@@ -275,9 +244,8 @@ class ResetPassword(View):
return result
# Builds the reset link for the email and puts the token into the database
- def build_reset_link(self, user, epochutc):
+ def build_reset_link(self, user, epochutc, base_url):
# set up the data
- host = 'account-staging.ungleich.ch'
tokengen = PasswordResetTokenGenerator()
# create some noise for use in the tokengenerator
pseudouser = PseudoUser()
@@ -288,7 +256,7 @@ class ResetPassword(View):
newdbentry = ResetToken(user=user, token=token, creation=epochutc)
newdbentry.save()
# set up the link
- link = 'https://%s/reset/%s/%s/' % (host, userpart.decode('utf-8'), token)
+ link = (base_url + '/reset/%s/%s/') % (userpart.decode('utf-8'), token)
return link
@@ -311,6 +279,7 @@ class ResetRequest(View):
user = b64decode(tmp_user)
user_clean = user.decode('utf-8')
# set checks_out = True if token is found in database
+ checks_out = False
dbentries = ResetToken.objects.all().filter(user=user_clean)
for entry in dbentries:
if entry.token == token:
@@ -334,7 +303,7 @@ class ResetRequest(View):
# get the hidden value of user
user = request.POST.get("user")
# some checks over the supplied data
- if user == "" or not user:
+ if user == "" or not user or user != self.request.user.username:
return render(request, 'error.html', { 'service': service, 'error': 'Something went wrong. Did you use the supplied form?' } )
if password1 == "" or not password1 or password2 == "" or not password2:
return render(request, 'error.html', { 'service': service, 'error': 'Please supply a password and confirm it.' } )
@@ -343,11 +312,14 @@ class ResetRequest(View):
if len(password1) < 8:
return render(request, 'error.html', { 'service': service, 'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
# everything checks out, now change the password
- with get_pool().next() as rpc:
- pwd = r'%s' % password1
- result = rpc.changepassword.change_password(user, pwd)
- # password change successfull
- if result == True:
+
+ ldap_manager = LdapManager()
+ result = ldap_manager.change_password(
+ user,
+ password1
+ )
+ # password change successful
+ if result:
return render(request, 'changedpassword.html', { 'user': user } )
# Something went wrong while changing the password
else:
@@ -367,8 +339,8 @@ class ResetRequest(View):
# The logged in user can change the password here
-class ChangePassword(View):
-
+class ChangePassword(LoginRequiredMixin, View):
+ login_url = reverse_lazy('login_index')
# Presents the page for a logged in user
def get(self, request):
if not request.user.is_authenticated:
@@ -402,12 +374,15 @@ class ChangePassword(View):
if len(password1) < 8:
return render(request, 'error.html', { 'urlname': urlname, 'service': service,
'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
- with get_pool().next() as rpc:
- # Trying to change the password
- pwd = r'%s' % password1
- result = rpc.changepassword.change_password(user, pwd)
+ from .ungleich_ldap import LdapManager
+ ldap_manager = LdapManager()
+ result = ldap_manager.change_password(
+ user,
+ password1
+ )
# Password was changed
- if result == True:
+ if result:
+ logout(request)
return render(request, 'changedpassword.html', { 'user': user } )
# Password not changed, instead got some kind of error
else:
@@ -415,7 +390,8 @@ class ChangePassword(View):
# Deletes an account
-class DeleteAccount(View):
+class DeleteAccount(LoginRequiredMixin, View):
+ login_url = reverse_lazy('login_index')
# Show the basic form for deleting an account
def get(self, request):
return render(request, 'deleteaccount.html')
@@ -428,32 +404,41 @@ class DeleteAccount(View):
# Does the user exist?
username = request.POST.get('username')
- if not check_user_exists(username):
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown user.' } )
-
- # Do user and password match?
- password = request.POST.get('password')
- pwd = r'%s' % password
- 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)
- # User deleted
- if result == True:
- logout(request)
- return render(request, 'deleteduser.html', { 'user': username } )
- # User not deleted, got some kind of error
+ ldap_manager = LdapManager()
+ user_exists, user_details = ldap_manager.check_user_exists(username)
+ if user_exists and request.user.username == username:
+ # Do user and password match?
+ password = request.POST.get('password')
+ pwd = r'%s' % password
+ 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.'})
+ result = ldap_manager.delete_user(username)
+ # User deleted
+ if result:
+ logout(request)
+ return render(request, 'deleteduser.html', {'user': username})
+ # User not deleted, got some kind of error
+ else:
+ return render(request, 'error.html',
+ {'urlname': urlname, 'service': service,
+ 'error': result})
else:
- return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': result } )
+ return render(request, 'error.html', { 'urlname': urlname, 'service': service, 'error': 'Unknown user.' } )
# Log out the session
class LogOut(View):
def get(self, request):
logout(request)
- return HttpResponse("You have been logged out.", status=200)
+ return HttpResponse(
+ "You have been logged out. You will be redirected in 2 seconds."
+ "",
+ status=200
+ )
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/logs/.keep b/logs/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/dal/manage.py b/manage.py
similarity index 100%
rename from dal/manage.py
rename to manage.py
diff --git a/requirements.txt b/requirements.txt
index 0767c8c..c68b636 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,7 @@
django
django-auth-ldap
python-ldap
-django-dotenv
+django-bootstrap3
+django-filter==2.1.0
+python-decouple
+ldap3