├── inc
└── __init__.py
├── .gitignore
├── .dockerignore
├── env.example
├── docker
├── start.sh
├── patch-crontab.py
└── my_mem.cnf
├── doc
└── refman.pdf
├── __init__.py
├── db
├── createdatabase.sql
├── clear.sql
└── ddl.sql
├── static
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ └── glyphicons-halflings-regular.woff
├── css
│ ├── jquery-cron.css
│ ├── asprom.css
│ ├── bootstrap-dialog.min.css
│ ├── bootstrap-table.min.css
│ ├── bootstrap-table.css
│ ├── bootstrap-theme.min.css
│ ├── bootstrap-theme.css
│ └── bootstrap-editable.css
└── js
│ ├── prettycron.js
│ ├── jquery-cron-min.js
│ ├── asprom.js
│ ├── bootstrap-dialog.min.js
│ └── bootstrap-table.min.js
├── requirements.txt
├── etc
└── asprom.cfg
├── Dockerfile
├── aspromMetrics.py
├── docker-compose.yml
├── supplemental
├── apache-definition
└── init-script
├── views
├── posture.tpl
├── baseline.tpl
├── alerts-exposed.tpl
├── alerts-closed.tpl
├── schedule.tpl
├── addjob.tpl
├── editjob.tpl
└── base.tpl
├── README.md
├── aspromNagiosCheck.py
├── aspromScan.py
├── LICENSE
└── aspromGUI.py
/inc/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | *.swp
3 | *.bak
4 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | supplemental
3 | doc
4 |
--------------------------------------------------------------------------------
/env.example:
--------------------------------------------------------------------------------
1 | DOCKER_SOCKET=/var/run/docker.sock
2 |
--------------------------------------------------------------------------------
/docker/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | cron
3 | python3 aspromGUI.py
4 |
--------------------------------------------------------------------------------
/doc/refman.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daimoniac/asprom/HEAD/doc/refman.pdf
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py file
2 |
3 | import pymysql
4 | pymysql.install_as_MySQLdb()
5 |
--------------------------------------------------------------------------------
/db/createdatabase.sql:
--------------------------------------------------------------------------------
1 | create database asprom;
2 | grant all privileges on asprom.* to asprom@localhost identified by 'asprom';
3 |
4 |
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daimoniac/asprom/HEAD/static/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daimoniac/asprom/HEAD/static/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/static/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daimoniac/asprom/HEAD/static/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/db/clear.sql:
--------------------------------------------------------------------------------
1 | truncate table criticality;
2 | truncate table servicelog;
3 | truncate table changelog;
4 | truncate table machinelog;;
5 | delete from services;
6 | delete from machines;
7 | truncate table scanlog;
8 |
9 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | anyascii==0.3.2
2 | mysqlclient==2.2.4
3 | python-crontab==3.2.0
4 | netaddr==1.3.0
5 | paste==3.10.1
6 | bottle==0.13.1
7 | config==0.4.2
8 | croniter==3.0.3
9 | prometheus-client==0.20.0
10 | python-nmap==0.7.1
11 |
--------------------------------------------------------------------------------
/etc/asprom.cfg:
--------------------------------------------------------------------------------
1 | # database
2 | db: {
3 | 'host':"mysql"
4 | 'user':"asprom"
5 | 'passwd':"asprom"
6 | 'db':"asprom"
7 | }
8 | # webserver parameters
9 | server: {
10 | 'listen': '0.0.0.0'
11 | 'port': 8080
12 | 'debug': True
13 | }
14 |
15 | # miscellaneous
16 | misc: {
17 | 'url':"http://localhost:8080"
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/docker/patch-crontab.py:
--------------------------------------------------------------------------------
1 | --- crontab.py 2024-09-17 06:56:19.752610239 +0000
2 | +++ 2.py 2024-09-17 06:57:56.279127134 +0000
3 | @@ -215,7 +215,7 @@
4 | return str(self) == other
5 |
6 |
7 | -class CronTab:
8 | +class CronTab(object):
9 | """
10 | Crontab object which can access any time based cron using the standard.
11 |
12 |
--------------------------------------------------------------------------------
/static/css/jquery-cron.css:
--------------------------------------------------------------------------------
1 | .cron-button {
2 | height: 16px;
3 | padding-left: 20px;
4 | margin-left: 5px;
5 | background-repeat: no-repeat;
6 | background-position: center center;
7 | cursor: pointer;
8 | }
9 | .cron-changed {
10 | padding-top: 5px;
11 | padding-bottom: 5px;
12 | background-color: #fdd;
13 | }
14 | .cron-controls {
15 | margin-left: 10px;
16 | color: #c77;
17 | font-size: 0.9em;
18 | }
19 | .cron-controls > span.cron-loading {
20 | background-image: url('img/loading.gif');
21 | }
--------------------------------------------------------------------------------
/docker/my_mem.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | performance_schema = off
3 | key_buffer_size = 16M
4 | tmp_table_size = 1M
5 | innodb_buffer_pool_size = 1M
6 | innodb_log_buffer_size = 1M
7 | max_connections = 20
8 | sort_buffer_size = 64M
9 | read_buffer_size = 256K
10 | read_rnd_buffer_size = 512K
11 | join_buffer_size = 128K
12 | thread_stack = 196K
13 | max-heap-table-size = 32M
14 | thread-cache-size = 50
15 | open-files-limit = 65535
16 | table-definition-cache = 1024
17 | table-open-cache = 2048
18 |
19 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM debian:bookworm-slim
2 | ENV TINI_VERSION=v0.19.0
3 | ENV DEBIAN_FRONTEND=noninteractive
4 | ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
5 | RUN chmod +x /tini
6 | COPY requirements.txt /tmp/
7 | RUN apt-get update && \
8 | apt-get -y install cron nmap patch libmariadb3 python3-minimal python3-pip \
9 | default-libmysqlclient-dev build-essential pkg-config && \
10 | pip install --break-system-packages -r /tmp/requirements.txt && \
11 | apt-get -y autoremove python3-dev python3-pip default-libmysqlclient-dev \
12 | build-essential pkg-config && \
13 | rm -rf /var/lib/apt/lists/*
14 | WORKDIR /asprom
15 | COPY . .
16 | # fix old style class in python-crontab leading to exception
17 | RUN patch -p0 /usr/local/lib/python3.11/dist-packages/crontab.py < docker/patch-crontab.py
18 | RUN chmod 640 aspromNagiosCheck.py
19 | EXPOSE 8080
20 | ENTRYPOINT ["/tini", "--"]
21 | CMD ["docker/start.sh"]
22 |
23 |
--------------------------------------------------------------------------------
/aspromMetrics.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Sep 05, 2024
3 |
4 | @author stefankn
5 | @namespace asprom.aspromNagiosCheck
6 | small and nice metrics server for asprom
7 | '''
8 | from inc.asprom import initDB, closeDB, AspromModel, Cfg
9 | from time import sleep
10 | from prometheus_client import start_http_server, Gauge
11 | from pprint import pprint
12 |
13 | localconf = Cfg()
14 |
15 | alertsExposed = Gauge('alerts_exposed', 'These Ports are unintentionally open and therefore to be checked with the highest priority.')
16 | alertsClosed = Gauge('alerts_closed', 'These Ports are unintentionally open and therefore to be checked with the highest priority.')
17 |
18 | initDB(localconf)
19 | M = AspromModel()
20 |
21 | def refreshMetrics():
22 |
23 | alertsExposed.set(len(M.getAlertsExposed()))
24 | alertsClosed.set(len(M.getAlertsClosed()))
25 |
26 | if __name__ == '__main__':
27 |
28 | pprint("starting asprom metrics server")
29 | # Start up the server to expose the metrics.
30 | start_http_server(5000)
31 |
32 | while True:
33 | sleep(5)
34 | refreshMetrics()
35 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 | services:
3 | asprom:
4 | restart: always
5 | environment:
6 | PYTHONUNBUFFERED: 1
7 | image: asprom
8 | build:
9 | context: .
10 | dockerfile: Dockerfile
11 | depends_on:
12 | - mysql
13 | volumes:
14 | - crontabs:/var/spool/cron/crontabs
15 | ports:
16 | - 8080:8080
17 | asprom-metrics:
18 | restart: always
19 | environment:
20 | PYTHONUNBUFFERED: 1
21 | image: asprom
22 | command:
23 | - python3
24 | - aspromMetrics.py
25 | depends_on:
26 | - mysql
27 | ports:
28 | - 5000:5000
29 | mysql:
30 | restart: always
31 | image: mysql:8.0
32 | cap_add:
33 | - SYS_NICE
34 | environment:
35 | MYSQL_USER: 'asprom'
36 | MYSQL_PASSWORD: 'asprom'
37 | MYSQL_DATABASE: 'asprom'
38 | MYSQL_RANDOM_ROOT_PASSWORD: 'true'
39 | volumes:
40 | - "mysqldata:/var/lib/mysql"
41 | - "./db/ddl.sql:/docker-entrypoint-initdb.d/1.sql"
42 | - "./docker/my_mem.cnf:/etc/mysql/conf.d/my_mem.cnf"
43 | volumes:
44 | mysqldata:
45 | crontabs:
46 |
47 |
--------------------------------------------------------------------------------
/supplemental/apache-definition:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Redirect / /alerts-exposed
5 |
6 | # Proxy Config
7 | ProxyPreserveHost On
8 | ProxyRequests On
9 | ProxyVia On
10 | ProxyPassMatch /(.+) http://127.0.0.1:8080/$1
11 | ProxyPassReverse / http://127.0.0.1:8080/
12 |
13 | # SSL Config
14 | SSLEngine on
15 | SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
16 | SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
17 |
18 | SSLOptions +StdEnvVars
19 |
20 |
21 | SSLOptions +StdEnvVars
22 |
23 | BrowserMatch "MSIE [2-6]" \
24 | nokeepalive ssl-unclean-shutdown \
25 | downgrade-1.0 force-response-1.0
26 | # MSIE 7 and newer should be able to use keepalive
27 | BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
28 |
29 | # Auth Config
30 |
31 | AuthType Basic
32 | AuthName "asprom GUI Login"
33 | AuthBasicProvider file
34 | AuthUserFile /home/asprom/asprom/.htpasswd
35 | Require valid-user
36 | #Order Deny,Allow
37 | #Deny from all
38 | #Allow from 192.168.0
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/static/css/asprom.css:
--------------------------------------------------------------------------------
1 | .ml10 {
2 | margin-left: 10px;
3 | }
4 |
5 | .infobox {
6 | margin-top: 15px;
7 | margin-bottom: 10px !important;
8 | }
9 |
10 | .glyphicon {
11 | text-shadow: 0 0 1px black;
12 | }
13 | .glyphicon-ok {
14 | color: #00EE00;
15 | }
16 |
17 | .glyphicon-remove {
18 | color: #FF3300;
19 | }
20 |
21 | .glyphicon-star {
22 | color: #FFCC00;
23 | }
24 |
25 | .glyphicon-search {
26 | color: #0000EE;
27 | }
28 | .glyphicon-edit {
29 | color: #0000EE;
30 | }
31 |
32 |
33 | .row-critical, .row-critical input {
34 | background-color: #FFAAAA;
35 | }
36 |
37 | .row-warning, .row-warning input {
38 | background-color: #FFFFAA;
39 | }
40 |
41 | .nopad {
42 | vertical-align: middle;
43 | padding: 0 !important;
44 | }
45 |
46 | .nopad input {
47 | box-shadow: none !important;
48 | border-radius: none !important;
49 | border: 0;
50 |
51 | }
52 |
53 | toggle {
54 | cursor: pointer;
55 | }
56 |
57 | .danger-2 {
58 | background-image: linear-gradient(to bottom, #FFEEEE 0px, #F7D3D3 100%);
59 | }
60 |
61 | .warning-2 {
62 | background-image: linear-gradient(to bottom, #FAFAF3 0px, #FAFAD0 100%);
63 | }
64 |
65 | .aspinfo {
66 | background-image: linear-gradient(to bottom, #F9FAFF 0px, #D9E0F0 100%);
67 | }
68 |
69 | .aspinfo-2 {
70 | background-image: linear-gradient(to bottom, #FFFFFF 0px, #E9EEFF 100%);
71 | }
72 |
73 | .moretolearn {
74 | display: none;
75 | }
76 |
77 | .container-fluid {
78 | margin-left: 15%;
79 | margin-right: 15%;
80 | margin-top: 10px;
81 | }
82 |
83 |
84 | .xlarge {
85 | font-size: 50px;
86 | text-shadow: 0 0 5px #FF8800;
87 | }
--------------------------------------------------------------------------------
/views/posture.tpl:
--------------------------------------------------------------------------------
1 | % rebase('base.tpl', title='posture')
2 |
22 |
23 |
24 |
About this view
25 |
The security posture is the actual profile of your networks found by forensic means.
26 |
You may rescan single ports by clicking the "rescan" button .
27 |
Learn more
28 |
29 |
--------------------------------------------------------------------------------
/static/css/bootstrap-dialog.min.css:
--------------------------------------------------------------------------------
1 | .bootstrap-dialog .modal-header{border-top-left-radius:4px;border-top-right-radius:4px}.bootstrap-dialog .bootstrap-dialog-title{color:#fff;display:inline-block}.bootstrap-dialog.type-default .bootstrap-dialog-title{color:#333}.bootstrap-dialog.size-normal .bootstrap-dialog-title{font-size:16px}.bootstrap-dialog.size-large .bootstrap-dialog-title{font-size:24px}.bootstrap-dialog .bootstrap-dialog-close-button{float:right;filter:alpha(opacity=90);-moz-opacity:.9;-khtml-opacity:.9;opacity:.9}.bootstrap-dialog.size-normal .bootstrap-dialog-close-button{font-size:20px}.bootstrap-dialog.size-large .bootstrap-dialog-close-button{font-size:30px}.bootstrap-dialog .bootstrap-dialog-close-button:hover{cursor:pointer;filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}.bootstrap-dialog.size-normal .bootstrap-dialog-message{font-size:14px}.bootstrap-dialog.size-large .bootstrap-dialog-message{font-size:18px}.bootstrap-dialog.type-default .modal-header{background-color:#fff}.bootstrap-dialog.type-info .modal-header{background-color:#5bc0de}.bootstrap-dialog.type-primary .modal-header{background-color:#428bca}.bootstrap-dialog.type-success .modal-header{background-color:#5cb85c}.bootstrap-dialog.type-warning .modal-header{background-color:#f0ad4e}.bootstrap-dialog.type-danger .modal-header{background-color:#d9534f}.bootstrap-dialog .bootstrap-dialog-button-icon{margin-right:3px}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0{-ms-transform:rotate(0)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0{transform:rotate(0)}100%{transform:rotate(359deg)}}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # asprom - Assault Profile Monitor
2 |
3 | asprom is a network security compliance scanner that monitors Layer 4 firewall configurations. It allows you to define service profiles for your networks and automatically scans them using nmap to detect any deviations from the established baseline.
4 |
5 | This tool helps ensure compliance with security standards such as PCI-DSS, BSI-Grundschutz, and ISO/IEC 27001.
6 |
7 | ## Quick Start with Docker
8 |
9 | The easiest way to get started is using Docker, which includes all dependencies:
10 |
11 | ```bash
12 | cp env.example .env
13 | docker-compose up -d
14 | ```
15 |
16 | Once running, access the GUI at [http://localhost:8080](http://localhost:8080).
17 |
18 | ## Getting Started
19 |
20 | 1. Navigate to the "Schedule" tab
21 | 2. Configure a scan target:
22 | - Enter a hostname, IP address, or IP range
23 | - Leave "port range" and "extra parameters" empty initially
24 | 3. Click "Add Job" to create the scan
25 | 4. Click the magnifying glass icon to execute the scan immediately
26 | 5. Wait for the scan completion notification
27 |
28 | ## Managing Alerts
29 |
30 | After scanning, you'll find detected services under the "Alerts: Exposed" tab. For each alert, you can:
31 |
32 | - Click the "star" icon to mark for mitigation
33 | - Click the "approve" icon to accept it as part of your baseline (requires business justification)
34 |
35 | Once you've processed alerts for all your IP ranges, your initial configuration is complete. asprom will now monitor these ranges and alert you to any new services that appear.
36 |
37 | ## Monitoring Integration
38 |
39 | ### Prometheus Metrics
40 | Access metrics about open ports and baseline deviations at:
41 | [http://localhost:5000/metrics](http://localhost:5000/metrics)
42 |
43 | ### Nagios Integration
44 | Use `aspromNagiosCheck.py` as a standard Nagios plugin to receive active alerts. The plugin will return CRITICAL status when unauthorized services are detected.
45 |
46 |
--------------------------------------------------------------------------------
/aspromNagiosCheck.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Oct 23, 2014
3 |
4 | @author stefankn
5 | @namespace asprom.aspromNagiosCheck
6 | This file is invoked from the CLI and can be directly used as a nagios plugin.
7 | if any of the services on the alerts-exposed or alerts-closed views
8 | are marked as critical,
9 | this script terminates with a return value of 2.
10 | if none are marked as critical, but at least one is marked as warning,
11 | this script terminates with a return value of 1.
12 | Else, it terminates with a value of 0 signalling everything is alright.
13 | '''
14 | from inc.asprom import initDB, closeDB, AspromModel, Cfg, genMessages
15 | import sys
16 |
17 | def main():
18 | exitstate = 0
19 | msg = ""
20 |
21 | localconf = Cfg()
22 | initDB(localconf)
23 | M = AspromModel()
24 |
25 | #exposed services
26 | messageCritExposed, messageWarnExposed = genMessages(M.getAlertsExposed())
27 |
28 | #closed services
29 | messageCritClosed, messageWarnClosed = genMessages(M.getAlertsClosed())
30 |
31 | closeDB()
32 |
33 | # Start up the server to expose the metrics.
34 | start_http_server(5000)
35 | if len(messageCritExposed):
36 | msg += 'CRITICAL-EXPOSED: ' + " | ".join(messageCritExposed) + "\n"
37 | exitstate = 2
38 | if len(messageCritClosed):
39 | msg += 'CRITICAL-CLOSED: ' + " | ".join(messageCritClosed) + "\n"
40 | exitstate = 2
41 | if len(messageWarnExposed):
42 | msg += 'WARNING-EXPOSED: ' + " | ".join(messageWarnExposed) + "\n"
43 | exitstate = exitstate or 1
44 | if len(messageWarnClosed):
45 | msg += 'WARNING-CLOSED: ' + " | ".join(messageWarnClosed) + "\n"
46 | exitstate = exitstate or 1
47 |
48 | if not exitstate:
49 | msg = 'all Profiles nominal.'
50 |
51 | msg += 'Profiling URL: ' + localconf['misc']['url']
52 |
53 | print(msg)
54 | sys.exit(exitstate)
55 |
56 |
57 | if __name__ == '__main__':
58 | main()
59 |
--------------------------------------------------------------------------------
/views/baseline.tpl:
--------------------------------------------------------------------------------
1 | % rebase('base.tpl', title='baseline')
2 |
23 |
24 |
25 |
About this view
26 |
The "baseline" speficies the attack profile your network presents as it should be.
27 |
It lists only the services that should be available including the reason why (business justification).
28 | You may rescan single ports by clicking "rescan" or delete them using "delete" .
29 |
Learn more
30 |
31 |
--------------------------------------------------------------------------------
/views/alerts-exposed.tpl:
--------------------------------------------------------------------------------
1 | % rebase('base.tpl', title='alerts-exposed')
2 |
22 |
23 |
24 |
About this view
25 |
These Ports are unintentionally open and therefore to be checked with the highest priority.
26 |
You can temporarily mark an alert as non-critical during your research by clicking the star button .
27 | To get completely rid of an alert, close the port and rescan using the magnifying glass - or add it to the "baseline" by
28 | clicking the green approval button and specifying a business justification (case id, ticket number etc.).
29 |
Learn more
30 |
31 |
--------------------------------------------------------------------------------
/views/alerts-closed.tpl:
--------------------------------------------------------------------------------
1 | % rebase('base.tpl', title='alerts-closed')
2 |
23 |
24 |
25 |
About this view
26 |
These Ports are closed, but the "baseline" specifies a business justification for them to be open.
27 |
Normally, this is not a security risk, but may hint at a service failure. These alerts are non-critical by default.
28 | You can mark an alert as critical by clicking the star button .
29 | To get completely rid of an alert, reopen the port and rescan using the magnifying glass -
30 | or remove it from the "baseline" by clicking the red delete button and entering a business justification.
31 |
Learn more
32 |
33 |
--------------------------------------------------------------------------------
/aspromScan.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Oct 23, 2014
3 |
4 | @author stefankn
5 | @namespace asprom.aspromScan
6 | this file is invoked on the CLI as a wrapper script to nmap.
7 | when invoked from the command line, the scan() method is called.
8 | '''
9 | import argparse
10 | import re
11 | from inc.asprom import scan, initDB, closeDB, Cfg
12 |
13 |
14 | def main():
15 | '''
16 | parse arguments from command line.
17 |
18 |
19 | > usage:
20 |
21 | aspromScan.py [-h] [-o EXTRA_OPTIONS] [-s SENSOR] [-p PORT_RANGE]
22 | [-j JOB_ID] TARGET
23 |
24 | Scans an IP Range for asprom. Needs nmap installed on the sensor host.
25 |
26 |
27 | positional arguments:
28 | TARGET the hostname/ip/ip range to be scanned
29 |
30 | optional arguments:
31 |
32 | -h, --help show this help message and exit
33 |
34 | -o EXTRA_OPTIONS, --extra-options EXTRA_OPTIONS
35 | extra options to be passed to nmap
36 |
37 | -s SENSOR, --sensor SENSOR
38 | start scanning on another sensor
39 |
40 | -p PORT_RANGE, --port-range PORT_RANGE
41 | set custom port range to be scanned
42 |
43 | -j JOB_ID, --job-id JOB_ID
44 | set arbitrary job id (used by aspromGUI and cron)
45 | '''
46 | parser = argparse.ArgumentParser(description='''Scans an IP Range for
47 | asprom. Needs nmap installed on the sensor host.''')
48 | parser.add_argument('target', metavar="TARGET",
49 | help='the hostname/ip/ip range to be scanned')
50 | parser.add_argument('-o', '--extra-options', default='',
51 | help='extra options to be passed to nmap')
52 | parser.add_argument('-s', '--sensor', default='localhost',
53 | help='start scanning on another sensor')
54 | parser.add_argument('-p', '--port-range', default=None,
55 | help='set custom port range to be scanned')
56 | parser.add_argument('-j', '--job-id', default=None,
57 | help='set arbitrary job id (used by aspromGUI and cron)')
58 |
59 | args = parser.parse_args()
60 |
61 | localconf = Cfg()
62 | initDB(localconf)
63 | scan(args.target, args.port_range, args.extra_options, args.job_id)
64 | closeDB()
65 |
66 | if __name__ == '__main__':
67 | main()
68 |
--------------------------------------------------------------------------------
/views/schedule.tpl:
--------------------------------------------------------------------------------
1 | % rebase('base.tpl', title='schedule')
2 |
3 |
4 |
5 |
27 |
28 |
29 |
About this view
30 |
In the schedule, you define which network ranges should be checked, and when they should be checked.
31 |
You can change the settings of each job by clicking the edit button .
32 | You can also run each scan right now by clicking the magnifying glass .
33 | When you delete a job in this interface, asprom will comment it out in the users' crontab.
34 |
Learn more
35 |
36 |
--------------------------------------------------------------------------------
/views/addjob.tpl:
--------------------------------------------------------------------------------
1 | Add Schedule
2 |
3 |
49 |
50 |
55 |
56 |
57 | IP Range
58 |
59 |
60 |
61 |
62 | Port Range
63 |
64 |
65 |
66 |
67 | extra Parameters
68 |
69 |
70 |
71 |
85 |
86 |
87 | Add Job
88 |
--------------------------------------------------------------------------------
/views/editjob.tpl:
--------------------------------------------------------------------------------
1 | Edit Schedule for {{iprange}}
2 |
3 |
49 |
50 |
55 |
56 |
57 | IP Range
58 |
59 |
60 |
61 |
62 | Port Range
63 |
64 |
65 |
66 |
67 | extra Parameters
68 |
69 |
70 |
71 |
85 |
86 |
87 | Apply
88 |
--------------------------------------------------------------------------------
/views/base.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | asprom: {{title}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | asprom assault profile monitor
34 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
51 |
52 | {{!base}}
53 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/static/css/bootstrap-table.min.css:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-table - v1.3.0 - 2014-10-16
3 | * https://github.com/wenzhixin/bootstrap-table
4 | * Copyright (c) 2014 zhixin wen
5 | * Licensed MIT License
6 | */
7 |
8 | .table{margin-bottom:0!important;border-bottom:1px solid #ddd;border-collapse:collapse!important;border-radius:1px}.fixed-table-container{position:relative;clear:both;border:1px solid #ddd;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px}.fixed-table-header{overflow:hidden;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0}.fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.fixed-table-container table{width:100%}.fixed-table-container thead th{height:0;padding:0;margin:0;border-left:1px solid #ddd}.fixed-table-container thead th:first-child{border-left:none;border-top-left-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fixed-table-container thead th .th-inner{padding:8px;line-height:24px;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fixed-table-container thead th .sortable{cursor:pointer}.fixed-table-container tbody td{border-left:1px solid #ddd}.fixed-table-container tbody tr:first-child td{border-top:none}.fixed-table-container tbody td:first-child{border-left:none}.fixed-table-container tbody .selected td{background-color:#f5f5f5}.fixed-table-container .bs-checkbox{text-align:center}.fixed-table-container .bs-checkbox .th-inner{padding:8px 0}.fixed-table-container input[type=checkbox],.fixed-table-container input[type=radio]{margin:0 auto!important}.fixed-table-container .no-records-found{text-align:center}.fixed-table-pagination .pagination,.fixed-table-pagination .pagination-detail{margin-top:10px;margin-bottom:10px}.fixed-table-pagination .pagination a{padding:6px 12px;line-height:1.428571429}.fixed-table-pagination .pagination-info{line-height:34px;margin-right:5px}.fixed-table-pagination .btn-group{position:relative;display:inline-block;vertical-align:middle}.fixed-table-pagination .dropup .dropdown-menu{margin-bottom:0}.fixed-table-pagination .page-list{display:inline-block}.fixed-table-toolbar .columns{margin-left:5px}.fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429}.fixed-table-toolbar .bars,.fixed-table-toolbar .columns,.fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px;line-height:34px}.fixed-table-pagination li.disabled a{pointer-events:none;cursor:default}.fixed-table-loading{display:none;position:absolute;top:42px;right:0;bottom:0;left:0;z-index:99;background-color:#fff;text-align:center}.fixed-table-body .card-view .title{font-weight:700;display:inline-block;min-width:30%;text-align:left!important}.fixed-table-body thead th .th-inner{box-sizing:border-box}.table td,.table th{vertical-align:middle;box-sizing:border-box}.fixed-table-toolbar .dropdown-menu{text-align:left;max-height:300px;overflow:auto}.fixed-table-toolbar .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.fixed-table-toolbar .btn-group>.btn-group>.btn{border-radius:0}.fixed-table-toolbar .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.fixed-table-toolbar .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table thead>tr>th{padding:0;margin:0}.pull-right .dropdown-menu{right:0;left:auto}p.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}
9 |
--------------------------------------------------------------------------------
/static/css/bootstrap-table.css:
--------------------------------------------------------------------------------
1 | .table {
2 | margin-bottom: 0 !important;
3 | border-bottom: 1px solid #dddddd;
4 | border-collapse: collapse !important;
5 | border-radius: 1px;
6 | }
7 |
8 | .fixed-table-container {
9 | position: relative;
10 | clear: both;
11 | border: 1px solid #dddddd;
12 | border-radius: 4px;
13 | -webkit-border-radius: 4px;
14 | -moz-border-radius: 4px;
15 | }
16 |
17 | .fixed-table-header {
18 | overflow: hidden;
19 | border-radius: 4px 4px 0 0;
20 | -webkit-border-radius: 4px 4px 0 0;
21 | -moz-border-radius: 4px 4px 0 0;
22 | }
23 |
24 | .fixed-table-body {
25 | overflow-x: auto;
26 | overflow-y: auto;
27 | height: 100%;
28 | }
29 |
30 | .fixed-table-container table {
31 | width: 100%;
32 | }
33 |
34 | .fixed-table-container thead th {
35 | height: 0;
36 | padding: 0;
37 | margin: 0;
38 | border-left: 1px solid #dddddd;
39 | }
40 |
41 | .fixed-table-container thead th:first-child {
42 | border-left: none;
43 | border-top-left-radius: 4px;
44 | -webkit-border-top-left-radius: 4px;
45 | -moz-border-radius-topleft: 4px;
46 | }
47 |
48 | .fixed-table-container thead th .th-inner {
49 | padding: 8px;
50 | line-height: 24px;
51 | vertical-align: top;
52 | overflow: hidden;
53 | text-overflow: ellipsis;
54 | white-space: nowrap;
55 | }
56 |
57 | .fixed-table-container thead th .sortable {
58 | cursor: pointer;
59 | }
60 |
61 | .fixed-table-container tbody td {
62 | border-left: 1px solid #dddddd;
63 | }
64 |
65 | .fixed-table-container tbody tr:first-child td {
66 | border-top: none;
67 | }
68 |
69 | .fixed-table-container tbody td:first-child {
70 | border-left: none;
71 | }
72 |
73 | /* the same color with .active */
74 | .fixed-table-container tbody .selected td {
75 | background-color: #f5f5f5;
76 | }
77 |
78 | .fixed-table-container .bs-checkbox {
79 | text-align: center;
80 | }
81 |
82 | .fixed-table-container .bs-checkbox .th-inner {
83 | padding: 8px 0;
84 | }
85 |
86 | .fixed-table-container input[type="radio"],
87 | .fixed-table-container input[type="checkbox"] {
88 | margin: 0 auto !important;
89 | }
90 |
91 | .fixed-table-container .no-records-found {
92 | text-align: center;
93 | }
94 |
95 |
96 | .fixed-table-pagination .pagination,
97 | .fixed-table-pagination .pagination-detail {
98 | margin-top: 10px;
99 | margin-bottom: 10px;
100 | }
101 |
102 | .fixed-table-pagination .pagination a {
103 | padding: 6px 12px;
104 | line-height: 1.428571429;
105 | }
106 |
107 | .fixed-table-pagination .pagination-info {
108 | line-height: 34px;
109 | margin-right: 5px;
110 | }
111 |
112 | .fixed-table-pagination .btn-group {
113 | position: relative;
114 | display: inline-block;
115 | vertical-align: middle;
116 | }
117 |
118 | .fixed-table-pagination .dropup .dropdown-menu {
119 | margin-bottom: 0;
120 | }
121 |
122 | .fixed-table-pagination .page-list {
123 | display: inline-block;
124 | }
125 |
126 | .fixed-table-toolbar .columns {
127 | margin-left: 5px;
128 | }
129 |
130 | .fixed-table-toolbar .columns label {
131 | display: block;
132 | padding: 3px 20px;
133 | clear: both;
134 | font-weight: normal;
135 | line-height: 1.428571429;
136 | }
137 |
138 | .fixed-table-toolbar .bars,
139 | .fixed-table-toolbar .search,
140 | .fixed-table-toolbar .columns {
141 | position: relative;
142 | margin-top: 10px;
143 | margin-bottom: 10px;
144 | line-height: 34px;
145 | }
146 |
147 | .fixed-table-pagination li.disabled a {
148 | pointer-events: none;
149 | cursor: default;
150 | }
151 |
152 | .fixed-table-loading {
153 | display: none;
154 | position: absolute;
155 | top: 42px;
156 | right: 0;
157 | bottom: 0;
158 | left: 0;
159 | z-index: 99;
160 | background-color: #fff;
161 | text-align: center;
162 | }
163 |
164 | .fixed-table-body .card-view .title {
165 | font-weight: bold;
166 | display: inline-block;
167 | min-width: 30%;
168 | text-align: left !important;
169 | }
170 |
171 | /* support bootstrap 2 */
172 | .fixed-table-body thead th .th-inner {
173 | box-sizing: border-box;
174 | }
175 |
176 | .table th, .table td {
177 | vertical-align: middle;
178 | box-sizing: border-box;
179 | }
180 |
181 | .fixed-table-toolbar .dropdown-menu {
182 | text-align: left;
183 | max-height: 300px;
184 | overflow: auto;
185 | }
186 |
187 | .fixed-table-toolbar .btn-group>.btn-group {
188 | display: inline-block;
189 | margin-left: -1px !important;
190 | }
191 |
192 | .fixed-table-toolbar .btn-group>.btn-group>.btn {
193 | border-radius: 0;
194 | }
195 |
196 | .fixed-table-toolbar .btn-group>.btn-group:first-child>.btn {
197 | border-top-left-radius: 4px;
198 | border-bottom-left-radius: 4px;
199 | }
200 |
201 | .fixed-table-toolbar .btn-group>.btn-group:last-child>.btn {
202 | border-top-right-radius: 4px;
203 | border-bottom-right-radius: 4px;
204 | }
205 |
206 | .table>thead>tr>th {
207 | vertical-align: bottom;
208 | border-bottom: 2px solid #ddd;
209 | }
210 |
211 | /* support bootstrap 3 */
212 | .table thead>tr>th {
213 | padding: 0;
214 | margin: 0;
215 | }
216 |
217 | .pull-right .dropdown-menu {
218 | right: 0;
219 | left: auto;
220 | }
221 |
222 | /* calculate scrollbar width */
223 | p.fixed-table-scroll-inner {
224 | width: 100%;
225 | height: 200px;
226 | }
227 |
228 | div.fixed-table-scroll-outer {
229 | top: 0;
230 | left: 0;
231 | visibility: hidden;
232 | width: 200px;
233 | height: 150px;
234 | overflow: hidden;
235 | }
236 |
--------------------------------------------------------------------------------
/supplemental/init-script:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | ### BEGIN INIT INFO
3 | # Provides: asprom
4 | # Required-Start: $network
5 | # Required-Stop: $network
6 | # Default-Start: 2 3 4 5
7 | # Default-Stop: 0 1 6
8 | # Short-Description: asprom assault profile monitor
9 | # Description: starts the asprom GUI.
10 | ### END INIT INFO
11 |
12 | # Author: stefan knott
13 | #
14 | # Please remove the "Author" lines above and replace them
15 | # with your own name if you copy and modify this script.
16 |
17 | # Do NOT "set -e"
18 |
19 | # PATH should only include /usr/* if it runs after the mountnfs.sh script
20 | PATH=/sbin:/usr/sbin:/bin:/usr/bin
21 |
22 | # change this
23 | MAINPATH=/home/asprom/asprom
24 | USER=asprom
25 |
26 | DESC="asprom assault profile monitor"
27 | NAME=aspromGUI.py
28 | DAEMON=/usr/bin/python
29 | DAEMON_ARGS="$MAINPATH/$NAME"
30 | PIDFILE=/var/run/$NAME.pid
31 | SCRIPTNAME=/etc/init.d/$NAME
32 |
33 | # Exit if the package is not installed
34 | [ -x "$DAEMON" ] || exit 0
35 |
36 | # Read configuration variable file if it is present
37 | [ -r /etc/default/$NAME ] && . /etc/default/$NAME
38 |
39 | # Load the VERBOSE setting and other rcS variables
40 | . /lib/init/vars.sh
41 |
42 | # Define LSB log_* functions.
43 | # Depend on lsb-base (>= 3.2-14) to ensure that this file is present
44 | # and status_of_proc is working.
45 | . /lib/lsb/init-functions
46 |
47 | #
48 | # Function that starts the daemon/service
49 | #
50 | do_start()
51 | {
52 | # Return
53 | # 0 if daemon has been started
54 | # 1 if daemon was already running
55 | # 2 if daemon could not be started
56 | start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -u $USER --test > /dev/null \
57 | || return 1
58 | start-stop-daemon --start --quiet --background --pidfile $PIDFILE --exec $DAEMON --user $USER \
59 | --chuid $USER --startas $DAEMON --make-pidfile --chdir "$MAINPATH" -- \
60 | $DAEMON_ARGS \
61 | || return 2
62 | # Add code here, if necessary, that waits for the process to be ready
63 | # to handle requests from services started subsequently which depend
64 | # on this one. As a last resort, sleep for some time.
65 | }
66 |
67 | #
68 | # Function that stops the daemon/service
69 | #
70 | do_stop()
71 | {
72 | # Return
73 | # 0 if daemon has been stopped
74 | # 1 if daemon was already stopped
75 | # 2 if daemon could not be stopped
76 | # other if a failure occurred
77 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
78 | RETVAL="$?"
79 | [ "$RETVAL" = 2 ] && return 2
80 | # Wait for children to finish too if this is a daemon that forks
81 | # and if the daemon is only ever run from this initscript.
82 | # If the above conditions are not satisfied then add some other code
83 | # that waits for the process to drop all resources that could be
84 | # needed by services started subsequently. A last resort is to
85 | # sleep for some time.
86 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
87 | [ "$?" = 2 ] && return 2
88 | # Many daemons don't delete their pidfiles when they exit.
89 | rm -f $PIDFILE
90 | return "$RETVAL"
91 | }
92 |
93 | #
94 | # Function that sends a SIGHUP to the daemon/service
95 | #
96 | do_reload() {
97 | #
98 | # If the daemon can reload its configuration without
99 | # restarting (for example, when it is sent a SIGHUP),
100 | # then implement that here.
101 | #
102 | start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
103 | return 0
104 | }
105 |
106 | case "$1" in
107 | start)
108 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
109 | do_start
110 | case "$?" in
111 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
112 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
113 | esac
114 | ;;
115 | stop)
116 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
117 | do_stop
118 | case "$?" in
119 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
120 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
121 | esac
122 | ;;
123 | status)
124 | status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
125 | ;;
126 | #reload|force-reload)
127 | #
128 | # If do_reload() is not implemented then leave this commented out
129 | # and leave 'force-reload' as an alias for 'restart'.
130 | #
131 | #log_daemon_msg "Reloading $DESC" "$NAME"
132 | #do_reload
133 | #log_end_msg $?
134 | #;;
135 | restart|force-reload)
136 | #
137 | # If the "reload" option is implemented then remove the
138 | # 'force-reload' alias
139 | #
140 | log_daemon_msg "Restarting $DESC" "$NAME"
141 | do_stop
142 | case "$?" in
143 | 0|1)
144 | do_start
145 | case "$?" in
146 | 0) log_end_msg 0 ;;
147 | 1) log_end_msg 1 ;; # Old process is still running
148 | *) log_end_msg 1 ;; # Failed to start
149 | esac
150 | ;;
151 | *)
152 | # Failed to stop
153 | log_end_msg 1
154 | ;;
155 | esac
156 | ;;
157 | *)
158 | #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
159 | echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
160 | exit 3
161 | ;;
162 | esac
163 |
164 | :
165 |
166 |
--------------------------------------------------------------------------------
/static/js/prettycron.js:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // prettycron.js
4 | // Generates human-readable sentences from a schedule string in cron format
5 | //
6 | // Based on an earlier version by Pehr Johansson
7 | // http://dsysadm.blogspot.com.au/2012/09/human-readable-cron-expressions-using.html
8 | //
9 | ////////////////////////////////////////////////////////////////////////////////////
10 | // This program is free software: you can redistribute it and/or modify
11 | // it under the terms of the GNU Lesser General Public License as published
12 | // by the Free Software Foundation, either version 3 of the License, or
13 | // (at your option) any later version.
14 | //
15 | // This program is distributed in the hope that it will be useful,
16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | // GNU Lesser General Public License for more details.
19 | //
20 | // You should have received a copy of the GNU Lesser General Public License
21 | // along with this program. If not, see .
22 | ////////////////////////////////////////////////////////////////////////////////////
23 |
24 | if ((!moment || !later) && (typeof require !== 'undefined')) {
25 | var moment = require('moment');
26 | var later = require('later').later;
27 | var cronParser = require('later').parse.cron;
28 | }
29 |
30 | (function() {
31 |
32 | /*
33 | * For an array of numbers, e.g. a list of hours in a schedule,
34 | * return a string listing out all of the values (complete with
35 | * "and" plus ordinal text on the last item).
36 | */
37 | var numberList = function(numbers) {
38 | if (numbers.length < 2) {
39 | //return numbers
40 | return moment.localeData().ordinal(numbers);
41 | }
42 |
43 | var last_val = numbers.pop();
44 | return numbers.join(', ') + ' and ' + moment.localeData().ordinal(last_val);
45 | };
46 |
47 | /*
48 | * Parse a number into day of week, or a month name;
49 | * used in dateList below.
50 | */
51 | var numberToDateName = function(value, type) {
52 | if (type == 'dow') {
53 | return moment().day(value - 1).format('ddd');
54 | } else if (type == 'mon') {
55 | return moment().month(value - 1).format('MMM');
56 | }
57 | };
58 |
59 | /*
60 | * From an array of numbers corresponding to dates (given in type: either
61 | * days of the week, or months), return a string listing all the values.
62 | */
63 | var dateList = function(numbers, type) {
64 | if (numbers.length < 2) {
65 | return numberToDateName(''+numbers[0], type);
66 | }
67 |
68 | var last_val = '' + numbers.pop();
69 | var output_text = '';
70 |
71 | for (var i=0, value; value=numbers[i]; i++) {
72 | if (output_text.length > 0) {
73 | output_text += ', ';
74 | }
75 | output_text += numberToDateName(value, type);
76 | }
77 | return output_text + ' and ' + numberToDateName(last_val, type);
78 | };
79 |
80 | /*
81 | * Pad to equivalent of sprintf('%02d'). Both moment.js and later.js
82 | * have zero-fill functions, but alas, they're private.
83 | */
84 | var zeroPad = function(x) {
85 | return (x < 10) ? '0' + x : x;
86 | };
87 |
88 | //----------------
89 |
90 | /*
91 | * Given a schedule from later.js (i.e. after parsing the cronspec),
92 | * generate a friendly sentence description.
93 | */
94 | var scheduleToSentence = function(schedule) {
95 | var output_text = 'Every ';
96 |
97 | if (schedule['h'] && schedule['m'] && schedule['h'].length <= 2 && schedule['m'].length <= 2) {
98 | // If there are only one or two specified values for
99 | // hour or minute, print them in HH:MM format
100 |
101 | var hm = [];
102 | for (var i=0; i < schedule['h'].length; i++) {
103 | for (var j=0; j < schedule['m'].length; j++) {
104 | hm.push(zeroPad(schedule['h'][i]) + ':' + zeroPad(schedule['m'][j]));
105 | }
106 | }
107 | if (hm.length < 2) {
108 | output_text = hm[0];
109 | } else {
110 | var last_val = hm.pop();
111 | output_text = hm.join(', ') + ' and ' + last_val;
112 | }
113 | if (!schedule['d'] && !schedule['D']) {
114 | output_text += ' every day';
115 | }
116 |
117 | } else {
118 | // Otherwise, list out every specified hour/minute value.
119 |
120 | if(schedule['h']) { // runs only at specific hours
121 | if (schedule['m']) { // and only at specific minutes
122 | output_text += numberList(schedule['m']) + ' minute past the ' + numberList(schedule['h']) + ' hour';
123 | } else { // specific hours, but every minute
124 | output_text += 'minute of ' + numberList(schedule['h']) + ' hour';
125 | }
126 | } else if(schedule['m']) { // every hour, but specific minutes
127 | if (schedule['m'].length == 1 && schedule['m'][0] == 0) {
128 | output_text += 'hour, on the hour';
129 | } else {
130 | output_text += numberList(schedule['m']) + ' minute past every hour';
131 | }
132 | } else { // cronspec has "*" for both hour and minute
133 | output_text += 'minute';
134 | }
135 | }
136 |
137 | if (schedule['D']) { // runs only on specific day(s) of month
138 | output_text += ' on the ' + numberList(schedule['D']);
139 | if (!schedule['M']) {
140 | output_text += ' of every month';
141 | }
142 | }
143 |
144 | if (schedule['d']) { // runs only on specific day(s) of week
145 | if (schedule['D']) {
146 | // if both day fields are specified, cron uses both; superuser.com/a/348372
147 | output_text += ' and every ';
148 | } else {
149 | output_text += ' on ';
150 | }
151 | output_text += dateList(schedule['d'], 'dow');
152 | }
153 |
154 | if (schedule['M']) {
155 | // runs only in specific months; put this output last
156 | output_text += ' in ' + dateList(schedule['M'], 'mon');
157 | }
158 |
159 | return output_text;
160 | };
161 |
162 | //----------------
163 |
164 | /*
165 | * Given a cronspec, return the human-readable string.
166 | */
167 | var toString = function(cronspec, sixth) {
168 | var schedule = later.parse.cron(cronspec, sixth);
169 | return scheduleToSentence(schedule['schedules'][0]);
170 | };
171 |
172 | /*
173 | * Given a cronspec, return a friendly string for when it will next run.
174 | * (This is just a wrapper for later.js and moment.js)
175 | */
176 | var getNext = function(cronspec, sixth) {
177 | var schedule = later.parse.cron(cronspec, sixth);
178 | return moment(
179 | later.schedule(schedule).next()
180 | ).calendar();
181 | };
182 |
183 | //----------------
184 |
185 | // attach ourselves to window in the browser, and to exports in Node,
186 | // so our functions can always be called as prettyCron.toString()
187 | var global_obj = (typeof exports !== "undefined" && exports !== null) ? exports : window.prettyCron = {};
188 |
189 | global_obj.toString = toString;
190 | global_obj.getNext = getNext;
191 |
192 | }).call(this);
193 |
--------------------------------------------------------------------------------
/static/js/jquery-cron-min.js:
--------------------------------------------------------------------------------
1 | (function(e){var n={initial:"* * * * *",minuteOpts:{minWidth:100,itemWidth:30,columns:4,rows:undefined,title:"Minutes Past the Hour"},timeHourOpts:{minWidth:100,itemWidth:20,columns:2,rows:undefined,title:"Time: Hour"},domOpts:{minWidth:100,itemWidth:30,columns:undefined,rows:10,title:"Day of Month"},monthOpts:{minWidth:100,itemWidth:100,columns:2,rows:undefined,title:undefined},dowOpts:{minWidth:100,itemWidth:undefined,columns:undefined,rows:undefined,title:undefined},timeMinuteOpts:{minWidth:100,itemWidth:20,columns:4,rows:undefined,title:"Time: Minute"},effectOpts:{openSpeed:400,closeSpeed:400,openEffect:"slide",closeEffect:"slide",hideOnMouseOut:true},url_set:undefined,customValues:undefined,onChange:undefined,useGentleSelect:false};var y="";for(var u=0;u<60;u++){var t=(u<10)?"0":"";y+=""+t+u+" \n"}var d="";for(var u=0;u<24;u++){var t=(u<10)?"0":"";d+=""+t+u+" \n"}var v="";for(var u=1;u<32;u++){if(u==1||u==21||u==31){var c="st"}else{if(u==2||u==22){var c="nd"}else{if(u==3||u==23){var c="rd"}else{var c="th"}}}v+=""+u+c+" \n"}var h="";var l=["January","February","March","April","May","June","July","August","September","October","November","December"];for(var u=0;u"+l[u]+"\n"}var s="";var g=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];for(var u=0;u"+g[u]+"\n"}var r="";var b=["minute","hour","day","week","month","year"];for(var u=0;u"+b[u]+"\n"}var p={minute:[],hour:["mins"],day:["time"],week:["dow","time"],month:["dom","time"],year:["dom","month","time"]};var w={minute:/^(\*\s){4}\*$/,hour:/^\d{1,2}\s(\*\s){3}\*$/,day:/^(\d{1,2}\s){2}(\*\s){2}\*$/,week:/^(\d{1,2}\s){2}(\*\s){2}\d{1,2}$/,month:/^(\d{1,2}\s){3}\*\s\*$/,year:/^(\d{1,2}\s){4}\*$/};function a(i){if(typeof i=="undefined"){return false}else{return true}}function q(i){return(!a(i)||typeof i=="object")}function z(A,j){if(a(j.customValues)){for(key in j.customValues){if(A==j.customValues[key]){return key}}}var E=/^((\d{1,2}|\*)\s){4}(\d{1,2}|\*)$/;if(typeof A!="string"||!E.test(A)){e.error("cron: invalid initial value");return undefined}var C=A.split(" ");var D=[0,0,1,1,0];var G=[59,23,31,12,6];for(var B=0;B=D[B]){continue}e.error("cron: invalid value found (col "+(B+1)+") in "+o.initial);return undefined}for(var H in w){if(w[H].test(A)){return H}}e.error("cron: valid but unsupported cron format. sorry.");return undefined}function f(j,i){if(!a(z(i.initial,i))){return true}if(!q(i.customValues)){return true}if(a(i.customValues)){for(key in i.customValues){if(w.hasOwnProperty(key)){e.error("cron: reserved keyword '"+key+"' should not be used as customValues key.");return true}}}return false}function k(B){var i=B.data("block");var j=hour=day=month=dow="*";var A=i.period.find("select").val();switch(A){case"minute":break;case"hour":j=i.mins.find("select").val();break;case"day":j=i.time.find("select.cron-time-min").val();hour=i.time.find("select.cron-time-hour").val();break;case"week":j=i.time.find("select.cron-time-min").val();hour=i.time.find("select.cron-time-hour").val();dow=i.dow.find("select").val();break;case"month":j=i.time.find("select.cron-time-min").val();hour=i.time.find("select.cron-time-hour").val();day=i.dom.find("select").val();break;case"year":j=i.time.find("select.cron-time-min").val();hour=i.time.find("select.cron-time-hour").val();day=i.dom.find("select").val();month=i.month.find("select").val();break;default:return A}return[j,hour,day,month,dow].join(" ")}var x={init:function(i){var G=i?i:{};var B=e.extend([],n,G);var j=e.extend({},n.effectOpts,G.effectOpts);e.extend(B,{minuteOpts:e.extend({},n.minuteOpts,j,G.minuteOpts),domOpts:e.extend({},n.domOpts,j,G.domOpts),monthOpts:e.extend({},n.monthOpts,j,G.monthOpts),dowOpts:e.extend({},n.dowOpts,j,G.dowOpts),timeHourOpts:e.extend({},n.timeHourOpts,j,G.timeHourOpts),timeMinuteOpts:e.extend({},n.timeMinuteOpts,j,G.timeMinuteOpts)});if(f(this,B)){return this}var C=[],A="",D=B.customValues;if(a(D)){for(var F in D){A+=""+F+" \n"}}C.period=e("Every "+A+r+" ").appendTo(this).data("root",this);var E=C.period.find("select");E.bind("change.cron",m.periodChanged).data("root",this);if(B.useGentleSelect){E.gentleSelect(j)}C.dom=e(" on the "+v+" ").appendTo(this).data("root",this);E=C.dom.find("select").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.domOpts)}C.month=e(" of "+h+" ").appendTo(this).data("root",this);E=C.month.find("select").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.monthOpts)}C.mins=e(" at "+y+" minutes past the hour ").appendTo(this).data("root",this);E=C.mins.find("select").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.minuteOpts)}C.dow=e(" on "+s+" ").appendTo(this).data("root",this);E=C.dow.find("select").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.dowOpts)}C.time=e(" at "+d+" :"+y+" ").appendTo(this).data("root",this);E=C.time.find("select.cron-time-hour").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.timeHourOpts)}E=C.time.find("select.cron-time-min").data("root",this);if(B.useGentleSelect){E.gentleSelect(B.timeMinuteOpts)}C.controls=e("« save ").appendTo(this).data("root",this).find("span.cron-button-save").bind("click.cron",m.saveClicked).data("root",this).end();this.find("select").bind("change.cron-callback",m.somethingChanged);this.data("options",B).data("block",C);this.data("current_value",B.initial);return x.value.call(this,B.initial)},value:function(C){if(!C){return k(this)}var A=this.data("options");var D=this.data("block");var F=A.useGentleSelect;var K=z(C,A);if(!a(K)){return false}if(a(A.customValues)&&A.customValues.hasOwnProperty(K)){K=A.customValues[K]}else{var H=C.split(" ");var J={mins:H[0],hour:H[1],dom:H[2],month:H[3],dow:H[4]};var G=p[K];for(var E=0;E',
4 | ' ',
5 | '',
6 | '',
7 | ' ',
8 | ' ',
9 | '',
10 | ' ',
11 | ' '
12 | ].join('');
13 | }
14 |
15 | function operateFormatterClosed(value, row, index) {
16 | return [
17 | '',
18 | ' ',
19 | ' ',
20 | '',
21 | ' ',
22 | ' ',
23 | '',
24 | ' ',
25 | ' '
26 | ].join('');
27 | }
28 |
29 | function operateFormatterNeatline(value, row, index) {
30 | return [
31 | '',
32 | ' ',
33 | ' ',
34 | '',
35 | ' ',
36 | ' '
37 | ].join('');
38 | }
39 |
40 |
41 | function operateFormatterSchedule(value, row, index) {
42 | return [
43 | '',
44 | ' ',
45 | ' ',
46 | '',
47 | ' ',
48 | ' ',
49 | '',
50 | ' ',
51 | ' '
52 | ].join('');
53 | }
54 |
55 | function operateFormatterForensic(value, row, index) {
56 | return [
57 | '',
58 | ' ',
59 | ' ',
60 | '',
61 | ' ',
62 | ' '
63 | ].join('');
64 | }
65 |
66 |
67 | function whenFormatter(value, row) {
68 | return '' + value + ' ';
69 | }
70 |
71 |
72 | function rowStyle(row, index) {
73 | if ((typeof(row.crit) !== 'undefined') && (row.crit !== null)) {
74 | if ( row.crit ) {
75 | if (index % 2) {
76 | return {classes:'alert-danger'};
77 | } else {
78 | return {classes:'alert-danger danger-2'}
79 | }
80 | } else {
81 | if (index % 2) {
82 | return {classes:'alert-warning'};
83 | } else {
84 | return {classes:'alert-warning warning-2'}
85 | }
86 | }
87 | }
88 | else {
89 | if (index % 2) {
90 | return {classes:'alert-info aspinfo'};
91 | } else {
92 | return {classes:'alert-info aspinfo-2'};
93 | }
94 | }
95 | return{classes:''};
96 | }
97 |
98 | window.operateEvents = {
99 | 'click .rescanjob': function (e, value, row, index) {
100 | subRescan("job", row.id);
101 | console.log("rescan scheduled for" + row.id);
102 | },
103 | 'click .rescan': function (e, value, row, index) {
104 | subRescan("service", row.id);
105 | console.log("rescan scheduled for" + row.id);
106 | },
107 | 'click .critEx': function (e, value, row, index) {
108 | subFlipCrit('exposed', row.id)
109 | console.log(value, row, index);
110 | },
111 | 'click .critCl': function (e, value, row, index) {
112 | subFlipCrit('closed', row.id)
113 | console.log(value, row, index);
114 | },
115 | 'click .editjob': function (e, value, row, index) {
116 | subEditJob(row.id);
117 | console.log(value, row, index);
118 | },
119 | 'click .deletejob': function (e, value, row, index) {
120 | subDeleteJob(row.id);
121 | console.log(value, row, index);
122 | },
123 | 'click .deletemachine': function (e, value, row, index) {
124 | if (confirm('The whole machine will be deleted (all service entries). Are you sure you want to delete this machine and all its services?')) {
125 | subDeleteMachine(row.machineId);
126 | }
127 | }
128 | };
129 |
130 | // Button events
131 |
132 | function subEditJob(argId) {
133 | BootstrapDialog.show({
134 | message: $('
').load('/dia/editjob/' + argId)
135 | })};
136 |
137 | function subDeleteJob(argId) {
138 | $.ajax({
139 | url: "/controller/deletejob/" + argId,
140 | type: "GET",
141 | cache: false,
142 | success: function( json ) {
143 | $('#datatable').bootstrapTable('refresh');
144 | },
145 | error: function( xhr, status, errorThrown ) {
146 | addAlert("Error deleting job " + argId + ".", 'danger');
147 | },
148 | })};
149 |
150 |
151 | // AJAX Stuff
152 | function subRescan(type, argId) {
153 | //Using the core $.ajax() method
154 | $.ajax({
155 | // the URL for the request
156 | url: "/controller/rescan" + type + "/" + argId,
157 | type: "GET",
158 | cache: false,
159 | // the type of data we expect back
160 | //dataType : "json",
161 | beforeSend: function () {
162 | addAlert("Commencing rescan of " + type + " " + argId + ".", 'info', true);
163 | },
164 | // code to run if the request succeeds;
165 | // the response is passed to the function
166 | success: function( json ) {
167 | $('#datatable').bootstrapTable('refresh');
168 | addAlert("Successfully rescanned " + type + " " + argId + ".", 'success', true);
169 | },
170 | // code to run if the request fails; the raw request and
171 | // status codes are passed to the function
172 | error: function( xhr, status, errorThrown ) {
173 | addAlert("Error rescanning " + type + " " + argId + ".", 'danger');
174 | },
175 | // code to run regardless of success or failure
176 | //always: function( xhr, status ) {
177 | //alert( "The request is complete!" );
178 | //}
179 | })};
180 |
181 |
182 | function subFlipCrit(page, argId) {
183 | $.ajax({
184 | url: "/controller/flipcrit/" + page + "/" + argId,
185 | type: "GET",
186 | cache: false,
187 | success: function( json ) {
188 | $('#datatable').bootstrapTable('refresh');
189 | },
190 | error: function( xhr, status, errorThrown ) {
191 | addAlert("Error flipping criticality of ID " + argId + ".", 'danger');
192 | },
193 | })};
194 |
195 |
196 | function alertTimeout(wait){
197 | setTimeout(function(){
198 | $('#notification-area').children('.autoclose:first-child').fadeTo(500, 0).slideUp(500, function(){
199 | $(this).remove();
200 | });
201 | }, wait);
202 | }
203 |
204 |
205 | function addAlert(message, clas, autoclose) {
206 | if (autoclose == true) {
207 | clas = clas + " autoclose";
208 | }
209 | $('#notification-area').append(
210 | '' +
211 | '' +
212 | '× ' + message + '
');
213 | if (autoclose == true) {
214 | alertTimeout(12000);
215 | }
216 | }
217 |
218 |
219 |
220 | $(document).ready(function() {
221 | //x-editable settings
222 | $.fn.editable.defaults.mode = 'popup';
223 |
224 | $('#dataform').editable({
225 | selector: '.approve i',
226 | url: '/controller/approve',
227 | type: 'text',
228 | emptytext: '',
229 | onblur: 'submit',
230 | showbuttons: true,
231 |
232 | ajaxOptions: {
233 | success: function( json ) {
234 | $('#datatable').bootstrapTable('refresh');
235 | }
236 | }
237 |
238 | });
239 | $('#dataform').editable({
240 | selector: '.remove i',
241 | url: '/controller/remove',
242 | type: 'text',
243 | emptytext: '',
244 | onblur: 'submit',
245 | showbuttons: true,
246 |
247 | ajaxOptions: {
248 | success: function( json ) {
249 | $('#datatable').bootstrapTable('refresh');
250 | }
251 | }
252 |
253 | });
254 |
255 | $('#learnmore').click(function() {
256 | $('#learnmore').fadeOut('slow');
257 | $('.moretolearn').fadeIn('slow');
258 | });
259 |
260 | $('#log').load('/log');
261 |
262 | });
263 |
264 | function subDeleteMachine(machineId) {
265 | $.ajax({
266 | url: "/controller/deletemachine/" + machineId,
267 | type: "GET",
268 | cache: false,
269 | success: function(json) {
270 | $('#datatable').bootstrapTable('refresh');
271 | addAlert("Successfully deleted machine and its services", 'success', true);
272 | },
273 | error: function(xhr, status, errorThrown) {
274 | addAlert("Error deleting machine", 'danger');
275 | }
276 | });
277 | }
278 |
279 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/aspromGUI.py:
--------------------------------------------------------------------------------
1 | '''
2 | Created on Oct 19, 2014
3 |
4 | @author stefankn
5 | @namespace asprom.aspromGUI
6 | Main Script for the asprom GUI. This script presents a webserver socket to
7 | which client browsers can connect to.
8 | Also, it orchestrates URL calls between the model, view and controller classes.
9 | '''
10 | from bottle import (route, run, static_file, abort, redirect, template,
11 | post, request, hook, response)
12 | from inc.asprom import (AspromModel, AspromScheduleModel, Controller, Machine, initDB,
13 | closeDB, Cfg)
14 |
15 | # Variable definitions
16 |
17 | ## relative path to static files
18 | sr = 'static/'
19 |
20 | ## main model
21 | M = None
22 |
23 | ## schedule model
24 | SM = None
25 |
26 | localconf = Cfg()
27 |
28 | #
29 | # hooks
30 | #
31 |
32 |
33 | @hook('before_request')
34 | def before_request():
35 | '''
36 | before each dynamic request, create DB connection and Model instances.
37 | '''
38 | username = None
39 | try:
40 | username = request.get_header("X-Forwarded-User", request.auth[0])
41 | except:
42 | pass
43 |
44 | p = request.path
45 | if p.startswith('/' + sr):
46 | return
47 | global M, SM
48 | try:
49 | initDB(localconf)
50 | M = AspromModel(username=username)
51 | SM = AspromScheduleModel(user=True)
52 | except:
53 | raise
54 |
55 | #
56 | # routes
57 | #
58 |
59 |
60 | @route('/')
61 | def serve_homepage():
62 | '''
63 | HTTP Redirect to http:///alerts-exposed.
64 | '''
65 | redirect('/alerts-exposed')
66 |
67 | # main views
68 |
69 |
70 | @route('/alerts-exposed')
71 | def serve_alertsexposed():
72 | '''
73 | Presents view: http:///alerts-exposed.
74 | '''
75 | return template('views/alerts-exposed')
76 |
77 |
78 | @route('/alerts-closed')
79 | def serve_alertsclosed():
80 | '''
81 | Presents view: http:///alerts-closed.
82 | '''
83 | return template('views/alerts-closed')
84 |
85 |
86 | @route('/baseline')
87 | def serve_baseline():
88 | '''
89 | Presents view: http:///baseline.
90 | '''
91 | return template('views/baseline')
92 |
93 |
94 | @route('/posture')
95 | def serve_forensic():
96 | '''
97 | Presents view: http:///posture.
98 | '''
99 | return template('views/posture')
100 |
101 |
102 | @route('/schedule')
103 | def serve_schedule():
104 | '''
105 | Presents view: http:///schedule.
106 | '''
107 | return template('views/schedule')
108 |
109 |
110 | @route('/log')
111 | def serve_log():
112 | '''
113 | Presents view: http:///log.
114 | '''
115 | return M.getLastLog(10)
116 |
117 |
118 | # dialog views
119 | @route('/dia/editjob/')
121 | def serve_editjob_view(jobid):
122 | '''
123 | Presents view: http:///dia/editjob.
124 | This is meant to be used as a dialog popup in the schedule view.
125 | On this dialog, the parameters of an existing job can be edited.
126 |
127 | @param jobid the job ID to be edited.
128 | '''
129 |
130 | j = SM.getScheduleEntryByID(jobid)
131 | return template('views/editjob', jobid=jobid, initial=j['when'], iprange=j
132 | ['iprange'], portrange=j['ports'], extraparams=j['params'])
133 |
134 |
135 | @route('/dia/addjob')
136 | def serve_addjob_view():
137 | '''
138 | Presents view: http:///dia/addjob.
139 | This is meant to be used as a dialog popup in the schedule view.
140 | On this dialog, the parameters of a new job can be entered.
141 | '''
142 | from uuid import uuid4
143 | return template('views/addjob', jobid=str(uuid4()), initial='0 1 * * *',
144 | iprange='192.168.0.0/24', portrange='0-1024',
145 | extraparams='-sV')
146 |
147 |
148 | # JSON Views
149 | @route('/json/')
150 | def returnjson(filename):
151 | '''
152 | Presents all json views: http:///json/*.
153 | These are used by the tables embedded in the main html views.
154 | The data is aquired using ajax calls.
155 | The data is pulled from the model in dict format and then converted
156 | to json.
157 |
158 | @param filename the json view to be shown. can be any of
159 | alerts-exposed, alerts-closed, baseline, posture or schedule.
160 | '''
161 | if filename == 'alerts-exposed':
162 | return M.tojson(M.getAlertsExposed())
163 | elif filename == 'alerts-closed':
164 | return M.tojson(M.getAlertsClosed())
165 | elif filename == 'baseline':
166 | return M.tojson(M.getNeatline())
167 | elif filename == 'posture':
168 | return M.tojson(M.getForensic())
169 | elif filename == 'schedule':
170 | return M.tojson(SM.getSchedule())
171 | else:
172 | abort(404, "undefined json")
173 | closeDB()
174 |
175 |
176 | # JSON Views
177 | @route('/plain/')
178 | def returnplain(filename):
179 | '''
180 | Presents all plaintext views: http:///plain/*.
181 | These are used by other scripts, like markusk's openvas-config-script
182 |
183 | @param filename the plaintext view to be shown.
184 | '''
185 | response.content_type = 'text/plain'
186 | if filename == 'scanned-ranges':
187 | return SM.getScannedRanges()
188 | else:
189 | abort(404, "undefined url")
190 | closeDB()
191 |
192 |
193 | # controller
194 | # rescan
195 | @route('/controller/rescanjob/')
197 | def serve_rescanController(jobid):
198 | '''
199 | Activates controller: http:///controller/rescanjob/.
200 | Instructs the controller to perform a forensic rescan of
201 | the job with id now.
202 |
203 | @param jobid the job ID to be scanned.
204 | '''
205 | rv = Controller.rescanJob(jobid)
206 | closeDB()
207 | return rv
208 |
209 |
210 | @route('/controller/rescanmachine/')
211 | @route('/controller/rescanmachine//')
212 | def serve_rescanMachine(host, port=None):
213 | '''
214 | Activates controller: http:///controller/rescanmachine/[/].
215 | Instructs the controller to perform a forensic rescan of the machine
216 | with id now.
217 | If is present, only this single port is being rescanned.
218 |
219 | @param host the host ID to be scanned.
220 | @param port the port to be rescanned on the specified machine.
221 | '''
222 | assert host.isdigit()
223 | rv = Controller.rescanMachine(int(host), int(port) if port else None)
224 | closeDB()
225 | return rv
226 |
227 |
228 | @route('/controller/rescanservice/')
229 | def serve_rescanService(serviceid):
230 | '''
231 | Activates controller: http:///controller/rescanservice/.
232 | Instructs the controller to perform a forensic rescan of the service
233 | with id now.
234 |
235 | @param serviceid The Service ID to be scanned.
236 | '''
237 | assert serviceid.isdigit()
238 | rv = Controller.rescanService(int(serviceid))
239 | closeDB()
240 | return rv
241 |
242 | @route('/controller/deletemachine/')
243 | def serve_deleteMachine(machineid):
244 | '''
245 | Activates controller: http:///controller/deletemachine/.
246 | Deletes the machine and all its associated services from inventory.
247 |
248 | @param machineid The Machine ID to be deleted.
249 | '''
250 | assert machineid.isdigit()
251 | machine = Machine(int(machineid))
252 |
253 | # Delete all services first
254 | for service in machine.getServices():
255 | service.delete()
256 |
257 | # Then delete the machine
258 | machine.delete()
259 |
260 | closeDB()
261 | return "ok"
262 |
263 | @route('/controller/deletejob/')
265 | def serve_deleteJob(jobid):
266 | '''
267 | Activates controller: http:///controller/deletejob/.
268 | Instructs the controller to delete the job with id .
269 |
270 | @param jobid The Job ID to be scanned.
271 | '''
272 | rv = SM.deleteJob(jobid)
273 | closeDB()
274 | return rv
275 |
276 |
277 | # flipcrit
278 | @route('/controller/flipcrit//')
279 | def serve_flipCrit(page, serviceid):
280 | '''
281 | Activates controller:
282 | http:///controller/flipcrit//.
283 | Instructs the controller to flip the criticality of service on
284 | the alerts- view.
285 | Flipping sets the service criticality to WARNING if it was CRITICAL before
286 | and the other way round.
287 |
288 | @param page Either "exposed" or "closed". Denominates the view
289 | on which the criticality of the service should be flipped.
290 | @param serviceid The Service whose criticality should be flipped.
291 | '''
292 | exposed = True if page == "exposed" else False
293 | Controller.flipCrit(serviceid, exposed)
294 | closeDB()
295 |
296 | # approve
297 |
298 |
299 | @post('/controller/approve')
300 | def serve_approve():
301 | '''
302 | Activates controller: http:///controller/approve.
303 | The arguments are to be passed by using the HTTP POST method.
304 | Using this method, a service can be approved to the baseline.
305 |
306 | @param pk The Service ID to be approved.
307 | @param value a business justification for the service to be approved.
308 | '''
309 | serviceid = request.forms.get('pk')
310 | justification = request.forms.get('value')
311 | Controller.approve(int(serviceid), justification, M.username)
312 | closeDB()
313 |
314 | # remove
315 |
316 |
317 | @post('/controller/remove')
318 | def serve_remove():
319 | '''
320 | Activates controller: http:///controller/remove.
321 | The arguments are to be passed by using the HTTP POST method.
322 | Using this method, a service can be removed from the baseline.
323 |
324 | @param pk The Service ID to be removed.
325 | @param value a business justification for the service to be removed.
326 | '''
327 | serviceid = request.forms.get('pk')
328 | justification = request.forms.get('value')
329 | Controller.remove(int(serviceid), justification, M.username)
330 | closeDB()
331 |
332 | # edit job
333 |
334 |
335 | @post('/controller/editjob/')
337 | def serve_changejob(jobid):
338 | '''
339 | Activates controller: http:///controller/editjob/.
340 | This method tells the controller to set or change the parameters
341 | of the specified job.
342 |
343 | @param jobid the job to be edited.
344 |
345 | The following arguments are to be passed by using the HTTP POST method.
346 |
347 | @param cronval the cron schedule string.
348 | @param iprange a CIDR range, single IP or hostname.
349 | @param portrange a single port or port range in the format
350 | - to be scanned.
351 | @param extraparams extra command line parameters for nmap.
352 | '''
353 | rv = SM.changeJob(jobid=jobid,
354 | cronval=request.forms.get('cronval'),
355 | iprange=request.forms.get('iprange'),
356 | portrange=request.forms.get('portrange'),
357 | extraparams=request.forms.get('extraparams')
358 | )
359 | closeDB()
360 | return rv
361 |
362 | # edit job
363 |
364 |
365 | @post('/controller/addjob/')
367 | def serve_addjob(jobid):
368 | '''
369 | Activates controller: http:///controller/addjob/.
370 | This method tells the controller to set the parameters of the specified job
371 | and add it to crontab.
372 |
373 | @param jobid the job to be edited.
374 |
375 | The following arguments are to be passed by using the HTTP POST method.
376 |
377 | @param cronval the cron schedule string.
378 | @param iprange a CIDR range, single IP or hostname.
379 | @param portrange a single port or port range in the format
380 | - to be scanned.
381 | @param extraparams extra command line parameters for nmap.
382 | '''
383 | rv = SM.addJob(jobid=jobid,
384 | cronval=request.forms.get('cronval'),
385 | iprange=request.forms.get('iprange'),
386 | portrange=request.forms.get('portrange'),
387 | extraparams=request.forms.get('extraparams')
388 | )
389 | closeDB()
390 | return rv
391 |
392 |
393 | # static files
394 | @route('/' + sr + '')
395 | def static(filename):
396 | '''
397 | returns static files from the path defined by variable SR.
398 |
399 | @param filename path to the static file relative to the SR directory.
400 | '''
401 | return static_file(filename, root=sr)
402 |
403 |
404 | # run the service!
405 | run(host=localconf['server']['listen'], port=localconf['server']['port'],
406 | debug=localconf['server']['debug'], server='paste')
407 |
--------------------------------------------------------------------------------
/db/ddl.sql:
--------------------------------------------------------------------------------
1 | -- MySQL dump 10.14 Distrib 5.5.39-MariaDB, for debian-linux-gnu (x86_64)
2 | --
3 | -- Host: localhost Database: asprom
4 | -- ------------------------------------------------------
5 | -- Server version 5.5.39-MariaDB-2
6 |
7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10 | /*!40101 SET NAMES utf8 */;
11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12 | /*!40103 SET TIME_ZONE='+00:00' */;
13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17 |
18 | --
19 | -- Table structure for table `changelog`
20 | --
21 |
22 | DROP TABLE IF EXISTS `changelog`;
23 | /*!40101 SET @saved_cs_client = @@character_set_client */;
24 | /*!40101 SET character_set_client = utf8 */;
25 | CREATE TABLE `changelog` (
26 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
27 | `serviceId` int(10) unsigned NOT NULL,
28 | `neat` tinyint(1) unsigned NOT NULL,
29 | `justification` varchar(500) COLLATE utf8_roman_ci DEFAULT NULL,
30 | `username` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_roman_ci',
31 | `date` datetime NOT NULL,
32 | PRIMARY KEY (`id`,`serviceId`),
33 | KEY `FK__servicesa` (`serviceId`),
34 | CONSTRAINT `FK__servicesa` FOREIGN KEY (`serviceId`) REFERENCES `services` (`id`)
35 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
36 | /*!40101 SET character_set_client = @saved_cs_client */;
37 |
38 | --
39 | -- Temporary table structure for view `closed`
40 | --
41 |
42 | DROP TABLE IF EXISTS `closed`;
43 | /*!50001 DROP VIEW IF EXISTS `closed`*/;
44 | SET @saved_cs_client = @@character_set_client;
45 | SET character_set_client = utf8;
46 | /*!50001 CREATE TABLE `closed` (
47 | `id` tinyint NOT NULL,
48 | `hostname` tinyint NOT NULL,
49 | `ip` tinyint NOT NULL,
50 | `port` tinyint NOT NULL,
51 | `product` tinyint NOT NULL,
52 | `version` tinyint NOT NULL,
53 | `extrainfo` tinyint NOT NULL,
54 | `justification` tinyint NOT NULL,
55 | `lsdate` tinyint NOT NULL,
56 | `ffdate` tinyint NOT NULL,
57 | `approvaldate` tinyint NOT NULL,
58 | `crit` tinyint NOT NULL
59 | ) ENGINE=MyISAM */;
60 | SET character_set_client = @saved_cs_client;
61 |
62 | --
63 | -- Table structure for table `criticality`
64 | --
65 |
66 | DROP TABLE IF EXISTS `criticality`;
67 | /*!40101 SET @saved_cs_client = @@character_set_client */;
68 | /*!40101 SET character_set_client = utf8 */;
69 | CREATE TABLE `criticality` (
70 | `serviceId` int(11) unsigned NOT NULL,
71 | `flipExposed` tinyint(1) NOT NULL DEFAULT '0',
72 | `flipClosed` tinyint(1) NOT NULL DEFAULT '0',
73 | PRIMARY KEY (`serviceId`),
74 | CONSTRAINT `FK_criticality_services` FOREIGN KEY (`serviceId`) REFERENCES `services` (`id`) ON DELETE CASCADE
75 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
76 | /*!40101 SET character_set_client = @saved_cs_client */;
77 |
78 | --
79 | -- Temporary table structure for view `exposed`
80 | --
81 |
82 | DROP TABLE IF EXISTS `exposed`;
83 | /*!50001 DROP VIEW IF EXISTS `exposed`*/;
84 | SET @saved_cs_client = @@character_set_client;
85 | SET character_set_client = utf8;
86 | /*!50001 CREATE TABLE `exposed` (
87 | `id` tinyint NOT NULL,
88 | `hostname` tinyint NOT NULL,
89 | `ip` tinyint NOT NULL,
90 | `port` tinyint NOT NULL,
91 | `product` tinyint NOT NULL,
92 | `version` tinyint NOT NULL,
93 | `extrainfo` tinyint NOT NULL,
94 | `lsdate` tinyint NOT NULL,
95 | `ffdate` tinyint NOT NULL,
96 | `crit` tinyint NOT NULL
97 | ) ENGINE=MyISAM */;
98 | SET character_set_client = @saved_cs_client;
99 |
100 | --
101 | -- Table structure for table `machinelog`
102 | --
103 |
104 | DROP TABLE IF EXISTS `machinelog`;
105 | /*!40101 SET @saved_cs_client = @@character_set_client */;
106 | /*!40101 SET character_set_client = utf8 */;
107 | CREATE TABLE `machinelog` (
108 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
109 | `machineId` int(10) unsigned NOT NULL,
110 | `exposed` tinyint(1) unsigned NOT NULL,
111 | `date` datetime NOT NULL,
112 | PRIMARY KEY (`id`,`machineId`),
113 | KEY `FK__machines` (`machineId`),
114 | CONSTRAINT `FK__machines` FOREIGN KEY (`machineId`) REFERENCES `machines` (`id`)
115 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
116 | /*!40101 SET character_set_client = @saved_cs_client */;
117 |
118 | --
119 | -- Table structure for table `machines`
120 | --
121 |
122 | DROP TABLE IF EXISTS `machines`;
123 | /*!40101 SET @saved_cs_client = @@character_set_client */;
124 | /*!40101 SET character_set_client = utf8 */;
125 | CREATE TABLE `machines` (
126 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
127 | `hostname` char(200) COLLATE utf8_roman_ci DEFAULT NULL,
128 | `ip` char(15) COLLATE utf8_roman_ci NOT NULL,
129 | `rangeId` int(10) unsigned NOT NULL,
130 | `lsdate` datetime NOT NULL,
131 | `ffdate` datetime NOT NULL,
132 | PRIMARY KEY (`id`),
133 | UNIQUE KEY `Schlüssel 2` (`ip`)
134 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
135 | /*!40101 SET character_set_client = @saved_cs_client */;
136 |
137 | --
138 | -- Temporary table structure for view `neatline`
139 | --
140 |
141 | DROP TABLE IF EXISTS `neatline`;
142 | /*!50001 DROP VIEW IF EXISTS `neatline`*/;
143 | SET @saved_cs_client = @@character_set_client;
144 | SET character_set_client = utf8;
145 | /*!50001 CREATE TABLE `neatline` (
146 | `id` tinyint NOT NULL,
147 | `serviceId` tinyint NOT NULL,
148 | `neat` tinyint NOT NULL,
149 | `justification` tinyint NOT NULL,
150 | `date` tinyint NOT NULL
151 | ) ENGINE=MyISAM */;
152 | SET character_set_client = @saved_cs_client;
153 |
154 | --
155 | -- Table structure for table `scanlog`
156 | --
157 |
158 | DROP TABLE IF EXISTS `scanlog`;
159 | /*!40101 SET @saved_cs_client = @@character_set_client */;
160 | /*!40101 SET character_set_client = utf8 */;
161 | CREATE TABLE `scanlog` (
162 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
163 | `jobid` char(36) CHARACTER SET latin1 COLLATE latin1_general_ci DEFAULT NULL,
164 | `state` varchar(100) COLLATE utf8_roman_ci NOT NULL DEFAULT 'IN PROGRESS',
165 | `startdate` datetime NOT NULL,
166 | `enddate` datetime DEFAULT NULL,
167 | `output` varchar(20000) COLLATE utf8_roman_ci DEFAULT NULL,
168 | `iprange` varchar(200) COLLATE utf8_roman_ci DEFAULT NULL,
169 | `portrange` varchar(20) COLLATE utf8_roman_ci DEFAULT NULL,
170 | `extraoptions` varchar(300) COLLATE utf8_roman_ci DEFAULT NULL,
171 | PRIMARY KEY (`id`)
172 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
173 | /*!40101 SET character_set_client = @saved_cs_client */;
174 |
175 | --
176 | -- Table structure for table `servicelog`
177 | --
178 |
179 | DROP TABLE IF EXISTS `servicelog`;
180 | /*!40101 SET @saved_cs_client = @@character_set_client */;
181 | /*!40101 SET character_set_client = utf8 */;
182 | CREATE TABLE `servicelog` (
183 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
184 | `serviceId` int(10) unsigned NOT NULL,
185 | `openp` tinyint(1) unsigned NOT NULL,
186 | `date` datetime NOT NULL,
187 | PRIMARY KEY (`id`,`serviceId`),
188 | KEY `FK__services` (`serviceId`),
189 | CONSTRAINT `FK__services` FOREIGN KEY (`serviceId`) REFERENCES `services` (`id`)
190 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci;
191 | /*!40101 SET character_set_client = @saved_cs_client */;
192 |
193 | --
194 | -- Temporary table structure for view `servicelogCur`
195 | --
196 |
197 | DROP TABLE IF EXISTS `servicelogCur`;
198 | /*!50001 DROP VIEW IF EXISTS `servicelogCur`*/;
199 | SET @saved_cs_client = @@character_set_client;
200 | SET character_set_client = utf8;
201 | /*!50001 CREATE TABLE `servicelogCur` (
202 | `serviceId` tinyint NOT NULL,
203 | `openp` tinyint NOT NULL,
204 | `date` tinyint NOT NULL
205 | ) ENGINE=MyISAM */;
206 | SET character_set_client = @saved_cs_client;
207 |
208 | --
209 | -- Table structure for table `services`
210 | --
211 |
212 | DROP TABLE IF EXISTS `services`;
213 | /*!40101 SET @saved_cs_client = @@character_set_client */;
214 | /*!40101 SET character_set_client = utf8 */;
215 | CREATE TABLE `services` (
216 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
217 | `port` mediumint(8) unsigned NOT NULL,
218 | `protocolId` tinyint(3) unsigned NOT NULL,
219 | `machineId` int(10) unsigned NOT NULL,
220 | `product` varchar(250) COLLATE utf8_roman_ci DEFAULT NULL,
221 | `extrainfo` varchar(250) COLLATE utf8_roman_ci DEFAULT NULL,
222 | `version` varchar(250) COLLATE utf8_roman_ci DEFAULT NULL,
223 | `lsdate` datetime NOT NULL,
224 | `ffdate` datetime NOT NULL,
225 | PRIMARY KEY (`id`),
226 | UNIQUE KEY `Schlüssel 2` (`port`,`machineId`),
227 | KEY `serviceToMachine` (`machineId`),
228 | CONSTRAINT `serviceToMachine` FOREIGN KEY (`machineId`) REFERENCES `machines` (`id`)
229 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci COMMENT='port, protocolId, machineId, product, extrainfo, version, lsdate, ffdate';
230 | /*!40101 SET character_set_client = @saved_cs_client */;
231 |
232 | --
233 | -- Final view structure for view `closed`
234 | --
235 |
236 | /*!50001 DROP TABLE IF EXISTS `closed`*/;
237 | /*!50001 DROP VIEW IF EXISTS `closed`*/;
238 | /*!50001 SET @saved_cs_client = @@character_set_client */;
239 | /*!50001 SET @saved_cs_results = @@character_set_results */;
240 | /*!50001 SET @saved_col_connection = @@collation_connection */;
241 | /*!50001 SET character_set_client = utf8 */;
242 | /*!50001 SET character_set_results = utf8 */;
243 | /*!50001 SET collation_connection = utf8_general_ci */;
244 | /*!50001 CREATE ALGORITHM=UNDEFINED */
245 | /*!50001 VIEW `closed` AS select `s`.`id` AS `id`,`m`.`hostname` AS `hostname`,`m`.`ip` AS `ip`,`s`.`port` AS `port`,`s`.`product` AS `product`,`s`.`version` AS `version`,`s`.`extrainfo` AS `extrainfo`,`n`.`justification` AS `justification`,`s`.`lsdate` AS `lsdate`,`s`.`ffdate` AS `ffdate`,`n`.`date` AS `approvaldate`,(not(coalesce(`c`.`flipClosed`,0))) AS `crit` from ((((`machines` `m` join `services` `s` on((`m`.`id` = `s`.`machineId`))) join `servicelogCur` `l` on((`s`.`id` = `l`.`serviceId`))) left join `criticality` `c` on((`s`.`id` = `c`.`serviceId`))) left join `neatline` `n` on((`n`.`serviceId` = `s`.`id`))) where ((`l`.`openp` = 0) and exists(select 1 from `neatline` where ((`neatline`.`neat` = 1) and (`s`.`machineId` = `m`.`id`) and (`neatline`.`serviceId` = `s`.`id`)))) */;
246 | /*!50001 SET character_set_client = @saved_cs_client */;
247 | /*!50001 SET character_set_results = @saved_cs_results */;
248 | /*!50001 SET collation_connection = @saved_col_connection */;
249 |
250 | --
251 | -- Final view structure for view `exposed`
252 | --
253 |
254 | /*!50001 DROP TABLE IF EXISTS `exposed`*/;
255 | /*!50001 DROP VIEW IF EXISTS `exposed`*/;
256 | /*!50001 SET @saved_cs_client = @@character_set_client */;
257 | /*!50001 SET @saved_cs_results = @@character_set_results */;
258 | /*!50001 SET @saved_col_connection = @@collation_connection */;
259 | /*!50001 SET character_set_client = utf8 */;
260 | /*!50001 SET character_set_results = utf8 */;
261 | /*!50001 SET collation_connection = utf8_general_ci */;
262 | /*!50001 CREATE ALGORITHM=UNDEFINED */
263 | /*!50001 VIEW `exposed` AS select `s`.`id` AS `id`,`m`.`hostname` AS `hostname`,`m`.`ip` AS `ip`,`s`.`port` AS `port`,`s`.`product` AS `product`,`s`.`version` AS `version`,`s`.`extrainfo` AS `extrainfo`,`s`.`lsdate` AS `lsdate`,`s`.`ffdate` AS `ffdate`,`c`.`flipExposed` AS `crit` from (((`machines` `m` join `services` `s` on((`m`.`id` = `s`.`machineId`))) join `servicelogCur` `l` on((`s`.`id` = `l`.`serviceId`))) left join `criticality` `c` on((`s`.`id` = `c`.`serviceId`))) where ((`l`.`openp` = 1) and (not(exists(select 1 from `neatline` where ((`neatline`.`neat` = 1) and (`s`.`machineId` = `m`.`id`) and (`neatline`.`serviceId` = `s`.`id`)))))) */;
264 | /*!50001 SET character_set_client = @saved_cs_client */;
265 | /*!50001 SET character_set_results = @saved_cs_results */;
266 | /*!50001 SET collation_connection = @saved_col_connection */;
267 |
268 | --
269 | -- Final view structure for view `neatline`
270 | --
271 |
272 | /*!50001 DROP TABLE IF EXISTS `neatline`*/;
273 | /*!50001 DROP VIEW IF EXISTS `neatline`*/;
274 | /*!50001 SET @saved_cs_client = @@character_set_client */;
275 | /*!50001 SET @saved_cs_results = @@character_set_results */;
276 | /*!50001 SET @saved_col_connection = @@collation_connection */;
277 | /*!50001 SET character_set_client = utf8 */;
278 | /*!50001 SET character_set_results = utf8 */;
279 | /*!50001 SET collation_connection = utf8_general_ci */;
280 | /*!50001 CREATE ALGORITHM=UNDEFINED */
281 | /*!50001 VIEW `neatline` AS select `l`.`id` AS `id`,`l`.`serviceId` AS `serviceId`,`l`.`neat` AS `neat`,`l`.`justification` AS `justification`,`l`.`date` AS `date` from `changelog` `l` where `l`.`id` in (select max(`changelog`.`id`) from `changelog` group by `changelog`.`serviceId`) */;
282 | /*!50001 SET character_set_client = @saved_cs_client */;
283 | /*!50001 SET character_set_results = @saved_cs_results */;
284 | /*!50001 SET collation_connection = @saved_col_connection */;
285 |
286 | --
287 | -- Final view structure for view `servicelogCur`
288 | --
289 |
290 | /*!50001 DROP TABLE IF EXISTS `servicelogCur`*/;
291 | /*!50001 DROP VIEW IF EXISTS `servicelogCur`*/;
292 | /*!50001 SET @saved_cs_client = @@character_set_client */;
293 | /*!50001 SET @saved_cs_results = @@character_set_results */;
294 | /*!50001 SET @saved_col_connection = @@collation_connection */;
295 | /*!50001 SET character_set_client = utf8 */;
296 | /*!50001 SET character_set_results = utf8 */;
297 | /*!50001 SET collation_connection = utf8_general_ci */;
298 | /*!50001 CREATE ALGORITHM=UNDEFINED */
299 | /*!50001 VIEW `servicelogCur` AS select `l`.`serviceId` AS `serviceId`,`l`.`openp` AS `openp`,`l`.`date` AS `date` from `servicelog` `l` where `l`.`id` in (select max(`servicelog`.`id`) from `servicelog` group by `servicelog`.`serviceId`) */;
300 | /*!50001 SET character_set_client = @saved_cs_client */;
301 | /*!50001 SET character_set_results = @saved_cs_results */;
302 | /*!50001 SET collation_connection = @saved_col_connection */;
303 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
304 |
305 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
306 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
307 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
308 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
309 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
310 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
311 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
312 |
313 | -- Dump completed on 2015-01-02 14:34:32
314 |
--------------------------------------------------------------------------------
/static/js/bootstrap-dialog.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){if(typeof module!=="undefined"&&module.exports){module.exports=b(require("jquery")(a))}else{if(typeof define==="function"&&define.amd){define("bootstrap-dialog",["jquery"],function(c){return b(c)})}else{a.BootstrapDialog=b(a.jQuery)}}}(this,function(b){var a=function(c){this.defaultOptions=b.extend(true,{id:a.newGuid(),buttons:[],data:{},onshow:null,onshown:null,onhide:null,onhidden:null},a.defaultOptions);this.indexedButtons={};this.registeredButtonHotkeys={};this.draggableData={isMouseDown:false,mouseOffset:{}};this.realized=false;this.opened=false;this.initOptions(c);this.holdThisInstance()};a.NAMESPACE="bootstrap-dialog";a.TYPE_DEFAULT="type-default";a.TYPE_INFO="type-info";a.TYPE_PRIMARY="type-primary";a.TYPE_SUCCESS="type-success";a.TYPE_WARNING="type-warning";a.TYPE_DANGER="type-danger";a.DEFAULT_TEXTS={};a.DEFAULT_TEXTS[a.TYPE_DEFAULT]="Information";a.DEFAULT_TEXTS[a.TYPE_INFO]="Information";a.DEFAULT_TEXTS[a.TYPE_PRIMARY]="Information";a.DEFAULT_TEXTS[a.TYPE_SUCCESS]="Success";a.DEFAULT_TEXTS[a.TYPE_WARNING]="Warning";a.DEFAULT_TEXTS[a.TYPE_DANGER]="Danger";a.DEFAULT_TEXTS.OK="OK";a.DEFAULT_TEXTS.CANCEL="Cancel";a.SIZE_NORMAL="size-normal";a.SIZE_WIDE="size-wide";a.SIZE_LARGE="size-large";a.BUTTON_SIZES={};a.BUTTON_SIZES[a.SIZE_NORMAL]="";a.BUTTON_SIZES[a.SIZE_WIDE]="";a.BUTTON_SIZES[a.SIZE_LARGE]="btn-lg";a.ICON_SPINNER="glyphicon glyphicon-asterisk";a.ZINDEX_BACKDROP=1040;a.ZINDEX_MODAL=1050;a.defaultOptions={type:a.TYPE_PRIMARY,size:a.SIZE_NORMAL,cssClass:"",title:null,message:null,nl2br:true,closable:true,closeByBackdrop:true,closeByKeyboard:true,spinicon:a.ICON_SPINNER,autodestroy:true,draggable:false,animate:true,description:""};a.configDefaultOptions=function(c){a.defaultOptions=b.extend(true,a.defaultOptions,c)};a.dialogs={};a.openAll=function(){b.each(a.dialogs,function(d,c){c.open()})};a.closeAll=function(){b.each(a.dialogs,function(d,c){c.close()})};a.moveFocus=function(){var c=null;b.each(a.dialogs,function(e,d){c=d});if(c!==null&&c.isRealized()){c.getModal().focus()}};a.showScrollbar=function(){var c=null;b.each(a.dialogs,function(f,e){c=e});if(c!==null&&c.isRealized()&&c.isOpened()){var d=c.getModal().data("bs.modal");d.checkScrollbar();b("body").addClass("modal-open");d.setScrollbar()}};a.prototype={constructor:a,initOptions:function(c){this.options=b.extend(true,this.defaultOptions,c);return this},holdThisInstance:function(){a.dialogs[this.getId()]=this;return this},initModalStuff:function(){this.setModal(this.createModal()).setModalDialog(this.createModalDialog()).setModalContent(this.createModalContent()).setModalHeader(this.createModalHeader()).setModalBody(this.createModalBody()).setModalFooter(this.createModalFooter());this.getModal().append(this.getModalDialog());this.getModalDialog().append(this.getModalContent());this.getModalContent().append(this.getModalHeader()).append(this.getModalBody()).append(this.getModalFooter());return this},createModal:function(){var c=b('
');c.prop("id",this.getId()).attr("aria-labelledby",this.getId()+"_title");return c},getModal:function(){return this.$modal},setModal:function(c){this.$modal=c;return this},createModalDialog:function(){return b('
')},getModalDialog:function(){return this.$modalDialog},setModalDialog:function(c){this.$modalDialog=c;return this},createModalContent:function(){return b('
')},getModalContent:function(){return this.$modalContent},setModalContent:function(c){this.$modalContent=c;return this},createModalHeader:function(){return b('')},getModalHeader:function(){return this.$modalHeader},setModalHeader:function(c){this.$modalHeader=c;return this},createModalBody:function(){return b('
')},getModalBody:function(){return this.$modalBody},setModalBody:function(c){this.$modalBody=c;return this},createModalFooter:function(){return b('')},getModalFooter:function(){return this.$modalFooter},setModalFooter:function(c){this.$modalFooter=c;return this},createDynamicContent:function(d){var c=null;if(typeof d==="function"){c=d.call(d,this)}else{c=d}if(typeof c==="string"){c=this.formatStringContent(c)}return c},formatStringContent:function(c){if(this.options.nl2br){return c.replace(/\r\n/g," ").replace(/[\r\n]/g," ")}return c},setData:function(c,d){this.options.data[c]=d;return this},getData:function(c){return this.options.data[c]},setId:function(c){this.options.id=c;return this},getId:function(){return this.options.id},getType:function(){return this.options.type},setType:function(c){this.options.type=c;this.updateType();return this},updateType:function(){if(this.isRealized()){var c=[a.TYPE_DEFAULT,a.TYPE_INFO,a.TYPE_PRIMARY,a.TYPE_SUCCESS,a.TYPE_WARNING,a.TYPE_DANGER];this.getModal().removeClass(c.join(" ")).addClass(this.getType())}return this},getSize:function(){return this.options.size},setSize:function(c){this.options.size=c;this.updateSize();return this},updateSize:function(){if(this.isRealized()){var c=this;this.getModal().removeClass(a.SIZE_NORMAL).removeClass(a.SIZE_WIDE).removeClass(a.SIZE_LARGE);this.getModal().addClass(this.getSize());this.getModalDialog().removeClass("modal-lg");if(this.getSize()===a.SIZE_WIDE){this.getModalDialog().addClass("modal-lg")}b.each(this.options.buttons,function(e,g){var i=c.getButton(g.id);var d=["btn-lg","btn-sm","btn-xs"];var h=false;if(typeof g.cssClass==="string"){var f=g.cssClass.split(" ");b.each(f,function(j,k){if(b.inArray(k,d)!==-1){h=true}})}if(!h){i.removeClass(d.join(" "));i.addClass(c.getButtonSize())}})}return this},getCssClass:function(){return this.options.cssClass},setCssClass:function(c){this.options.cssClass=c;return this},getTitle:function(){return this.options.title},setTitle:function(c){this.options.title=c;this.updateTitle();return this},updateTitle:function(){if(this.isRealized()){var c=this.getTitle()!==null?this.createDynamicContent(this.getTitle()):this.getDefaultText();this.getModalHeader().find("."+this.getNamespace("title")).html("").append(c).prop("id",this.getId()+"_title")}return this},getMessage:function(){return this.options.message},setMessage:function(c){this.options.message=c;this.updateMessage();return this},updateMessage:function(){if(this.isRealized()){var c=this.createDynamicContent(this.getMessage());this.getModalBody().find("."+this.getNamespace("message")).html("").append(c)}return this},isClosable:function(){return this.options.closable},setClosable:function(c){this.options.closable=c;this.updateClosable();return this},setCloseByBackdrop:function(c){this.options.closeByBackdrop=c;return this},canCloseByBackdrop:function(){return this.options.closeByBackdrop},setCloseByKeyboard:function(c){this.options.closeByKeyboard=c;return this},canCloseByKeyboard:function(){return this.options.closeByKeyboard},isAnimate:function(){return this.options.animate},setAnimate:function(c){this.options.animate=c;return this},updateAnimate:function(){if(this.isRealized()){this.getModal().toggleClass("fade",this.isAnimate())}return this},getSpinicon:function(){return this.options.spinicon},setSpinicon:function(c){this.options.spinicon=c;return this},addButton:function(c){this.options.buttons.push(c);return this},addButtons:function(d){var c=this;b.each(d,function(e,f){c.addButton(f)});return this},getButtons:function(){return this.options.buttons},setButtons:function(c){this.options.buttons=c;this.updateButtons();return this},getButton:function(c){if(typeof this.indexedButtons[c]!=="undefined"){return this.indexedButtons[c]}return null},getButtonSize:function(){if(typeof a.BUTTON_SIZES[this.getSize()]!=="undefined"){return a.BUTTON_SIZES[this.getSize()]}return""},updateButtons:function(){if(this.isRealized()){if(this.getButtons().length===0){this.getModalFooter().hide()}else{this.getModalFooter().find("."+this.getNamespace("footer")).html("").append(this.createFooterButtons())}}return this},isAutodestroy:function(){return this.options.autodestroy},setAutodestroy:function(c){this.options.autodestroy=c},getDescription:function(){return this.options.description},setDescription:function(c){this.options.description=c;return this},getDefaultText:function(){return a.DEFAULT_TEXTS[this.getType()]},getNamespace:function(c){return a.NAMESPACE+"-"+c},createHeaderContent:function(){var c=b("
");c.addClass(this.getNamespace("header"));c.append(this.createTitleContent());c.prepend(this.createCloseButton());return c},createTitleContent:function(){var c=b("
");c.addClass(this.getNamespace("title"));return c},createCloseButton:function(){var d=b("
");d.addClass(this.getNamespace("close-button"));var c=b('× ');d.append(c);d.on("click",{dialog:this},function(e){e.data.dialog.close()});return d},createBodyContent:function(){var c=b("
");c.addClass(this.getNamespace("body"));c.append(this.createMessageContent());return c},createMessageContent:function(){var c=b("
");c.addClass(this.getNamespace("message"));return c},createFooterContent:function(){var c=b("
");c.addClass(this.getNamespace("footer"));return c},createFooterButtons:function(){var c=this;var d=b("
");d.addClass(this.getNamespace("footer-buttons"));this.indexedButtons={};b.each(this.options.buttons,function(e,f){if(!f.id){f.id=a.newGuid()}var g=c.createButton(f);c.indexedButtons[f.id]=g;d.append(g)});return d},createButton:function(c){var d=b(' ');d.prop("id",c.id);if(typeof c.icon!=="undefined"&&b.trim(c.icon)!==""){d.append(this.createButtonIcon(c.icon))}if(typeof c.label!=="undefined"){d.append(c.label)}if(typeof c.cssClass!=="undefined"&&b.trim(c.cssClass)!==""){d.addClass(c.cssClass)}else{d.addClass("btn-default")}if(typeof c.hotkey!=="undefined"){this.registeredButtonHotkeys[c.hotkey]=d}d.on("click",{dialog:this,$button:d,button:c},function(g){var f=g.data.dialog;var h=g.data.$button;var e=g.data.button;if(typeof e.action==="function"){e.action.call(h,f)}if(e.autospin){h.toggleSpin(true)}});this.enhanceButton(d);return d},enhanceButton:function(c){c.dialog=this;c.toggleEnable=function(d){var e=this;if(typeof d!=="undefined"){e.prop("disabled",!d).toggleClass("disabled",!d)}else{e.prop("disabled",!e.prop("disabled"))}return e};c.enable=function(){var d=this;d.toggleEnable(true);return d};c.disable=function(){var d=this;d.toggleEnable(false);return d};c.toggleSpin=function(g){var f=this;var e=f.dialog;var d=f.find("."+e.getNamespace("button-icon"));if(typeof g==="undefined"){g=!(c.find(".icon-spin").length>0)}if(g){d.hide();c.prepend(e.createButtonIcon(e.getSpinicon()).addClass("icon-spin"))}else{d.show();c.find(".icon-spin").remove()}return f};c.spin=function(){var d=this;d.toggleSpin(true);return d};c.stopSpin=function(){var d=this;d.toggleSpin(false);return d};return this},createButtonIcon:function(d){var c=b(" ");c.addClass(this.getNamespace("button-icon")).addClass(d);return c},enableButtons:function(c){b.each(this.indexedButtons,function(e,d){d.toggleEnable(c)});return this},updateClosable:function(){if(this.isRealized()){this.getModalHeader().find("."+this.getNamespace("close-button")).toggle(this.isClosable())}return this},onShow:function(c){this.options.onshow=c;return this},onShown:function(c){this.options.onshown=c;return this},onHide:function(c){this.options.onhide=c;return this},onHidden:function(c){this.options.onhidden=c;return this},isRealized:function(){return this.realized},setRealized:function(c){this.realized=c;return this},isOpened:function(){return this.opened},setOpened:function(c){this.opened=c;return this},handleModalEvents:function(){this.getModal().on("show.bs.modal",{dialog:this},function(d){var c=d.data.dialog;if(c.isModalEvent(d)&&typeof c.options.onshow==="function"){return c.options.onshow(c)}});this.getModal().on("shown.bs.modal",{dialog:this},function(d){var c=d.data.dialog;c.isModalEvent(d)&&typeof c.options.onshown==="function"&&c.options.onshown(c)});this.getModal().on("hide.bs.modal",{dialog:this},function(d){var c=d.data.dialog;if(c.isModalEvent(d)&&typeof c.options.onhide==="function"){return c.options.onhide(c)}});this.getModal().on("hidden.bs.modal",{dialog:this},function(d){var c=d.data.dialog;c.isModalEvent(d)&&typeof c.options.onhidden==="function"&&c.options.onhidden(c);c.isAutodestroy()&&b(this).remove();a.moveFocus()});this.getModal().on("click",{dialog:this},function(c){c.target===this&&c.data.dialog.isClosable()&&c.data.dialog.canCloseByBackdrop()&&c.data.dialog.close()});this.getModal().on("keyup",{dialog:this},function(c){c.which===27&&c.data.dialog.isClosable()&&c.data.dialog.canCloseByKeyboard()&&c.data.dialog.close()});this.getModal().on("keyup",{dialog:this},function(d){var c=d.data.dialog;if(typeof c.registeredButtonHotkeys[d.which]!=="undefined"){var e=b(c.registeredButtonHotkeys[d.which]);!e.prop("disabled")&&e.focus().trigger("click")}});return this},isModalEvent:function(c){return typeof c.namespace!=="undefined"&&c.namespace==="bs.modal"},makeModalDraggable:function(){if(this.options.draggable){this.getModalHeader().addClass(this.getNamespace("draggable")).on("mousedown",{dialog:this},function(e){var d=e.data.dialog;d.draggableData.isMouseDown=true;var c=d.getModalDialog().offset();d.draggableData.mouseOffset={top:e.clientY-c.top,left:e.clientX-c.left}});this.getModal().on("mouseup mouseleave",{dialog:this},function(c){c.data.dialog.draggableData.isMouseDown=false});b("body").on("mousemove",{dialog:this},function(d){var c=d.data.dialog;if(!c.draggableData.isMouseDown){return}c.getModalDialog().offset({top:d.clientY-c.draggableData.mouseOffset.top,left:d.clientX-c.draggableData.mouseOffset.left})})}return this},updateZIndex:function(){var e=0;b.each(a.dialogs,function(f,g){e++});var d=this.getModal();var c=d.data("bs.modal").$backdrop;d.css("z-index",a.ZINDEX_MODAL+(e-1)*20);c.css("z-index",a.ZINDEX_BACKDROP+(e-1)*20);return this},realize:function(){this.initModalStuff();this.getModal().addClass(a.NAMESPACE).addClass(this.getCssClass());this.updateSize();if(this.getDescription()){this.getModal().attr("aria-describedby",this.getDescription())}this.getModalFooter().append(this.createFooterContent());this.getModalHeader().append(this.createHeaderContent());this.getModalBody().append(this.createBodyContent());this.getModal().modal({backdrop:"static",keyboard:false,show:false});this.makeModalDraggable();this.handleModalEvents();this.setRealized(true);this.updateButtons();this.updateType();this.updateTitle();this.updateMessage();this.updateClosable();this.updateAnimate();this.updateSize();return this},open:function(){!this.isRealized()&&this.realize();this.getModal().modal("show");this.updateZIndex();this.setOpened(true);return this},close:function(){this.getModal().modal("hide");if(this.isAutodestroy()){delete a.dialogs[this.getId()]}this.setOpened(false);a.showScrollbar();return this}};a.newGuid=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(f){var e=Math.random()*16|0,d=f==="x"?e:(e&3|8);return d.toString(16)})};a.show=function(c){return new a(c).open()};a.alert=function(){var d={};var c={type:a.TYPE_PRIMARY,title:null,message:null,closable:true,buttonLabel:a.DEFAULT_TEXTS.OK,callback:null};if(typeof arguments[0]==="object"&&arguments[0].constructor==={}.constructor){d=b.extend(true,c,arguments[0])}else{d=b.extend(true,c,{message:arguments[0],closable:false,buttonLabel:a.DEFAULT_TEXTS.OK,callback:typeof arguments[1]!=="undefined"?arguments[1]:null})}return new a({type:d.type,title:d.title,message:d.message,closable:d.closable,data:{callback:d.callback},onhide:function(e){!e.getData("btnClicked")&&e.isClosable()&&typeof e.getData("callback")==="function"&&e.getData("callback")(false)},buttons:[{label:d.buttonLabel,action:function(e){e.setData("btnClicked",true);typeof e.getData("callback")==="function"&&e.getData("callback")(true);e.close()}}]}).open()};a.confirm=function(c,d){return new a({title:"Confirmation",message:c,closable:false,data:{callback:d},buttons:[{label:a.DEFAULT_TEXTS.CANCEL,action:function(e){typeof e.getData("callback")==="function"&&e.getData("callback")(false);e.close()}},{label:a.DEFAULT_TEXTS.OK,cssClass:"btn-primary",action:function(e){typeof e.getData("callback")==="function"&&e.getData("callback")(true);e.close()}}]}).open()};a.warning=function(c,d){return new a({type:a.TYPE_WARNING,message:c}).open()};a.danger=function(c,d){return new a({type:a.TYPE_DANGER,message:c}).open()};a.success=function(c,d){return new a({type:a.TYPE_SUCCESS,message:c}).open()};return a}));
--------------------------------------------------------------------------------
/static/css/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.2.0 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f3f3f3));background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-o-linear-gradient(top,#222 0,#282828 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#282828));background-image:linear-gradient(to bottom,#222 0,#282828 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
--------------------------------------------------------------------------------
/static/css/bootstrap-theme.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.2.0 (http://getbootstrap.com)
3 | * Copyright 2011-2014 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 |
7 | .btn-default,
8 | .btn-primary,
9 | .btn-success,
10 | .btn-info,
11 | .btn-warning,
12 | .btn-danger {
13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
16 | }
17 | .btn-default:active,
18 | .btn-primary:active,
19 | .btn-success:active,
20 | .btn-info:active,
21 | .btn-warning:active,
22 | .btn-danger:active,
23 | .btn-default.active,
24 | .btn-primary.active,
25 | .btn-success.active,
26 | .btn-info.active,
27 | .btn-warning.active,
28 | .btn-danger.active {
29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
31 | }
32 | .btn:active,
33 | .btn.active {
34 | background-image: none;
35 | }
36 | .btn-default {
37 | text-shadow: 0 1px 0 #fff;
38 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
39 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
40 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
41 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
42 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
43 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
44 | background-repeat: repeat-x;
45 | border-color: #dbdbdb;
46 | border-color: #ccc;
47 | }
48 | .btn-default:hover,
49 | .btn-default:focus {
50 | background-color: #e0e0e0;
51 | background-position: 0 -15px;
52 | }
53 | .btn-default:active,
54 | .btn-default.active {
55 | background-color: #e0e0e0;
56 | border-color: #dbdbdb;
57 | }
58 | .btn-default:disabled,
59 | .btn-default[disabled] {
60 | background-color: #e0e0e0;
61 | background-image: none;
62 | }
63 | .btn-primary {
64 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
65 | background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
66 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2));
67 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
68 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
69 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
70 | background-repeat: repeat-x;
71 | border-color: #2b669a;
72 | }
73 | .btn-primary:hover,
74 | .btn-primary:focus {
75 | background-color: #2d6ca2;
76 | background-position: 0 -15px;
77 | }
78 | .btn-primary:active,
79 | .btn-primary.active {
80 | background-color: #2d6ca2;
81 | border-color: #2b669a;
82 | }
83 | .btn-primary:disabled,
84 | .btn-primary[disabled] {
85 | background-color: #2d6ca2;
86 | background-image: none;
87 | }
88 | .btn-success {
89 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
90 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
91 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
92 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
94 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
95 | background-repeat: repeat-x;
96 | border-color: #3e8f3e;
97 | }
98 | .btn-success:hover,
99 | .btn-success:focus {
100 | background-color: #419641;
101 | background-position: 0 -15px;
102 | }
103 | .btn-success:active,
104 | .btn-success.active {
105 | background-color: #419641;
106 | border-color: #3e8f3e;
107 | }
108 | .btn-success:disabled,
109 | .btn-success[disabled] {
110 | background-color: #419641;
111 | background-image: none;
112 | }
113 | .btn-info {
114 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
115 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
116 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
117 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
119 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
120 | background-repeat: repeat-x;
121 | border-color: #28a4c9;
122 | }
123 | .btn-info:hover,
124 | .btn-info:focus {
125 | background-color: #2aabd2;
126 | background-position: 0 -15px;
127 | }
128 | .btn-info:active,
129 | .btn-info.active {
130 | background-color: #2aabd2;
131 | border-color: #28a4c9;
132 | }
133 | .btn-info:disabled,
134 | .btn-info[disabled] {
135 | background-color: #2aabd2;
136 | background-image: none;
137 | }
138 | .btn-warning {
139 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
140 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
141 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
142 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
143 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
144 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
145 | background-repeat: repeat-x;
146 | border-color: #e38d13;
147 | }
148 | .btn-warning:hover,
149 | .btn-warning:focus {
150 | background-color: #eb9316;
151 | background-position: 0 -15px;
152 | }
153 | .btn-warning:active,
154 | .btn-warning.active {
155 | background-color: #eb9316;
156 | border-color: #e38d13;
157 | }
158 | .btn-warning:disabled,
159 | .btn-warning[disabled] {
160 | background-color: #eb9316;
161 | background-image: none;
162 | }
163 | .btn-danger {
164 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
165 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
166 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
167 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
168 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
169 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
170 | background-repeat: repeat-x;
171 | border-color: #b92c28;
172 | }
173 | .btn-danger:hover,
174 | .btn-danger:focus {
175 | background-color: #c12e2a;
176 | background-position: 0 -15px;
177 | }
178 | .btn-danger:active,
179 | .btn-danger.active {
180 | background-color: #c12e2a;
181 | border-color: #b92c28;
182 | }
183 | .btn-danger:disabled,
184 | .btn-danger[disabled] {
185 | background-color: #c12e2a;
186 | background-image: none;
187 | }
188 | .thumbnail,
189 | .img-thumbnail {
190 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
191 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
192 | }
193 | .dropdown-menu > li > a:hover,
194 | .dropdown-menu > li > a:focus {
195 | background-color: #e8e8e8;
196 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
197 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
198 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
199 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
200 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
201 | background-repeat: repeat-x;
202 | }
203 | .dropdown-menu > .active > a,
204 | .dropdown-menu > .active > a:hover,
205 | .dropdown-menu > .active > a:focus {
206 | background-color: #357ebd;
207 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
208 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
209 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
210 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
211 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
212 | background-repeat: repeat-x;
213 | }
214 | .navbar-default {
215 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
216 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
218 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
220 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
221 | background-repeat: repeat-x;
222 | border-radius: 4px;
223 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
224 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
225 | }
226 | .navbar-default .navbar-nav > .active > a {
227 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
228 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
229 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f3f3f3));
230 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
231 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
232 | background-repeat: repeat-x;
233 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
234 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
235 | }
236 | .navbar-brand,
237 | .navbar-nav > li > a {
238 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
239 | }
240 | .navbar-inverse {
241 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
242 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
243 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
244 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
247 | background-repeat: repeat-x;
248 | }
249 | .navbar-inverse .navbar-nav > .active > a {
250 | background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
251 | background-image: -o-linear-gradient(top, #222 0%, #282828 100%);
252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#222), to(#282828));
253 | background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
255 | background-repeat: repeat-x;
256 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
257 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
258 | }
259 | .navbar-inverse .navbar-brand,
260 | .navbar-inverse .navbar-nav > li > a {
261 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
262 | }
263 | .navbar-static-top,
264 | .navbar-fixed-top,
265 | .navbar-fixed-bottom {
266 | border-radius: 0;
267 | }
268 | .alert {
269 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
270 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
271 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
272 | }
273 | .alert-success {
274 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
275 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
276 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
277 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
278 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
279 | background-repeat: repeat-x;
280 | border-color: #b2dba1;
281 | }
282 | .alert-info {
283 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
284 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
285 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
286 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
288 | background-repeat: repeat-x;
289 | border-color: #9acfea;
290 | }
291 | .alert-warning {
292 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
293 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
294 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
295 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
296 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
297 | background-repeat: repeat-x;
298 | border-color: #f5e79e;
299 | }
300 | .alert-danger {
301 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
302 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
303 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
304 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
305 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
306 | background-repeat: repeat-x;
307 | border-color: #dca7a7;
308 | }
309 | .progress {
310 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
311 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
312 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
313 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
314 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
315 | background-repeat: repeat-x;
316 | }
317 | .progress-bar {
318 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
319 | background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);
320 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9));
321 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
323 | background-repeat: repeat-x;
324 | }
325 | .progress-bar-success {
326 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
327 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
328 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
329 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
330 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
331 | background-repeat: repeat-x;
332 | }
333 | .progress-bar-info {
334 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
335 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
336 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
337 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
338 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
339 | background-repeat: repeat-x;
340 | }
341 | .progress-bar-warning {
342 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
343 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
344 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
345 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
346 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
347 | background-repeat: repeat-x;
348 | }
349 | .progress-bar-danger {
350 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
351 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
352 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
353 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
355 | background-repeat: repeat-x;
356 | }
357 | .progress-bar-striped {
358 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
359 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
360 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
361 | }
362 | .list-group {
363 | border-radius: 4px;
364 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
365 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
366 | }
367 | .list-group-item.active,
368 | .list-group-item.active:hover,
369 | .list-group-item.active:focus {
370 | text-shadow: 0 -1px 0 #3071a9;
371 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
372 | background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);
373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3));
374 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
376 | background-repeat: repeat-x;
377 | border-color: #3278b3;
378 | }
379 | .panel {
380 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
381 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
382 | }
383 | .panel-default > .panel-heading {
384 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
385 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
386 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
387 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
388 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
389 | background-repeat: repeat-x;
390 | }
391 | .panel-primary > .panel-heading {
392 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
393 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);
394 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd));
395 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
396 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
397 | background-repeat: repeat-x;
398 | }
399 | .panel-success > .panel-heading {
400 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
401 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
403 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
405 | background-repeat: repeat-x;
406 | }
407 | .panel-info > .panel-heading {
408 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
409 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
410 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
411 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
412 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
413 | background-repeat: repeat-x;
414 | }
415 | .panel-warning > .panel-heading {
416 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
417 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
418 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
419 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
420 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
421 | background-repeat: repeat-x;
422 | }
423 | .panel-danger > .panel-heading {
424 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
425 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
426 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
427 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
428 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
429 | background-repeat: repeat-x;
430 | }
431 | .well {
432 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
433 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
435 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
437 | background-repeat: repeat-x;
438 | border-color: #dcdcdc;
439 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
440 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
441 | }
442 | /*# sourceMappingURL=bootstrap-theme.css.map */
443 |
--------------------------------------------------------------------------------
/static/css/bootstrap-editable.css:
--------------------------------------------------------------------------------
1 | /*! X-editable - v1.5.1
2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
3 | * http://github.com/vitalets/x-editable
4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
5 | .editableform {
6 | margin-bottom: 0; /* overwrites bootstrap margin */
7 | }
8 |
9 | .editableform .control-group {
10 | margin-bottom: 0; /* overwrites bootstrap margin */
11 | white-space: nowrap; /* prevent wrapping buttons on new line */
12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */
13 | }
14 |
15 | /*
16 | BS3 width:1005 for inputs breaks editable form in popup
17 | See: https://github.com/vitalets/x-editable/issues/393
18 | */
19 | .editableform .form-control {
20 | width: auto;
21 | }
22 |
23 | .editable-buttons {
24 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
25 | vertical-align: top;
26 | margin-left: 7px;
27 | /* inline-block emulation for IE7*/
28 | zoom: 1;
29 | *display: inline;
30 | }
31 |
32 | .editable-buttons.editable-buttons-bottom {
33 | display: block;
34 | margin-top: 7px;
35 | margin-left: 0;
36 | }
37 |
38 | .editable-input {
39 | vertical-align: top;
40 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
41 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */
42 | white-space: normal; /* reset white-space decalred in parent*/
43 | /* display-inline emulation for IE7*/
44 | zoom: 1;
45 | *display: inline;
46 | }
47 |
48 | .editable-buttons .editable-cancel {
49 | margin-left: 7px;
50 | }
51 |
52 | /*for jquery-ui buttons need set height to look more pretty*/
53 | .editable-buttons button.ui-button-icon-only {
54 | height: 24px;
55 | width: 30px;
56 | }
57 |
58 | .editableform-loading {
59 | /* background: url('../img/loading.gif') center center no-repeat;*/
60 | height: 25px;
61 | width: auto;
62 | min-width: 25px;
63 | }
64 |
65 | .editable-inline .editableform-loading {
66 | background-position: left 5px;
67 | }
68 |
69 | .editable-error-block {
70 | max-width: 300px;
71 | margin: 5px 0 0 0;
72 | width: auto;
73 | white-space: normal;
74 | }
75 |
76 | /*add padding for jquery ui*/
77 | .editable-error-block.ui-state-error {
78 | padding: 3px;
79 | }
80 |
81 | .editable-error {
82 | color: red;
83 | }
84 |
85 | /* ---- For specific types ---- */
86 |
87 | .editableform .editable-date {
88 | padding: 0;
89 | margin: 0;
90 | float: left;
91 | }
92 |
93 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */
94 | .editable-inline .add-on .icon-th {
95 | margin-top: 3px;
96 | margin-left: 1px;
97 | }
98 |
99 |
100 | /* checklist vertical alignment */
101 | .editable-checklist label input[type="checkbox"],
102 | .editable-checklist label span {
103 | vertical-align: middle;
104 | margin: 0;
105 | }
106 |
107 | .editable-checklist label {
108 | white-space: nowrap;
109 | }
110 |
111 | /* set exact width of textarea to fit buttons toolbar */
112 | .editable-wysihtml5 {
113 | width: 566px;
114 | height: 250px;
115 | }
116 |
117 | /* clear button shown as link in date inputs */
118 | .editable-clear {
119 | clear: both;
120 | font-size: 0.9em;
121 | text-decoration: none;
122 | text-align: right;
123 | }
124 |
125 | /* IOS-style clear button for text inputs */
126 | .editable-clear-x {
127 | /* background: url('../img/clear.png') center center no-repeat;*/
128 | display: block;
129 | width: 13px;
130 | height: 13px;
131 | position: absolute;
132 | opacity: 0.6;
133 | z-index: 100;
134 |
135 | top: 50%;
136 | right: 6px;
137 | margin-top: -6px;
138 |
139 | }
140 |
141 | .editable-clear-x:hover {
142 | opacity: 1;
143 | }
144 |
145 | .editable-pre-wrapped {
146 | white-space: pre-wrap;
147 | }
148 | .editable-container.editable-popup {
149 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
150 | }
151 |
152 | .editable-container.popover {
153 | width: auto; /* without this rule popover does not stretch */
154 | }
155 |
156 | .editable-container.editable-inline {
157 | display: inline-block;
158 | vertical-align: middle;
159 | width: auto;
160 | /* inline-block emulation for IE7*/
161 | zoom: 1;
162 | *display: inline;
163 | }
164 |
165 | .editable-container.ui-widget {
166 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */
167 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */
168 | }
169 | .editable-click,
170 | a.editable-click,
171 | a.editable-click:hover {
172 | text-decoration: none;
173 | border-bottom: dashed 1px #0088cc;
174 | }
175 |
176 | .editable-click.editable-disabled,
177 | a.editable-click.editable-disabled,
178 | a.editable-click.editable-disabled:hover {
179 | color: #585858;
180 | cursor: default;
181 | border-bottom: none;
182 | }
183 |
184 | .editable-empty, .editable-empty:hover, .editable-empty:focus{
185 | font-style: italic;
186 | color: #DD1144;
187 | /* border-bottom: none; */
188 | text-decoration: none;
189 | }
190 |
191 | .editable-unsaved {
192 | font-weight: bold;
193 | }
194 |
195 | .editable-unsaved:after {
196 | /* content: '*'*/
197 | }
198 |
199 | .editable-bg-transition {
200 | -webkit-transition: background-color 1400ms ease-out;
201 | -moz-transition: background-color 1400ms ease-out;
202 | -o-transition: background-color 1400ms ease-out;
203 | -ms-transition: background-color 1400ms ease-out;
204 | transition: background-color 1400ms ease-out;
205 | }
206 |
207 | /*see https://github.com/vitalets/x-editable/issues/139 */
208 | .form-horizontal .editable
209 | {
210 | padding-top: 5px;
211 | display:inline-block;
212 | }
213 |
214 |
215 | /*!
216 | * Datepicker for Bootstrap
217 | *
218 | * Copyright 2012 Stefan Petre
219 | * Improvements by Andrew Rowls
220 | * Licensed under the Apache License v2.0
221 | * http://www.apache.org/licenses/LICENSE-2.0
222 | *
223 | */
224 | .datepicker {
225 | padding: 4px;
226 | -webkit-border-radius: 4px;
227 | -moz-border-radius: 4px;
228 | border-radius: 4px;
229 | direction: ltr;
230 | /*.dow {
231 | border-top: 1px solid #ddd !important;
232 | }*/
233 |
234 | }
235 | .datepicker-inline {
236 | width: 220px;
237 | }
238 | .datepicker.datepicker-rtl {
239 | direction: rtl;
240 | }
241 | .datepicker.datepicker-rtl table tr td span {
242 | float: right;
243 | }
244 | .datepicker-dropdown {
245 | top: 0;
246 | left: 0;
247 | }
248 | .datepicker-dropdown:before {
249 | content: '';
250 | display: inline-block;
251 | border-left: 7px solid transparent;
252 | border-right: 7px solid transparent;
253 | border-bottom: 7px solid #ccc;
254 | border-bottom-color: rgba(0, 0, 0, 0.2);
255 | position: absolute;
256 | top: -7px;
257 | left: 6px;
258 | }
259 | .datepicker-dropdown:after {
260 | content: '';
261 | display: inline-block;
262 | border-left: 6px solid transparent;
263 | border-right: 6px solid transparent;
264 | border-bottom: 6px solid #ffffff;
265 | position: absolute;
266 | top: -6px;
267 | left: 7px;
268 | }
269 | .datepicker > div {
270 | display: none;
271 | }
272 | .datepicker.days div.datepicker-days {
273 | display: block;
274 | }
275 | .datepicker.months div.datepicker-months {
276 | display: block;
277 | }
278 | .datepicker.years div.datepicker-years {
279 | display: block;
280 | }
281 | .datepicker table {
282 | margin: 0;
283 | }
284 | .datepicker td,
285 | .datepicker th {
286 | text-align: center;
287 | width: 20px;
288 | height: 20px;
289 | -webkit-border-radius: 4px;
290 | -moz-border-radius: 4px;
291 | border-radius: 4px;
292 | border: none;
293 | }
294 | .table-striped .datepicker table tr td,
295 | .table-striped .datepicker table tr th {
296 | background-color: transparent;
297 | }
298 | .datepicker table tr td.day:hover {
299 | background: #eeeeee;
300 | cursor: pointer;
301 | }
302 | .datepicker table tr td.old,
303 | .datepicker table tr td.new {
304 | color: #999999;
305 | }
306 | .datepicker table tr td.disabled,
307 | .datepicker table tr td.disabled:hover {
308 | background: none;
309 | color: #999999;
310 | cursor: default;
311 | }
312 | .datepicker table tr td.today,
313 | .datepicker table tr td.today:hover,
314 | .datepicker table tr td.today.disabled,
315 | .datepicker table tr td.today.disabled:hover {
316 | background-color: #fde19a;
317 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
318 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
319 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
320 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
321 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
322 | background-image: linear-gradient(top, #fdd49a, #fdf59a);
323 | background-repeat: repeat-x;
324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
325 | border-color: #fdf59a #fdf59a #fbed50;
326 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
327 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
328 | color: #000;
329 | }
330 | .datepicker table tr td.today:hover,
331 | .datepicker table tr td.today:hover:hover,
332 | .datepicker table tr td.today.disabled:hover,
333 | .datepicker table tr td.today.disabled:hover:hover,
334 | .datepicker table tr td.today:active,
335 | .datepicker table tr td.today:hover:active,
336 | .datepicker table tr td.today.disabled:active,
337 | .datepicker table tr td.today.disabled:hover:active,
338 | .datepicker table tr td.today.active,
339 | .datepicker table tr td.today:hover.active,
340 | .datepicker table tr td.today.disabled.active,
341 | .datepicker table tr td.today.disabled:hover.active,
342 | .datepicker table tr td.today.disabled,
343 | .datepicker table tr td.today:hover.disabled,
344 | .datepicker table tr td.today.disabled.disabled,
345 | .datepicker table tr td.today.disabled:hover.disabled,
346 | .datepicker table tr td.today[disabled],
347 | .datepicker table tr td.today:hover[disabled],
348 | .datepicker table tr td.today.disabled[disabled],
349 | .datepicker table tr td.today.disabled:hover[disabled] {
350 | background-color: #fdf59a;
351 | }
352 | .datepicker table tr td.today:active,
353 | .datepicker table tr td.today:hover:active,
354 | .datepicker table tr td.today.disabled:active,
355 | .datepicker table tr td.today.disabled:hover:active,
356 | .datepicker table tr td.today.active,
357 | .datepicker table tr td.today:hover.active,
358 | .datepicker table tr td.today.disabled.active,
359 | .datepicker table tr td.today.disabled:hover.active {
360 | background-color: #fbf069 \9;
361 | }
362 | .datepicker table tr td.today:hover:hover {
363 | color: #000;
364 | }
365 | .datepicker table tr td.today.active:hover {
366 | color: #fff;
367 | }
368 | .datepicker table tr td.range,
369 | .datepicker table tr td.range:hover,
370 | .datepicker table tr td.range.disabled,
371 | .datepicker table tr td.range.disabled:hover {
372 | background: #eeeeee;
373 | -webkit-border-radius: 0;
374 | -moz-border-radius: 0;
375 | border-radius: 0;
376 | }
377 | .datepicker table tr td.range.today,
378 | .datepicker table tr td.range.today:hover,
379 | .datepicker table tr td.range.today.disabled,
380 | .datepicker table tr td.range.today.disabled:hover {
381 | background-color: #f3d17a;
382 | background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
383 | background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
384 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
385 | background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
386 | background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
387 | background-image: linear-gradient(top, #f3c17a, #f3e97a);
388 | background-repeat: repeat-x;
389 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
390 | border-color: #f3e97a #f3e97a #edde34;
391 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
392 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
393 | -webkit-border-radius: 0;
394 | -moz-border-radius: 0;
395 | border-radius: 0;
396 | }
397 | .datepicker table tr td.range.today:hover,
398 | .datepicker table tr td.range.today:hover:hover,
399 | .datepicker table tr td.range.today.disabled:hover,
400 | .datepicker table tr td.range.today.disabled:hover:hover,
401 | .datepicker table tr td.range.today:active,
402 | .datepicker table tr td.range.today:hover:active,
403 | .datepicker table tr td.range.today.disabled:active,
404 | .datepicker table tr td.range.today.disabled:hover:active,
405 | .datepicker table tr td.range.today.active,
406 | .datepicker table tr td.range.today:hover.active,
407 | .datepicker table tr td.range.today.disabled.active,
408 | .datepicker table tr td.range.today.disabled:hover.active,
409 | .datepicker table tr td.range.today.disabled,
410 | .datepicker table tr td.range.today:hover.disabled,
411 | .datepicker table tr td.range.today.disabled.disabled,
412 | .datepicker table tr td.range.today.disabled:hover.disabled,
413 | .datepicker table tr td.range.today[disabled],
414 | .datepicker table tr td.range.today:hover[disabled],
415 | .datepicker table tr td.range.today.disabled[disabled],
416 | .datepicker table tr td.range.today.disabled:hover[disabled] {
417 | background-color: #f3e97a;
418 | }
419 | .datepicker table tr td.range.today:active,
420 | .datepicker table tr td.range.today:hover:active,
421 | .datepicker table tr td.range.today.disabled:active,
422 | .datepicker table tr td.range.today.disabled:hover:active,
423 | .datepicker table tr td.range.today.active,
424 | .datepicker table tr td.range.today:hover.active,
425 | .datepicker table tr td.range.today.disabled.active,
426 | .datepicker table tr td.range.today.disabled:hover.active {
427 | background-color: #efe24b \9;
428 | }
429 | .datepicker table tr td.selected,
430 | .datepicker table tr td.selected:hover,
431 | .datepicker table tr td.selected.disabled,
432 | .datepicker table tr td.selected.disabled:hover {
433 | background-color: #9e9e9e;
434 | background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
435 | background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
436 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
437 | background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
438 | background-image: -o-linear-gradient(top, #b3b3b3, #808080);
439 | background-image: linear-gradient(top, #b3b3b3, #808080);
440 | background-repeat: repeat-x;
441 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
442 | border-color: #808080 #808080 #595959;
443 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
444 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
445 | color: #fff;
446 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
447 | }
448 | .datepicker table tr td.selected:hover,
449 | .datepicker table tr td.selected:hover:hover,
450 | .datepicker table tr td.selected.disabled:hover,
451 | .datepicker table tr td.selected.disabled:hover:hover,
452 | .datepicker table tr td.selected:active,
453 | .datepicker table tr td.selected:hover:active,
454 | .datepicker table tr td.selected.disabled:active,
455 | .datepicker table tr td.selected.disabled:hover:active,
456 | .datepicker table tr td.selected.active,
457 | .datepicker table tr td.selected:hover.active,
458 | .datepicker table tr td.selected.disabled.active,
459 | .datepicker table tr td.selected.disabled:hover.active,
460 | .datepicker table tr td.selected.disabled,
461 | .datepicker table tr td.selected:hover.disabled,
462 | .datepicker table tr td.selected.disabled.disabled,
463 | .datepicker table tr td.selected.disabled:hover.disabled,
464 | .datepicker table tr td.selected[disabled],
465 | .datepicker table tr td.selected:hover[disabled],
466 | .datepicker table tr td.selected.disabled[disabled],
467 | .datepicker table tr td.selected.disabled:hover[disabled] {
468 | background-color: #808080;
469 | }
470 | .datepicker table tr td.selected:active,
471 | .datepicker table tr td.selected:hover:active,
472 | .datepicker table tr td.selected.disabled:active,
473 | .datepicker table tr td.selected.disabled:hover:active,
474 | .datepicker table tr td.selected.active,
475 | .datepicker table tr td.selected:hover.active,
476 | .datepicker table tr td.selected.disabled.active,
477 | .datepicker table tr td.selected.disabled:hover.active {
478 | background-color: #666666 \9;
479 | }
480 | .datepicker table tr td.active,
481 | .datepicker table tr td.active:hover,
482 | .datepicker table tr td.active.disabled,
483 | .datepicker table tr td.active.disabled:hover {
484 | background-color: #006dcc;
485 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
486 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
487 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
488 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
489 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
490 | background-image: linear-gradient(top, #0088cc, #0044cc);
491 | background-repeat: repeat-x;
492 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
493 | border-color: #0044cc #0044cc #002a80;
494 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
495 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
496 | color: #fff;
497 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
498 | }
499 | .datepicker table tr td.active:hover,
500 | .datepicker table tr td.active:hover:hover,
501 | .datepicker table tr td.active.disabled:hover,
502 | .datepicker table tr td.active.disabled:hover:hover,
503 | .datepicker table tr td.active:active,
504 | .datepicker table tr td.active:hover:active,
505 | .datepicker table tr td.active.disabled:active,
506 | .datepicker table tr td.active.disabled:hover:active,
507 | .datepicker table tr td.active.active,
508 | .datepicker table tr td.active:hover.active,
509 | .datepicker table tr td.active.disabled.active,
510 | .datepicker table tr td.active.disabled:hover.active,
511 | .datepicker table tr td.active.disabled,
512 | .datepicker table tr td.active:hover.disabled,
513 | .datepicker table tr td.active.disabled.disabled,
514 | .datepicker table tr td.active.disabled:hover.disabled,
515 | .datepicker table tr td.active[disabled],
516 | .datepicker table tr td.active:hover[disabled],
517 | .datepicker table tr td.active.disabled[disabled],
518 | .datepicker table tr td.active.disabled:hover[disabled] {
519 | background-color: #0044cc;
520 | }
521 | .datepicker table tr td.active:active,
522 | .datepicker table tr td.active:hover:active,
523 | .datepicker table tr td.active.disabled:active,
524 | .datepicker table tr td.active.disabled:hover:active,
525 | .datepicker table tr td.active.active,
526 | .datepicker table tr td.active:hover.active,
527 | .datepicker table tr td.active.disabled.active,
528 | .datepicker table tr td.active.disabled:hover.active {
529 | background-color: #003399 \9;
530 | }
531 | .datepicker table tr td span {
532 | display: block;
533 | width: 23%;
534 | height: 54px;
535 | line-height: 54px;
536 | float: left;
537 | margin: 1%;
538 | cursor: pointer;
539 | -webkit-border-radius: 4px;
540 | -moz-border-radius: 4px;
541 | border-radius: 4px;
542 | }
543 | .datepicker table tr td span:hover {
544 | background: #eeeeee;
545 | }
546 | .datepicker table tr td span.disabled,
547 | .datepicker table tr td span.disabled:hover {
548 | background: none;
549 | color: #999999;
550 | cursor: default;
551 | }
552 | .datepicker table tr td span.active,
553 | .datepicker table tr td span.active:hover,
554 | .datepicker table tr td span.active.disabled,
555 | .datepicker table tr td span.active.disabled:hover {
556 | background-color: #006dcc;
557 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
558 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
559 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
560 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
561 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
562 | background-image: linear-gradient(top, #0088cc, #0044cc);
563 | background-repeat: repeat-x;
564 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
565 | border-color: #0044cc #0044cc #002a80;
566 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
567 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
568 | color: #fff;
569 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
570 | }
571 | .datepicker table tr td span.active:hover,
572 | .datepicker table tr td span.active:hover:hover,
573 | .datepicker table tr td span.active.disabled:hover,
574 | .datepicker table tr td span.active.disabled:hover:hover,
575 | .datepicker table tr td span.active:active,
576 | .datepicker table tr td span.active:hover:active,
577 | .datepicker table tr td span.active.disabled:active,
578 | .datepicker table tr td span.active.disabled:hover:active,
579 | .datepicker table tr td span.active.active,
580 | .datepicker table tr td span.active:hover.active,
581 | .datepicker table tr td span.active.disabled.active,
582 | .datepicker table tr td span.active.disabled:hover.active,
583 | .datepicker table tr td span.active.disabled,
584 | .datepicker table tr td span.active:hover.disabled,
585 | .datepicker table tr td span.active.disabled.disabled,
586 | .datepicker table tr td span.active.disabled:hover.disabled,
587 | .datepicker table tr td span.active[disabled],
588 | .datepicker table tr td span.active:hover[disabled],
589 | .datepicker table tr td span.active.disabled[disabled],
590 | .datepicker table tr td span.active.disabled:hover[disabled] {
591 | background-color: #0044cc;
592 | }
593 | .datepicker table tr td span.active:active,
594 | .datepicker table tr td span.active:hover:active,
595 | .datepicker table tr td span.active.disabled:active,
596 | .datepicker table tr td span.active.disabled:hover:active,
597 | .datepicker table tr td span.active.active,
598 | .datepicker table tr td span.active:hover.active,
599 | .datepicker table tr td span.active.disabled.active,
600 | .datepicker table tr td span.active.disabled:hover.active {
601 | background-color: #003399 \9;
602 | }
603 | .datepicker table tr td span.old,
604 | .datepicker table tr td span.new {
605 | color: #999999;
606 | }
607 | .datepicker th.datepicker-switch {
608 | width: 145px;
609 | }
610 | .datepicker thead tr:first-child th,
611 | .datepicker tfoot tr th {
612 | cursor: pointer;
613 | }
614 | .datepicker thead tr:first-child th:hover,
615 | .datepicker tfoot tr th:hover {
616 | background: #eeeeee;
617 | }
618 | .datepicker .cw {
619 | font-size: 10px;
620 | width: 12px;
621 | padding: 0 2px 0 5px;
622 | vertical-align: middle;
623 | }
624 | .datepicker thead tr:first-child th.cw {
625 | cursor: default;
626 | background-color: transparent;
627 | }
628 | .input-append.date .add-on i,
629 | .input-prepend.date .add-on i {
630 | display: block;
631 | cursor: pointer;
632 | width: 16px;
633 | height: 16px;
634 | }
635 | .input-daterange input {
636 | text-align: center;
637 | }
638 | .input-daterange input:first-child {
639 | -webkit-border-radius: 3px 0 0 3px;
640 | -moz-border-radius: 3px 0 0 3px;
641 | border-radius: 3px 0 0 3px;
642 | }
643 | .input-daterange input:last-child {
644 | -webkit-border-radius: 0 3px 3px 0;
645 | -moz-border-radius: 0 3px 3px 0;
646 | border-radius: 0 3px 3px 0;
647 | }
648 | .input-daterange .add-on {
649 | display: inline-block;
650 | width: auto;
651 | min-width: 16px;
652 | height: 18px;
653 | padding: 4px 5px;
654 | font-weight: normal;
655 | line-height: 18px;
656 | text-align: center;
657 | text-shadow: 0 1px 0 #ffffff;
658 | vertical-align: middle;
659 | background-color: #eeeeee;
660 | border: 1px solid #ccc;
661 | margin-left: -5px;
662 | margin-right: -5px;
663 | }
664 |
--------------------------------------------------------------------------------
/static/js/bootstrap-table.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-table - v1.3.0 - 2014-10-16
3 | * https://github.com/wenzhixin/bootstrap-table
4 | * Copyright (c) 2014 zhixin wen
5 | * Licensed MIT License
6 | */
7 | !function(a){"use strict";var b=function(a){var b=arguments,c=!0,d=1;return a=a.replace(/%s/g,function(){var a=b[d++];return"undefined"==typeof a?(c=!1,""):a}),c?a:""},c=function(b,c,d,e){var f="";return a.each(b,function(a,b){return b[c]===e?(f=b[d],!1):!0}),f},d=function(b,c){var d=-1;return a.each(b,function(a,b){return b.field===c?(d=a,!1):!0}),d},e=function(){var b,c,d=a("
").addClass("fixed-table-scroll-inner"),e=a("
").addClass("fixed-table-scroll-outer");return e.append(d),a("body").append(e),b=d[0].offsetWidth,e.css("overflow","scroll"),c=d[0].offsetWidth,b==c&&(c=e[0].clientWidth),e.remove(),b-c},f=function(b,c,d,e){if("string"==typeof c){var f=c.split(".");f.length>1?(c=window,a.each(f,function(a,b){c=c[b]})):c=window[c]}return"object"==typeof c?c:"function"==typeof c?c.apply(b,d):e},g=function(b,c){this.options=c,this.$el=a(b),this.$el_=this.$el.clone(),this.timeoutId_=0,this.init()};g.DEFAULTS={classes:"table table-hover",height:void 0,undefinedText:"-",sortName:void 0,sortOrder:"asc",striped:!1,columns:[],data:[],method:"get",url:void 0,cache:!0,contentType:"application/json",queryParams:function(a){return a},queryParamsType:"limit",responseHandler:function(a){return a},pagination:!1,sidePagination:"client",totalRows:0,pageNumber:1,pageSize:10,pageList:[10,25,50,100],search:!1,selectItemName:"btSelectItem",showHeader:!0,showColumns:!1,showRefresh:!1,showToggle:!1,minimumCountColumns:1,idField:void 0,cardView:!1,clickToSelect:!1,singleSelect:!1,toolbar:void 0,checkboxHeader:!0,sortable:!0,maintainSelected:!1,rowStyle:function(){return{}},formatLoadingMessage:function(){return"Loading, please wait…"},formatRecordsPerPage:function(a){return b("%s records per page",a)},formatShowingRows:function(a,c,d){return b("Showing %s to %s of %s rows",a,c,d)},formatSearch:function(){return"Search"},formatNoMatches:function(){return"No matching records found"},onAll:function(){return!1},onClickRow:function(){return!1},onDblClickRow:function(){return!1},onSort:function(){return!1},onCheck:function(){return!1},onUncheck:function(){return!1},onCheckAll:function(){return!1},onUncheckAll:function(){return!1},onLoadSuccess:function(){return!1},onLoadError:function(){return!1},onColumnSwitch:function(){return!1}},g.COLUMN_DEFAULTS={radio:!1,checkbox:!1,checkboxEnabled:!0,field:void 0,title:void 0,"class":void 0,align:void 0,halign:void 0,valign:void 0,width:void 0,sortable:!1,order:"asc",visible:!0,switchable:!0,clickToSelect:!0,formatter:void 0,events:void 0,sorter:void 0,cellStyle:void 0},g.EVENTS={"all.bs.table":"onAll","click-row.bs.table":"onClickRow","dbl-click-row.bs.table":"onDblClickRow","sort.bs.table":"onSort","check.bs.table":"onCheck","uncheck.bs.table":"onUncheck","check-all.bs.table":"onCheckAll","uncheck-all.bs.table":"onUncheckAll","load-success.bs.table":"onLoadSuccess","load-error.bs.table":"onLoadError","column-switch.bs.table":"onColumnSwitch"},g.prototype.init=function(){this.initContainer(),this.initTable(),this.initHeader(),this.initData(),this.initToolbar(),this.initPagination(),this.initBody(),this.initServer()},g.prototype.initContainer=function(){this.$container=a(['','
','
','','
','
',this.options.formatLoadingMessage(),"
","
",'',"
","
"].join("")),this.$container.insertAfter(this.$el),this.$container.find(".fixed-table-body").append(this.$el),this.$container.after('
'),this.$loading=this.$container.find(".fixed-table-loading"),this.$el.addClass(this.options.classes),this.options.striped&&this.$el.addClass("table-striped")},g.prototype.initTable=function(){var b=this,c=[],d=[];this.$header=this.$el.find("thead"),this.$header.length||(this.$header=a(" ").appendTo(this.$el)),this.$header.find("tr").length||this.$header.append(" "),this.$header.find("th").each(function(){var b=a.extend({},{title:a(this).html(),"class":a(this).attr("class")},a(this).data());c.push(b)}),this.options.columns=a.extend([],c,this.options.columns),a.each(this.options.columns,function(c,d){b.options.columns[c]=a.extend({},g.COLUMN_DEFAULTS,{field:c},d)}),this.options.data.length||(this.$el.find("tbody tr").each(function(){var c={};a(this).find("td").each(function(d){c[b.options.columns[d].field]=a(this).html()}),d.push(c)}),this.options.data=d)},g.prototype.initHeader=function(){var c=this,d=[],e=[];this.header={fields:[],styles:[],classes:[],formatters:[],events:[],sorters:[],cellStyles:[],clickToSelects:[]},a.each(this.options.columns,function(a,f){{var g="",h=b("text-align: %s; ",f.align)+b("vertical-align: %s; ",f.valign),i=b(' class="%s"',f["class"]);c.options.sortOrder||f.order}f.visible&&(d.push(f),c.header.fields.push(f.field),c.header.styles.push(h),c.header.classes.push(i),c.header.formatters.push(f.formatter),c.header.events.push(f.events),c.header.sorters.push(f.sorter),c.header.cellStyles.push(f.cellStyle),c.header.clickToSelects.push(f.clickToSelect),f.halign&&(h=b("text-align: %s; ",f.halign)+b("vertical-align: %s; ",f.valign)),h+=b("width: %spx; ",f.checkbox||f.radio?36:f.width),e.push(""),e.push(b('',c.options.sortable&&f.sortable?"sortable":"")),g=f.title,c.options.sortName===f.field&&c.options.sortable&&f.sortable&&(g+=c.getCaretHtml()),f.checkbox&&(!c.options.singleSelect&&c.options.checkboxHeader&&(g=' '),c.header.stateField=f.field),f.radio&&(g="",c.header.stateField=f.field,c.options.singleSelect=!0),e.push(g),e.push("
"),e.push('
'),e.push(" "))}),this.$header.find("tr").html(e.join("")),this.$header.find("th").each(function(b){a(this).data(d[b])}),this.$container.off("click","th").on("click","th",function(b){c.options.sortable&&a(this).data().sortable&&c.onSort(b)}),!this.options.showHeader||this.options.cardView?(this.$header.hide(),this.$container.find(".fixed-table-header").hide(),this.$loading.css("top",0)):(this.$header.show(),this.$container.find(".fixed-table-header").show(),this.$loading.css("top","37px")),this.$selectAll=this.$header.find('[name="btSelectAll"]'),this.$container.off("click",'[name="btSelectAll"]').on("click",'[name="btSelectAll"]',function(){var b=a(this).prop("checked");c[b?"checkAll":"uncheckAll"]()})},g.prototype.initData=function(a,b){this.data=b?this.data.concat(a):a||this.options.data,this.options.data=this.data,"server"!==this.options.sidePagination&&this.initSort()},g.prototype.initSort=function(){var b=this,c=this.options.sortName,d="desc"===this.options.sortOrder?-1:1,e=a.inArray(this.options.sortName,this.header.fields);-1!==e&&this.data.sort(function(a,g){var h=f(b.header,b.header.sorters[e],[a[c],g[c]]);return void 0!==h?d*h:a[c]===g[c]?0:a[c]').appendTo(this.$toolbar).append(a(this.options.toolbar)),f=[''],this.options.showRefresh&&f.push('
',' '," "),this.options.showToggle&&f.push('
',' '," "),this.options.showColumns&&(f.push(b('
',this.options.showRefresh||this.options.showToggle?"btn-group":""),'',' ',' '," ",'","
")),f.push("
"),f.length>2&&this.$toolbar.append(f.join("")),this.options.showRefresh&&this.$toolbar.find('button[name="refresh"]').off("click").on("click",a.proxy(this.refresh,this)),this.options.showToggle&&this.$toolbar.find('button[name="toggle"]').off("click").on("click",function(){e.options.cardView=!e.options.cardView,e.initHeader(),e.initBody()}),this.options.showColumns&&(c=this.$toolbar.find(".keep-open"),c.find("li").off("click").on("click",function(a){a.stopImmediatePropagation()}),c.find("input").off("click").on("click",function(){var b=a(this);e.toggleColumn(b.val(),b.prop("checked"),!1),e.trigger("column-switch",a(this).data("field"),b.prop("checked"))})),this.options.search&&(f=[],f.push('',b(' ',this.options.formatSearch()),"
"),this.$toolbar.append(f.join("")),d=this.$toolbar.find(".search input"),d.off("keyup").on("keyup",function(a){clearTimeout(g),g=setTimeout(function(){e.onSearch(a)},500)}))},g.prototype.onSearch=function(b){var c=a.trim(a(b.currentTarget).val());a(b.currentTarget).val(c),c!==this.searchText&&(this.searchText=c,this.options.pageNumber=1,this.initSearch(),this.updatePagination())},g.prototype.initSearch=function(){var b=this;if("server"!==this.options.sidePagination){var c=this.searchText&&this.searchText.toLowerCase();this.data=c?a.grep(this.options.data,function(d,e){g=a.isNumeric(g)?parseInt(g,10):g;for(var g in d){var h=d[g];if(h=f(b.header,b.header.formatters[a.inArray(g,b.header.fields)],[h,d,e],h),-1!==a.inArray(g,b.header.fields)&&("string"==typeof h||"number"==typeof h)&&-1!==(h+"").toLowerCase().indexOf(c))return!0}return!1}):this.options.data}},g.prototype.initPagination=function(){if(this.$pagination=this.$container.find(".fixed-table-pagination"),this.options.pagination){var c,d,e,f,g,h,i,j,k,l=this,m=[],n=this.searchText?this.data:this.options.data;"server"!==this.options.sidePagination&&(this.options.totalRows=n.length),this.totalPages=0,this.options.totalRows&&(this.totalPages=~~((this.options.totalRows-1)/this.options.pageSize)+1),this.totalPages>0&&this.options.pageNumber>this.totalPages&&(this.options.pageNumber=this.totalPages),this.pageFrom=(this.options.pageNumber-1)*this.options.pageSize+1,this.pageTo=this.options.pageNumber*this.options.pageSize,this.pageTo>this.options.totalRows&&(this.pageTo=this.options.totalRows),m.push('",'"),this.$pagination.html(m.join("")),f=this.$pagination.find(".page-list a"),g=this.$pagination.find(".page-first"),h=this.$pagination.find(".page-pre"),i=this.$pagination.find(".page-next"),j=this.$pagination.find(".page-last"),k=this.$pagination.find(".page-number"),this.options.pageNumber<=1&&(g.addClass("disabled"),h.addClass("disabled")),this.options.pageNumber>=this.totalPages&&(i.addClass("disabled"),j.addClass("disabled")),f.off("click").on("click",a.proxy(this.onPageListChange,this)),g.off("click").on("click",a.proxy(this.onPageFirst,this)),h.off("click").on("click",a.proxy(this.onPagePre,this)),i.off("click").on("click",a.proxy(this.onPageNext,this)),j.off("click").on("click",a.proxy(this.onPageLast,this)),k.off("click").on("click",a.proxy(this.onPageNumber,this))}},g.prototype.updatePagination=function(){this.options.maintainSelected||this.resetRows(),this.initPagination(),"server"===this.options.sidePagination?this.initServer():this.initBody()},g.prototype.onPageListChange=function(b){var c=a(b.currentTarget);c.parent().addClass("active").siblings().removeClass("active"),this.options.pageSize=+c.text(),this.$toolbar.find(".page-size").text(this.options.pageSize),this.updatePagination()},g.prototype.onPageFirst=function(){this.options.pageNumber=1,this.updatePagination()},g.prototype.onPagePre=function(){this.options.pageNumber--,this.updatePagination()},g.prototype.onPageNext=function(){this.options.pageNumber++,this.updatePagination()},g.prototype.onPageLast=function(){this.options.pageNumber=this.totalPages,this.updatePagination()},g.prototype.onPageNumber=function(b){this.options.pageNumber!==+a(b.currentTarget).text()&&(this.options.pageNumber=+a(b.currentTarget).text(),this.updatePagination())},g.prototype.initBody=function(d){var e=this,g=[],h=this.getData();this.$body=this.$el.find("tbody"),this.$body.length||(this.$body=a(" ").appendTo(this.$el)),"server"===this.options.sidePagination&&(h=this.data),this.options.pagination&&"server"!==this.options.sidePagination||(this.pageFrom=1,this.pageTo=h.length);for(var i=this.pageFrom-1;i"),this.options.cardView&&g.push(b('',this.header.fields.length)),a.each(this.header.fields,function(a,d){var h="",m=j[d],n="",o={},p=e.header.classes[a];if(k=b('style="%s"',l.concat(e.header.styles[a]).join("; ")),m=f(e.header,e.header.formatters[a],[m,j,i],m),o=f(e.header,e.header.cellStyles[a],[m,j,i],o),o.classes&&(p=b(' class="%s"',o.classes)),o.css){l=[];for(var q in o.css)l.push(q+": "+o.css[q]);k=b('style="%s"',l.concat(e.header.styles[a]).join("; "))}if(e.options.columns[a].checkbox||e.options.columns[a].radio){if(e.options.cardView)return!0;n=e.options.columns[a].checkbox?"checkbox":n,n=e.options.columns[a].radio?"radio":n,h=[' '," "," "].join("")}else m="undefined"==typeof m?e.options.undefinedText:m,h=e.options.cardView?['',e.options.showHeader?b('%s ',k,c(e.options.columns,"field","title",d)):"",b('%s ',m),"
"].join(""):[b("",p,k),m," "].join("");g.push(h)}),this.options.cardView&&g.push(""),g.push("")}g.length||g.push('',b('%s ',this.header.fields.length,this.options.formatNoMatches())," "),this.$body.html(g.join("")),d||this.$container.find(".fixed-table-body").scrollTop(0),this.$body.find("> tr > td").off("click").on("click",function(){var c=a(this).parent();e.trigger("click-row",e.data[c.data("index")],c),e.options.clickToSelect&&e.header.clickToSelects[c.children().index(a(this))]&&c.find(b('[name="%s"]',e.options.selectItemName)).trigger("click")}),this.$body.find("tr").off("dblclick").on("dblclick",function(){e.trigger("dbl-click-row",e.data[a(this).data("index")],a(this))}),this.$selectItem=this.$body.find(b('[name="%s"]',this.options.selectItemName)),this.$selectItem.off("click").on("click",function(b){b.stopImmediatePropagation(),a(this).is(":radio")&&a(this).prop("checked",!0);var c=e.$selectItem.filter(":enabled").length===e.$selectItem.filter(":enabled").filter(":checked").length,d=a(this).prop("checked"),f=e.data[a(this).data("index")];e.$selectAll.add(e.$selectAll_).prop("checked",c),f[e.header.stateField]=d,e.trigger(d?"check":"uncheck",f),e.options.singleSelect&&(e.$selectItem.not(this).each(function(){e.data[a(this).data("index")][e.header.stateField]=!1}),e.$selectItem.filter(":checked").not(this).prop("checked",!1)),e.updateSelected()}),a.each(this.header.events,function(b,c){if(c){"string"==typeof c&&(c=f(null,c));for(var d in c)e.$body.find("tr").each(function(){var f=a(this),g=f.find("td").eq(b),h=d.indexOf(" "),i=d.substring(0,h),j=d.substring(h+1),k=c[d];g.find(j).off(i).on(i,function(a){var c=f.data("index"),d=e.data[c],g=d[e.header.fields[b]];k(a,g,d,c)})})}}),this.updateSelected(),this.resetView()},g.prototype.initServer=function(b){var c=this,d={},e={pageSize:this.options.pageSize,pageNumber:this.options.pageNumber,searchText:this.searchText,sortName:this.options.sortName,sortOrder:this.options.sortOrder};this.options.url&&("limit"===this.options.queryParamsType&&(e={limit:e.pageSize,offset:e.pageSize*(e.pageNumber-1),search:e.searchText,sort:e.sortName,order:e.sortOrder}),d=f(this.options,this.options.queryParams,[e],d),d!==!1&&(b||this.$loading.show(),a.ajax({type:this.options.method,url:this.options.url,data:d,cache:this.options.cache,contentType:this.options.contentType,dataType:"json",success:function(a){a=f(c.options,c.options.responseHandler,[a],a);var b=a;"server"===c.options.sidePagination&&(c.options.totalRows=a.total,b=a.rows),c.load(b),c.trigger("load-success",b)},error:function(a){c.trigger("load-error",a.status)},complete:function(){b||c.$loading.hide()}})))},g.prototype.getCaretHtml=function(){return['',' '," "].join("")},g.prototype.updateSelected=function(){this.$selectItem.each(function(){a(this).parents("tr")[a(this).prop("checked")?"addClass":"removeClass"]("selected")})},g.prototype.updateRows=function(b){var c=this;this.$selectItem.each(function(){c.data[a(this).data("index")][c.header.stateField]=b})},g.prototype.resetRows=function(){var b=this;a.each(this.data,function(a,c){b.$selectAll.prop("checked",!1),b.$selectItem.prop("checked",!1),c[b.header.stateField]=!1})},g.prototype.trigger=function(b){var c=Array.prototype.slice.call(arguments,1);b+=".bs.table",this.options[g.EVENTS[b]].apply(this.options,c),this.$el.trigger(a.Event(b),c),this.options.onAll(b,c),this.$el.trigger(a.Event("all.bs.table"),[b,c])},g.prototype.resetHeader=function(){var b=this,c=this.$container.find(".fixed-table-header"),d=this.$container.find(".fixed-table-body"),f=this.$el.width()>d.width()?e():0;return this.$el.is(":hidden")?(clearTimeout(this.timeoutId_),void(this.timeoutId_=setTimeout(a.proxy(this.resetHeader,this),100))):(this.$header_=this.$header.clone(!0,!0),this.$selectAll_=this.$header_.find('[name="btSelectAll"]'),void setTimeout(function(){c.css({height:"37px","border-bottom":"1px solid #dddddd","margin-right":f}).find("table").css("width",b.$el.css("width")).html("").attr("class",b.$el.attr("class")).append(b.$header_),b.$header.find("th").each(function(c){b.$header_.find("th").eq(c).data(a(this).data())}),b.$body.find("tr:first-child:not(.no-records-found) > *").each(function(c){b.$header_.find("div.fht-cell").eq(c).width(a(this).innerWidth())}),b.$el.css("margin-top",-b.$header.height()),d.off("scroll").on("scroll",function(){c.scrollLeft(a(this).scrollLeft())})}))},g.prototype.toggleColumn=function(a,c,d){if(-1!==a&&(this.options.columns[a].visible=c,this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns)){var e=this.$toolbar.find(".keep-open input").prop("disabled",!1);d&&e.filter(b('[value="%s"]',a)).prop("checked",c),e.filter(":checked").length<=this.options.minimumCountColumns&&e.filter(":checked").prop("disabled",!0)}},g.prototype.resetView=function(a){{var b=this;this.header}if(a&&a.height&&(this.options.height=a.height),this.$selectAll.prop("checked",this.$selectItem.length>0&&this.$selectItem.length===this.$selectItem.filter(":checked").length),this.options.height){var c=+this.$toolbar.children().outerHeight(!0),d=+this.$pagination.children().outerHeight(!0),e=this.options.height-c-d;this.$container.find(".fixed-table-container").css("height",e+"px")}return this.options.cardView?(b.$el.css("margin-top","0"),void b.$container.find(".fixed-table-container").css("padding-bottom","0")):(this.options.showHeader&&this.options.height&&this.resetHeader(),void(this.options.height&&this.options.showHeader&&this.$container.find(".fixed-table-container").css("padding-bottom","37px")))},g.prototype.getData=function(){return this.searchText?this.data:this.options.data},g.prototype.load=function(a){this.initData(a),this.initSearch(),this.initPagination(),this.initBody()},g.prototype.append=function(a){this.initData(a,!0),this.initSearch(),this.initPagination(),this.initBody(!0)},g.prototype.remove=function(b){var c,d,e=this.options.data.length;if(b.hasOwnProperty("field")&&b.hasOwnProperty("values")){for(c=e-1;c>=0;c--){if(d=this.options.data[c],!d.hasOwnProperty(b.field))return;-1!==a.inArray(d[b.field],b.values)&&this.options.data.splice(c,1)}e!==this.options.data.length&&(this.initSearch(),this.initPagination(),this.initBody(!0))}},g.prototype.updateRow=function(b){b.hasOwnProperty("index")&&b.hasOwnProperty("row")&&(a.extend(this.data[b.index],b.row),this.initBody())},g.prototype.mergeCells=function(b){var c,d,e=b.index,f=a.inArray(b.field,this.header.fields),g=b.rowspan||1,h=b.colspan||1,i=this.$body.find("tr"),j=i.eq(e).find("td").eq(f);if(!(0>e||0>f||e>=this.data.length)){for(c=e;e+g>c;c++)for(d=f;f+h>d;d++)i.eq(c).find("td").eq(d).hide();j.attr("rowspan",g).attr("colspan",h).show(10,a.proxy(this.resetView,this))}},g.prototype.getSelections=function(){var b=this;return a.grep(this.data,function(a){return a[b.header.stateField]})},g.prototype.checkAll=function(){this.$selectAll.add(this.$selectAll_).prop("checked",!0),this.$selectItem.filter(":enabled").prop("checked",!0),this.updateRows(!0),this.updateSelected(),this.trigger("check-all")},g.prototype.uncheckAll=function(){this.$selectAll.add(this.$selectAll_).prop("checked",!1),this.$selectItem.filter(":enabled").prop("checked",!1),this.updateRows(!1),this.updateSelected(),this.trigger("uncheck-all")},g.prototype.destroy=function(){this.$el.insertBefore(this.$container),a(this.options.toolbar).insertBefore(this.$el),this.$container.next().remove(),this.$container.remove(),this.$el.html(this.$el_.html()).attr("class",this.$el_.attr("class")||"")},g.prototype.showLoading=function(){this.$loading.show()},g.prototype.hideLoading=function(){this.$loading.hide()},g.prototype.refresh=function(a){a&&a.url&&(this.options.url=a.url),this.initServer(a&&a.silent)},g.prototype.showColumn=function(a){this.toggleColumn(d(this.options.columns,a),!0,!0)},g.prototype.hideColumn=function(a){this.toggleColumn(d(this.options.columns,a),!1,!0)},a.fn.bootstrapTable=function(b,c){var d,e=["getSelections","getData","load","append","remove","updateRow","mergeCells","checkAll","uncheckAll","refresh","resetView","destroy","showLoading","hideLoading","showColumn","hideColumn"];return this.each(function(){var f=a(this),h=f.data("bootstrap.table"),i=a.extend({},g.DEFAULTS,f.data(),"object"==typeof b&&b);if("string"==typeof b){if(a.inArray(b,e)<0)throw"Unknown method: "+b;if(!h)return;d=h[b](c),"destroy"===b&&f.removeData("bootstrap.table")}h||f.data("bootstrap.table",h=new g(this,i))}),"undefined"==typeof d?this:d},a.fn.bootstrapTable.Constructor=g,a.fn.bootstrapTable.defaults=g.DEFAULTS,a.fn.bootstrapTable.columnDefaults=g.COLUMN_DEFAULTS,a(function(){a('[data-toggle="table"]').bootstrapTable()})}(jQuery);
8 |
9 |
--------------------------------------------------------------------------------