├── app ├── static │ ├── css │ │ ├── css │ │ │ ├── mixins │ │ │ │ └── _text-hide.css │ │ │ └── bootstrap-reboot.css │ │ ├── Flaticon.woff │ │ ├── Flaticon.woff2 │ │ ├── ajax-loader.gif │ │ ├── owl.theme.default.min.css │ │ ├── flaticon.css │ │ ├── jquery.timepicker.css │ │ ├── _flaticon.scss │ │ ├── owl.carousel.min.css │ │ ├── content.css │ │ └── bootstrap │ │ │ └── bootstrap-reboot.css │ ├── images │ │ ├── 404.jpg │ │ ├── bg_1.jpg │ │ └── favicon.png │ ├── scss │ │ └── bootstrap │ │ │ ├── utilities │ │ │ ├── _clearfix.scss │ │ │ ├── _screenreaders.scss │ │ │ ├── _visibility.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _float.scss │ │ │ ├── _align.scss │ │ │ ├── _background.scss │ │ │ ├── _position.scss │ │ │ ├── _embed.scss │ │ │ ├── _display.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ ├── _borders.scss │ │ │ └── _flex.scss │ │ │ ├── _media.scss │ │ │ ├── mixins │ │ │ ├── _box-shadow.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _size.scss │ │ │ ├── _visibility.scss │ │ │ ├── _lists.scss │ │ │ ├── _text-truncate.scss │ │ │ ├── _resize.scss │ │ │ ├── _float.scss │ │ │ ├── _badge.scss │ │ │ ├── _alert.scss │ │ │ ├── _nav-divider.scss │ │ │ ├── _text-emphasis.scss │ │ │ ├── _transition.scss │ │ │ ├── _text-hide.scss │ │ │ ├── _list-group.scss │ │ │ ├── _pagination.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _reset-text.scss │ │ │ ├── _table-row.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _hover.scss │ │ │ ├── _image.scss │ │ │ ├── _caret.scss │ │ │ ├── _grid.scss │ │ │ ├── _grid-framework.scss │ │ │ ├── _gradients.scss │ │ │ ├── _buttons.scss │ │ │ ├── _forms.scss │ │ │ └── _breakpoints.scss │ │ │ ├── _transitions.scss │ │ │ ├── _jumbotron.scss │ │ │ ├── bootstrap-reboot.scss │ │ │ ├── _utilities.scss │ │ │ ├── _root.scss │ │ │ ├── bootstrap-grid.scss │ │ │ ├── _close.scss │ │ │ ├── _progress.scss │ │ │ ├── bootstrap.scss │ │ │ ├── _mixins.scss │ │ │ ├── _badge.scss │ │ │ ├── _grid.scss │ │ │ ├── _code.scss │ │ │ ├── _images.scss │ │ │ ├── _alert.scss │ │ │ ├── _breadcrumb.scss │ │ │ ├── _pagination.scss │ │ │ ├── _nav.scss │ │ │ ├── _type.scss │ │ │ ├── _functions.scss │ │ │ ├── _tooltip.scss │ │ │ ├── _print.scss │ │ │ ├── _list-group.scss │ │ │ ├── _buttons.scss │ │ │ ├── _tables.scss │ │ │ ├── _dropdown.scss │ │ │ ├── _button-group.scss │ │ │ ├── _popover.scss │ │ │ ├── _modal.scss │ │ │ ├── _input-group.scss │ │ │ ├── _carousel.scss │ │ │ ├── _card.scss │ │ │ └── _navbar.scss │ ├── fonts │ │ ├── icomoon │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.ttf │ │ │ └── icomoon.woff │ │ ├── flaticon │ │ │ ├── font │ │ │ │ ├── Flaticon.eot │ │ │ │ ├── Flaticon.ttf │ │ │ │ ├── Flaticon.woff │ │ │ │ ├── Flaticon.woff2 │ │ │ │ ├── flaticon.css │ │ │ │ └── _flaticon.scss │ │ │ └── license │ │ │ │ └── license.pdf │ │ ├── ionicons │ │ │ └── fonts │ │ │ │ ├── ionicons.eot │ │ │ │ ├── ionicons.ttf │ │ │ │ ├── ionicons.woff │ │ │ │ └── ionicons.woff2 │ │ └── open-iconic │ │ │ ├── open-iconic.eot │ │ │ ├── open-iconic.otf │ │ │ ├── open-iconic.ttf │ │ │ └── open-iconic.woff │ └── js │ │ ├── jquery.animateNumber.min.js │ │ ├── google-map.js │ │ ├── search.js │ │ └── jquery.waypoints.min.js ├── templates │ ├── 404.html │ ├── reset.html │ └── layout.html ├── src │ └── config.json ├── requirements.txt ├── forms.py ├── app.py └── model.py ├── src ├── pypass.png └── screen.png ├── Dockerfile ├── .gitignore ├── LICENSE └── README.md /app/static/css/css/mixins/_text-hide.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pypass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/src/pypass.png -------------------------------------------------------------------------------- /src/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/src/screen.png -------------------------------------------------------------------------------- /app/static/images/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/images/404.jpg -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_clearfix.scss: -------------------------------------------------------------------------------- 1 | .clearfix { 2 | @include clearfix(); 3 | } 4 | -------------------------------------------------------------------------------- /app/static/css/Flaticon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/css/Flaticon.woff -------------------------------------------------------------------------------- /app/static/images/bg_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/images/bg_1.jpg -------------------------------------------------------------------------------- /app/static/css/Flaticon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/css/Flaticon.woff2 -------------------------------------------------------------------------------- /app/static/css/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/css/ajax-loader.gif -------------------------------------------------------------------------------- /app/static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/images/favicon.png -------------------------------------------------------------------------------- /app/static/fonts/icomoon/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/icomoon/icomoon.eot -------------------------------------------------------------------------------- /app/static/fonts/icomoon/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/icomoon/icomoon.ttf -------------------------------------------------------------------------------- /app/static/fonts/icomoon/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/icomoon/icomoon.woff -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/Flaticon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/flaticon/font/Flaticon.eot -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/Flaticon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/flaticon/font/Flaticon.ttf -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/Flaticon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/flaticon/font/Flaticon.woff -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/Flaticon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/flaticon/font/Flaticon.woff2 -------------------------------------------------------------------------------- /app/static/fonts/flaticon/license/license.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/flaticon/license/license.pdf -------------------------------------------------------------------------------- /app/static/fonts/ionicons/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/ionicons/fonts/ionicons.eot -------------------------------------------------------------------------------- /app/static/fonts/ionicons/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/ionicons/fonts/ionicons.ttf -------------------------------------------------------------------------------- /app/static/fonts/ionicons/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/ionicons/fonts/ionicons.woff -------------------------------------------------------------------------------- /app/static/fonts/open-iconic/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/open-iconic/open-iconic.eot -------------------------------------------------------------------------------- /app/static/fonts/open-iconic/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/open-iconic/open-iconic.otf -------------------------------------------------------------------------------- /app/static/fonts/open-iconic/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/open-iconic/open-iconic.ttf -------------------------------------------------------------------------------- /app/static/fonts/open-iconic/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/open-iconic/open-iconic.woff -------------------------------------------------------------------------------- /app/static/fonts/ionicons/fonts/ionicons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZioGuillo/PYPASS/HEAD/app/static/fonts/ionicons/fonts/ionicons.woff2 -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_media.scss: -------------------------------------------------------------------------------- 1 | .media { 2 | display: flex; 3 | align-items: flex-start; 4 | } 5 | 6 | .media-body { 7 | flex: 1; 8 | } 9 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_box-shadow.scss: -------------------------------------------------------------------------------- 1 | @mixin box-shadow($shadow...) { 2 | @if $enable-shadows { 3 | box-shadow: $shadow; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_clearfix.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix() { 2 | &::after { 3 | display: block; 4 | clear: both; 5 | content: ""; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_size.scss: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | @mixin size($width, $height: $width) { 4 | width: $width; 5 | height: $height; 6 | } 7 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_visibility.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Visibility 4 | 5 | @mixin invisible($visibility) { 6 | visibility: $visibility !important; 7 | } 8 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_screenreaders.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Screenreaders 3 | // 4 | 5 | .sr-only { 6 | @include sr-only(); 7 | } 8 | 9 | .sr-only-focusable { 10 | @include sr-only-focusable(); 11 | } 12 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_visibility.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Visibility utilities 3 | // 4 | 5 | .visible { 6 | @include invisible(visible); 7 | } 8 | 9 | .invisible { 10 | @include invisible(hidden); 11 | } 12 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_lists.scss: -------------------------------------------------------------------------------- 1 | // Lists 2 | 3 | // Unstyled keeps list items block level, just removes default browser padding and list-style 4 | @mixin list-unstyled { 5 | padding-left: 0; 6 | list-style: none; 7 | } 8 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_text-truncate.scss: -------------------------------------------------------------------------------- 1 | // Text truncate 2 | // Requires inline-block or block for proper styling 3 | 4 | @mixin text-truncate() { 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } 9 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_resize.scss: -------------------------------------------------------------------------------- 1 | // Resize anything 2 | 3 | @mixin resizable($direction) { 4 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` 5 | resize: $direction; // Options: horizontal, vertical, both 6 | } 7 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_float.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | @mixin float-left { 4 | float: left !important; 5 | } 6 | @mixin float-right { 7 | float: right !important; 8 | } 9 | @mixin float-none { 10 | float: none !important; 11 | } 12 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_shadows.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | .shadow-sm { box-shadow: $box-shadow-sm !important; } 4 | .shadow { box-shadow: $box-shadow !important; } 5 | .shadow-lg { box-shadow: $box-shadow-lg !important; } 6 | .shadow-none { box-shadow: none !important; } 7 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_badge.scss: -------------------------------------------------------------------------------- 1 | @mixin badge-variant($bg) { 2 | color: color-yiq($bg); 3 | background-color: $bg; 4 | 5 | &[href] { 6 | @include hover-focus { 7 | color: color-yiq($bg); 8 | text-decoration: none; 9 | background-color: darken($bg, 10%); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_alert.scss: -------------------------------------------------------------------------------- 1 | @mixin alert-variant($background, $border, $color) { 2 | color: $color; 3 | @include gradient-bg($background); 4 | border-color: $border; 5 | 6 | hr { 7 | border-top-color: darken($border, 5%); 8 | } 9 | 10 | .alert-link { 11 | color: darken($color, 10%); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_nav-divider.scss: -------------------------------------------------------------------------------- 1 | // Horizontal dividers 2 | // 3 | // Dividers (basically an hr) within dropdowns and nav lists 4 | 5 | @mixin nav-divider($color: $nav-divider-color, $margin-y: $nav-divider-margin-y) { 6 | height: 0; 7 | margin: $margin-y 0; 8 | overflow: hidden; 9 | border-top: 1px solid $color; 10 | } 11 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_text-emphasis.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Typography 4 | 5 | @mixin text-emphasis-variant($parent, $color) { 6 | #{$parent} { 7 | color: $color !important; 8 | } 9 | a#{$parent} { 10 | @include hover-focus { 11 | color: darken($color, 10%) !important; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_transition.scss: -------------------------------------------------------------------------------- 1 | @mixin transition($transition...) { 2 | @if $enable-transitions { 3 | @if length($transition) == 0 { 4 | transition: $transition-base; 5 | } @else { 6 | transition: $transition; 7 | } 8 | } 9 | 10 | @media screen and (prefers-reduced-motion: reduce) { 11 | transition: none; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_sizing.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Width and height 4 | 5 | @each $prop, $abbrev in (width: w, height: h) { 6 | @each $size, $length in $sizes { 7 | .#{$abbrev}-#{$size} { #{$prop}: $length !important; } 8 | } 9 | } 10 | 11 | .mw-100 { max-width: 100% !important; } 12 | .mh-100 { max-height: 100% !important; } 13 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_float.scss: -------------------------------------------------------------------------------- 1 | @each $breakpoint in map-keys($grid-breakpoints) { 2 | @include media-breakpoint-up($breakpoint) { 3 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints); 4 | 5 | .float#{$infix}-left { @include float-left; } 6 | .float#{$infix}-right { @include float-right; } 7 | .float#{$infix}-none { @include float-none; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_text-hide.scss: -------------------------------------------------------------------------------- 1 | // CSS image replacement 2 | @mixin text-hide() { 3 | // stylelint-disable-next-line font-family-no-missing-generic-family-keyword 4 | font: 0/0 a; 5 | color: transparent; 6 | text-shadow: none; 7 | background-color: transparent; 8 | border: 0; 9 | 10 | @warn "The `text-hide()` mixin has been deprecated as of v4.1.0. It will be removed entirely in v5."; 11 | } 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | MAINTAINER PABLO CISNEROS "pcisnerp@gmail.com" 3 | RUN apt-get update \ 4 | && apt-get install -y python3-pip python3-dev libsasl2-dev python-dev libldap2-dev libssl-dev libsnmp-dev apt-utils iputils-ping \ 5 | && cd /usr/local/bin \ 6 | && ln -s /usr/bin/python3 python \ 7 | && pip3 install --upgrade pip 8 | 9 | COPY ./app /app 10 | 11 | WORKDIR /app 12 | 13 | RUN pip install -r requirements.txt 14 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_transitions.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable selector-no-qualifying-type 2 | 3 | .fade { 4 | @include transition($transition-fade); 5 | 6 | &:not(.show) { 7 | opacity: 0; 8 | } 9 | } 10 | 11 | .collapse { 12 | &:not(.show) { 13 | display: none; 14 | } 15 | } 16 | 17 | .collapsing { 18 | position: relative; 19 | height: 0; 20 | overflow: hidden; 21 | @include transition($transition-collapse); 22 | } 23 | -------------------------------------------------------------------------------- /app/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block header %} 3 |

{% block title %} Error - Digitale Brain {% endblock %}

4 | {% endblock %} 5 | 6 | {% block content %} 7 |
8 |

"Everything’s impossible until somebody does it.” but now... there is an ERROR

9 |
10 | {% endblock content %} -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_jumbotron.scss: -------------------------------------------------------------------------------- 1 | .jumbotron { 2 | padding: $jumbotron-padding ($jumbotron-padding / 2); 3 | margin-bottom: $jumbotron-padding; 4 | background-color: $jumbotron-bg; 5 | @include border-radius($border-radius-lg); 6 | 7 | @include media-breakpoint-up(sm) { 8 | padding: ($jumbotron-padding * 2) $jumbotron-padding; 9 | } 10 | } 11 | 12 | .jumbotron-fluid { 13 | padding-right: 0; 14 | padding-left: 0; 15 | @include border-radius(0); 16 | } 17 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_align.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | .align-baseline { vertical-align: baseline !important; } // Browser default 4 | .align-top { vertical-align: top !important; } 5 | .align-middle { vertical-align: middle !important; } 6 | .align-bottom { vertical-align: bottom !important; } 7 | .align-text-bottom { vertical-align: text-bottom !important; } 8 | .align-text-top { vertical-align: text-top !important; } 9 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/bootstrap-reboot.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | 9 | @import "functions"; 10 | @import "variables"; 11 | @import "mixins"; 12 | @import "reboot"; 13 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_background.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | @each $color, $value in $theme-colors { 4 | @include bg-variant(".bg-#{$color}", $value); 5 | } 6 | 7 | @if $enable-gradients { 8 | @each $color, $value in $theme-colors { 9 | @include bg-gradient-variant(".bg-gradient-#{$color}", $value); 10 | } 11 | } 12 | 13 | .bg-white { 14 | background-color: $white !important; 15 | } 16 | 17 | .bg-transparent { 18 | background-color: transparent !important; 19 | } 20 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_utilities.scss: -------------------------------------------------------------------------------- 1 | @import "utilities/align"; 2 | @import "utilities/background"; 3 | @import "utilities/borders"; 4 | @import "utilities/clearfix"; 5 | @import "utilities/display"; 6 | @import "utilities/embed"; 7 | @import "utilities/flex"; 8 | @import "utilities/float"; 9 | @import "utilities/position"; 10 | @import "utilities/screenreaders"; 11 | @import "utilities/shadows"; 12 | @import "utilities/sizing"; 13 | @import "utilities/spacing"; 14 | @import "utilities/text"; 15 | @import "utilities/visibility"; 16 | -------------------------------------------------------------------------------- /app/src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "SECRET_KEY_FLASK": "werewtrwetewrwer53535353", 3 | "SLACK_BOT_TOKEN" : "xoxb-", 4 | "domain": "domain.com", 5 | "BASEDN": "OU=Users,dc=domain,dc=com", 6 | "user_admin" : "admin-user", 7 | "passwd_admin" : "password_admin", 8 | "slack_db" : "slack_db.json", 9 | "Slack_Activation" : "False", 10 | "debug": "True", 11 | "company": "DIGITALEBRAIN", 12 | "RECAPTCHA_PUBLIC_KEY": "GOOGLE CODE", 13 | "RECAPTCHA_PRIVATE_KEY": "GOOGLE CODE", 14 | "CRT_CERTIFICATE":"name.crt", 15 | "KEY_CERTIFICATE":"name.key" 16 | } -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_list-group.scss: -------------------------------------------------------------------------------- 1 | // List Groups 2 | 3 | @mixin list-group-item-variant($state, $background, $color) { 4 | .list-group-item-#{$state} { 5 | color: $color; 6 | background-color: $background; 7 | 8 | &.list-group-item-action { 9 | @include hover-focus { 10 | color: $color; 11 | background-color: darken($background, 5%); 12 | } 13 | 14 | &.active { 15 | color: $white; 16 | background-color: $color; 17 | border-color: $color; 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_pagination.scss: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | @mixin pagination-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) { 4 | .page-link { 5 | padding: $padding-y $padding-x; 6 | font-size: $font-size; 7 | line-height: $line-height; 8 | } 9 | 10 | .page-item { 11 | &:first-child { 12 | .page-link { 13 | @include border-left-radius($border-radius); 14 | } 15 | } 16 | &:last-child { 17 | .page-link { 18 | @include border-right-radius($border-radius); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_background-variant.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Contextual backgrounds 4 | 5 | @mixin bg-variant($parent, $color) { 6 | #{$parent} { 7 | background-color: $color !important; 8 | } 9 | a#{$parent}, 10 | button#{$parent} { 11 | @include hover-focus { 12 | background-color: darken($color, 10%) !important; 13 | } 14 | } 15 | } 16 | 17 | @mixin bg-gradient-variant($parent, $color) { 18 | #{$parent} { 19 | background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x !important; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_reset-text.scss: -------------------------------------------------------------------------------- 1 | @mixin reset-text { 2 | font-family: $font-family-base; 3 | // We deliberately do NOT reset font-size or word-wrap. 4 | font-style: normal; 5 | font-weight: $font-weight-normal; 6 | line-height: $line-height-base; 7 | text-align: left; // Fallback for where `start` is not supported 8 | text-align: start; // stylelint-disable-line declaration-block-no-duplicate-properties 9 | text-decoration: none; 10 | text-shadow: none; 11 | text-transform: none; 12 | letter-spacing: normal; 13 | word-break: normal; 14 | word-spacing: normal; 15 | white-space: normal; 16 | line-break: auto; 17 | } 18 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_root.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | // Custom variable values only support SassScript inside `#{}`. 3 | @each $color, $value in $colors { 4 | --#{$color}: #{$value}; 5 | } 6 | 7 | @each $color, $value in $theme-colors { 8 | --#{$color}: #{$value}; 9 | } 10 | 11 | @each $bp, $value in $grid-breakpoints { 12 | --breakpoint-#{$bp}: #{$value}; 13 | } 14 | 15 | // Use `inspect` for lists so that quoted items keep the quotes. 16 | // See https://github.com/sass/sass/issues/2383#issuecomment-336349172 17 | --font-family-sans-serif: #{inspect($font-family-sans-serif)}; 18 | --font-family-monospace: #{inspect($font-family-monospace)}; 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | *.pyc 10 | 11 | 12 | # Packages # 13 | ############ 14 | # it's better to unpack these files and commit the raw source 15 | # git has its own built in compression methods 16 | *.7z 17 | *.dmg 18 | *.gz 19 | *.iso 20 | *.jar 21 | *.rar 22 | *.tar 23 | *.zip 24 | *.doc 25 | *.docx 26 | 27 | # Logs and databases # 28 | ###################### 29 | *.log 30 | *.sql 31 | *.sqlite 32 | 33 | # OS generated files # 34 | ###################### 35 | .DS_Store 36 | .DS_Store? 37 | ._* 38 | .Spotlight-V100 39 | .Trashes 40 | ehthumbs.db 41 | Thumbs.db 42 | .vs 43 | .vs* 44 | bin/ 45 | venv 46 | .idea 47 | _pycache_ 48 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_table-row.scss: -------------------------------------------------------------------------------- 1 | // Tables 2 | 3 | @mixin table-row-variant($state, $background) { 4 | // Exact selectors below required to override `.table-striped` and prevent 5 | // inheritance to nested tables. 6 | .table-#{$state} { 7 | &, 8 | > th, 9 | > td { 10 | background-color: $background; 11 | } 12 | } 13 | 14 | // Hover states for `.table-hover` 15 | // Note: this is not available for cells or rows within `thead` or `tfoot`. 16 | .table-hover { 17 | $hover-background: darken($background, 5%); 18 | 19 | .table-#{$state} { 20 | @include hover { 21 | background-color: $hover-background; 22 | 23 | > td, 24 | > th { 25 | background-color: $hover-background; 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/bootstrap-grid.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Grid v4.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | 8 | @at-root { 9 | @-ms-viewport { width: device-width; } // stylelint-disable-line at-rule-no-vendor-prefix 10 | } 11 | 12 | html { 13 | box-sizing: border-box; 14 | -ms-overflow-style: scrollbar; 15 | } 16 | 17 | *, 18 | *::before, 19 | *::after { 20 | box-sizing: inherit; 21 | } 22 | 23 | @import "functions"; 24 | @import "variables"; 25 | 26 | @import "mixins/breakpoints"; 27 | @import "mixins/grid-framework"; 28 | @import "mixins/grid"; 29 | 30 | @import "grid"; 31 | @import "utilities/display"; 32 | @import "utilities/flex"; 33 | -------------------------------------------------------------------------------- /app/requirements.txt: -------------------------------------------------------------------------------- 1 | config 2 | aniso8601==3.0.2 3 | asn1crypto==0.24.0 4 | astroid==2.1.0 5 | autopep8==1.4.3 6 | certifi==2024.7.4 7 | cffi==1.12.2 8 | chardet==3.0.4 9 | click==6.7 10 | cryptography==43.0.1 11 | Flask==2.2.5 12 | Flask-RESTful==0.3.6 13 | Flask-WTF==0.14.2 14 | future==0.18.3 15 | idna==3.7 16 | isort==4.3.4 17 | itsdangerous==0.24 18 | Jinja2==3.1.5 19 | jsondatabase==0.1.7 20 | lazy-object-proxy==1.3.1 21 | ldap3==2.5.2 22 | MarkupSafe==1.0 23 | mccabe==0.6.1 24 | pyad==0.5.20 25 | pyasn1==0.4.5 26 | pyasn1-modules==0.2.4 27 | pycodestyle==2.5.0 28 | pycparser==2.19 29 | pylint==2.2.2 30 | pymongo==4.6.3 31 | pyOpenSSL==19.0.0 32 | python-ldap==3.4.0 33 | pytz==2018.5 34 | requests==2.32.2 35 | six==1.12.0 36 | slackclient==1.3.1 37 | urllib3==1.26.19 38 | websocket-client==0.54.0 39 | Werkzeug==3.0.6 40 | wrapt==1.11.0 41 | WTForms==2.2.1 42 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_position.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Common values 4 | 5 | // Sass list not in variables since it's not intended for customization. 6 | // stylelint-disable-next-line scss/dollar-variable-default 7 | $positions: static, relative, absolute, fixed, sticky; 8 | 9 | @each $position in $positions { 10 | .position-#{$position} { position: $position !important; } 11 | } 12 | 13 | // Shorthand 14 | 15 | .fixed-top { 16 | position: fixed; 17 | top: 0; 18 | right: 0; 19 | left: 0; 20 | z-index: $zindex-fixed; 21 | } 22 | 23 | .fixed-bottom { 24 | position: fixed; 25 | right: 0; 26 | bottom: 0; 27 | left: 0; 28 | z-index: $zindex-fixed; 29 | } 30 | 31 | .sticky-top { 32 | @supports (position: sticky) { 33 | position: sticky; 34 | top: 0; 35 | z-index: $zindex-sticky; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_border-radius.scss: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | @mixin border-radius($radius: $border-radius) { 4 | @if $enable-rounded { 5 | border-radius: $radius; 6 | } 7 | } 8 | 9 | @mixin border-top-radius($radius) { 10 | @if $enable-rounded { 11 | border-top-left-radius: $radius; 12 | border-top-right-radius: $radius; 13 | } 14 | } 15 | 16 | @mixin border-right-radius($radius) { 17 | @if $enable-rounded { 18 | border-top-right-radius: $radius; 19 | border-bottom-right-radius: $radius; 20 | } 21 | } 22 | 23 | @mixin border-bottom-radius($radius) { 24 | @if $enable-rounded { 25 | border-bottom-right-radius: $radius; 26 | border-bottom-left-radius: $radius; 27 | } 28 | } 29 | 30 | @mixin border-left-radius($radius) { 31 | @if $enable-rounded { 32 | border-top-left-radius: $radius; 33 | border-bottom-left-radius: $radius; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Only display content to screen readers 2 | // 3 | // See: https://a11yproject.com/posts/how-to-hide-content/ 4 | // See: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/ 5 | 6 | @mixin sr-only { 7 | position: absolute; 8 | width: 1px; 9 | height: 1px; 10 | padding: 0; 11 | overflow: hidden; 12 | clip: rect(0, 0, 0, 0); 13 | white-space: nowrap; 14 | border: 0; 15 | } 16 | 17 | // Use in conjunction with .sr-only to only display content when it's focused. 18 | // 19 | // Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 20 | // 21 | // Credit: HTML5 Boilerplate 22 | 23 | @mixin sr-only-focusable { 24 | &:active, 25 | &:focus { 26 | position: static; 27 | width: auto; 28 | height: auto; 29 | overflow: visible; 30 | clip: auto; 31 | white-space: normal; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_hover.scss: -------------------------------------------------------------------------------- 1 | // Hover mixin and `$enable-hover-media-query` are deprecated. 2 | // 3 | // Origally added during our alphas and maintained during betas, this mixin was 4 | // designed to prevent `:hover` stickiness on iOS-an issue where hover styles 5 | // would persist after initial touch. 6 | // 7 | // For backward compatibility, we've kept these mixins and updated them to 8 | // always return their regular psuedo-classes instead of a shimmed media query. 9 | // 10 | // Issue: https://github.com/twbs/bootstrap/issues/25195 11 | 12 | @mixin hover { 13 | &:hover { @content; } 14 | } 15 | 16 | @mixin hover-focus { 17 | &:hover, 18 | &:focus { 19 | @content; 20 | } 21 | } 22 | 23 | @mixin plain-hover-focus { 24 | &, 25 | &:hover, 26 | &:focus { 27 | @content; 28 | } 29 | } 30 | 31 | @mixin hover-focus-active { 32 | &:hover, 33 | &:focus, 34 | &:active { 35 | @content; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm, RecaptchaField 2 | from wtforms import StringField, PasswordField, SubmitField 3 | from wtforms.validators import DataRequired, Length, EqualTo 4 | 5 | 6 | class passwdchangeform(FlaskForm): 7 | username = StringField('Username', validators=[DataRequired()]) 8 | password = PasswordField('Password', validators=[DataRequired()]) 9 | new_password = PasswordField('New Password', validators=[DataRequired(), Length(min=8)]) 10 | confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), Length(min=8), 11 | EqualTo('new_password')]) 12 | submit = SubmitField('Change Password') 13 | recaptcha = RecaptchaField() 14 | 15 | 16 | class loginform(FlaskForm): 17 | username = StringField('Username', validators=[DataRequired()]) 18 | password = PasswordField('Password', validators=[DataRequired()]) 19 | submit = SubmitField('Check') 20 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_embed.scss: -------------------------------------------------------------------------------- 1 | // Credit: Nicolas Gallagher and SUIT CSS. 2 | 3 | .embed-responsive { 4 | position: relative; 5 | display: block; 6 | width: 100%; 7 | padding: 0; 8 | overflow: hidden; 9 | 10 | &::before { 11 | display: block; 12 | content: ""; 13 | } 14 | 15 | .embed-responsive-item, 16 | iframe, 17 | embed, 18 | object, 19 | video { 20 | position: absolute; 21 | top: 0; 22 | bottom: 0; 23 | left: 0; 24 | width: 100%; 25 | height: 100%; 26 | border: 0; 27 | } 28 | } 29 | 30 | .embed-responsive-21by9 { 31 | &::before { 32 | padding-top: percentage(9 / 21); 33 | } 34 | } 35 | 36 | .embed-responsive-16by9 { 37 | &::before { 38 | padding-top: percentage(9 / 16); 39 | } 40 | } 41 | 42 | .embed-responsive-4by3 { 43 | &::before { 44 | padding-top: percentage(3 / 4); 45 | } 46 | } 47 | 48 | .embed-responsive-1by1 { 49 | &::before { 50 | padding-top: percentage(1 / 1); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_close.scss: -------------------------------------------------------------------------------- 1 | .close { 2 | float: right; 3 | font-size: $close-font-size; 4 | font-weight: $close-font-weight; 5 | line-height: 1; 6 | color: $close-color; 7 | text-shadow: $close-text-shadow; 8 | opacity: .5; 9 | 10 | @include hover-focus { 11 | color: $close-color; 12 | text-decoration: none; 13 | opacity: .75; 14 | } 15 | 16 | // Opinionated: add "hand" cursor to non-disabled .close elements 17 | &:not(:disabled):not(.disabled) { 18 | cursor: pointer; 19 | } 20 | } 21 | 22 | // Additional properties for button version 23 | // iOS requires the button element instead of an anchor tag. 24 | // If you want the anchor version, it requires `href="#"`. 25 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 26 | 27 | // stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type 28 | button.close { 29 | padding: 0; 30 | background-color: transparent; 31 | border: 0; 32 | -webkit-appearance: none; 33 | } 34 | // stylelint-enable 35 | -------------------------------------------------------------------------------- /app/static/css/owl.theme.default.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Owl Carousel v2.2.1 3 | * Copyright 2013-2017 David Deutsch 4 | * Licensed under () 5 | */ 6 | .owl-theme .owl-dots, 7 | .owl-theme .owl-nav{text-align:center;-webkit-tap-highlight-color:transparent} 8 | .owl-theme .owl-nav{margin-top:10px} 9 | .owl-theme .owl-nav [class*=owl-]{color:#FFF;font-size:14px;margin:5px;padding:4px 7px;background:#D6D6D6;display:inline-block;cursor:pointer;border-radius:3px;position: absolute;} 10 | .owl-theme .owl-nav [class*=owl-]:hover{background:#869791;color:#FFF;text-decoration:none} 11 | .owl-theme .owl-nav .disabled{opacity:.5;cursor:default} 12 | .owl-theme .owl-nav.disabled+.owl-dots{margin-top:10px} 13 | .owl-theme .owl-dots .owl-dot{display:inline-block;zoom:1} 14 | .owl-theme .owl-dots .owl-dot span{width:10px;height:10px;margin:5px 7px;background:#D6D6D6;display:block;-webkit-backface-visibility:visible;transition:opacity .2s ease;border-radius:30px} 15 | .owl-theme .owl-dots .owl-dot.active span,.owl-theme .owl-dots .owl-dot:hover span{background:#869791} -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_progress.scss: -------------------------------------------------------------------------------- 1 | @keyframes progress-bar-stripes { 2 | from { background-position: $progress-height 0; } 3 | to { background-position: 0 0; } 4 | } 5 | 6 | .progress { 7 | display: flex; 8 | height: $progress-height; 9 | overflow: hidden; // force rounded corners by cropping it 10 | font-size: $progress-font-size; 11 | background-color: $progress-bg; 12 | @include border-radius($progress-border-radius); 13 | @include box-shadow($progress-box-shadow); 14 | } 15 | 16 | .progress-bar { 17 | display: flex; 18 | flex-direction: column; 19 | justify-content: center; 20 | color: $progress-bar-color; 21 | text-align: center; 22 | white-space: nowrap; 23 | background-color: $progress-bar-bg; 24 | @include transition($progress-bar-transition); 25 | } 26 | 27 | .progress-bar-striped { 28 | @include gradient-striped(); 29 | background-size: $progress-height $progress-height; 30 | } 31 | 32 | .progress-bar-animated { 33 | animation: progress-bar-stripes $progress-bar-animation-timing; 34 | } 35 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/bootstrap.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.1.0 (https://getbootstrap.com/) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | 8 | @import "functions"; 9 | @import "variables"; 10 | @import "mixins"; 11 | @import "root"; 12 | @import "reboot"; 13 | @import "type"; 14 | @import "images"; 15 | @import "code"; 16 | @import "grid"; 17 | @import "tables"; 18 | @import "forms"; 19 | @import "buttons"; 20 | @import "transitions"; 21 | @import "dropdown"; 22 | @import "button-group"; 23 | @import "input-group"; 24 | @import "custom-forms"; 25 | @import "nav"; 26 | @import "navbar"; 27 | @import "card"; 28 | @import "breadcrumb"; 29 | @import "pagination"; 30 | @import "badge"; 31 | @import "jumbotron"; 32 | @import "alert"; 33 | @import "progress"; 34 | @import "media"; 35 | @import "list-group"; 36 | @import "close"; 37 | @import "modal"; 38 | @import "tooltip"; 39 | @import "popover"; 40 | @import "carousel"; 41 | @import "utilities"; 42 | @import "print"; 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Joseph N. Mutumi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Toggles 2 | // 3 | // Used in conjunction with global variables to enable certain theme features. 4 | 5 | // Utilities 6 | @import "mixins/breakpoints"; 7 | @import "mixins/hover"; 8 | @import "mixins/image"; 9 | @import "mixins/badge"; 10 | @import "mixins/resize"; 11 | @import "mixins/screen-reader"; 12 | @import "mixins/size"; 13 | @import "mixins/reset-text"; 14 | @import "mixins/text-emphasis"; 15 | @import "mixins/text-hide"; 16 | @import "mixins/text-truncate"; 17 | @import "mixins/visibility"; 18 | 19 | // // Components 20 | @import "mixins/alert"; 21 | @import "mixins/buttons"; 22 | @import "mixins/caret"; 23 | @import "mixins/pagination"; 24 | @import "mixins/lists"; 25 | @import "mixins/list-group"; 26 | @import "mixins/nav-divider"; 27 | @import "mixins/forms"; 28 | @import "mixins/table-row"; 29 | 30 | // // Skins 31 | @import "mixins/background-variant"; 32 | @import "mixins/border-radius"; 33 | @import "mixins/box-shadow"; 34 | @import "mixins/gradients"; 35 | @import "mixins/transition"; 36 | 37 | // // Layout 38 | @import "mixins/clearfix"; 39 | @import "mixins/grid-framework"; 40 | @import "mixins/grid"; 41 | @import "mixins/float"; 42 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_badge.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Requires one of the contextual, color modifier classes for `color` and 4 | // `background-color`. 5 | 6 | .badge { 7 | display: inline-block; 8 | padding: $badge-padding-y $badge-padding-x; 9 | font-size: $badge-font-size; 10 | font-weight: $badge-font-weight; 11 | line-height: 1; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | @include border-radius($badge-border-radius); 16 | 17 | // Empty badges collapse automatically 18 | &:empty { 19 | display: none; 20 | } 21 | } 22 | 23 | // Quick fix for badges in buttons 24 | .btn .badge { 25 | position: relative; 26 | top: -1px; 27 | } 28 | 29 | // Pill badges 30 | // 31 | // Make them extra rounded with a modifier to replace v3's badges. 32 | 33 | .badge-pill { 34 | padding-right: $badge-pill-padding-x; 35 | padding-left: $badge-pill-padding-x; 36 | @include border-radius($badge-pill-border-radius); 37 | } 38 | 39 | // Colors 40 | // 41 | // Contextual variations (linked badges get darker on :hover). 42 | 43 | @each $color, $value in $theme-colors { 44 | .badge-#{$color} { 45 | @include badge-variant($value); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_grid.scss: -------------------------------------------------------------------------------- 1 | // Container widths 2 | // 3 | // Set the container width, and override it for fixed navbars in media queries. 4 | 5 | @if $enable-grid-classes { 6 | .container { 7 | @include make-container(); 8 | @include make-container-max-widths(); 9 | } 10 | } 11 | 12 | // Fluid container 13 | // 14 | // Utilizes the mixin meant for fixed width containers, but with 100% width for 15 | // fluid, full width layouts. 16 | 17 | @if $enable-grid-classes { 18 | .container-fluid { 19 | @include make-container(); 20 | } 21 | } 22 | 23 | // Row 24 | // 25 | // Rows contain and clear the floats of your columns. 26 | 27 | @if $enable-grid-classes { 28 | .row { 29 | @include make-row(); 30 | } 31 | 32 | // Remove the negative margin from default .row, then the horizontal padding 33 | // from all immediate children columns (to prevent runaway style inheritance). 34 | .no-gutters { 35 | margin-right: 0; 36 | margin-left: 0; 37 | 38 | > .col, 39 | > [class*="col-"] { 40 | padding-right: 0; 41 | padding-left: 0; 42 | } 43 | } 44 | } 45 | 46 | // Columns 47 | // 48 | // Common styles for small and large grid columns 49 | 50 | @if $enable-grid-classes { 51 | @include make-grid-columns(); 52 | } 53 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_code.scss: -------------------------------------------------------------------------------- 1 | // Inline and block code styles 2 | code, 3 | kbd, 4 | pre, 5 | samp { 6 | font-family: $font-family-monospace; 7 | } 8 | 9 | // Inline code 10 | code { 11 | font-size: $code-font-size; 12 | color: $code-color; 13 | word-break: break-word; 14 | 15 | // Streamline the style when inside anchors to avoid broken underline and more 16 | a > & { 17 | color: inherit; 18 | } 19 | } 20 | 21 | // User input typically entered via keyboard 22 | kbd { 23 | padding: $kbd-padding-y $kbd-padding-x; 24 | font-size: $kbd-font-size; 25 | color: $kbd-color; 26 | background-color: $kbd-bg; 27 | @include border-radius($border-radius-sm); 28 | @include box-shadow($kbd-box-shadow); 29 | 30 | kbd { 31 | padding: 0; 32 | font-size: 100%; 33 | font-weight: $nested-kbd-font-weight; 34 | @include box-shadow(none); 35 | } 36 | } 37 | 38 | // Blocks of code 39 | pre { 40 | display: block; 41 | font-size: $code-font-size; 42 | color: $pre-color; 43 | 44 | // Account for some code outputs that place code tags in pre tags 45 | code { 46 | font-size: inherit; 47 | color: inherit; 48 | word-break: normal; 49 | } 50 | } 51 | 52 | // Enable scrollable blocks of code 53 | .pre-scrollable { 54 | max-height: $pre-scrollable-max-height; 55 | overflow-y: scroll; 56 | } 57 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_images.scss: -------------------------------------------------------------------------------- 1 | // Responsive images (ensure images don't scale beyond their parents) 2 | // 3 | // This is purposefully opt-in via an explicit class rather than being the default for all ``s. 4 | // We previously tried the "images are responsive by default" approach in Bootstrap v2, 5 | // and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) 6 | // which weren't expecting the images within themselves to be involuntarily resized. 7 | // See also https://github.com/twbs/bootstrap/issues/18178 8 | .img-fluid { 9 | @include img-fluid; 10 | } 11 | 12 | 13 | // Image thumbnails 14 | .img-thumbnail { 15 | padding: $thumbnail-padding; 16 | background-color: $thumbnail-bg; 17 | border: $thumbnail-border-width solid $thumbnail-border-color; 18 | @include border-radius($thumbnail-border-radius); 19 | @include box-shadow($thumbnail-box-shadow); 20 | 21 | // Keep them at most 100% wide 22 | @include img-fluid; 23 | } 24 | 25 | // 26 | // Figures 27 | // 28 | 29 | .figure { 30 | // Ensures the caption's text aligns with the image. 31 | display: inline-block; 32 | } 33 | 34 | .figure-img { 35 | margin-bottom: ($spacer / 2); 36 | line-height: 1; 37 | } 38 | 39 | .figure-caption { 40 | font-size: $figure-caption-font-size; 41 | color: $figure-caption-color; 42 | } 43 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_image.scss: -------------------------------------------------------------------------------- 1 | // Image Mixins 2 | // - Responsive image 3 | // - Retina image 4 | 5 | 6 | // Responsive image 7 | // 8 | // Keep images from scaling beyond the width of their parents. 9 | 10 | @mixin img-fluid { 11 | // Part 1: Set a maximum relative to the parent 12 | max-width: 100%; 13 | // Part 2: Override the height to auto, otherwise images will be stretched 14 | // when setting a width and height attribute on the img element. 15 | height: auto; 16 | } 17 | 18 | 19 | // Retina image 20 | // 21 | // Short retina mixin for setting background-image and -size. 22 | 23 | // stylelint-disable indentation, media-query-list-comma-newline-after 24 | @mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) { 25 | background-image: url($file-1x); 26 | 27 | // Autoprefixer takes care of adding -webkit-min-device-pixel-ratio and -o-min-device-pixel-ratio, 28 | // but doesn't convert dppx=>dpi. 29 | // There's no such thing as unprefixed min-device-pixel-ratio since it's nonstandard. 30 | // Compatibility info: https://caniuse.com/#feat=css-media-resolution 31 | @media only screen and (min-resolution: 192dpi), // IE9-11 don't support dppx 32 | only screen and (min-resolution: 2dppx) { // Standardized 33 | background-image: url($file-2x); 34 | background-size: $width-1x $height-1x; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_alert.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .alert { 6 | position: relative; 7 | padding: $alert-padding-y $alert-padding-x; 8 | margin-bottom: $alert-margin-bottom; 9 | border: $alert-border-width solid transparent; 10 | @include border-radius($alert-border-radius); 11 | } 12 | 13 | // Headings for larger alerts 14 | .alert-heading { 15 | // Specified to prevent conflicts of changing $headings-color 16 | color: inherit; 17 | } 18 | 19 | // Provide class for links that match alerts 20 | .alert-link { 21 | font-weight: $alert-link-font-weight; 22 | } 23 | 24 | 25 | // Dismissible alerts 26 | // 27 | // Expand the right padding and account for the close button's positioning. 28 | 29 | .alert-dismissible { 30 | padding-right: ($close-font-size + $alert-padding-x * 2); 31 | 32 | // Adjust close link position 33 | .close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | padding: $alert-padding-y $alert-padding-x; 38 | color: inherit; 39 | } 40 | } 41 | 42 | 43 | // Alternate styles 44 | // 45 | // Generate contextual modifier classes for colorizing the alert. 46 | 47 | @each $color, $value in $theme-colors { 48 | .alert-#{$color} { 49 | @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/static/js/jquery.animateNumber.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery animateNumber plugin v0.0.14 3 | (c) 2013, Alexandr Borisov. 4 | https://github.com/aishek/jquery-animateNumber 5 | */ 6 | (function(d){var r=function(b){return b.split("").reverse().join("")},m={numberStep:function(b,a){var e=Math.floor(b);d(a.elem).text(e)}},g=function(b){var a=b.elem;a.nodeType&&a.parentNode&&(a=a._animateNumberSetter,a||(a=m.numberStep),a(b.now,b))};d.Tween&&d.Tween.propHooks?d.Tween.propHooks.number={set:g}:d.fx.step.number=g;d.animateNumber={numberStepFactories:{append:function(b){return function(a,e){var f=Math.floor(a);d(e.elem).prop("number",a).text(f+b)}},separator:function(b,a,e){b=b||" "; 7 | a=a||3;e=e||"";return function(f,k){var u=0>f,c=Math.floor((u?-1:1)*f).toString(),n=d(k.elem);if(c.length>a){for(var h=c,l=a,m=h.split("").reverse(),c=[],p,s,q,t=0,g=Math.ceil(h.length/l);t`s. The `::before` pseudo-element generates an element 26 | // *within* the .breadcrumb-item and thereby inherits the `text-decoration`. 27 | // 28 | // To trick IE into suppressing the underline, we give the pseudo-element an 29 | // underline and then immediately remove it. 30 | + .breadcrumb-item:hover::before { 31 | text-decoration: underline; 32 | } 33 | // stylelint-disable-next-line no-duplicate-selectors 34 | + .breadcrumb-item:hover::before { 35 | text-decoration: none; 36 | } 37 | 38 | &.active { 39 | color: $breadcrumb-active-color; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_display.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // 4 | // Utilities for common `display` values 5 | // 6 | 7 | @each $breakpoint in map-keys($grid-breakpoints) { 8 | @include media-breakpoint-up($breakpoint) { 9 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints); 10 | 11 | .d#{$infix}-none { display: none !important; } 12 | .d#{$infix}-inline { display: inline !important; } 13 | .d#{$infix}-inline-block { display: inline-block !important; } 14 | .d#{$infix}-block { display: block !important; } 15 | .d#{$infix}-table { display: table !important; } 16 | .d#{$infix}-table-row { display: table-row !important; } 17 | .d#{$infix}-table-cell { display: table-cell !important; } 18 | .d#{$infix}-flex { display: flex !important; } 19 | .d#{$infix}-inline-flex { display: inline-flex !important; } 20 | } 21 | } 22 | 23 | 24 | // 25 | // Utilities for toggling `display` in print 26 | // 27 | 28 | @media print { 29 | .d-print-none { display: none !important; } 30 | .d-print-inline { display: inline !important; } 31 | .d-print-inline-block { display: inline-block !important; } 32 | .d-print-block { display: block !important; } 33 | .d-print-table { display: table !important; } 34 | .d-print-table-row { display: table-row !important; } 35 | .d-print-table-cell { display: table-cell !important; } 36 | .d-print-flex { display: flex !important; } 37 | .d-print-inline-flex { display: inline-flex !important; } 38 | } 39 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_spacing.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // Margin and Padding 4 | 5 | @each $breakpoint in map-keys($grid-breakpoints) { 6 | @include media-breakpoint-up($breakpoint) { 7 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints); 8 | 9 | @each $prop, $abbrev in (margin: m, padding: p) { 10 | @each $size, $length in $spacers { 11 | 12 | .#{$abbrev}#{$infix}-#{$size} { #{$prop}: $length !important; } 13 | .#{$abbrev}t#{$infix}-#{$size}, 14 | .#{$abbrev}y#{$infix}-#{$size} { 15 | #{$prop}-top: $length !important; 16 | } 17 | .#{$abbrev}r#{$infix}-#{$size}, 18 | .#{$abbrev}x#{$infix}-#{$size} { 19 | #{$prop}-right: $length !important; 20 | } 21 | .#{$abbrev}b#{$infix}-#{$size}, 22 | .#{$abbrev}y#{$infix}-#{$size} { 23 | #{$prop}-bottom: $length !important; 24 | } 25 | .#{$abbrev}l#{$infix}-#{$size}, 26 | .#{$abbrev}x#{$infix}-#{$size} { 27 | #{$prop}-left: $length !important; 28 | } 29 | } 30 | } 31 | 32 | // Some special margin utils 33 | .m#{$infix}-auto { margin: auto !important; } 34 | .mt#{$infix}-auto, 35 | .my#{$infix}-auto { 36 | margin-top: auto !important; 37 | } 38 | .mr#{$infix}-auto, 39 | .mx#{$infix}-auto { 40 | margin-right: auto !important; 41 | } 42 | .mb#{$infix}-auto, 43 | .my#{$infix}-auto { 44 | margin-bottom: auto !important; 45 | } 46 | .ml#{$infix}-auto, 47 | .mx#{$infix}-auto { 48 | margin-left: auto !important; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/static/css/flaticon.css: -------------------------------------------------------------------------------- 1 | /* 2 | Flaticon icon font: Flaticon 3 | Creation date: 09/02/2019 00:29 4 | */ 5 | 6 | @font-face { 7 | font-family: "Flaticon"; 8 | src: url("./Flaticon.eot"); 9 | src: url("./Flaticon.eot?#iefix") format("embedded-opentype"), 10 | url("Flaticon.woff2") format("woff2"), 11 | url("Flaticon.woff") format("woff"), 12 | url("./Flaticon.ttf") format("truetype"), 13 | url("./Flaticon.svg#Flaticon") format("svg"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @media screen and (-webkit-min-device-pixel-ratio:0) { 19 | @font-face { 20 | font-family: "Flaticon"; 21 | src: url("./Flaticon.svg#Flaticon") format("svg"); 22 | } 23 | } 24 | 25 | [class^="flaticon-"]:before, [class*=" flaticon-"]:before, 26 | [class^="flaticon-"]:after, [class*=" flaticon-"]:after { 27 | font-family: Flaticon; 28 | font-size: 20px; 29 | font-style: normal; 30 | } 31 | 32 | .flaticon-brain:before { content: "\f100"; } 33 | .flaticon-brain-1:before { content: "\f101"; } 34 | .flaticon-brain-2:before { content: "\f102"; } 35 | .flaticon-brain-3:before { content: "\f103"; } 36 | .flaticon-brain-4:before { content: "\f104"; } 37 | .flaticon-brain-5:before { content: "\f105"; } 38 | .flaticon-brain-6:before { content: "\f106"; } 39 | .flaticon-twitter:before { content: "\f107"; } 40 | .flaticon-facebook:before { content: "\f108"; } 41 | .flaticon-instagram:before { content: "\f109"; } 42 | .flaticon-twitter-1:before { content: "\f10a"; } 43 | .flaticon-brand:before { content: "\f10b"; } 44 | .flaticon-linkedin:before { content: "\f10c"; } 45 | .flaticon-telegram:before { content: "\f10d"; } 46 | .flaticon-github:before { content: "\f10e"; } -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/flaticon.css: -------------------------------------------------------------------------------- 1 | /* 2 | Flaticon icon font: Flaticon 3 | Creation date: 09/02/2019 00:29 4 | */ 5 | 6 | @font-face { 7 | font-family: "Flaticon"; 8 | src: url("Flaticon.eot"); 9 | src: url("Flaticon.eot?#iefix") format("embedded-opentype"), 10 | url("Flaticon.woff2") format("woff2"), 11 | url("Flaticon.woff") format("woff"), 12 | url("Flaticon.ttf") format("truetype"), 13 | url("Flaticon.svg#Flaticon") format("svg"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @media screen and (-webkit-min-device-pixel-ratio:0) { 19 | @font-face { 20 | font-family: "Flaticon"; 21 | src: url("Flaticon.svg#Flaticon") format("svg"); 22 | } 23 | } 24 | 25 | [class^="flaticon-"]:before, [class*=" flaticon-"]:before, 26 | [class^="flaticon-"]:after, [class*=" flaticon-"]:after { 27 | font-family: Flaticon; 28 | font-size: 20px; 29 | font-style: normal; 30 | margin-left: 20px; 31 | } 32 | 33 | .flaticon-brain:before { content: "\f100"; } 34 | .flaticon-brain-1:before { content: "\f101"; } 35 | .flaticon-brain-2:before { content: "\f102"; } 36 | .flaticon-brain-3:before { content: "\f103"; } 37 | .flaticon-brain-4:before { content: "\f104"; } 38 | .flaticon-brain-5:before { content: "\f105"; } 39 | .flaticon-brain-6:before { content: "\f106"; } 40 | .flaticon-twitter:before { content: "\f107"; } 41 | .flaticon-facebook:before { content: "\f108"; } 42 | .flaticon-instagram:before { content: "\f109"; } 43 | .flaticon-twitter-1:before { content: "\f10a"; } 44 | .flaticon-brand:before { content: "\f10b"; } 45 | .flaticon-linkedin:before { content: "\f10c"; } 46 | .flaticon-telegram:before { content: "\f10d"; } 47 | .flaticon-github:before { content: "\f10e"; } -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_caret.scss: -------------------------------------------------------------------------------- 1 | @mixin caret-down { 2 | border-top: $caret-width solid; 3 | border-right: $caret-width solid transparent; 4 | border-bottom: 0; 5 | border-left: $caret-width solid transparent; 6 | } 7 | 8 | @mixin caret-up { 9 | border-top: 0; 10 | border-right: $caret-width solid transparent; 11 | border-bottom: $caret-width solid; 12 | border-left: $caret-width solid transparent; 13 | } 14 | 15 | @mixin caret-right { 16 | border-top: $caret-width solid transparent; 17 | border-right: 0; 18 | border-bottom: $caret-width solid transparent; 19 | border-left: $caret-width solid; 20 | } 21 | 22 | @mixin caret-left { 23 | border-top: $caret-width solid transparent; 24 | border-right: $caret-width solid; 25 | border-bottom: $caret-width solid transparent; 26 | } 27 | 28 | @mixin caret($direction: down) { 29 | @if $enable-caret { 30 | &::after { 31 | display: inline-block; 32 | width: 0; 33 | height: 0; 34 | margin-left: $caret-width * .85; 35 | vertical-align: $caret-width * .85; 36 | content: ""; 37 | @if $direction == down { 38 | @include caret-down; 39 | } @else if $direction == up { 40 | @include caret-up; 41 | } @else if $direction == right { 42 | @include caret-right; 43 | } 44 | } 45 | 46 | @if $direction == left { 47 | &::after { 48 | display: none; 49 | } 50 | 51 | &::before { 52 | display: inline-block; 53 | width: 0; 54 | height: 0; 55 | margin-right: $caret-width * .85; 56 | vertical-align: $caret-width * .85; 57 | content: ""; 58 | @include caret-left; 59 | } 60 | } 61 | 62 | &:empty::after { 63 | margin-left: 0; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_text.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // 4 | // Text 5 | // 6 | 7 | .text-monospace { font-family: $font-family-monospace; } 8 | 9 | // Alignment 10 | 11 | .text-justify { text-align: justify !important; } 12 | .text-nowrap { white-space: nowrap !important; } 13 | .text-truncate { @include text-truncate; } 14 | 15 | // Responsive alignment 16 | 17 | @each $breakpoint in map-keys($grid-breakpoints) { 18 | @include media-breakpoint-up($breakpoint) { 19 | $infix: breakpoint-infix($breakpoint, $grid-breakpoints); 20 | 21 | .text#{$infix}-left { text-align: left !important; } 22 | .text#{$infix}-right { text-align: right !important; } 23 | .text#{$infix}-center { text-align: center !important; } 24 | } 25 | } 26 | 27 | // Transformation 28 | 29 | .text-lowercase { text-transform: lowercase !important; } 30 | .text-uppercase { text-transform: uppercase !important; } 31 | .text-capitalize { text-transform: capitalize !important; } 32 | 33 | // Weight and italics 34 | 35 | .font-weight-light { font-weight: $font-weight-light !important; } 36 | .font-weight-normal { font-weight: $font-weight-normal !important; } 37 | .font-weight-bold { font-weight: $font-weight-bold !important; } 38 | .font-italic { font-style: italic !important; } 39 | 40 | // Contextual colors 41 | 42 | .text-white { color: $white !important; } 43 | 44 | @each $color, $value in $theme-colors { 45 | @include text-emphasis-variant(".text-#{$color}", $value); 46 | } 47 | 48 | .text-body { color: $body-color !important; } 49 | .text-muted { color: $text-muted !important; } 50 | 51 | .text-black-50 { color: rgba($black, .5) !important; } 52 | .text-white-50 { color: rgba($white, .5) !important; } 53 | 54 | // Misc 55 | 56 | .text-hide { 57 | @include text-hide(); 58 | } 59 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/utilities/_borders.scss: -------------------------------------------------------------------------------- 1 | // stylelint-disable declaration-no-important 2 | 3 | // 4 | // Border 5 | // 6 | 7 | .border { border: $border-width solid $border-color !important; } 8 | .border-top { border-top: $border-width solid $border-color !important; } 9 | .border-right { border-right: $border-width solid $border-color !important; } 10 | .border-bottom { border-bottom: $border-width solid $border-color !important; } 11 | .border-left { border-left: $border-width solid $border-color !important; } 12 | 13 | .border-0 { border: 0 !important; } 14 | .border-top-0 { border-top: 0 !important; } 15 | .border-right-0 { border-right: 0 !important; } 16 | .border-bottom-0 { border-bottom: 0 !important; } 17 | .border-left-0 { border-left: 0 !important; } 18 | 19 | @each $color, $value in $theme-colors { 20 | .border-#{$color} { 21 | border-color: $value !important; 22 | } 23 | } 24 | 25 | .border-white { 26 | border-color: $white !important; 27 | } 28 | 29 | // 30 | // Border-radius 31 | // 32 | 33 | .rounded { 34 | border-radius: $border-radius !important; 35 | } 36 | .rounded-top { 37 | border-top-left-radius: $border-radius !important; 38 | border-top-right-radius: $border-radius !important; 39 | } 40 | .rounded-right { 41 | border-top-right-radius: $border-radius !important; 42 | border-bottom-right-radius: $border-radius !important; 43 | } 44 | .rounded-bottom { 45 | border-bottom-right-radius: $border-radius !important; 46 | border-bottom-left-radius: $border-radius !important; 47 | } 48 | .rounded-left { 49 | border-top-left-radius: $border-radius !important; 50 | border-bottom-left-radius: $border-radius !important; 51 | } 52 | 53 | .rounded-circle { 54 | border-radius: 50% !important; 55 | } 56 | 57 | .rounded-0 { 58 | border-radius: 0 !important; 59 | } 60 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_grid.scss: -------------------------------------------------------------------------------- 1 | /// Grid system 2 | // 3 | // Generate semantic grid columns with these mixins. 4 | 5 | @mixin make-container() { 6 | width: 100%; 7 | padding-right: ($grid-gutter-width / 2); 8 | padding-left: ($grid-gutter-width / 2); 9 | margin-right: auto; 10 | margin-left: auto; 11 | } 12 | 13 | 14 | // For each breakpoint, define the maximum width of the container in a media query 15 | @mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { 16 | @each $breakpoint, $container-max-width in $max-widths { 17 | @include media-breakpoint-up($breakpoint, $breakpoints) { 18 | max-width: $container-max-width; 19 | } 20 | } 21 | } 22 | 23 | @mixin make-row() { 24 | display: flex; 25 | flex-wrap: wrap; 26 | margin-right: ($grid-gutter-width / -2); 27 | margin-left: ($grid-gutter-width / -2); 28 | } 29 | 30 | @mixin make-col-ready() { 31 | position: relative; 32 | // Prevent columns from becoming too narrow when at smaller grid tiers by 33 | // always setting `width: 100%;`. This works because we use `flex` values 34 | // later on to override this initial width. 35 | width: 100%; 36 | min-height: 1px; // Prevent collapsing 37 | padding-right: ($grid-gutter-width / 2); 38 | padding-left: ($grid-gutter-width / 2); 39 | } 40 | 41 | @mixin make-col($size, $columns: $grid-columns) { 42 | flex: 0 0 percentage($size / $columns); 43 | // Add a `max-width` to ensure content within each column does not blow out 44 | // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari 45 | // do not appear to require this. 46 | max-width: percentage($size / $columns); 47 | } 48 | 49 | @mixin make-col-offset($size, $columns: $grid-columns) { 50 | $num: $size / $columns; 51 | margin-left: if($num == 0, 0, percentage($num)); 52 | } 53 | -------------------------------------------------------------------------------- /app/static/css/jquery.timepicker.css: -------------------------------------------------------------------------------- 1 | .ui-timepicker-wrapper { 2 | overflow-y: auto; 3 | max-height: 150px; 4 | width: 6.5em; 5 | background: #fff; 6 | border: 1px solid #ddd; 7 | -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2); 8 | -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2); 9 | box-shadow:0 5px 10px rgba(0,0,0,0.2); 10 | outline: none; 11 | z-index: 10001; 12 | margin: 0; 13 | } 14 | 15 | .ui-timepicker-wrapper.ui-timepicker-with-duration { 16 | width: 13em; 17 | } 18 | 19 | .ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30, 20 | .ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 { 21 | width: 11em; 22 | } 23 | 24 | .ui-timepicker-list { 25 | margin: 0; 26 | padding: 0; 27 | list-style: none; 28 | } 29 | 30 | .ui-timepicker-duration { 31 | margin-left: 5px; color: #888; 32 | } 33 | 34 | .ui-timepicker-list:hover .ui-timepicker-duration { 35 | color: #888; 36 | } 37 | 38 | .ui-timepicker-list li { 39 | padding: 3px 0 3px 5px; 40 | cursor: pointer; 41 | white-space: nowrap; 42 | color: #000; 43 | list-style: none; 44 | margin: 0; 45 | } 46 | 47 | .ui-timepicker-list:hover .ui-timepicker-selected { 48 | background: #fff; color: #000; 49 | } 50 | 51 | li.ui-timepicker-selected, 52 | .ui-timepicker-list li:hover, 53 | .ui-timepicker-list .ui-timepicker-selected:hover { 54 | background: #1980EC; color: #fff; 55 | } 56 | 57 | li.ui-timepicker-selected .ui-timepicker-duration, 58 | .ui-timepicker-list li:hover .ui-timepicker-duration { 59 | color: #ccc; 60 | } 61 | 62 | .ui-timepicker-list li.ui-timepicker-disabled, 63 | .ui-timepicker-list li.ui-timepicker-disabled:hover, 64 | .ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { 65 | color: #888; 66 | cursor: default; 67 | } 68 | 69 | .ui-timepicker-list li.ui-timepicker-disabled:hover, 70 | .ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { 71 | background: #f2f2f2; 72 | } 73 | -------------------------------------------------------------------------------- /app/static/js/google-map.js: -------------------------------------------------------------------------------- 1 | 2 | var google; 3 | 4 | function init() { 5 | // Basic options for a simple Google Map 6 | // For more options see: https://developers.google.com/maps/documentation/javascript/reference#MapOptions 7 | // var myLatlng = new google.maps.LatLng(40.71751, -73.990922); 8 | var myLatlng = new google.maps.LatLng(40.69847032728747, -73.9514422416687); 9 | // 39.399872 10 | // -8.224454 11 | 12 | var mapOptions = { 13 | // How zoomed in you want the map to start at (always required) 14 | zoom: 7, 15 | 16 | // The latitude and longitude to center the map (always required) 17 | center: myLatlng, 18 | 19 | // How you would like to style the map. 20 | scrollwheel: false, 21 | styles: [ 22 | { 23 | "featureType": "administrative.country", 24 | "elementType": "geometry", 25 | "stylers": [ 26 | { 27 | "visibility": "simplified" 28 | }, 29 | { 30 | "hue": "#ff0000" 31 | } 32 | ] 33 | } 34 | ] 35 | }; 36 | 37 | 38 | 39 | // Get the HTML DOM element that will contain your map 40 | // We are using a div with id="map" seen below in the 41 | var mapElement = document.getElementById('map'); 42 | 43 | // Create the Google Map using out element and options defined above 44 | var map = new google.maps.Map(mapElement, mapOptions); 45 | 46 | var addresses = ['New York']; 47 | 48 | for (var x = 0; x < addresses.length; x++) { 49 | $.getJSON('http://maps.googleapis.com/maps/api/geocode/json?address='+addresses[x]+'&sensor=false', null, function (data) { 50 | var p = data.results[0].geometry.location 51 | var latlng = new google.maps.LatLng(p.lat, p.lng); 52 | new google.maps.Marker({ 53 | position: latlng, 54 | map: map, 55 | icon: 'images/loc.png' 56 | }); 57 | 58 | }); 59 | } 60 | 61 | } 62 | google.maps.event.addDomListener(window, 'load', init); -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_grid-framework.scss: -------------------------------------------------------------------------------- 1 | // Framework grid generation 2 | // 3 | // Used only by Bootstrap to generate the correct number of grid classes given 4 | // any value of `$grid-columns`. 5 | 6 | @mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { 7 | // Common properties for all breakpoints 8 | %grid-column { 9 | position: relative; 10 | width: 100%; 11 | min-height: 1px; // Prevent columns from collapsing when empty 12 | padding-right: ($gutter / 2); 13 | padding-left: ($gutter / 2); 14 | } 15 | 16 | @each $breakpoint in map-keys($breakpoints) { 17 | $infix: breakpoint-infix($breakpoint, $breakpoints); 18 | 19 | // Allow columns to stretch full width below their breakpoints 20 | @for $i from 1 through $columns { 21 | .col#{$infix}-#{$i} { 22 | @extend %grid-column; 23 | } 24 | } 25 | .col#{$infix}, 26 | .col#{$infix}-auto { 27 | @extend %grid-column; 28 | } 29 | 30 | @include media-breakpoint-up($breakpoint, $breakpoints) { 31 | // Provide basic `.col-{bp}` classes for equal-width flexbox columns 32 | .col#{$infix} { 33 | flex-basis: 0; 34 | flex-grow: 1; 35 | max-width: 100%; 36 | } 37 | .col#{$infix}-auto { 38 | flex: 0 0 auto; 39 | width: auto; 40 | max-width: none; // Reset earlier grid tiers 41 | } 42 | 43 | @for $i from 1 through $columns { 44 | .col#{$infix}-#{$i} { 45 | @include make-col($i, $columns); 46 | } 47 | } 48 | 49 | .order#{$infix}-first { order: -1; } 50 | 51 | .order#{$infix}-last { order: $columns + 1; } 52 | 53 | @for $i from 0 through $columns { 54 | .order#{$infix}-#{$i} { order: $i; } 55 | } 56 | 57 | // `$columns - 1` because offsetting by the width of an entire row isn't possible 58 | @for $i from 0 through ($columns - 1) { 59 | @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 60 | .offset#{$infix}-#{$i} { 61 | @include make-col-offset($i, $columns); 62 | } 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_pagination.scss: -------------------------------------------------------------------------------- 1 | .pagination { 2 | display: flex; 3 | @include list-unstyled(); 4 | @include border-radius(); 5 | } 6 | 7 | .page-link { 8 | position: relative; 9 | display: block; 10 | padding: $pagination-padding-y $pagination-padding-x; 11 | margin-left: -$pagination-border-width; 12 | line-height: $pagination-line-height; 13 | color: $pagination-color; 14 | background-color: $pagination-bg; 15 | border: $pagination-border-width solid $pagination-border-color; 16 | 17 | &:hover { 18 | z-index: 2; 19 | color: $pagination-hover-color; 20 | text-decoration: none; 21 | background-color: $pagination-hover-bg; 22 | border-color: $pagination-hover-border-color; 23 | } 24 | 25 | &:focus { 26 | z-index: 2; 27 | outline: $pagination-focus-outline; 28 | box-shadow: $pagination-focus-box-shadow; 29 | } 30 | 31 | // Opinionated: add "hand" cursor to non-disabled .page-link elements 32 | &:not(:disabled):not(.disabled) { 33 | cursor: pointer; 34 | } 35 | } 36 | 37 | .page-item { 38 | &:first-child { 39 | .page-link { 40 | margin-left: 0; 41 | @include border-left-radius($border-radius); 42 | } 43 | } 44 | &:last-child { 45 | .page-link { 46 | @include border-right-radius($border-radius); 47 | } 48 | } 49 | 50 | &.active .page-link { 51 | z-index: 1; 52 | color: $pagination-active-color; 53 | background-color: $pagination-active-bg; 54 | border-color: $pagination-active-border-color; 55 | } 56 | 57 | &.disabled .page-link { 58 | color: $pagination-disabled-color; 59 | pointer-events: none; 60 | // Opinionated: remove the "hand" cursor set previously for .page-link 61 | cursor: auto; 62 | background-color: $pagination-disabled-bg; 63 | border-color: $pagination-disabled-border-color; 64 | } 65 | } 66 | 67 | 68 | // 69 | // Sizing 70 | // 71 | 72 | .pagination-lg { 73 | @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $border-radius-lg); 74 | } 75 | 76 | .pagination-sm { 77 | @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $border-radius-sm); 78 | } 79 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/mixins/_gradients.scss: -------------------------------------------------------------------------------- 1 | // Gradients 2 | 3 | @mixin gradient-bg($color) { 4 | @if $enable-gradients { 5 | background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x; 6 | } @else { 7 | background-color: $color; 8 | } 9 | } 10 | 11 | // Horizontal gradient, from left to right 12 | // 13 | // Creates two color stops, start and end, by specifying a color and position for each color stop. 14 | @mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { 15 | background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); 16 | background-repeat: repeat-x; 17 | } 18 | 19 | // Vertical gradient, from top to bottom 20 | // 21 | // Creates two color stops, start and end, by specifying a color and position for each color stop. 22 | @mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { 23 | background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); 24 | background-repeat: repeat-x; 25 | } 26 | 27 | @mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { 28 | background-image: linear-gradient($deg, $start-color, $end-color); 29 | background-repeat: repeat-x; 30 | } 31 | @mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { 32 | background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); 33 | background-repeat: no-repeat; 34 | } 35 | @mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { 36 | background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); 37 | background-repeat: no-repeat; 38 | } 39 | @mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { 40 | background-image: radial-gradient(circle, $inner-color, $outer-color); 41 | background-repeat: no-repeat; 42 | } 43 | @mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { 44 | background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); 45 | } 46 | -------------------------------------------------------------------------------- /app/static/js/search.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | function displaySearchResults(results, store) { 3 | var searchResults = document.getElementById('search-results'); 4 | 5 | if (results.length) { // Are there any results? 6 | var appendString = ''; 7 | 8 | for (var i = 0; i < results.length; i++) { // Iterate over the results 9 | var item = store[results[i].ref]; 10 | appendString += '
  • ' + item.title + '

    '; 11 | appendString += '

    ' + item.content.substring(0, 150) + '...

  • '; 12 | } 13 | 14 | searchResults.innerHTML = appendString; 15 | } else { 16 | searchResults.innerHTML = '
  • No results found
  • '; 17 | } 18 | } 19 | 20 | function getQueryVariable(variable) { 21 | var query = window.location.search.substring(1); 22 | var vars = query.split('&'); 23 | 24 | for (var i = 0; i < vars.length; i++) { 25 | var pair = vars[i].split('='); 26 | 27 | if (pair[0] === variable) { 28 | return decodeURIComponent(pair[1].replace(/\+/g, '%20')); 29 | } 30 | } 31 | } 32 | 33 | var searchTerm = getQueryVariable('query'); 34 | 35 | if (searchTerm) { 36 | document.getElementById('search-box').setAttribute("value", searchTerm); 37 | 38 | // Initalize lunr with the fields it will be searching on. I've given title 39 | // a boost of 10 to indicate matches on this field are more important. 40 | var idx = lunr(function () { 41 | this.field('id'); 42 | this.field('title', { boost: 10 }); 43 | this.field('author'); 44 | this.field('category'); 45 | this.field('content'); 46 | }); 47 | 48 | for (var key in window.store) { // Add the data to lunr 49 | idx.add({ 50 | 'id': key, 51 | 'title': window.store[key].title, 52 | 'author': window.store[key].author, 53 | 'category': window.store[key].category, 54 | 'content': window.store[key].content 55 | }); 56 | 57 | var results = idx.search(searchTerm); // Get lunr to perform a search 58 | displaySearchResults(results, window.store); // We'll write this in the next section 59 | } 60 | } 61 | })(); -------------------------------------------------------------------------------- /app/static/css/_flaticon.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Flaticon icon font: Flaticon 3 | Creation date: 09/02/2019 00:29 4 | */ 5 | 6 | @font-face { 7 | font-family: "Flaticon"; 8 | src: url("./Flaticon.eot"); 9 | src: url("./Flaticon.eot?#iefix") format("embedded-opentype"), 10 | url("Flaticon.woff2") format("woff2"), 11 | url("Flaticon.woff") format("woff"), 12 | url("./Flaticon.ttf") format("truetype"), 13 | url("./Flaticon.svg#Flaticon") format("svg"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @media screen and (-webkit-min-device-pixel-ratio:0) { 19 | @font-face { 20 | font-family: "Flaticon"; 21 | src: url("./Flaticon.svg#Flaticon") format("svg"); 22 | } 23 | } 24 | 25 | .fi:before{ 26 | display: inline-block; 27 | font-family: "Flaticon"; 28 | font-style: normal; 29 | font-weight: normal; 30 | font-variant: normal; 31 | line-height: 1; 32 | text-decoration: inherit; 33 | text-rendering: optimizeLegibility; 34 | text-transform: none; 35 | -moz-osx-font-smoothing: grayscale; 36 | -webkit-font-smoothing: antialiased; 37 | font-smoothing: antialiased; 38 | } 39 | 40 | .flaticon-brain:before { content: "\f100"; } 41 | .flaticon-brain-1:before { content: "\f101"; } 42 | .flaticon-brain-2:before { content: "\f102"; } 43 | .flaticon-brain-3:before { content: "\f103"; } 44 | .flaticon-brain-4:before { content: "\f104"; } 45 | .flaticon-brain-5:before { content: "\f105"; } 46 | .flaticon-brain-6:before { content: "\f106"; } 47 | .flaticon-twitter:before { content: "\f107"; } 48 | .flaticon-facebook:before { content: "\f108"; } 49 | .flaticon-instagram:before { content: "\f109"; } 50 | .flaticon-twitter-1:before { content: "\f10a"; } 51 | .flaticon-brand:before { content: "\f10b"; } 52 | .flaticon-linkedin:before { content: "\f10c"; } 53 | .flaticon-telegram:before { content: "\f10d"; } 54 | .flaticon-github:before { content: "\f10e"; } 55 | 56 | $font-Flaticon-brain: "\f100"; 57 | $font-Flaticon-brain-1: "\f101"; 58 | $font-Flaticon-brain-2: "\f102"; 59 | $font-Flaticon-brain-3: "\f103"; 60 | $font-Flaticon-brain-4: "\f104"; 61 | $font-Flaticon-brain-5: "\f105"; 62 | $font-Flaticon-brain-6: "\f106"; 63 | $font-Flaticon-twitter: "\f107"; 64 | $font-Flaticon-facebook: "\f108"; 65 | $font-Flaticon-instagram: "\f109"; 66 | $font-Flaticon-twitter-1: "\f10a"; 67 | $font-Flaticon-brand: "\f10b"; 68 | $font-Flaticon-linkedin: "\f10c"; 69 | $font-Flaticon-telegram: "\f10d"; 70 | $font-Flaticon-github: "\f10e"; -------------------------------------------------------------------------------- /app/static/fonts/flaticon/font/_flaticon.scss: -------------------------------------------------------------------------------- 1 | /* 2 | Flaticon icon font: Flaticon 3 | Creation date: 09/02/2019 00:29 4 | */ 5 | 6 | @font-face { 7 | font-family: "Flaticon"; 8 | src: url("./Flaticon.eot"); 9 | src: url("./Flaticon.eot?#iefix") format("embedded-opentype"), 10 | url("./Flaticon.woff2") format("woff2"), 11 | url("./Flaticon.woff") format("woff"), 12 | url("./Flaticon.ttf") format("truetype"), 13 | url("./Flaticon.svg#Flaticon") format("svg"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @media screen and (-webkit-min-device-pixel-ratio:0) { 19 | @font-face { 20 | font-family: "Flaticon"; 21 | src: url("./Flaticon.svg#Flaticon") format("svg"); 22 | } 23 | } 24 | 25 | .fi:before{ 26 | display: inline-block; 27 | font-family: "Flaticon"; 28 | font-style: normal; 29 | font-weight: normal; 30 | font-variant: normal; 31 | line-height: 1; 32 | text-decoration: inherit; 33 | text-rendering: optimizeLegibility; 34 | text-transform: none; 35 | -moz-osx-font-smoothing: grayscale; 36 | -webkit-font-smoothing: antialiased; 37 | font-smoothing: antialiased; 38 | } 39 | 40 | .flaticon-brain:before { content: "\f100"; } 41 | .flaticon-brain-1:before { content: "\f101"; } 42 | .flaticon-brain-2:before { content: "\f102"; } 43 | .flaticon-brain-3:before { content: "\f103"; } 44 | .flaticon-brain-4:before { content: "\f104"; } 45 | .flaticon-brain-5:before { content: "\f105"; } 46 | .flaticon-brain-6:before { content: "\f106"; } 47 | .flaticon-twitter:before { content: "\f107"; } 48 | .flaticon-facebook:before { content: "\f108"; } 49 | .flaticon-instagram:before { content: "\f109"; } 50 | .flaticon-twitter-1:before { content: "\f10a"; } 51 | .flaticon-brand:before { content: "\f10b"; } 52 | .flaticon-linkedin:before { content: "\f10c"; } 53 | .flaticon-telegram:before { content: "\f10d"; } 54 | .flaticon-github:before { content: "\f10e"; } 55 | 56 | $font-Flaticon-brain: "\f100"; 57 | $font-Flaticon-brain-1: "\f101"; 58 | $font-Flaticon-brain-2: "\f102"; 59 | $font-Flaticon-brain-3: "\f103"; 60 | $font-Flaticon-brain-4: "\f104"; 61 | $font-Flaticon-brain-5: "\f105"; 62 | $font-Flaticon-brain-6: "\f106"; 63 | $font-Flaticon-twitter: "\f107"; 64 | $font-Flaticon-facebook: "\f108"; 65 | $font-Flaticon-instagram: "\f109"; 66 | $font-Flaticon-twitter-1: "\f10a"; 67 | $font-Flaticon-brand: "\f10b"; 68 | $font-Flaticon-linkedin: "\f10c"; 69 | $font-Flaticon-telegram: "\f10d"; 70 | $font-Flaticon-github: "\f10e"; -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_nav.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Kickstart any navigation component with a set of style resets. Works with 4 | // ` 44 | 45 | 46 | 47 |
    48 |
    49 |
    50 |
    51 | {% with messages = get_flashed_messages(with_categories=true) %} 52 | {% if messages %} 53 | {% for category, message in messages %} 54 |
    55 | {{ message }} 56 |
    57 | {% endfor %} 58 | {% endif %} 59 | {% endwith %} 60 | {% block content %}{% endblock %} 61 |
    62 |
    63 |
    64 |
    65 | 66 | 67 | 68 | 89 | 90 | 91 |
    92 | 93 | 94 | 95 | 96 |
    97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_carousel.scss: -------------------------------------------------------------------------------- 1 | // Notes on the classes: 2 | // 3 | // 1. The .carousel-item-left and .carousel-item-right is used to indicate where 4 | // the active slide is heading. 5 | // 2. .active.carousel-item is the current slide. 6 | // 3. .active.carousel-item-left and .active.carousel-item-right is the current 7 | // slide in its in-transition state. Only one of these occurs at a time. 8 | // 4. .carousel-item-next.carousel-item-left and .carousel-item-prev.carousel-item-right 9 | // is the upcoming slide in transition. 10 | 11 | .carousel { 12 | position: relative; 13 | } 14 | 15 | .carousel-inner { 16 | position: relative; 17 | width: 100%; 18 | overflow: hidden; 19 | } 20 | 21 | .carousel-item { 22 | position: relative; 23 | display: none; 24 | align-items: center; 25 | width: 100%; 26 | @include transition($carousel-transition); 27 | backface-visibility: hidden; 28 | perspective: 1000px; 29 | } 30 | 31 | .carousel-item.active, 32 | .carousel-item-next, 33 | .carousel-item-prev { 34 | display: block; 35 | } 36 | 37 | .carousel-item-next, 38 | .carousel-item-prev { 39 | position: absolute; 40 | top: 0; 41 | } 42 | 43 | .carousel-item-next.carousel-item-left, 44 | .carousel-item-prev.carousel-item-right { 45 | transform: translateX(0); 46 | 47 | @supports (transform-style: preserve-3d) { 48 | transform: translate3d(0, 0, 0); 49 | } 50 | } 51 | 52 | .carousel-item-next, 53 | .active.carousel-item-right { 54 | transform: translateX(100%); 55 | 56 | @supports (transform-style: preserve-3d) { 57 | transform: translate3d(100%, 0, 0); 58 | } 59 | } 60 | 61 | .carousel-item-prev, 62 | .active.carousel-item-left { 63 | transform: translateX(-100%); 64 | 65 | @supports (transform-style: preserve-3d) { 66 | transform: translate3d(-100%, 0, 0); 67 | } 68 | } 69 | 70 | 71 | // 72 | // Alternate transitions 73 | // 74 | 75 | .carousel-fade { 76 | .carousel-item { 77 | opacity: 0; 78 | transition-duration: .6s; 79 | transition-property: opacity; 80 | } 81 | 82 | .carousel-item.active, 83 | .carousel-item-next.carousel-item-left, 84 | .carousel-item-prev.carousel-item-right { 85 | opacity: 1; 86 | } 87 | 88 | .active.carousel-item-left, 89 | .active.carousel-item-right { 90 | opacity: 0; 91 | } 92 | 93 | .carousel-item-next, 94 | .carousel-item-prev, 95 | .carousel-item.active, 96 | .active.carousel-item-left, 97 | .active.carousel-item-prev { 98 | transform: translateX(0); 99 | 100 | @supports (transform-style: preserve-3d) { 101 | transform: translate3d(0, 0, 0); 102 | } 103 | } 104 | } 105 | 106 | 107 | // 108 | // Left/right controls for nav 109 | // 110 | 111 | .carousel-control-prev, 112 | .carousel-control-next { 113 | position: absolute; 114 | top: 0; 115 | bottom: 0; 116 | // Use flex for alignment (1-3) 117 | display: flex; // 1. allow flex styles 118 | align-items: center; // 2. vertically center contents 119 | justify-content: center; // 3. horizontally center contents 120 | width: $carousel-control-width; 121 | color: $carousel-control-color; 122 | text-align: center; 123 | opacity: $carousel-control-opacity; 124 | // We can't have a transition here because WebKit cancels the carousel 125 | // animation if you trip this while in the middle of another animation. 126 | 127 | // Hover/focus state 128 | @include hover-focus { 129 | color: $carousel-control-color; 130 | text-decoration: none; 131 | outline: 0; 132 | opacity: .9; 133 | } 134 | } 135 | .carousel-control-prev { 136 | left: 0; 137 | @if $enable-gradients { 138 | background: linear-gradient(90deg, rgba($black, .25), rgba($black, .001)); 139 | } 140 | } 141 | .carousel-control-next { 142 | right: 0; 143 | @if $enable-gradients { 144 | background: linear-gradient(270deg, rgba($black, .25), rgba($black, .001)); 145 | } 146 | } 147 | 148 | // Icons for within 149 | .carousel-control-prev-icon, 150 | .carousel-control-next-icon { 151 | display: inline-block; 152 | width: $carousel-control-icon-width; 153 | height: $carousel-control-icon-width; 154 | background: transparent no-repeat center center; 155 | background-size: 100% 100%; 156 | } 157 | .carousel-control-prev-icon { 158 | background-image: $carousel-control-prev-icon-bg; 159 | } 160 | .carousel-control-next-icon { 161 | background-image: $carousel-control-next-icon-bg; 162 | } 163 | 164 | 165 | // Optional indicator pips 166 | // 167 | // Add an ordered list with the following class and add a list item for each 168 | // slide your carousel holds. 169 | 170 | .carousel-indicators { 171 | position: absolute; 172 | right: 0; 173 | bottom: 10px; 174 | left: 0; 175 | z-index: 15; 176 | display: flex; 177 | justify-content: center; 178 | padding-left: 0; // override
      default 179 | // Use the .carousel-control's width as margin so we don't overlay those 180 | margin-right: $carousel-control-width; 181 | margin-left: $carousel-control-width; 182 | list-style: none; 183 | 184 | li { 185 | position: relative; 186 | flex: 0 1 auto; 187 | width: $carousel-indicator-width; 188 | height: $carousel-indicator-height; 189 | margin-right: $carousel-indicator-spacer; 190 | margin-left: $carousel-indicator-spacer; 191 | text-indent: -999px; 192 | background-color: rgba($carousel-indicator-active-bg, .5); 193 | 194 | // Use pseudo classes to increase the hit area by 10px on top and bottom. 195 | &::before { 196 | position: absolute; 197 | top: -10px; 198 | left: 0; 199 | display: inline-block; 200 | width: 100%; 201 | height: 10px; 202 | content: ""; 203 | } 204 | &::after { 205 | position: absolute; 206 | bottom: -10px; 207 | left: 0; 208 | display: inline-block; 209 | width: 100%; 210 | height: 10px; 211 | content: ""; 212 | } 213 | } 214 | 215 | .active { 216 | background-color: $carousel-indicator-active-bg; 217 | } 218 | } 219 | 220 | 221 | // Optional captions 222 | // 223 | // 224 | 225 | .carousel-caption { 226 | position: absolute; 227 | right: ((100% - $carousel-caption-width) / 2); 228 | bottom: 20px; 229 | left: ((100% - $carousel-caption-width) / 2); 230 | z-index: 10; 231 | padding-top: 20px; 232 | padding-bottom: 20px; 233 | color: $carousel-caption-color; 234 | text-align: center; 235 | } 236 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Active Directory Password Reset Service ![PyPass Logo](src/pypass.png) 2 | # PyPass: A self-service password change utility for Active Directory 3 | 4 | *:star: Please star this project if you find it useful!* 5 | 6 | - [PyPass: A self-service password change utility for Active Directory](#pypass-a-self-service-password-change-utility-for-active-directory) 7 | - [Overview](#overview) 8 | - [Features](#features) 9 | - [Installation](#installation) 10 | - [Docker](#docker) 11 | - [Customization and Configuration](#customization-and-configuration) 12 | - [Slack](#slack) 13 | - [Troubleshooting](#troubleshooting) 14 | - [LDAP Support](#ldap-support) 15 | - [Build your own version](#build-your-own-version) 16 | - [Create your own provider](#create-your-own-provider) 17 | - [License](#license) 18 | 19 | ## Overview 20 | 21 | PyPass is a very simple 1-page web application written in [Python](https://www.python.org/), using [Flask](http://flask.pocoo.org/) , [Angular Material](https://material.angular.io/), [Ldap3](https://ldap3.readthedocs.io/), and [Microsoft Directory Services](https://docs.microsoft.com/en-us/dotnet/api/system.directoryservices) (Default provider). 22 | 23 | It allows users to change their Active Directory password on their own, provided the user is not disabled. 24 | 25 | PyPass does not require any configuration, as it obtains the principal context from the current domain. There really is no free alternative out there (that I know of) so hopefully this saves someone else some time and money. 26 | 27 | ### Features 28 | 29 | PyPass has the following features: 30 | 31 | - Easily localizable 32 | - Supports [reCAPTCHA](https://www.google.com/recaptcha/intro/index.html) 33 | - Responsive design that works on mobiles, tablets, and desktops. 34 | - Works with Windows/Linux servers. 35 | 36 | 37 | 38 | ## Installation 39 | 40 | *You can easily install using Python3 and Flask. Check the next section to know how.* 41 | 42 | *To enable ldap services in the server(Windows) you need to install the Certificate services on the server. 43 | [Follow this steps to do it](https://www.watchguard.com/help/docs/ssl/3/en-us/content/en-us/manage_system/active_directory_auth_w-ldap-ssl.html)* 44 | 45 | 46 | ## Docker 47 | 48 | 1. Just clone the repo and Modify the *config.json* file with the correct entries. 49 | 2. After run the follow docker command: 50 | 51 | ``` docker 52 | >>>docker build -t pypass:latest . 53 | ``` 54 | 3. Run the Docker command to run the image: 55 | 56 | ```docker 57 | >>>docker run --dns --name pypaxs -d -p 80:5000 --rm pypass:latest 58 | ``` 59 | By default the container will be run in the port:5000 and localhost. With this command you can route the port to the 80 or any you prefer. 60 | 61 | 62 | ## Customization and Configuration 63 | 64 | All server-side settings and client-side settings are stored in the `src/config.json` file inside the APP folder. 65 | The most relevant configuration entries are shown below. Make sure you make your changes to the `config.json` file using a regular text editor like [Visual Studio Code](https://code.visualstudio.com) or [sublime Text](https://www.sublimetext.com/). 66 | 67 | This is the Format of the config file: 68 | 69 | ``` json 70 | { 71 | "SECRET_KEY_FLASK": "werewtrwetewrwer53535353", 72 | "SLACK_BOT_TOKEN" : "xoxb-", 73 | "domain": "domain.com", 74 | "BASEDN": "OU=Users,dc=domain,dc=com", 75 | "user_admin" : "admin-user", 76 | "passwd_admin" : "password_admin", 77 | "slack_db" : "slack_db.json", 78 | "Slack_Activation" : "False", 79 | "debug": "True", 80 | "company": "DIGITALEBRAIN", 81 | "RECAPTCHA_PUBLIC_KEY": "GOOGLE CODE", 82 | "RECAPTCHA_PRIVATE_KEY": "GOOGLE CODE" 83 | } 84 | ``` 85 | 86 | 87 | 1. To enable The Secret Key in the App: 88 | Find the `SECRET_KEY_FLASK` entry and enter your private key: 89 | To create your personal SECRET_KEY_FLASK In a command promt do the following: 90 | ``` command 91 | >>>python3 92 | Python 3.7.2 93 | [Clang 10.0.0 (clang-1000.11.45.5)] on darwin 94 | Type "help", "copyright", "credits" or "license" for more information. 95 | >>> import secrets 96 | >>> stk = secrets.token_hex(16) 97 | >>> print(stk) 98 | ``` 99 | Copy the code in the entrie. 100 | 101 | 2. Find the `SLACK_BOT_TOKEN` entry and enter your Slack Token 102 | To get your slack Token [follow this steps](https://get.slack.help/hc/en-us/articles/215770388-Create-and-regenerate-API-tokens) and your Token need to start with *xoxb-* 103 | 104 | 3. For the AD Credentials need to have admin priviligies or the user be able to change passwords. 105 | 106 | ``` json 107 | "domain": "domain.com", 108 | "BASEDN": "OU=Users,dc=domain,dc=com", 109 | "user_admin" : "admin-user", 110 | "passwd_admin" : "password_admin", 111 | ``` 112 | ## Slack 113 | 114 | 4. To enable and use the slack notification, you need to download the slack DB in a file and put in the same folder *SRC FOLDER* of the config file. 115 | - To Download the Slack DB do the follow. 116 | - Create a Python file and put this code: 117 | 118 | ``` python 119 | import json 120 | from slackclient import SlackClient 121 | 122 | SLACK_BOT_TOKEN = "xoxb-YOUR-TOKEN" 123 | data = json.dumps(sc.api_call("users.list"), indent=4, sort_keys=True) 124 | print(data) 125 | ``` 126 | 127 | Once in the command promt line export the results in a JSON file: 128 | 129 | ``` cmd 130 | >>>python3 slack_file.py >> slack_db.json 131 | 132 | ``` 133 | The File have to be in the *src* folder and put the complete name of the file in the entrie ```"slack_db" : "slack_db.json",``` 134 | Once you have that change the ```"Slack_Activation" : "False"``` to ```True```. 135 | 136 | 5. Put the Recaptcha Codes in the entries: 137 | 138 | ``` json 139 | "RECAPTCHA_PUBLIC_KEY": "GOOGLE CODE", 140 | "RECAPTCHA_PRIVATE_KEY": "GOOGLE CODE" 141 | ``` 142 | To get this codes [click in this link](https://developers.google.com/recaptcha/) 143 | 144 | 6. The rest of the configuration entries are all pretty much all UI strings. Change them to localize, or to brand this utility, to meet your needs. 145 | 146 | ## Troubleshooting 147 | 148 | - None Reported 149 | 150 | ### LDAP Support 151 | 152 | - None reported 153 | 154 | 155 | ## Build your own version 156 | 157 | If you need to modify the source code (either backend or frontend). You require Python3 and Flask. 158 | 159 | 160 | *Note* - 161 | 162 | 163 | ## License 164 | 165 | PyPass is open source software and [MIT licensed](https://github.com/ZioGuillo/PYPASS/blob/master/LICENSE). *Please star this project if you like it.* -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_card.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .card { 6 | position: relative; 7 | display: flex; 8 | flex-direction: column; 9 | min-width: 0; 10 | word-wrap: break-word; 11 | background-color: $card-bg; 12 | background-clip: border-box; 13 | border: $card-border-width solid $card-border-color; 14 | @include border-radius($card-border-radius); 15 | 16 | > hr { 17 | margin-right: 0; 18 | margin-left: 0; 19 | } 20 | 21 | > .list-group:first-child { 22 | .list-group-item:first-child { 23 | @include border-top-radius($card-border-radius); 24 | } 25 | } 26 | 27 | > .list-group:last-child { 28 | .list-group-item:last-child { 29 | @include border-bottom-radius($card-border-radius); 30 | } 31 | } 32 | } 33 | 34 | .card-body { 35 | // Enable `flex-grow: 1` for decks and groups so that card blocks take up 36 | // as much space as possible, ensuring footers are aligned to the bottom. 37 | flex: 1 1 auto; 38 | padding: $card-spacer-x; 39 | } 40 | 41 | .card-title { 42 | margin-bottom: $card-spacer-y; 43 | } 44 | 45 | .card-subtitle { 46 | margin-top: -($card-spacer-y / 2); 47 | margin-bottom: 0; 48 | } 49 | 50 | .card-text:last-child { 51 | margin-bottom: 0; 52 | } 53 | 54 | .card-link { 55 | @include hover { 56 | text-decoration: none; 57 | } 58 | 59 | + .card-link { 60 | margin-left: $card-spacer-x; 61 | } 62 | } 63 | 64 | // 65 | // Optional textual caps 66 | // 67 | 68 | .card-header { 69 | padding: $card-spacer-y $card-spacer-x; 70 | margin-bottom: 0; // Removes the default margin-bottom of 71 | background-color: $card-cap-bg; 72 | border-bottom: $card-border-width solid $card-border-color; 73 | 74 | &:first-child { 75 | @include border-radius($card-inner-border-radius $card-inner-border-radius 0 0); 76 | } 77 | 78 | + .list-group { 79 | .list-group-item:first-child { 80 | border-top: 0; 81 | } 82 | } 83 | } 84 | 85 | .card-footer { 86 | padding: $card-spacer-y $card-spacer-x; 87 | background-color: $card-cap-bg; 88 | border-top: $card-border-width solid $card-border-color; 89 | 90 | &:last-child { 91 | @include border-radius(0 0 $card-inner-border-radius $card-inner-border-radius); 92 | } 93 | } 94 | 95 | 96 | // 97 | // Header navs 98 | // 99 | 100 | .card-header-tabs { 101 | margin-right: -($card-spacer-x / 2); 102 | margin-bottom: -$card-spacer-y; 103 | margin-left: -($card-spacer-x / 2); 104 | border-bottom: 0; 105 | } 106 | 107 | .card-header-pills { 108 | margin-right: -($card-spacer-x / 2); 109 | margin-left: -($card-spacer-x / 2); 110 | } 111 | 112 | // Card image 113 | .card-img-overlay { 114 | position: absolute; 115 | top: 0; 116 | right: 0; 117 | bottom: 0; 118 | left: 0; 119 | padding: $card-img-overlay-padding; 120 | } 121 | 122 | .card-img { 123 | width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch 124 | @include border-radius($card-inner-border-radius); 125 | } 126 | 127 | // Card image caps 128 | .card-img-top { 129 | width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch 130 | @include border-top-radius($card-inner-border-radius); 131 | } 132 | 133 | .card-img-bottom { 134 | width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch 135 | @include border-bottom-radius($card-inner-border-radius); 136 | } 137 | 138 | 139 | // Card deck 140 | 141 | .card-deck { 142 | display: flex; 143 | flex-direction: column; 144 | 145 | .card { 146 | margin-bottom: $card-deck-margin; 147 | } 148 | 149 | @include media-breakpoint-up(sm) { 150 | flex-flow: row wrap; 151 | margin-right: -$card-deck-margin; 152 | margin-left: -$card-deck-margin; 153 | 154 | .card { 155 | display: flex; 156 | // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 157 | flex: 1 0 0%; 158 | flex-direction: column; 159 | margin-right: $card-deck-margin; 160 | margin-bottom: 0; // Override the default 161 | margin-left: $card-deck-margin; 162 | } 163 | } 164 | } 165 | 166 | 167 | // 168 | // Card groups 169 | // 170 | 171 | .card-group { 172 | display: flex; 173 | flex-direction: column; 174 | 175 | // The child selector allows nested `.card` within `.card-group` 176 | // to display properly. 177 | > .card { 178 | margin-bottom: $card-group-margin; 179 | } 180 | 181 | @include media-breakpoint-up(sm) { 182 | flex-flow: row wrap; 183 | // The child selector allows nested `.card` within `.card-group` 184 | // to display properly. 185 | > .card { 186 | // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 187 | flex: 1 0 0%; 188 | margin-bottom: 0; 189 | 190 | + .card { 191 | margin-left: 0; 192 | border-left: 0; 193 | } 194 | 195 | // Handle rounded corners 196 | @if $enable-rounded { 197 | &:first-child { 198 | @include border-right-radius(0); 199 | 200 | .card-img-top, 201 | .card-header { 202 | border-top-right-radius: 0; 203 | } 204 | .card-img-bottom, 205 | .card-footer { 206 | border-bottom-right-radius: 0; 207 | } 208 | } 209 | 210 | &:last-child { 211 | @include border-left-radius(0); 212 | 213 | .card-img-top, 214 | .card-header { 215 | border-top-left-radius: 0; 216 | } 217 | .card-img-bottom, 218 | .card-footer { 219 | border-bottom-left-radius: 0; 220 | } 221 | } 222 | 223 | &:only-child { 224 | @include border-radius($card-border-radius); 225 | 226 | .card-img-top, 227 | .card-header { 228 | @include border-top-radius($card-border-radius); 229 | } 230 | .card-img-bottom, 231 | .card-footer { 232 | @include border-bottom-radius($card-border-radius); 233 | } 234 | } 235 | 236 | &:not(:first-child):not(:last-child):not(:only-child) { 237 | @include border-radius(0); 238 | 239 | .card-img-top, 240 | .card-img-bottom, 241 | .card-header, 242 | .card-footer { 243 | @include border-radius(0); 244 | } 245 | } 246 | } 247 | } 248 | } 249 | } 250 | 251 | 252 | // 253 | // Columns 254 | // 255 | 256 | .card-columns { 257 | .card { 258 | margin-bottom: $card-columns-margin; 259 | } 260 | 261 | @include media-breakpoint-up(sm) { 262 | column-count: $card-columns-count; 263 | column-gap: $card-columns-gap; 264 | orphans: 1; 265 | widows: 1; 266 | 267 | .card { 268 | display: inline-block; // Don't let them vertically span multiple columns 269 | width: 100%; // Don't let their width change 270 | } 271 | } 272 | } 273 | 274 | 275 | // 276 | // Accordion 277 | // 278 | 279 | .accordion { 280 | .card:not(:first-of-type):not(:last-of-type) { 281 | border-bottom: 0; 282 | border-radius: 0; 283 | } 284 | 285 | .card:not(:first-of-type) { 286 | .card-header:first-child { 287 | border-radius: 0; 288 | } 289 | } 290 | 291 | .card:first-of-type { 292 | border-bottom: 0; 293 | border-bottom-right-radius: 0; 294 | border-bottom-left-radius: 0; 295 | } 296 | 297 | .card:last-of-type { 298 | border-top-left-radius: 0; 299 | border-top-right-radius: 0; 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /app/static/scss/bootstrap/_navbar.scss: -------------------------------------------------------------------------------- 1 | // Contents 2 | // 3 | // Navbar 4 | // Navbar brand 5 | // Navbar nav 6 | // Navbar text 7 | // Navbar divider 8 | // Responsive navbar 9 | // Navbar position 10 | // Navbar themes 11 | 12 | 13 | // Navbar 14 | // 15 | // Provide a static navbar from which we expand to create full-width, fixed, and 16 | // other navbar variations. 17 | 18 | .navbar { 19 | position: relative; 20 | display: flex; 21 | flex-wrap: wrap; // allow us to do the line break for collapsing content 22 | align-items: center; 23 | justify-content: space-between; // space out brand from logo 24 | padding: $navbar-padding-y $navbar-padding-x; 25 | 26 | // Because flex properties aren't inherited, we need to redeclare these first 27 | // few properities so that content nested within behave properly. 28 | > .container, 29 | > .container-fluid { 30 | display: flex; 31 | flex-wrap: wrap; 32 | align-items: center; 33 | justify-content: space-between; 34 | } 35 | } 36 | 37 | 38 | // Navbar brand 39 | // 40 | // Used for brand, project, or site names. 41 | 42 | .navbar-brand { 43 | display: inline-block; 44 | padding-top: $navbar-brand-padding-y; 45 | padding-bottom: $navbar-brand-padding-y; 46 | margin-right: $navbar-padding-x; 47 | font-size: $navbar-brand-font-size; 48 | line-height: inherit; 49 | white-space: nowrap; 50 | 51 | @include hover-focus { 52 | text-decoration: none; 53 | } 54 | } 55 | 56 | 57 | // Navbar nav 58 | // 59 | // Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`). 60 | 61 | .navbar-nav { 62 | display: flex; 63 | flex-direction: column; // cannot use `inherit` to get the `.navbar`s value 64 | padding-left: 0; 65 | margin-bottom: 0; 66 | list-style: none; 67 | 68 | .nav-link { 69 | padding-right: 0; 70 | padding-left: 0; 71 | } 72 | 73 | .dropdown-menu { 74 | position: static; 75 | float: none; 76 | } 77 | } 78 | 79 | 80 | // Navbar text 81 | // 82 | // 83 | 84 | .navbar-text { 85 | display: inline-block; 86 | padding-top: $nav-link-padding-y; 87 | padding-bottom: $nav-link-padding-y; 88 | } 89 | 90 | 91 | // Responsive navbar 92 | // 93 | // Custom styles for responsive collapsing and toggling of navbar contents. 94 | // Powered by the collapse Bootstrap JavaScript plugin. 95 | 96 | // When collapsed, prevent the toggleable navbar contents from appearing in 97 | // the default flexbox row orienation. Requires the use of `flex-wrap: wrap` 98 | // on the `.navbar` parent. 99 | .navbar-collapse { 100 | flex-basis: 100%; 101 | flex-grow: 1; 102 | // For always expanded or extra full navbars, ensure content aligns itself 103 | // properly vertically. Can be easily overridden with flex utilities. 104 | align-items: center; 105 | } 106 | 107 | // Button for toggling the navbar when in its collapsed state 108 | .navbar-toggler { 109 | padding: $navbar-toggler-padding-y $navbar-toggler-padding-x; 110 | font-size: $navbar-toggler-font-size; 111 | line-height: 1; 112 | background-color: transparent; // remove default button style 113 | border: $border-width solid transparent; // remove default button style 114 | @include border-radius($navbar-toggler-border-radius); 115 | 116 | @include hover-focus { 117 | text-decoration: none; 118 | } 119 | 120 | // Opinionated: add "hand" cursor to non-disabled .navbar-toggler elements 121 | &:not(:disabled):not(.disabled) { 122 | cursor: pointer; 123 | } 124 | } 125 | 126 | // Keep as a separate element so folks can easily override it with another icon 127 | // or image file as needed. 128 | .navbar-toggler-icon { 129 | display: inline-block; 130 | width: 1.5em; 131 | height: 1.5em; 132 | vertical-align: middle; 133 | content: ""; 134 | background: no-repeat center center; 135 | background-size: 100% 100%; 136 | } 137 | 138 | // Generate series of `.navbar-expand-*` responsive classes for configuring 139 | // where your navbar collapses. 140 | .navbar-expand { 141 | @each $breakpoint in map-keys($grid-breakpoints) { 142 | $next: breakpoint-next($breakpoint, $grid-breakpoints); 143 | $infix: breakpoint-infix($next, $grid-breakpoints); 144 | 145 | &#{$infix} { 146 | @include media-breakpoint-down($breakpoint) { 147 | > .container, 148 | > .container-fluid { 149 | padding-right: 0; 150 | padding-left: 0; 151 | } 152 | } 153 | 154 | @include media-breakpoint-up($next) { 155 | flex-flow: row nowrap; 156 | justify-content: flex-start; 157 | 158 | .navbar-nav { 159 | flex-direction: row; 160 | 161 | .dropdown-menu { 162 | position: absolute; 163 | } 164 | 165 | .nav-link { 166 | padding-right: $navbar-nav-link-padding-x; 167 | padding-left: $navbar-nav-link-padding-x; 168 | } 169 | } 170 | 171 | // For nesting containers, have to redeclare for alignment purposes 172 | > .container, 173 | > .container-fluid { 174 | flex-wrap: nowrap; 175 | } 176 | 177 | .navbar-collapse { 178 | display: flex !important; // stylelint-disable-line declaration-no-important 179 | 180 | // Changes flex-bases to auto because of an IE10 bug 181 | flex-basis: auto; 182 | } 183 | 184 | .navbar-toggler { 185 | display: none; 186 | } 187 | } 188 | } 189 | } 190 | } 191 | 192 | 193 | // Navbar themes 194 | // 195 | // Styles for switching between navbars with light or dark background. 196 | 197 | // Dark links against a light background 198 | .navbar-light { 199 | .navbar-brand { 200 | color: $navbar-light-active-color; 201 | 202 | @include hover-focus { 203 | color: $navbar-light-active-color; 204 | } 205 | } 206 | 207 | .navbar-nav { 208 | .nav-link { 209 | color: $navbar-light-color; 210 | 211 | @include hover-focus { 212 | color: $navbar-light-hover-color; 213 | } 214 | 215 | &.disabled { 216 | color: $navbar-light-disabled-color; 217 | } 218 | } 219 | 220 | .show > .nav-link, 221 | .active > .nav-link, 222 | .nav-link.show, 223 | .nav-link.active { 224 | color: $navbar-light-active-color; 225 | } 226 | } 227 | 228 | .navbar-toggler { 229 | color: $navbar-light-color; 230 | border-color: $navbar-light-toggler-border-color; 231 | } 232 | 233 | .navbar-toggler-icon { 234 | background-image: $navbar-light-toggler-icon-bg; 235 | } 236 | 237 | .navbar-text { 238 | color: $navbar-light-color; 239 | a { 240 | color: $navbar-light-active-color; 241 | 242 | @include hover-focus { 243 | color: $navbar-light-active-color; 244 | } 245 | } 246 | } 247 | } 248 | 249 | // White links against a dark background 250 | .navbar-dark { 251 | .navbar-brand { 252 | color: $navbar-dark-active-color; 253 | 254 | @include hover-focus { 255 | color: $navbar-dark-active-color; 256 | } 257 | } 258 | 259 | .navbar-nav { 260 | .nav-link { 261 | color: $navbar-dark-color; 262 | 263 | @include hover-focus { 264 | color: $navbar-dark-hover-color; 265 | } 266 | 267 | &.disabled { 268 | color: $navbar-dark-disabled-color; 269 | } 270 | } 271 | 272 | .show > .nav-link, 273 | .active > .nav-link, 274 | .nav-link.show, 275 | .nav-link.active { 276 | color: $navbar-dark-active-color; 277 | } 278 | } 279 | 280 | .navbar-toggler { 281 | color: $navbar-dark-color; 282 | border-color: $navbar-dark-toggler-border-color; 283 | } 284 | 285 | .navbar-toggler-icon { 286 | background-image: $navbar-dark-toggler-icon-bg; 287 | } 288 | 289 | .navbar-text { 290 | color: $navbar-dark-color; 291 | a { 292 | color: $navbar-dark-active-color; 293 | 294 | @include hover-focus { 295 | color: $navbar-dark-active-color; 296 | } 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /app/static/js/jquery.waypoints.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | Waypoints - 4.0.0 3 | Copyright © 2011-2015 Caleb Troughton 4 | Licensed under the MIT license. 5 | https://github.com/imakewebthings/waypoints/blog/master/licenses.txt 6 | */ 7 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.invokeAll("enable")},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical);t&&e&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s],l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=y+l-f,h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}(); --------------------------------------------------------------------------------