├── .gitignore
├── LICENSE
├── README.md
├── cert_manage
├── __init__.py
├── celery.py
├── context_processor.py
├── settings.py
├── tasks.py
├── urls.py
├── utils.py
├── views.py
└── wsgi.py
├── certs
├── __init__.py
├── admin.py
├── api.py
├── apps.py
├── forms.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── signals_handler.py
├── tasks.py
├── templates
│ └── cert
│ │ ├── _base_create_update.html
│ │ ├── cert_create_update.html
│ │ ├── cert_detail.html
│ │ └── cert_list.html
├── tests.py
├── urls
│ ├── __init__.py
│ ├── api_urls.py
│ └── views_urls.py
├── utils.py
└── views.py
├── cms
├── config_example.py
├── data
└── .gitkeep
├── i18n
└── zh_CN
│ └── LC_MESSAGES
│ └── django.po
├── logs
└── .gitkeep
├── manage.py
├── requirements
├── .gitkeep
└── requirements.txt
├── run_server.py
├── static
├── css
│ ├── bootstrap.css
│ ├── bootstrap.css.map
│ ├── bootstrap.min.css
│ ├── bootstrap.min.css.map
│ ├── plugin
│ │ ├── datatables
│ │ │ ├── datatables.min.css
│ │ │ └── datatables.min.css.bak
│ │ ├── font-awesome
│ │ │ ├── css
│ │ │ │ ├── fa-brands.css
│ │ │ │ ├── fa-brands.min.css
│ │ │ │ ├── fa-regular.css
│ │ │ │ ├── fa-regular.min.css
│ │ │ │ ├── fa-solid.css
│ │ │ │ ├── fa-solid.min.css
│ │ │ │ ├── fontawesome-all.css
│ │ │ │ ├── fontawesome-all.min.css
│ │ │ │ ├── fontawesome.css
│ │ │ │ └── fontawesome.min.css
│ │ │ ├── less
│ │ │ │ ├── _animated.less
│ │ │ │ ├── _bordered-pulled.less
│ │ │ │ ├── _core.less
│ │ │ │ ├── _fixed-width.less
│ │ │ │ ├── _icons.less
│ │ │ │ ├── _larger.less
│ │ │ │ ├── _list.less
│ │ │ │ ├── _mixins.less
│ │ │ │ ├── _rotated-flipped.less
│ │ │ │ ├── _screen-reader.less
│ │ │ │ ├── _stacked.less
│ │ │ │ ├── _variables.less
│ │ │ │ ├── fa-brands.less
│ │ │ │ ├── fa-regular.less
│ │ │ │ ├── fa-solid.less
│ │ │ │ └── fontawesome.less
│ │ │ ├── scss
│ │ │ │ ├── _animated.scss
│ │ │ │ ├── _bordered-pulled.scss
│ │ │ │ ├── _core.scss
│ │ │ │ ├── _fixed-width.scss
│ │ │ │ ├── _icons.scss
│ │ │ │ ├── _larger.scss
│ │ │ │ ├── _list.scss
│ │ │ │ ├── _mixins.scss
│ │ │ │ ├── _rotated-flipped.scss
│ │ │ │ ├── _screen-reader.scss
│ │ │ │ ├── _stacked.scss
│ │ │ │ ├── _variables.scss
│ │ │ │ ├── fa-brands.scss
│ │ │ │ ├── fa-regular.scss
│ │ │ │ ├── fa-solid.scss
│ │ │ │ └── fontawesome.scss
│ │ │ └── webfonts
│ │ │ │ ├── fa-brands-400.eot
│ │ │ │ ├── fa-brands-400.svg
│ │ │ │ ├── fa-brands-400.ttf
│ │ │ │ ├── fa-brands-400.woff
│ │ │ │ ├── fa-brands-400.woff2
│ │ │ │ ├── fa-regular-400.eot
│ │ │ │ ├── fa-regular-400.svg
│ │ │ │ ├── fa-regular-400.ttf
│ │ │ │ ├── fa-regular-400.woff
│ │ │ │ ├── fa-regular-400.woff2
│ │ │ │ ├── fa-solid-900.eot
│ │ │ │ ├── fa-solid-900.svg
│ │ │ │ ├── fa-solid-900.ttf
│ │ │ │ ├── fa-solid-900.woff
│ │ │ │ └── fa-solid-900.woff2
│ │ ├── select2
│ │ │ ├── select2-bootstrap.min.css
│ │ │ └── select2.min.css
│ │ ├── skins
│ │ │ ├── _all-skins.css
│ │ │ ├── _all-skins.min.css
│ │ │ ├── skin-black-light.css
│ │ │ ├── skin-black-light.min.css
│ │ │ ├── skin-black.css
│ │ │ ├── skin-black.min.css
│ │ │ ├── skin-blue-light.css
│ │ │ ├── skin-blue-light.min.css
│ │ │ ├── skin-blue.css
│ │ │ ├── skin-blue.min.css
│ │ │ ├── skin-green-light.css
│ │ │ ├── skin-green-light.min.css
│ │ │ ├── skin-green.css
│ │ │ ├── skin-green.min.css
│ │ │ ├── skin-purple-light.css
│ │ │ ├── skin-purple-light.min.css
│ │ │ ├── skin-purple.css
│ │ │ ├── skin-purple.min.css
│ │ │ ├── skin-red-light.css
│ │ │ ├── skin-red-light.min.css
│ │ │ ├── skin-red.css
│ │ │ ├── skin-red.min.css
│ │ │ ├── skin-yellow-light.css
│ │ │ ├── skin-yellow-light.min.css
│ │ │ ├── skin-yellow.css
│ │ │ └── skin-yellow.min.css
│ │ ├── sweetalert2
│ │ │ ├── sweetalert2.css
│ │ │ └── sweetalert2.min.css
│ │ └── toastr
│ │ │ └── toastr.min.css
│ └── style.css
└── js
│ ├── bootstrap.min.js
│ ├── cert.js
│ ├── jquery-2.2.4.js
│ └── plugin
│ ├── datatables
│ ├── datatables.min.js
│ ├── i18n
│ │ ├── English.lang
│ │ └── zh-hans.json
│ └── pdfmake.min.js.map
│ ├── select2
│ ├── select2.full.min.js
│ └── select2.i18n.cn.js
│ ├── sweetalert2
│ ├── sweetalert2.all.js
│ ├── sweetalert2.all.min.js
│ ├── sweetalert2.js
│ └── sweetalert2.min.js
│ └── toastr
│ └── toastr.min.js
├── support
├── .gitkeep
└── supervisord
│ └── cert_manage.ini
├── templates
├── _base.html
├── _copyright.html
├── _foot_js.html
├── _head_css_js.html
├── flash_message_standalone.html
└── index.html
├── tmp
└── .gitkeep
└── users
├── __init__.py
├── admin.py
├── api.py
├── apps.py
├── authentication.py
├── forms.py
├── migrations
├── 0001_initial.py
└── __init__.py
├── mixins.py
├── models
├── __init__.py
├── authentication.py
└── user.py
├── permissions.py
├── serializers.py
├── signals.py
├── templates
└── users
│ └── login.html
├── tests.py
├── urls
├── __init__.py
├── api_urls.py
└── views_urls.py
├── utils.py
└── views.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | .idea/
18 | data/static/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 | *.pid
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | .hypothesis/
51 | .pytest_cache/
52 |
53 | # Translations
54 | *.mo
55 | *.pot
56 |
57 | # Django stuff:
58 | *.log
59 | config.py
60 | local_settings.py
61 | db.sqlite3
62 |
63 | # Flask stuff:
64 | instance/
65 | .webassets-cache
66 |
67 | # Scrapy stuff:
68 | .scrapy
69 |
70 | # Sphinx documentation
71 | docs/_build/
72 |
73 | # PyBuilder
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # pyenv
80 | .python-version
81 |
82 | # celery beat schedule file
83 | celerybeat-schedule
84 |
85 | # SageMath parsed files
86 | *.sage.py
87 |
88 | # Environments
89 | .env
90 | .venv
91 | env/
92 | venv/
93 | ENV/
94 | env.bak/
95 | venv.bak/
96 |
97 | # Spyder project settings
98 | .spyderproject
99 | .spyproject
100 |
101 | # Rope project settings
102 | .ropeproject
103 |
104 | # mkdocs documentation
105 | /site
106 |
107 | # mypy
108 | .mypy_cache/
109 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 ericwinn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cert_manage
2 | 证书管理系统
3 |
4 | 
5 | 
6 | [](https://www.python.org/)
7 | [](https://www.djangoproject.com/)
8 |
9 | ---
10 |
11 | Cert_manage 是一个开源的证书管理系统,用于检测证书到期日期并提醒管理者,支持基于URL的在线检测和PEM文件离线检测,支持WEB SSL证书、APP开发者证书、APP推送证书等,使用MIT开源协议
12 |
13 | Cert_manage 使用 Python / Django 进行开发,遵循 Web 2.0 规范
14 |
15 | 
16 |
17 |
18 | # 安装文档
19 |
20 | ## 安装Python 3.6
21 |
22 | ~~~
23 | 参考网上其它文档
24 | ~~~
25 |
26 | ## 创建虚拟环境
27 |
28 | ~~~
29 | $ python3 -m venv /opt/py3
30 | ~~~
31 |
32 | ## 载入虚拟环境
33 |
34 | ~~~
35 | $ source /opt/py3/bin/activate
36 | ~~~
37 |
38 | ## 获取cert_mange代码
39 |
40 | ~~~
41 | $ cd /opt/
42 | $ git clone --depth=1 https://github.com/itnotebooks/cert_manage.git
43 | # 如果没有安装 git 请先安装
44 | ~~~
45 |
46 | ## 安装依赖
47 |
48 | ~~~
49 | $ cd /opt/cert_manage
50 | $ pip install -r requirements/requirements.txt
51 | ~~~
52 |
53 | ## 修改配置文件
54 |
55 | ~~~
56 | $ cd /opt/cert_manage
57 | $ cp config_example.py config.py
58 | $ vim config.py
59 | ~~~
60 |
61 | ## 启动 cert_manage
62 |
63 | ~~~
64 | $ cd /opt/cert_manage
65 | $ python run_server.py
66 | ~~~
67 |
68 | ## 访问
69 |
70 | ~~~
71 | http://127.0.0.1:8080
72 | 初始用户名:admin
73 | 初始密码:admin
74 | ~~~
75 |
--------------------------------------------------------------------------------
/cert_manage/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/cert_manage/__init__.py
--------------------------------------------------------------------------------
/cert_manage/celery.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-4 上午7:01
6 | # @Version : 1.0
7 | # @File : celery
8 | # @Software : PyCharm
9 |
10 | import os
11 |
12 | from celery import Celery
13 | from django.conf import settings
14 |
15 | C_FORCE_ROOT = True
16 |
17 | # set the default Django settings module for the 'celery' program.
18 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cert_manage.settings')
19 |
20 | app = Celery('cert_manage', backend=settings.CELERY_BROKER_URL, broker=settings.CELERY_BROKER_URL)
21 |
22 | app.conf.timezone = 'Asia/Shanghai'
23 |
24 | app.conf.update(
25 | task_serializer='json',
26 | accept_content=['json', 'pickle'],
27 | result_serializer='json',
28 | timezone='Asia/Shanghai',
29 | enable_utc=True,
30 | )
31 |
32 | FORKS = 60
33 | TIMEOUT = 180
34 | PERIOD_TASK = os.environ.get("PERIOD_TASK", "on")
35 |
--------------------------------------------------------------------------------
/cert_manage/context_processor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 |
4 |
5 | def cmdb_processor(request):
6 | context = {}
7 |
8 | # Setting default pk
9 | context.update(
10 | {'DEFAULT_PK': '00000000-0000-0000-0000-000000000000'}
11 | )
12 | return context
13 |
--------------------------------------------------------------------------------
/cert_manage/tasks.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 下午5:26
6 | # @Version : 1.0
7 | # @File : tasks
8 | # @Software : PyCharm
9 | from .celery import app
10 | from django.core.mail import send_mail
11 | from django.conf import settings
12 |
13 |
14 | @app.task
15 | def send_mail_async(*args, **kwargs):
16 | """ Using celery to send email async
17 |
18 | You can use it as django send_mail function
19 |
20 | Example:
21 | send_mail_sync.delay(subject, message, from_mail, recipient_list, fail_silently=False, html_message=None)
22 |
23 | Also you can ignore the from_mail, unlike django send_mail, from_email is not a require args:
24 |
25 | Example:
26 | send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None)
27 | """
28 | if len(args) == 3:
29 | args = list(args)
30 | args[0] = settings.EMAIL_SUBJECT_PREFIX + args[0]
31 | args.insert(2, settings.EMAIL_HOST_USER)
32 | args = tuple(args)
33 |
34 | try:
35 | send_mail(*args, **kwargs)
36 | except Exception as e:
37 | print("Sending mail error: {}".format(e))
38 |
--------------------------------------------------------------------------------
/cert_manage/urls.py:
--------------------------------------------------------------------------------
1 | """cert_manage URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 |
17 | from django.contrib import admin
18 | from django.conf import settings
19 | from django.conf.urls import url, include
20 | from django.conf.urls.static import static
21 | from cert_manage.views import IndexView
22 |
23 | urlpatterns = [
24 | url(r'^$', IndexView.as_view(), name='index'),
25 | url(r'^users/', include('users.urls.views_urls', namespace='users')),
26 | url(r'^certs/', include('certs.urls.views_urls', namespace='certs')),
27 |
28 | url(r'^api/users/', include('users.urls.api_urls', namespace='api-users')),
29 | url(r'^api/certs/', include('certs.urls.api_urls', namespace='api-certs')),
30 | # External apps url
31 | url(r'^admin/', admin.site.urls),
32 | url(r'^captcha/', include('captcha.urls')),
33 | ]
34 |
35 | urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
36 | + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
37 |
--------------------------------------------------------------------------------
/cert_manage/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 下午4:29
6 | # @Version : 1.0
7 | # @File : utils
8 | # @Software : PyCharm
9 | import time
10 | import base64
11 | import calendar
12 | import hashlib
13 | import threading
14 |
15 | from datetime import datetime
16 | from email.utils import formatdate
17 |
18 | from django.utils.translation import ugettext as _
19 | from django.contrib.auth.mixins import UserPassesTestMixin
20 |
21 | from cert_manage.tasks import send_mail_async
22 |
23 |
24 | class AdminUserRequiredMixin(UserPassesTestMixin):
25 | def test_func(self):
26 | if not self.request.user.is_authenticated:
27 | return False
28 | elif not self.request.user.is_superuser:
29 | self.raise_exception = True
30 | return False
31 | return True
32 |
33 |
34 | def content_md5(data):
35 | """计算data的MD5值,经过Base64编码并返回str类型。
36 |
37 | 返回值可以直接作为HTTP Content-Type头部的值
38 | """
39 | if isinstance(data, str):
40 | data = hashlib.md5(data.encode('utf-8'))
41 | value = base64.b64encode(data.hexdigest().encode('utf-8'))
42 | return value.decode('utf-8')
43 |
44 |
45 | _STRPTIME_LOCK = threading.Lock()
46 |
47 | _GMT_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
48 | _ISO8601_FORMAT = "%Y-%m-%dT%H:%M:%S.000Z"
49 |
50 |
51 | def to_unixtime(time_string, format_string):
52 | time_string = time_string.decode("ascii")
53 | with _STRPTIME_LOCK:
54 | return int(calendar.timegm(time.strptime(time_string, format_string)))
55 |
56 |
57 | def http_date(timeval=None):
58 | """返回符合HTTP标准的GMT时间字符串,用strftime的格式表示就是"%a, %d %b %Y %H:%M:%S GMT"。
59 | 但不能使用strftime,因为strftime的结果是和locale相关的。
60 | """
61 | return formatdate(timeval, usegmt=True)
62 |
63 |
64 | def http_to_unixtime(time_string):
65 | """把HTTP Date格式的字符串转换为UNIX时间(自1970年1月1日UTC零点的秒数)。
66 |
67 | HTTP Date形如 `Sat, 05 Dec 2015 11:10:29 GMT` 。
68 | """
69 | return to_unixtime(time_string, _GMT_FORMAT)
70 |
71 |
72 | def iso8601_to_unixtime(time_string):
73 | """把ISO8601时间字符串(形如,2012-02-24T06:07:48.000Z)转换为UNIX时间,精确到秒。"""
74 | return to_unixtime(time_string, _ISO8601_FORMAT)
75 |
76 |
77 | def make_signature(access_key_secret, date=None):
78 | if isinstance(date, bytes):
79 | date = bytes.decode(date)
80 | if isinstance(date, int):
81 | date_gmt = http_date(date)
82 | elif date is None:
83 | date_gmt = http_date(int(time.time()))
84 | else:
85 | date_gmt = date
86 |
87 | data = str(access_key_secret) + "\n" + date_gmt
88 | return content_md5(data)
89 |
90 |
91 | def encrypt_password(password, salt=None):
92 | from passlib.hash import sha512_crypt
93 | if password:
94 | return sha512_crypt.using(rounds=5000).hash(password, salt=salt)
95 | return None
96 |
97 |
98 | def get_object_or_none(model, **kwargs):
99 | try:
100 | obj = model.objects.get(**kwargs)
101 | except model.DoesNotExist:
102 | return None
103 | return obj
104 |
105 |
106 | def certs_messages_remaind_email(cert, cert_info):
107 | base_message = '还有Days天到期'
108 | if int(cert_info.get('remain_days')) == 0:
109 | message = '已到期'
110 | elif int(cert_info.get('remain_days')) < 0:
111 | message = '已过期'
112 | elif int(cert_info.get('remain_days')) in [90, 60, 45, 30, 15] or int(cert_info.get('remain_days')) <= 14:
113 | message = base_message.replace('Days', str(cert_info.get('remain_days')))
114 | else:
115 | message = None
116 |
117 | if message:
118 | if len(cert_info.get('orther_domain')) > 0:
119 | orther_domain = [domain[1] for domain in cert_info.get('orther_domain')]
120 | else:
121 | orther_domain = cert_info.get('orther_domain')
122 | subject = _('重要通知:%(domain)s证书到期提醒(%(time)s)') % {'domain': cert_info.get('domain'),
123 | 'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
124 | recipient_list = [user.email for user in cert.users.all()]
125 | message = _("""
126 | 艾瑞巴蒂~
127 |
128 | %(domain)s证书%(message)s,避免影响业务的正常运行请及时更新。
129 | =========================================================
130 | 颁发机构: %(issued_by)s
131 | 证书类型: %(cert_type)s
132 | 域名信息: %(domain)s
133 | 备用域名: %(orther_domain)s
134 | 有效期至: %(notafter)s
135 | =========================================================
136 | """) % {
137 | 'domain': cert_info.get('domain'),
138 | 'message': message,
139 | 'issued_by': cert_info.get('issued_by'),
140 | 'cert_type': cert_info.get('cert_type'),
141 | 'orther_domain': orther_domain,
142 | 'notafter': cert_info.get('notafter'),
143 | }
144 |
145 | send_mail_async.delay(subject, message, recipient_list, html_message=message)
146 |
--------------------------------------------------------------------------------
/cert_manage/views.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:03
6 | # @Version : 1.0
7 | # @File : views
8 | # @Software : PyCharm
9 |
10 | from django.views.generic import TemplateView
11 | from django.contrib.auth.mixins import LoginRequiredMixin
12 |
13 |
14 | # 首页
15 | class IndexView(LoginRequiredMixin, TemplateView):
16 | template_name = 'index.html'
17 |
18 | session_week = None
19 | session_month = None
20 | session_month_dates = []
21 | session_month_dates_archive = []
22 |
23 | def get(self, request, *args, **kwargs):
24 | return super(IndexView, self).get(request, *args, **kwargs)
25 |
26 | def get_context_data(self, **kwargs):
27 | return super(IndexView, self).get_context_data(**kwargs)
28 |
--------------------------------------------------------------------------------
/cert_manage/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for cert_manage project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cert_manage.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/certs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/certs/__init__.py
--------------------------------------------------------------------------------
/certs/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/certs/api.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:22
6 | # @Version : 1.0
7 | # @File : api
8 | # @Software : PyCharm
9 |
10 |
11 | from users.mixins import IDInFilterMixin
12 | from rest_framework_bulk import BulkModelViewSet
13 | from rest_framework.pagination import LimitOffsetPagination
14 |
15 | from users.permissions import IsSuperUser
16 | from certs import serializers
17 | from certs.models import Certs
18 |
19 |
20 | class CertViewSet(IDInFilterMixin, BulkModelViewSet):
21 | """
22 | 证书操作接口
23 | """
24 | filter_fields = ('name', 'domain', 'orther_domain', 'organization_name', 'cert_type', 'comment')
25 | search_fields = filter_fields
26 | ordering_fields = ('domain',)
27 | queryset = Certs.objects.all()
28 | serializer_class = serializers.CertSerializer
29 | pagination_class = LimitOffsetPagination
30 | permission_classes = (IsSuperUser,)
31 |
--------------------------------------------------------------------------------
/certs/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CertsConfig(AppConfig):
5 | name = 'certs'
6 |
7 | def ready(self):
8 | from . import signals_handler
9 | super().ready()
10 |
--------------------------------------------------------------------------------
/certs/forms.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 上午9:01
6 | # @Version : 1.0
7 | # @File : forms
8 | # @Software : PyCharm
9 |
10 |
11 | from django import forms
12 | from django.utils.translation import ugettext_lazy as _
13 |
14 | from certs.models import Certs
15 | from users.models import User
16 |
17 |
18 | class CertCreateUpdateForm(forms.ModelForm):
19 | is_domain = forms.BooleanField(initial=True, required=False, help_text=_('域名或证书文件'),
20 | label='is_domain')
21 |
22 | class Meta:
23 | model = Certs
24 | fields = [
25 | 'name', 'method', 'domain_url', 'crt_file', 'key_file', 'users', 'comment'
26 | ]
27 |
28 | widgets = {
29 | 'domain_url': forms.TextInput(
30 | attrs={
31 | 'placeholder': _('通用名称')
32 | }
33 | ),
34 | 'users': forms.SelectMultiple(attrs={
35 | 'class': 'select2',
36 | 'data-placeholder': _('选择用户')
37 | }),
38 | }
39 |
40 | help_texts = {
41 | 'name': '* required',
42 | 'domain_url': 'eg: www.itnotebooks.com',
43 | }
44 |
45 | # 重写init方法
46 | def __init__(self, initial, *args, **kwargs):
47 | super(CertCreateUpdateForm, self).__init__(*args, **kwargs)
48 | if initial.get('pk'):
49 | cert = Certs.objects.get(id=initial.get('pk'))
50 | if int(cert.method) == 1:
51 | self.fields['is_domain'].initial = False
52 |
53 | # 重写save方法,处理多个字段的问题
54 | def save(self, commit=True):
55 | certs = super().save(commit=commit)
56 | if not self.cleaned_data.get('is_domain'):
57 | certs.method = 1
58 | certs.save()
59 | return certs
60 |
--------------------------------------------------------------------------------
/certs/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1 on 2019-09-18 14:24
2 |
3 | from django.conf import settings
4 | from django.db import migrations, models
5 | import uuid
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | initial = True
11 |
12 | dependencies = [
13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14 | ]
15 |
16 | operations = [
17 | migrations.CreateModel(
18 | name='Certs',
19 | fields=[
20 | ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
21 | ('name', models.CharField(max_length=45, verbose_name='名称')),
22 | ('domain', models.CharField(max_length=128, null=True, verbose_name='通用名称')),
23 | ('orther_domain', models.TextField(blank=True, max_length=4096, null=True, verbose_name='备用名称')),
24 | ('organization_name', models.CharField(blank=True, max_length=64, null=True, verbose_name='Organization Name')),
25 | ('serial_number', models.CharField(blank=True, max_length=64, null=True, verbose_name='Serial number')),
26 | ('issued_by', models.CharField(blank=True, max_length=64, null=True, verbose_name='Issued By')),
27 | ('cert_type', models.CharField(blank=True, max_length=4, null=True, verbose_name='证书类型')),
28 | ('method', models.BooleanField(choices=[(0, '域名'), (1, '证书')], default=0, verbose_name='Cert Detection Approach')),
29 | ('domain_url', models.CharField(blank=True, max_length=128, null=True, verbose_name='域名')),
30 | ('crt_file', models.TextField(blank=True, null=True, verbose_name='Crt File')),
31 | ('key_file', models.TextField(blank=True, null=True, verbose_name='Key File')),
32 | ('notbefore', models.CharField(blank=True, max_length=24, null=True, verbose_name='Not Before')),
33 | ('notafter', models.CharField(blank=True, max_length=24, null=True, verbose_name='Not After')),
34 | ('remain_days', models.IntegerField(blank=True, null=True, verbose_name='Remaining Days')),
35 | ('create_date', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
36 | ('comment', models.TextField(blank=True, max_length=128, null=True, verbose_name='Comment')),
37 | ('users', models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='Contact')),
38 | ],
39 | options={
40 | 'db_table': 'certs',
41 | },
42 | ),
43 | ]
44 |
--------------------------------------------------------------------------------
/certs/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/certs/migrations/__init__.py
--------------------------------------------------------------------------------
/certs/models.py:
--------------------------------------------------------------------------------
1 | import uuid
2 | from django.db import models
3 | from django.utils.translation import ugettext_lazy as _
4 | from users.models import User
5 |
6 |
7 | # Create your models here.
8 | class Certs(models.Model):
9 | '''
10 | 证书
11 | '''
12 | CERT_METHOD_CHOICES = (
13 | (0, _('域名')),
14 | (1, _('证书')),
15 | )
16 | id = models.UUIDField(default=uuid.uuid4, primary_key=True)
17 | name = models.CharField(max_length=45, verbose_name=_("名称"), null=False)
18 |
19 | # 通用名称
20 | domain = models.CharField(max_length=128, verbose_name=_("通用名称"), null=True)
21 | # 备用名称
22 | orther_domain = models.TextField(max_length=4096, null=True, blank=True, verbose_name=_("备用名称"))
23 | organization_name = models.CharField(max_length=64, null=True, blank=True, verbose_name=_("Organization Name"))
24 |
25 | serial_number = models.CharField(max_length=64, null=True, blank=True, verbose_name=_("Serial number"))
26 | issued_by = models.CharField(max_length=64, null=True, blank=True, verbose_name=_('Issued By'))
27 |
28 | # 证书类型
29 | cert_type = models.CharField(max_length=4, null=True, blank=True, verbose_name=_("证书类型"))
30 |
31 | # 在线解析,还是离线解析
32 | method = models.BooleanField(default=0, choices=CERT_METHOD_CHOICES, verbose_name=_("Cert Detection Approach"))
33 |
34 | # 通过域名,在线解析
35 | domain_url = models.CharField(max_length=128, null=True, blank=True, verbose_name=_("域名"))
36 |
37 | # 通过证书文件离线解析
38 | crt_file = models.TextField(null=True, blank=True, verbose_name=_("Crt File"))
39 | key_file = models.TextField(null=True, blank=True, verbose_name=_("Key File"))
40 |
41 | # 起至日期
42 | notbefore = models.CharField(max_length=24, null=True, blank=True, verbose_name=_('Not Before'))
43 | notafter = models.CharField(max_length=24, null=True, blank=True, verbose_name=_('Not After'))
44 |
45 | # 剩余天数
46 | remain_days = models.IntegerField(null=True, blank=True, verbose_name=_('Remaining Days'))
47 |
48 | users = models.ManyToManyField(User, verbose_name=_("Contact"))
49 | # 创建时间
50 | create_date = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
51 | # 描述
52 | comment = models.TextField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
53 |
54 | def __str__(self):
55 | return self.name
56 |
57 | @property
58 | def get_method(self):
59 | return self.get_method_display
60 |
61 | @property
62 | def get_contact(self):
63 | contact_lisst = [user.name for user in self.users.all()]
64 | return ','.join(contact_lisst)
65 |
66 | @property
67 | def get_user_info(self):
68 | user_info = []
69 | for u in self.users.all():
70 | info = {'name': u.name,
71 | 'phone': u.phone,
72 | 'email': u.email
73 | }
74 | user_info.append(info)
75 | return user_info
76 |
77 | class Meta:
78 | db_table = "certs"
79 |
--------------------------------------------------------------------------------
/certs/serializers.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 上午9:08
6 | # @Version : 1.0
7 | # @File : serializers
8 | # @Software : PyCharm
9 |
10 |
11 | from rest_framework import serializers
12 | from rest_framework_bulk import BulkListSerializer
13 |
14 | from users.mixins import BulkSerializerMixin
15 | from certs.models import Certs
16 | from users.serializers import UserSerializer
17 |
18 |
19 | class CertSerializer(BulkSerializerMixin, serializers.ModelSerializer):
20 | """
21 | 证书的数据结构
22 | """
23 |
24 | class Meta:
25 | model = Certs
26 | list_serializer_class = BulkListSerializer
27 | fields = '__all__'
28 | validators = []
29 |
30 | def get_field_names(self, declared_fields, info):
31 | fields = super().get_field_names(declared_fields, info)
32 | fields.extend([
33 | 'get_method'
34 | ])
35 | return fields
36 |
--------------------------------------------------------------------------------
/certs/signals_handler.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 下午5:37
6 | # @Version : 1.0
7 | # @File : signals_handler
8 | # @Software : PyCharm
9 |
10 | from django.db.models.signals import post_save
11 | from django.dispatch import receiver
12 |
13 | from certs.tasks import refresh_certs_messages_to_db
14 |
15 | from certs.models import Certs
16 |
17 |
18 | @receiver(post_save, sender=Certs)
19 | def certs_pre_create_or_update(sender, instance, **kwargs):
20 | refresh_certs_messages_to_db.delay(instance.id)
21 | return instance
22 |
--------------------------------------------------------------------------------
/certs/tasks.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 下午5:35
6 | # @Version : 1.0
7 | # @File : tasks
8 | # @Software : PyCharm
9 | from cert_manage.celery import app
10 |
11 | from cert_manage.utils import certs_messages_remaind_email
12 | from certs.models import Certs
13 | from certs.utils import load_certificate
14 |
15 |
16 | @app.task
17 | def refresh_certs_messages_to_db(cert_obj_id=None):
18 | '''
19 | 此函数用于刷新证书的详细信息
20 | :return:
21 | '''
22 | certs = Certs.objects.filter(id=cert_obj_id) if cert_obj_id else Certs.objects.all()
23 |
24 | for cert in certs:
25 |
26 | Certs._meta.auto_created = True
27 | try:
28 | if not cert.method: cert.method = 0
29 | if cert.method == 0:
30 | cert_info = load_certificate(cert.method, cert.domain_url)
31 | else:
32 | cert_info = load_certificate(cert.method, cert.crt_file)
33 |
34 | for k, v in cert_info.items():
35 | setattr(cert, k, v)
36 | if k.startswith('remain_days'):
37 | if int(v) <= 90:
38 | certs_messages_remaind_email(cert, cert_info)
39 | cert.save()
40 | except Exception as e:
41 | print(e)
42 | finally:
43 | Certs._meta.auto_created = False
44 | return 0
45 |
--------------------------------------------------------------------------------
/certs/templates/cert/_base_create_update.html:
--------------------------------------------------------------------------------
1 | {% extends '_base.html' %}
2 | {% load i18n %}
3 | {% load static %}
4 | {% load bootstrap3 %}
5 | {% block custom_head_css_js %}
6 |
7 |
8 | {% block custom_head_css_js_create %} {% endblock %}
9 | {% endblock %}
10 |
11 | {% block nav_status %}active{% endblock %}
12 |
13 | {% block content %}
14 |
15 |
16 |
17 |
18 |
19 |
{{ action }}
20 |
21 |
22 |
23 | {% if form.errors.all %}
24 |
25 | {{ form.errors.all }}
26 |
27 | {% endif %}
28 | {% block form %}
29 | {% endblock %}
30 |
31 |
32 |
33 |
34 |
35 | {% endblock %}
36 |
37 |
--------------------------------------------------------------------------------
/certs/templates/cert/cert_create_update.html:
--------------------------------------------------------------------------------
1 | {% extends 'cert/_base_create_update.html' %}
2 | {% load static %}
3 | {% load bootstrap3 %}
4 | {% load i18n %}
5 |
6 | {% block form %}
7 |
52 | {% endblock %}
53 |
54 | {% block custom_foot_js %}
55 |
84 | {% endblock %}
--------------------------------------------------------------------------------
/certs/templates/cert/cert_detail.html:
--------------------------------------------------------------------------------
1 | {% extends '_base.html' %}
2 | {% load static %}
3 | {% load i18n %}
4 |
5 | {% block nav_status %}active{% endblock %}
6 | {% block content %}
7 |
8 |
9 |
10 |
11 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | {% trans 'Name' %}: |
28 | {{ cert.name }} |
29 |
30 |
31 | {% trans 'Common Domain' %}: |
32 | {{ cert.domain }} |
33 |
34 |
35 | {% trans 'Orther Domain' %}: |
36 |
37 | {{ cert.orther_domain }} |
38 |
39 |
40 |
41 |
42 | {% trans 'Organization Name' %}: |
43 |
44 | {{ cert.organization_name }} |
45 |
46 |
47 | {% trans 'Serial number' %}: |
48 |
49 | {{ cert.serial_number }} |
50 |
51 |
52 | {% trans 'Issued By' %}: |
53 |
54 | {{ cert.issued_by }} |
55 |
56 |
57 | {% trans 'SSL Cert Type' %}: |
58 |
59 | {{ cert.cert_type }} |
60 |
61 |
62 | {% trans 'Cert Detection Approach' %}: |
63 |
64 | {{ cert.get_method }} |
65 |
66 |
67 | {% trans 'Not Before' %}: |
68 |
69 | {{ cert.notbefore }} |
70 |
71 |
72 | {% trans 'Not After' %}: |
73 |
74 | {{ cert.notafter }} |
75 |
76 |
77 | {% trans 'Remaining Days' %}: |
78 |
79 | {{ cert.remain_days }} |
80 |
81 |
82 | {% trans 'Contact' %}: |
83 |
84 | {{ cert.get_contact }} |
85 |
86 |
87 | {% trans 'Comment' %}: |
88 |
89 | {{ asset.comment|safe }}
90 | |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | {% endblock %}
105 |
106 | {% block custom_foot_js %}
107 |
112 | {% endblock %}
113 |
--------------------------------------------------------------------------------
/certs/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/certs/urls/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:19
6 | # @Version : 1.0
7 | # @File : __init__.py
8 | # @Software : PyCharm
--------------------------------------------------------------------------------
/certs/urls/api_urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:19
6 | # @Version : 1.0
7 | # @File : api_urls
8 | # @Software : PyCharm
9 |
10 | from certs import api
11 |
12 | from rest_framework_bulk.routes import BulkRouter
13 |
14 | app_name = 'certs'
15 |
16 | router = BulkRouter()
17 |
18 | # 证书
19 | router.register(r'v1/cert', api.CertViewSet, 'cert')
20 |
21 | urlpatterns = []
22 | urlpatterns += router.urls
23 |
--------------------------------------------------------------------------------
/certs/urls/views_urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:19
6 | # @Version : 1.0
7 | # @File : views_urls
8 | # @Software : PyCharm
9 |
10 |
11 | from django.conf.urls import url
12 | from certs import views
13 |
14 | app_name = 'certs'
15 |
16 | urlpatterns = [
17 | # 证书
18 | url(r'^$', views.CertListView.as_view(), name='cert-index'),
19 | url(r'^create/$', views.CertCreateView.as_view(), name='cert-create'),
20 | url(r'^(?P[0-9a-zA-Z\-]{36})/update/$', views.CertUpdateView.as_view(),
21 | name='cert-update'),
22 | url(r'^(?P[0-9a-zA-Z\-]{36})/$', views.CertDetailView.as_view(), name='cert-detail'),
23 | ]
24 |
--------------------------------------------------------------------------------
/certs/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-5 下午5:24
6 | # @Version : 1.0
7 | # @File : utils
8 | # @Software : PyCharm
9 |
10 |
11 | from datetime import datetime
12 | from urllib3.contrib import pyopenssl as reqs
13 |
14 |
15 | # 从域名或pem文件解析SSL证书,获取签发信息
16 | def load_certificate(method, obj):
17 | if method == 0:
18 | cert = reqs.ssl.get_server_certificate((obj, 443))
19 | elif method == 1:
20 | cert = obj
21 | else:
22 | return {}
23 |
24 | try:
25 | x509 = reqs.OpenSSL.crypto.load_certificate(reqs.OpenSSL.crypto.FILETYPE_PEM, cert)
26 | notbefore = datetime.strptime(x509.get_notBefore().decode()[0:-1], '%Y%m%d%H%M%S')
27 | notafter = datetime.strptime(x509.get_notAfter().decode()[0:-1], '%Y%m%d%H%M%S')
28 | remain_days = notafter - datetime.now()
29 | organization_name = x509.get_subject().organizationName
30 | serial_number = x509.get_subject().serialNumber
31 |
32 | if serial_number:
33 | cert_type = 'EV'
34 | elif not organization_name:
35 | cert_type = 'DV'
36 | else:
37 | cert_type = 'OV'
38 |
39 | ret_json = {
40 | 'domain': x509.get_subject().CN,
41 | 'orther_domain': reqs.get_subj_alt_name(x509),
42 | 'organization_name': organization_name,
43 | 'serial_number': serial_number,
44 | 'issued_by': x509.get_issuer().CN,
45 | 'cert_type': cert_type,
46 | 'notbefore': notbefore.strftime('%Y-%m-%d %H:%M:%S'),
47 | 'notafter': notafter.strftime('%Y-%m-%d %H:%M:%S'),
48 | 'remain_days': remain_days.days,
49 | }
50 | except Exception as e:
51 | raise Exception(e)
52 | return ret_json
53 |
--------------------------------------------------------------------------------
/certs/views.py:
--------------------------------------------------------------------------------
1 | from django.contrib.messages.views import SuccessMessageMixin
2 | from django.shortcuts import render
3 | from django.urls import reverse_lazy
4 | from django.views.generic import TemplateView, CreateView, UpdateView, DetailView
5 |
6 | from django.utils.translation import ugettext as _
7 |
8 | from users.utils import create_success_msg
9 | from cert_manage.utils import AdminUserRequiredMixin
10 |
11 | from certs import forms
12 | from certs.models import Certs
13 |
14 |
15 | # Create your views here.
16 |
17 |
18 | class CertListView(AdminUserRequiredMixin, TemplateView):
19 | """
20 | 列出所有证书
21 | """
22 | template_name = 'cert/cert_list.html'
23 |
24 | def get_context_data(self, **kwargs):
25 | context = {
26 | 'app': _('Cert'),
27 | 'action': _('List')
28 | }
29 | kwargs.update(context)
30 | return super().get_context_data(**kwargs)
31 |
32 |
33 | class CertCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
34 | '''
35 | 创建证书
36 | '''
37 | model = Certs
38 | form_class = forms.CertCreateUpdateForm
39 | template_name = 'cert/cert_create_update.html'
40 |
41 | def get_form(self, form_class=None):
42 | form = super().get_form(form_class=form_class)
43 | return form
44 |
45 | # 重写get_form_kwargs,在initial中传入参数pk
46 | def get_form_kwargs(self):
47 | kwargs = super(CertCreateView, self).get_form_kwargs()
48 | if hasattr(self, 'object'):
49 | kwargs.update({'instance': self.object})
50 | kwargs['initial']['pk'] = False
51 | return kwargs
52 |
53 | def get_context_data(self, **kwargs):
54 | context = {
55 | 'app': _('Cert'),
56 | 'action': _('Create'),
57 | }
58 | kwargs.update(context)
59 | return super().get_context_data(**kwargs)
60 |
61 | def get_success_message(self, cleaned_data):
62 | return create_success_msg % ({"name": cleaned_data["name"]})
63 |
64 | def get_success_url(self):
65 | return reverse_lazy('certs:cert-index')
66 |
67 |
68 | class CertUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
69 | '''
70 | 更新证书
71 | '''
72 | model = Certs
73 | form_class = forms.CertCreateUpdateForm
74 | template_name = 'cert/cert_create_update.html'
75 |
76 | def get_form(self, form_class=None):
77 | form = super().get_form(form_class=form_class)
78 | return form
79 |
80 | # 重写get_form_kwargs,在initial中传入参数pk
81 | def get_form_kwargs(self):
82 | kwargs = super(CertUpdateView, self).get_form_kwargs()
83 | if hasattr(self, 'object'):
84 | kwargs.update({'instance': self.object})
85 | kwargs['initial']['pk'] = self.kwargs.get('pk')
86 | return kwargs
87 |
88 | def get_context_data(self, **kwargs):
89 | context = {
90 | 'app': _('Cert'),
91 | 'action': _('Update'),
92 | }
93 | kwargs.update(context)
94 | return super().get_context_data(**kwargs)
95 |
96 | def get_success_message(self, cleaned_data):
97 | return create_success_msg % ({"name": cleaned_data["name"]})
98 |
99 | def get_success_url(self):
100 | return reverse_lazy('certs:cert-index')
101 |
102 |
103 | class CertDetailView(AdminUserRequiredMixin, DetailView):
104 | '''
105 | 证书详细信息
106 | '''
107 | model = Certs
108 | context_object_name = 'cert'
109 | template_name = 'cert/cert_detail.html'
110 |
111 | def get_context_data(self, **kwargs):
112 | context = {
113 | 'app': _('Cert'),
114 | 'action': _('Detail'),
115 | }
116 | kwargs.update(context)
117 | return super().get_context_data(**kwargs)
118 |
--------------------------------------------------------------------------------
/config_example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-2 下午9:13
6 | # @Version : 1.0
7 | # @File : config
8 | # @Software : PyCharm
9 |
10 | import os
11 |
12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__))
13 |
14 |
15 | class Config:
16 | SECRET_KEY = os.environ.get('SECRET_KEY') or 'l(=lclv!iupi^%v5ybysmkcv8&a@b9^4lj#=!379r#yh=o^tk_'
17 |
18 | # Django security setting. if your disable debug model, you should setting that
19 | ALLOWED_HOSTS = ['*']
20 |
21 | # Development env open this, when error occur display the full process track, Production disable it
22 | DEBUG = True
23 |
24 | # DEBUG, INFO, WARNING, ERROR, CRITICAL can set. See https://docs.djangoproject.com/en/1.10/topics/logging/
25 | LOG_LEVEL = 'DEBUG'
26 | LOG_DIR = os.path.join(BASE_DIR, 'logs')
27 |
28 | # Database setting, Support sqlite3, mysql, postgres ....
29 | # See https://docs.djangoproject.com/en/1.10/ref/settings/#databases
30 |
31 | # SQLite setting:
32 | DB_ENGINE = 'sqlite3'
33 | DB_NAME = os.path.join(BASE_DIR, 'data', 'db.sqlite3')
34 |
35 | # MySQL or postgres setting like:
36 | # DB_ENGINE = 'mysql'
37 | # DB_HOST = '127.0.0.1'
38 | # DB_PORT = 3306
39 | # DB_USER = 'root'
40 | # DB_PASSWORD = ''
41 | # DB_NAME = 'cert_manage'
42 |
43 | # When Django start it will bind this host and port
44 | # ./manage.py runserver 127.0.0.1:8080
45 | HTTP_BIND_HOST = '127.0.0.1'
46 | HTTP_LISTEN_PORT = 8080
47 |
48 | # Use Redis as broker for celery and web socket
49 | REDIS_HOST = '127.0.0.1'
50 | REDIS_PORT = 6379
51 | REDIS_PASSWORD = ''
52 | BROKER_URL = 'redis://%(password)s@%(host)s:%(port)s/3' % {
53 | 'password': REDIS_PASSWORD,
54 | 'host': REDIS_HOST,
55 | 'port': REDIS_PORT,
56 | }
57 |
58 | def __init__(self):
59 | pass
60 |
61 | def __getattr__(self, item):
62 | return None
63 |
64 |
65 | class DevelopmentConfig(Config):
66 | pass
67 |
68 |
69 | class TestConfig(Config):
70 | pass
71 |
72 |
73 | class ProductionConfig(Config):
74 | pass
75 |
76 |
77 | # Default using Config settings, you can write if/else for different env
78 | config = DevelopmentConfig()
79 |
--------------------------------------------------------------------------------
/data/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/data/.gitkeep
--------------------------------------------------------------------------------
/logs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/logs/.gitkeep
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cert_manage.settings')
9 | try:
10 | from django.core.management import execute_from_command_line
11 | except ImportError as exc:
12 | raise ImportError(
13 | "Couldn't import Django. Are you sure it's installed and "
14 | "available on your PYTHONPATH environment variable? Did you "
15 | "forget to activate a virtual environment?"
16 | ) from exc
17 | execute_from_command_line(sys.argv)
18 |
19 |
20 | if __name__ == '__main__':
21 | main()
22 |
--------------------------------------------------------------------------------
/requirements/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/requirements/.gitkeep
--------------------------------------------------------------------------------
/requirements/requirements.txt:
--------------------------------------------------------------------------------
1 | amqp==2.5.1
2 | anyjson==0.3.3
3 | asn1crypto==0.24.0
4 | billiard==3.6.1.0
5 | celery==4.3.0
6 | cffi==1.12.3
7 | cryptography==2.7
8 | Django==2.1.11
9 | django-bootstrap3==11.1.0
10 | django-celery-beat==1.5.0
11 | django-filter==2.2.0
12 | django-ranged-response==0.2.0
13 | django-redis-cache==2.0.0
14 | django-simple-captcha==0.5.12
15 | django-timezone-field==3.0
16 | djangorestframework==3.10.2
17 | djangorestframework-bulk==0.2.1
18 | gunicorn==19.9.0
19 | idna==2.8
20 | importlib-metadata==0.20
21 | kombu==4.6.4
22 | more-itertools==7.2.0
23 | passlib==1.7.1
24 | Pillow==6.1.0
25 | pycparser==2.19
26 | pyOpenSSL==19.0.0
27 | python-crontab==2.3.8
28 | python-dateutil==2.8.0
29 | pytz==2019.2
30 | redis==3.3.8
31 | six==1.12.0
32 | sqlparse==0.3.0
33 | urllib3==1.25.3
34 | vine==1.3.0
35 | zipp==0.6.0
36 |
--------------------------------------------------------------------------------
/run_server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 下午9:18
6 | # @Version : 1.0
7 | # @File : run_server
8 | # @Software : PyCharm
9 |
10 | import sys
11 | import subprocess
12 |
13 | if __name__ == '__main__':
14 | subprocess.call('python3 cms start all', shell=True,
15 | stdin=sys.stdin, stdout=sys.stdout)
16 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-brands.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Brands';
7 | font-style: normal;
8 | font-weight: normal;
9 | src: url("../webfonts/fa-brands-400.eot");
10 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); }
11 |
12 | .fab {
13 | font-family: 'Font Awesome 5 Brands'; }
14 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-brands.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-regular.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 400;
9 | src: url("../webfonts/fa-regular-400.eot");
10 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); }
11 |
12 | .far {
13 | font-family: 'Font Awesome 5 Free';
14 | font-weight: 400; }
15 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-regular.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:Font Awesome\ 5 Free;font-weight:400}
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-solid.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 900;
9 | src: url("../webfonts/fa-solid-900.eot");
10 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
11 |
12 | .fa,
13 | .fas {
14 | font-family: 'Font Awesome 5 Free';
15 | font-weight: 900; }
16 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/css/fa-solid.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:Font Awesome\ 5 Free;font-weight:900}
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_animated.less:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .@{fa-css-prefix}-spin {
5 | animation: fa-spin 2s infinite linear;
6 | }
7 |
8 | .@{fa-css-prefix}-pulse {
9 | animation: fa-spin 1s infinite steps(8);
10 | }
11 |
12 | @keyframes fa-spin {
13 | 0% {
14 | transform: rotate(0deg);
15 | }
16 | 100% {
17 | transform: rotate(360deg);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_bordered-pulled.less:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-border {
5 | border-radius: .1em;
6 | border: solid .08em @fa-border-color;
7 | padding: .2em .25em .15em;
8 | }
9 |
10 | .@{fa-css-prefix}-pull-left { float: left; }
11 | .@{fa-css-prefix}-pull-right { float: right; }
12 |
13 | .@{fa-css-prefix}, .fas, .far, .fal, .fab {
14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; }
15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; }
16 | }
17 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_core.less:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}, .fas, .far, .fal, .fab {
5 | -moz-osx-font-smoothing: grayscale;
6 | -webkit-font-smoothing: antialiased;
7 | display: inline-block;
8 | font-style: normal;
9 | font-variant: normal;
10 | text-rendering: auto;
11 | line-height: 1;
12 | }
13 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_fixed-width.less:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .@{fa-css-prefix}-fw {
4 | text-align: center;
5 | width: (20em / 16);
6 | }
7 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_larger.less:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | .larger(@factor) when (@factor > 0) {
5 | .larger((@factor - 1));
6 |
7 | .@{fa-css-prefix}-@{factor}x {
8 | font-size: (@factor * 1em);
9 | }
10 | }
11 |
12 | /* makes the font 33% larger relative to the icon container */
13 | .@{fa-css-prefix}-lg {
14 | font-size: (4em / 3);
15 | line-height: (3em / 4);
16 | vertical-align: -.0667em;
17 | }
18 |
19 | .@{fa-css-prefix}-xs {
20 | font-size: .75em;
21 | }
22 |
23 | .@{fa-css-prefix}-sm {
24 | font-size: .875em;
25 | }
26 |
27 | .larger(10);
28 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_list.less:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-ul {
5 | list-style-type: none;
6 | margin-left: @fa-li-width * 5/4;
7 | padding-left: 0;
8 |
9 | > li { position: relative; }
10 | }
11 |
12 | .@{fa-css-prefix}-li {
13 | left: -@fa-li-width;
14 | position: absolute;
15 | text-align: center;
16 | width: @fa-li-width;
17 | line-height: inherit;
18 | }
19 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_mixins.less:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | .fa-icon() {
5 | -moz-osx-font-smoothing: grayscale;
6 | -webkit-font-smoothing: antialiased;
7 | display: inline-block;
8 | font-style: normal;
9 | font-variant: normal;
10 | font-weight: normal;
11 | line-height: 1;
12 | vertical-align: -.125em;
13 | }
14 |
15 | .fa-icon-rotate(@degrees, @rotation) {
16 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
17 | transform: rotate(@degrees);
18 | }
19 |
20 | .fa-icon-flip(@horiz, @vert, @rotation) {
21 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
22 | transform: scale(@horiz, @vert);
23 | }
24 |
25 |
26 | // Only display content to screen readers. A la Bootstrap 4.
27 | //
28 | // See: http://a11yproject.com/posts/how-to-hide-content/
29 |
30 | .sr-only() {
31 | border: 0;
32 | clip: rect(0,0,0,0);
33 | height: 1px;
34 | margin: -1px;
35 | overflow: hidden;
36 | padding: 0;
37 | position: absolute;
38 | width: 1px;
39 | }
40 |
41 | // Use in conjunction with .sr-only to only display content when it's focused.
42 | //
43 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
44 | //
45 | // Credit: HTML5 Boilerplate
46 |
47 | .sr-only-focusable() {
48 | &:active,
49 | &:focus {
50 | clip: auto;
51 | height: auto;
52 | margin: 0;
53 | overflow: visible;
54 | position: static;
55 | width: auto;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_rotated-flipped.less:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); }
5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); }
6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); }
7 |
8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); }
9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); }
10 | .@{fa-css-prefix}-flip-horizontal.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(-1, -1, 2); }
11 |
12 | // Hook for IE8-9
13 | // -------------------------
14 |
15 | :root {
16 | .@{fa-css-prefix}-rotate-90,
17 | .@{fa-css-prefix}-rotate-180,
18 | .@{fa-css-prefix}-rotate-270,
19 | .@{fa-css-prefix}-flip-horizontal,
20 | .@{fa-css-prefix}-flip-vertical {
21 | filter: none;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_screen-reader.less:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { .sr-only(); }
5 | .sr-only-focusable { .sr-only-focusable(); }
6 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/_stacked.less:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .@{fa-css-prefix}-stack {
5 | display: inline-block;
6 | height: 2em;
7 | line-height: 2em;
8 | position: relative;
9 | vertical-align: middle;
10 | width: 2em;
11 | }
12 |
13 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x {
14 | left: 0;
15 | position: absolute;
16 | text-align: center;
17 | width: 100%;
18 | }
19 |
20 | .@{fa-css-prefix}-stack-1x { line-height: inherit; }
21 | .@{fa-css-prefix}-stack-2x { font-size: 2em; }
22 | .@{fa-css-prefix}-inverse { color: @fa-inverse; }
23 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/fa-brands.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import "_variables.less";
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Brands';
9 | font-style: normal;
10 | font-weight: normal;
11 | src: url('@{fa-font-path}/fa-brands-400.eot');
12 | src: url('@{fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'),
13 | url('@{fa-font-path}/fa-brands-400.woff2') format('woff2'),
14 | url('@{fa-font-path}/fa-brands-400.woff') format('woff'),
15 | url('@{fa-font-path}/fa-brands-400.ttf') format('truetype'),
16 | url('@{fa-font-path}/fa-brands-400.svg#fontawesome') format('svg');
17 | }
18 |
19 | .fab {
20 | font-family: 'Font Awesome 5 Brands';
21 | }
22 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/fa-regular.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import "_variables.less";
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Free';
9 | font-style: normal;
10 | font-weight: 400;
11 | src: url('@{fa-font-path}/fa-regular-400.eot');
12 | src: url('@{fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'),
13 | url('@{fa-font-path}/fa-regular-400.woff2') format('woff2'),
14 | url('@{fa-font-path}/fa-regular-400.woff') format('woff'),
15 | url('@{fa-font-path}/fa-regular-400.ttf') format('truetype'),
16 | url('@{fa-font-path}/fa-regular-400.svg#fontawesome') format('svg');
17 | }
18 |
19 | .far {
20 | font-family: 'Font Awesome 5 Free';
21 | font-weight: 400;
22 | }
23 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/fa-solid.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import "_variables.less";
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Free';
9 | font-style: normal;
10 | font-weight: 900;
11 | src: url('@{fa-font-path}/fa-solid-900.eot');
12 | src: url('@{fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'),
13 | url('@{fa-font-path}/fa-solid-900.woff2') format('woff2'),
14 | url('@{fa-font-path}/fa-solid-900.woff') format('woff'),
15 | url('@{fa-font-path}/fa-solid-900.ttf') format('truetype'),
16 | url('@{fa-font-path}/fa-solid-900.svg#fontawesome') format('svg');
17 | }
18 |
19 | .fa,
20 | .fas {
21 | font-family: 'Font Awesome 5 Free';
22 | font-weight: 900;
23 | }
24 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/less/fontawesome.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import "_variables.less";
6 | @import "_mixins.less";
7 | @import "_core.less";
8 | @import "_larger.less";
9 | @import "_fixed-width.less";
10 | @import "_list.less";
11 | @import "_bordered-pulled.less";
12 | @import "_animated.less";
13 | @import "_rotated-flipped.less";
14 | @import "_stacked.less";
15 | @import "_icons.less";
16 | @import "_screen-reader.less";
17 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_animated.scss:
--------------------------------------------------------------------------------
1 | // Animated Icons
2 | // --------------------------
3 |
4 | .#{$fa-css-prefix}-spin {
5 | animation: fa-spin 2s infinite linear;
6 | }
7 |
8 | .#{$fa-css-prefix}-pulse {
9 | animation: fa-spin 1s infinite steps(8);
10 | }
11 |
12 | @keyframes fa-spin {
13 | 0% {
14 | transform: rotate(0deg);
15 | }
16 |
17 | 100% {
18 | transform: rotate(360deg);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_bordered-pulled.scss:
--------------------------------------------------------------------------------
1 | // Bordered & Pulled
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-border {
5 | border: solid .08em $fa-border-color;
6 | border-radius: .1em;
7 | padding: .2em .25em .15em;
8 | }
9 |
10 | .#{$fa-css-prefix}-pull-left { float: left; }
11 | .#{$fa-css-prefix}-pull-right { float: right; }
12 |
13 | .#{$fa-css-prefix},
14 | .fas,
15 | .far,
16 | .fal,
17 | .fab {
18 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
19 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
20 | }
21 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_core.scss:
--------------------------------------------------------------------------------
1 | // Base Class Definition
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix},
5 | .fas,
6 | .far,
7 | .fal,
8 | .fab {
9 | -moz-osx-font-smoothing: grayscale;
10 | -webkit-font-smoothing: antialiased;
11 | display: inline-block;
12 | font-style: normal;
13 | font-variant: normal;
14 | text-rendering: auto;
15 | line-height: 1;
16 | }
17 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_fixed-width.scss:
--------------------------------------------------------------------------------
1 | // Fixed Width Icons
2 | // -------------------------
3 | .#{$fa-css-prefix}-fw {
4 | text-align: center;
5 | width: (20em / 16);
6 | }
7 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_larger.scss:
--------------------------------------------------------------------------------
1 | // Icon Sizes
2 | // -------------------------
3 |
4 | // makes the font 33% larger relative to the icon container
5 | .#{$fa-css-prefix}-lg {
6 | font-size: (4em / 3);
7 | line-height: (3em / 4);
8 | vertical-align: -.0667em;
9 | }
10 |
11 | .#{$fa-css-prefix}-xs {
12 | font-size: .75em;
13 | }
14 |
15 | .#{$fa-css-prefix}-sm {
16 | font-size: .875em;
17 | }
18 |
19 | @for $i from 1 through 10 {
20 | .#{$fa-css-prefix}-#{$i}x {
21 | font-size: $i * 1em;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_list.scss:
--------------------------------------------------------------------------------
1 | // List Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-ul {
5 | list-style-type: none;
6 | margin-left: $fa-li-width * 5/4;
7 | padding-left: 0;
8 |
9 | > li { position: relative; }
10 | }
11 |
12 | .#{$fa-css-prefix}-li {
13 | left: -$fa-li-width;
14 | position: absolute;
15 | text-align: center;
16 | width: $fa-li-width;
17 | line-height: inherit;
18 | }
19 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Mixins
2 | // --------------------------
3 |
4 | @mixin fa-icon {
5 | -webkit-font-smoothing: antialiased;
6 | -moz-osx-font-smoothing: grayscale;
7 | display: inline-block;
8 | font-style: normal;
9 | font-variant: normal;
10 | font-weight: normal;
11 | line-height: 1;
12 | vertical-align: -.125em;
13 | }
14 |
15 | @mixin fa-icon-rotate($degrees, $rotation) {
16 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
17 | transform: rotate($degrees);
18 | }
19 |
20 | @mixin fa-icon-flip($horiz, $vert, $rotation) {
21 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
22 | transform: scale($horiz, $vert);
23 | }
24 |
25 |
26 | // Only display content to screen readers. A la Bootstrap 4.
27 | //
28 | // See: http://a11yproject.com/posts/how-to-hide-content/
29 |
30 | @mixin sr-only {
31 | border: 0;
32 | clip: rect(0, 0, 0, 0);
33 | height: 1px;
34 | margin: -1px;
35 | overflow: hidden;
36 | padding: 0;
37 | position: absolute;
38 | width: 1px;
39 | }
40 |
41 | // Use in conjunction with .sr-only to only display content when it's focused.
42 | //
43 | // Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
44 | //
45 | // Credit: HTML5 Boilerplate
46 |
47 | @mixin sr-only-focusable {
48 | &:active,
49 | &:focus {
50 | clip: auto;
51 | height: auto;
52 | margin: 0;
53 | overflow: visible;
54 | position: static;
55 | width: auto;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_rotated-flipped.scss:
--------------------------------------------------------------------------------
1 | // Rotated & Flipped Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); }
5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); }
6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); }
7 |
8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); }
9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); }
10 | .#{$fa-css-prefix}-flip-horizontal.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(-1, -1, 2); }
11 |
12 | // Hook for IE8-9
13 | // -------------------------
14 |
15 | :root {
16 | .#{$fa-css-prefix}-rotate-90,
17 | .#{$fa-css-prefix}-rotate-180,
18 | .#{$fa-css-prefix}-rotate-270,
19 | .#{$fa-css-prefix}-flip-horizontal,
20 | .#{$fa-css-prefix}-flip-vertical {
21 | filter: none;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_screen-reader.scss:
--------------------------------------------------------------------------------
1 | // Screen Readers
2 | // -------------------------
3 |
4 | .sr-only { @include sr-only; }
5 | .sr-only-focusable { @include sr-only-focusable; }
6 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/_stacked.scss:
--------------------------------------------------------------------------------
1 | // Stacked Icons
2 | // -------------------------
3 |
4 | .#{$fa-css-prefix}-stack {
5 | display: inline-block;
6 | height: 2em;
7 | line-height: 2em;
8 | position: relative;
9 | vertical-align: middle;
10 | width: 2em;
11 | }
12 |
13 | .#{$fa-css-prefix}-stack-1x,
14 | .#{$fa-css-prefix}-stack-2x {
15 | left: 0;
16 | position: absolute;
17 | text-align: center;
18 | width: 100%;
19 | }
20 |
21 | .#{$fa-css-prefix}-stack-1x {
22 | line-height: inherit;
23 | }
24 |
25 | .#{$fa-css-prefix}-stack-2x {
26 | font-size: 2em;
27 | }
28 |
29 | .#{$fa-css-prefix}-inverse {
30 | color: $fa-inverse;
31 | }
32 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/fa-brands.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import 'variables';
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Brands';
9 | font-style: normal;
10 | font-weight: normal;
11 | src: url('#{$fa-font-path}/fa-brands-400.eot');
12 | src: url('#{$fa-font-path}/fa-brands-400.eot?#iefix') format('embedded-opentype'),
13 | url('#{$fa-font-path}/fa-brands-400.woff2') format('woff2'),
14 | url('#{$fa-font-path}/fa-brands-400.woff') format('woff'),
15 | url('#{$fa-font-path}/fa-brands-400.ttf') format('truetype'),
16 | url('#{$fa-font-path}/fa-brands-400.svg#fontawesome') format('svg');
17 | }
18 |
19 | .fab {
20 | font-family: 'Font Awesome 5 Brands';
21 | }
22 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/fa-regular.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import 'variables';
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Free';
9 | font-style: normal;
10 | font-weight: 400;
11 | src: url('#{$fa-font-path}/fa-regular-400.eot');
12 | src: url('#{$fa-font-path}/fa-regular-400.eot?#iefix') format('embedded-opentype'),
13 | url('#{$fa-font-path}/fa-regular-400.woff2') format('woff2'),
14 | url('#{$fa-font-path}/fa-regular-400.woff') format('woff'),
15 | url('#{$fa-font-path}/fa-regular-400.ttf') format('truetype'),
16 | url('#{$fa-font-path}/fa-regular-400.svg#fontawesome') format('svg');
17 | }
18 |
19 | .far {
20 | font-family: 'Font Awesome 5 Free';
21 | font-weight: 400;
22 | }
23 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/fa-solid.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import 'variables';
6 |
7 | @font-face {
8 | font-family: 'Font Awesome 5 Free';
9 | font-style: normal;
10 | font-weight: 900;
11 | src: url('#{$fa-font-path}/fa-solid-900.eot');
12 | src: url('#{$fa-font-path}/fa-solid-900.eot?#iefix') format('embedded-opentype'),
13 | url('#{$fa-font-path}/fa-solid-900.woff2') format('woff2'),
14 | url('#{$fa-font-path}/fa-solid-900.woff') format('woff'),
15 | url('#{$fa-font-path}/fa-solid-900.ttf') format('truetype'),
16 | url('#{$fa-font-path}/fa-solid-900.svg#fontawesome') format('svg');
17 | }
18 |
19 | .fa,
20 | .fas {
21 | font-family: 'Font Awesome 5 Free';
22 | font-weight: 900;
23 | }
24 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/scss/fontawesome.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.0.13 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @import 'variables';
6 | @import 'mixins';
7 | @import 'core';
8 | @import 'larger';
9 | @import 'fixed-width';
10 | @import 'list';
11 | @import 'bordered-pulled';
12 | @import 'animated';
13 | @import 'rotated-flipped';
14 | @import 'stacked';
15 | @import 'icons';
16 | @import 'screen-reader';
17 |
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/static/css/plugin/font-awesome/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/css/plugin/font-awesome/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-black-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Black
3 | * -----------
4 | */
5 | /* skin-black navbar */
6 | .skin-black-light .main-header {
7 | border-bottom: 1px solid #d2d6de;
8 | }
9 | .skin-black-light .main-header .navbar-toggle {
10 | color: #333;
11 | }
12 | .skin-black-light .main-header .navbar-brand {
13 | color: #333;
14 | border-right: 1px solid #d2d6de;
15 | }
16 | .skin-black-light .main-header .navbar {
17 | background-color: #ffffff;
18 | }
19 | .skin-black-light .main-header .navbar .nav > li > a {
20 | color: #333333;
21 | }
22 | .skin-black-light .main-header .navbar .nav > li > a:hover,
23 | .skin-black-light .main-header .navbar .nav > li > a:active,
24 | .skin-black-light .main-header .navbar .nav > li > a:focus,
25 | .skin-black-light .main-header .navbar .nav .open > a,
26 | .skin-black-light .main-header .navbar .nav .open > a:hover,
27 | .skin-black-light .main-header .navbar .nav .open > a:focus,
28 | .skin-black-light .main-header .navbar .nav > .active > a {
29 | background: #ffffff;
30 | color: #999999;
31 | }
32 | .skin-black-light .main-header .navbar .sidebar-toggle {
33 | color: #333333;
34 | }
35 | .skin-black-light .main-header .navbar .sidebar-toggle:hover {
36 | color: #999999;
37 | background: #ffffff;
38 | }
39 | .skin-black-light .main-header .navbar > .sidebar-toggle {
40 | color: #333;
41 | border-right: 1px solid #d2d6de;
42 | }
43 | .skin-black-light .main-header .navbar .navbar-nav > li > a {
44 | border-right: 1px solid #d2d6de;
45 | }
46 | .skin-black-light .main-header .navbar .navbar-custom-menu .navbar-nav > li > a,
47 | .skin-black-light .main-header .navbar .navbar-right > li > a {
48 | border-left: 1px solid #d2d6de;
49 | border-right-width: 0;
50 | }
51 | .skin-black-light .main-header > .logo {
52 | background-color: #ffffff;
53 | color: #333333;
54 | border-bottom: 0 solid transparent;
55 | border-right: 1px solid #d2d6de;
56 | }
57 | .skin-black-light .main-header > .logo:hover {
58 | background-color: #fcfcfc;
59 | }
60 | @media (max-width: 767px) {
61 | .skin-black-light .main-header > .logo {
62 | background-color: #222222;
63 | color: #ffffff;
64 | border-bottom: 0 solid transparent;
65 | border-right: none;
66 | }
67 | .skin-black-light .main-header > .logo:hover {
68 | background-color: #1f1f1f;
69 | }
70 | }
71 | .skin-black-light .main-header li.user-header {
72 | background-color: #222;
73 | }
74 | .skin-black-light .content-header {
75 | background: transparent;
76 | box-shadow: none;
77 | }
78 | .skin-black-light .wrapper,
79 | .skin-black-light .main-sidebar,
80 | .skin-black-light .left-side {
81 | background-color: #f9fafc;
82 | }
83 | .skin-black-light .main-sidebar {
84 | border-right: 1px solid #d2d6de;
85 | }
86 | .skin-black-light .user-panel > .info,
87 | .skin-black-light .user-panel > .info > a {
88 | color: #444444;
89 | }
90 | .skin-black-light .sidebar-menu > li {
91 | -webkit-transition: border-left-color 0.3s ease;
92 | -o-transition: border-left-color 0.3s ease;
93 | transition: border-left-color 0.3s ease;
94 | }
95 | .skin-black-light .sidebar-menu > li.header {
96 | color: #848484;
97 | background: #f9fafc;
98 | }
99 | .skin-black-light .sidebar-menu > li > a {
100 | border-left: 3px solid transparent;
101 | font-weight: 600;
102 | }
103 | .skin-black-light .sidebar-menu > li:hover > a,
104 | .skin-black-light .sidebar-menu > li.active > a {
105 | color: #000000;
106 | background: #f4f4f5;
107 | }
108 | .skin-black-light .sidebar-menu > li.active {
109 | border-left-color: #ffffff;
110 | }
111 | .skin-black-light .sidebar-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-black-light .sidebar-menu > li > .treeview-menu {
115 | background: #f4f4f5;
116 | }
117 | .skin-black-light .sidebar a {
118 | color: #444444;
119 | }
120 | .skin-black-light .sidebar a:hover {
121 | text-decoration: none;
122 | }
123 | .skin-black-light .sidebar-menu .treeview-menu > li > a {
124 | color: #777777;
125 | }
126 | .skin-black-light .sidebar-menu .treeview-menu > li.active > a,
127 | .skin-black-light .sidebar-menu .treeview-menu > li > a:hover {
128 | color: #000000;
129 | }
130 | .skin-black-light .sidebar-menu .treeview-menu > li.active > a {
131 | font-weight: 600;
132 | }
133 | .skin-black-light .sidebar-form {
134 | border-radius: 3px;
135 | border: 1px solid #d2d6de;
136 | margin: 10px 10px;
137 | }
138 | .skin-black-light .sidebar-form input[type="text"],
139 | .skin-black-light .sidebar-form .btn {
140 | box-shadow: none;
141 | background-color: #fff;
142 | border: 1px solid transparent;
143 | height: 35px;
144 | }
145 | .skin-black-light .sidebar-form input[type="text"] {
146 | color: #666;
147 | border-top-left-radius: 2px;
148 | border-top-right-radius: 0;
149 | border-bottom-right-radius: 0;
150 | border-bottom-left-radius: 2px;
151 | }
152 | .skin-black-light .sidebar-form input[type="text"]:focus,
153 | .skin-black-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
154 | background-color: #fff;
155 | color: #666;
156 | }
157 | .skin-black-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
158 | border-left-color: #fff;
159 | }
160 | .skin-black-light .sidebar-form .btn {
161 | color: #999;
162 | border-top-left-radius: 0;
163 | border-top-right-radius: 2px;
164 | border-bottom-right-radius: 2px;
165 | border-bottom-left-radius: 0;
166 | }
167 | @media (min-width: 768px) {
168 | .skin-black-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
169 | border-left: 1px solid #d2d6de;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-black-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-black-light .main-header{border-bottom:1px solid #d2d6de}.skin-black-light .main-header .navbar-toggle{color:#333}.skin-black-light .main-header .navbar-brand{color:#333;border-right:1px solid #d2d6de}.skin-black-light .main-header .navbar{background-color:#fff}.skin-black-light .main-header .navbar .nav>li>a{color:#333}.skin-black-light .main-header .navbar .nav>li>a:hover,.skin-black-light .main-header .navbar .nav>li>a:active,.skin-black-light .main-header .navbar .nav>li>a:focus,.skin-black-light .main-header .navbar .nav .open>a,.skin-black-light .main-header .navbar .nav .open>a:hover,.skin-black-light .main-header .navbar .nav .open>a:focus,.skin-black-light .main-header .navbar .nav>.active>a{background:#fff;color:#999}.skin-black-light .main-header .navbar .sidebar-toggle{color:#333}.skin-black-light .main-header .navbar .sidebar-toggle:hover{color:#999;background:#fff}.skin-black-light .main-header .navbar>.sidebar-toggle{color:#333;border-right:1px solid #d2d6de}.skin-black-light .main-header .navbar .navbar-nav>li>a{border-right:1px solid #d2d6de}.skin-black-light .main-header .navbar .navbar-custom-menu .navbar-nav>li>a,.skin-black-light .main-header .navbar .navbar-right>li>a{border-left:1px solid #d2d6de;border-right-width:0}.skin-black-light .main-header>.logo{background-color:#fff;color:#333;border-bottom:0 solid transparent;border-right:1px solid #d2d6de}.skin-black-light .main-header>.logo:hover{background-color:#fcfcfc}@media (max-width:767px){.skin-black-light .main-header>.logo{background-color:#222;color:#fff;border-bottom:0 solid transparent;border-right:none}.skin-black-light .main-header>.logo:hover{background-color:#1f1f1f}}.skin-black-light .main-header li.user-header{background-color:#222}.skin-black-light .content-header{background:transparent;box-shadow:none}.skin-black-light .wrapper,.skin-black-light .main-sidebar,.skin-black-light .left-side{background-color:#f9fafc}.skin-black-light .main-sidebar{border-right:1px solid #d2d6de}.skin-black-light .user-panel>.info,.skin-black-light .user-panel>.info>a{color:#444}.skin-black-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-black-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-black-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-black-light .sidebar-menu>li:hover>a,.skin-black-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-black-light .sidebar-menu>li.active{border-left-color:#fff}.skin-black-light .sidebar-menu>li.active>a{font-weight:600}.skin-black-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-black-light .sidebar a{color:#444}.skin-black-light .sidebar a:hover{text-decoration:none}.skin-black-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-black-light .sidebar-menu .treeview-menu>li.active>a,.skin-black-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-black-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-black-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-black-light .sidebar-form input[type="text"],.skin-black-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-black-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-black-light .sidebar-form input[type="text"]:focus,.skin-black-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-black-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-black.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Black
3 | * -----------
4 | */
5 | /* skin-black navbar */
6 | .skin-black .main-header {
7 | -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05);
8 | box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05);
9 | }
10 | .skin-black .main-header .navbar-toggle {
11 | color: #333;
12 | }
13 | .skin-black .main-header .navbar-brand {
14 | color: #333;
15 | border-right: 1px solid #eee;
16 | }
17 | .skin-black .main-header .navbar {
18 | background-color: #ffffff;
19 | }
20 | .skin-black .main-header .navbar .nav > li > a {
21 | color: #333333;
22 | }
23 | .skin-black .main-header .navbar .nav > li > a:hover,
24 | .skin-black .main-header .navbar .nav > li > a:active,
25 | .skin-black .main-header .navbar .nav > li > a:focus,
26 | .skin-black .main-header .navbar .nav .open > a,
27 | .skin-black .main-header .navbar .nav .open > a:hover,
28 | .skin-black .main-header .navbar .nav .open > a:focus,
29 | .skin-black .main-header .navbar .nav > .active > a {
30 | background: #ffffff;
31 | color: #999999;
32 | }
33 | .skin-black .main-header .navbar .sidebar-toggle {
34 | color: #333333;
35 | }
36 | .skin-black .main-header .navbar .sidebar-toggle:hover {
37 | color: #999999;
38 | background: #ffffff;
39 | }
40 | .skin-black .main-header .navbar > .sidebar-toggle {
41 | color: #333;
42 | border-right: 1px solid #eee;
43 | }
44 | .skin-black .main-header .navbar .navbar-nav > li > a {
45 | border-right: 1px solid #eee;
46 | }
47 | .skin-black .main-header .navbar .navbar-custom-menu .navbar-nav > li > a,
48 | .skin-black .main-header .navbar .navbar-right > li > a {
49 | border-left: 1px solid #eee;
50 | border-right-width: 0;
51 | }
52 | .skin-black .main-header > .logo {
53 | background-color: #ffffff;
54 | color: #333333;
55 | border-bottom: 0 solid transparent;
56 | border-right: 1px solid #eee;
57 | }
58 | .skin-black .main-header > .logo:hover {
59 | background-color: #fcfcfc;
60 | }
61 | @media (max-width: 767px) {
62 | .skin-black .main-header > .logo {
63 | background-color: #222222;
64 | color: #ffffff;
65 | border-bottom: 0 solid transparent;
66 | border-right: none;
67 | }
68 | .skin-black .main-header > .logo:hover {
69 | background-color: #1f1f1f;
70 | }
71 | }
72 | .skin-black .main-header li.user-header {
73 | background-color: #222;
74 | }
75 | .skin-black .content-header {
76 | background: transparent;
77 | box-shadow: none;
78 | }
79 | .skin-black .wrapper,
80 | .skin-black .main-sidebar,
81 | .skin-black .left-side {
82 | background-color: #222d32;
83 | }
84 | .skin-black .user-panel > .info,
85 | .skin-black .user-panel > .info > a {
86 | color: #fff;
87 | }
88 | .skin-black .sidebar-menu > li.header {
89 | color: #4b646f;
90 | background: #1a2226;
91 | }
92 | .skin-black .sidebar-menu > li > a {
93 | border-left: 3px solid transparent;
94 | }
95 | .skin-black .sidebar-menu > li:hover > a,
96 | .skin-black .sidebar-menu > li.active > a,
97 | .skin-black .sidebar-menu > li.menu-open > a {
98 | color: #ffffff;
99 | background: #1e282c;
100 | }
101 | .skin-black .sidebar-menu > li.active > a {
102 | border-left-color: #ffffff;
103 | }
104 | .skin-black .sidebar-menu > li > .treeview-menu {
105 | margin: 0 1px;
106 | background: #2c3b41;
107 | }
108 | .skin-black .sidebar a {
109 | color: #b8c7ce;
110 | }
111 | .skin-black .sidebar a:hover {
112 | text-decoration: none;
113 | }
114 | .skin-black .sidebar-menu .treeview-menu > li > a {
115 | color: #8aa4af;
116 | }
117 | .skin-black .sidebar-menu .treeview-menu > li.active > a,
118 | .skin-black .sidebar-menu .treeview-menu > li > a:hover {
119 | color: #ffffff;
120 | }
121 | .skin-black .sidebar-form {
122 | border-radius: 3px;
123 | border: 1px solid #374850;
124 | margin: 10px 10px;
125 | }
126 | .skin-black .sidebar-form input[type="text"],
127 | .skin-black .sidebar-form .btn {
128 | box-shadow: none;
129 | background-color: #374850;
130 | border: 1px solid transparent;
131 | height: 35px;
132 | }
133 | .skin-black .sidebar-form input[type="text"] {
134 | color: #666;
135 | border-top-left-radius: 2px;
136 | border-top-right-radius: 0;
137 | border-bottom-right-radius: 0;
138 | border-bottom-left-radius: 2px;
139 | }
140 | .skin-black .sidebar-form input[type="text"]:focus,
141 | .skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
142 | background-color: #fff;
143 | color: #666;
144 | }
145 | .skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
146 | border-left-color: #fff;
147 | }
148 | .skin-black .sidebar-form .btn {
149 | color: #999;
150 | border-top-left-radius: 0;
151 | border-top-right-radius: 2px;
152 | border-bottom-right-radius: 2px;
153 | border-bottom-left-radius: 0;
154 | }
155 | .skin-black .pace .pace-progress {
156 | background: #222;
157 | }
158 | .skin-black .pace .pace-activity {
159 | border-top-color: #222;
160 | border-left-color: #222;
161 | }
162 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-black.min.css:
--------------------------------------------------------------------------------
1 | .skin-black .main-header{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.skin-black .main-header .navbar-toggle{color:#333}.skin-black .main-header .navbar-brand{color:#333;border-right:1px solid #eee}.skin-black .main-header .navbar{background-color:#fff}.skin-black .main-header .navbar .nav>li>a{color:#333}.skin-black .main-header .navbar .nav>li>a:hover,.skin-black .main-header .navbar .nav>li>a:active,.skin-black .main-header .navbar .nav>li>a:focus,.skin-black .main-header .navbar .nav .open>a,.skin-black .main-header .navbar .nav .open>a:hover,.skin-black .main-header .navbar .nav .open>a:focus,.skin-black .main-header .navbar .nav>.active>a{background:#fff;color:#999}.skin-black .main-header .navbar .sidebar-toggle{color:#333}.skin-black .main-header .navbar .sidebar-toggle:hover{color:#999;background:#fff}.skin-black .main-header .navbar>.sidebar-toggle{color:#333;border-right:1px solid #eee}.skin-black .main-header .navbar .navbar-nav>li>a{border-right:1px solid #eee}.skin-black .main-header .navbar .navbar-custom-menu .navbar-nav>li>a,.skin-black .main-header .navbar .navbar-right>li>a{border-left:1px solid #eee;border-right-width:0}.skin-black .main-header>.logo{background-color:#fff;color:#333;border-bottom:0 solid transparent;border-right:1px solid #eee}.skin-black .main-header>.logo:hover{background-color:#fcfcfc}@media (max-width:767px){.skin-black .main-header>.logo{background-color:#222;color:#fff;border-bottom:0 solid transparent;border-right:none}.skin-black .main-header>.logo:hover{background-color:#1f1f1f}}.skin-black .main-header li.user-header{background-color:#222}.skin-black .content-header{background:transparent;box-shadow:none}.skin-black .wrapper,.skin-black .main-sidebar,.skin-black .left-side{background-color:#222d32}.skin-black .user-panel>.info,.skin-black .user-panel>.info>a{color:#fff}.skin-black .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-black .sidebar-menu>li>a{border-left:3px solid transparent}.skin-black .sidebar-menu>li:hover>a,.skin-black .sidebar-menu>li.active>a,.skin-black .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-black .sidebar-menu>li.active>a{border-left-color:#fff}.skin-black .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-black .sidebar a{color:#b8c7ce}.skin-black .sidebar a:hover{text-decoration:none}.skin-black .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-black .sidebar-menu .treeview-menu>li.active>a,.skin-black .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-black .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-black .sidebar-form input[type="text"],.skin-black .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-black .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-black .sidebar-form input[type="text"]:focus,.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-black .pace .pace-progress{background:#222}.skin-black .pace .pace-activity{border-top-color:#222;border-left-color:#222}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-blue-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Blue
3 | * ----------
4 | */
5 | .skin-blue-light .main-header .navbar {
6 | background-color: #3c8dbc;
7 | }
8 | .skin-blue-light .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-blue-light .main-header .navbar .nav > li > a:hover,
12 | .skin-blue-light .main-header .navbar .nav > li > a:active,
13 | .skin-blue-light .main-header .navbar .nav > li > a:focus,
14 | .skin-blue-light .main-header .navbar .nav .open > a,
15 | .skin-blue-light .main-header .navbar .nav .open > a:hover,
16 | .skin-blue-light .main-header .navbar .nav .open > a:focus,
17 | .skin-blue-light .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-blue-light .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-blue-light .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-blue-light .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-blue-light .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #367fa9;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-blue-light .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-blue-light .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-blue-light .main-header .navbar .dropdown-menu li a:hover {
42 | background: #367fa9;
43 | }
44 | }
45 | .skin-blue-light .main-header .logo {
46 | background-color: #3c8dbc;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-blue-light .main-header .logo:hover {
51 | background-color: #3b8ab8;
52 | }
53 | .skin-blue-light .main-header li.user-header {
54 | background-color: #3c8dbc;
55 | }
56 | .skin-blue-light .content-header {
57 | background: transparent;
58 | }
59 | .skin-blue-light .wrapper,
60 | .skin-blue-light .main-sidebar,
61 | .skin-blue-light .left-side {
62 | background-color: #f9fafc;
63 | }
64 | .skin-blue-light .main-sidebar {
65 | border-right: 1px solid #d2d6de;
66 | }
67 | .skin-blue-light .user-panel > .info,
68 | .skin-blue-light .user-panel > .info > a {
69 | color: #444444;
70 | }
71 | .skin-blue-light .sidebar-menu > li {
72 | -webkit-transition: border-left-color 0.3s ease;
73 | -o-transition: border-left-color 0.3s ease;
74 | transition: border-left-color 0.3s ease;
75 | }
76 | .skin-blue-light .sidebar-menu > li.header {
77 | color: #848484;
78 | background: #f9fafc;
79 | }
80 | .skin-blue-light .sidebar-menu > li > a {
81 | border-left: 3px solid transparent;
82 | font-weight: 600;
83 | }
84 | .skin-blue-light .sidebar-menu > li:hover > a,
85 | .skin-blue-light .sidebar-menu > li.active > a {
86 | color: #000000;
87 | background: #f4f4f5;
88 | }
89 | .skin-blue-light .sidebar-menu > li.active {
90 | border-left-color: #3c8dbc;
91 | }
92 | .skin-blue-light .sidebar-menu > li.active > a {
93 | font-weight: 600;
94 | }
95 | .skin-blue-light .sidebar-menu > li > .treeview-menu {
96 | background: #f4f4f5;
97 | }
98 | .skin-blue-light .sidebar a {
99 | color: #444444;
100 | }
101 | .skin-blue-light .sidebar a:hover {
102 | text-decoration: none;
103 | }
104 | .skin-blue-light .sidebar-menu .treeview-menu > li > a {
105 | color: #777777;
106 | }
107 | .skin-blue-light .sidebar-menu .treeview-menu > li.active > a,
108 | .skin-blue-light .sidebar-menu .treeview-menu > li > a:hover {
109 | color: #000000;
110 | }
111 | .skin-blue-light .sidebar-menu .treeview-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-blue-light .sidebar-form {
115 | border-radius: 3px;
116 | border: 1px solid #d2d6de;
117 | margin: 10px 10px;
118 | }
119 | .skin-blue-light .sidebar-form input[type="text"],
120 | .skin-blue-light .sidebar-form .btn {
121 | box-shadow: none;
122 | background-color: #fff;
123 | border: 1px solid transparent;
124 | height: 35px;
125 | }
126 | .skin-blue-light .sidebar-form input[type="text"] {
127 | color: #666;
128 | border-top-left-radius: 2px;
129 | border-top-right-radius: 0;
130 | border-bottom-right-radius: 0;
131 | border-bottom-left-radius: 2px;
132 | }
133 | .skin-blue-light .sidebar-form input[type="text"]:focus,
134 | .skin-blue-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
135 | background-color: #fff;
136 | color: #666;
137 | }
138 | .skin-blue-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
139 | border-left-color: #fff;
140 | }
141 | .skin-blue-light .sidebar-form .btn {
142 | color: #999;
143 | border-top-left-radius: 0;
144 | border-top-right-radius: 2px;
145 | border-bottom-right-radius: 2px;
146 | border-bottom-left-radius: 0;
147 | }
148 | @media (min-width: 768px) {
149 | .skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
150 | border-left: 1px solid #d2d6de;
151 | }
152 | }
153 | .skin-blue-light .main-footer {
154 | border-top-color: #d2d6de;
155 | }
156 | .skin-blue.layout-top-nav .main-header > .logo {
157 | background-color: #3c8dbc;
158 | color: #ffffff;
159 | border-bottom: 0 solid transparent;
160 | }
161 | .skin-blue.layout-top-nav .main-header > .logo:hover {
162 | background-color: #3b8ab8;
163 | }
164 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-blue-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-blue-light .main-header .navbar{background-color:#3c8dbc}.skin-blue-light .main-header .navbar .nav>li>a{color:#fff}.skin-blue-light .main-header .navbar .nav>li>a:hover,.skin-blue-light .main-header .navbar .nav>li>a:active,.skin-blue-light .main-header .navbar .nav>li>a:focus,.skin-blue-light .main-header .navbar .nav .open>a,.skin-blue-light .main-header .navbar .nav .open>a:hover,.skin-blue-light .main-header .navbar .nav .open>a:focus,.skin-blue-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue-light .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue-light .main-header .logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue-light .main-header .logo:hover{background-color:#3b8ab8}.skin-blue-light .main-header li.user-header{background-color:#3c8dbc}.skin-blue-light .content-header{background:transparent}.skin-blue-light .wrapper,.skin-blue-light .main-sidebar,.skin-blue-light .left-side{background-color:#f9fafc}.skin-blue-light .main-sidebar{border-right:1px solid #d2d6de}.skin-blue-light .user-panel>.info,.skin-blue-light .user-panel>.info>a{color:#444}.skin-blue-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-blue-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-blue-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-blue-light .sidebar-menu>li:hover>a,.skin-blue-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-blue-light .sidebar-menu>li.active{border-left-color:#3c8dbc}.skin-blue-light .sidebar-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-blue-light .sidebar a{color:#444}.skin-blue-light .sidebar a:hover{text-decoration:none}.skin-blue-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-blue-light .sidebar-menu .treeview-menu>li.active>a,.skin-blue-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-blue-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-blue-light .sidebar-form input[type="text"],.skin-blue-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-blue-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue-light .sidebar-form input[type="text"]:focus,.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-blue-light .main-footer{border-top-color:#d2d6de}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-blue.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Blue
3 | * ----------
4 | */
5 | .skin-blue .main-header .navbar {
6 | background-color: #3c8dbc;
7 | }
8 | .skin-blue .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-blue .main-header .navbar .nav > li > a:hover,
12 | .skin-blue .main-header .navbar .nav > li > a:active,
13 | .skin-blue .main-header .navbar .nav > li > a:focus,
14 | .skin-blue .main-header .navbar .nav .open > a,
15 | .skin-blue .main-header .navbar .nav .open > a:hover,
16 | .skin-blue .main-header .navbar .nav .open > a:focus,
17 | .skin-blue .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-blue .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-blue .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-blue .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-blue .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #367fa9;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-blue .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-blue .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-blue .main-header .navbar .dropdown-menu li a:hover {
42 | background: #367fa9;
43 | }
44 | }
45 | .skin-blue .main-header .logo {
46 | background-color: #367fa9;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-blue .main-header .logo:hover {
51 | background-color: #357ca5;
52 | }
53 | .skin-blue .main-header li.user-header {
54 | background-color: #3c8dbc;
55 | }
56 | .skin-blue .content-header {
57 | background: transparent;
58 | }
59 | .skin-blue .wrapper,
60 | .skin-blue .main-sidebar,
61 | .skin-blue .left-side {
62 | background-color: #222d32;
63 | }
64 | .skin-blue .user-panel > .info,
65 | .skin-blue .user-panel > .info > a {
66 | color: #fff;
67 | }
68 | .skin-blue .sidebar-menu > li.header {
69 | color: #4b646f;
70 | background: #1a2226;
71 | }
72 | .skin-blue .sidebar-menu > li > a {
73 | border-left: 3px solid transparent;
74 | }
75 | .skin-blue .sidebar-menu > li:hover > a,
76 | .skin-blue .sidebar-menu > li.active > a,
77 | .skin-blue .sidebar-menu > li.menu-open > a {
78 | color: #ffffff;
79 | background: #1e282c;
80 | }
81 | .skin-blue .sidebar-menu > li.active > a {
82 | border-left-color: #3c8dbc;
83 | }
84 | .skin-blue .sidebar-menu > li > .treeview-menu {
85 | margin: 0 1px;
86 | background: #2c3b41;
87 | }
88 | .skin-blue .sidebar a {
89 | color: #b8c7ce;
90 | }
91 | .skin-blue .sidebar a:hover {
92 | text-decoration: none;
93 | }
94 | .skin-blue .sidebar-menu .treeview-menu > li > a {
95 | color: #8aa4af;
96 | }
97 | .skin-blue .sidebar-menu .treeview-menu > li.active > a,
98 | .skin-blue .sidebar-menu .treeview-menu > li > a:hover {
99 | color: #ffffff;
100 | }
101 | .skin-blue .sidebar-form {
102 | border-radius: 3px;
103 | border: 1px solid #374850;
104 | margin: 10px 10px;
105 | }
106 | .skin-blue .sidebar-form input[type="text"],
107 | .skin-blue .sidebar-form .btn {
108 | box-shadow: none;
109 | background-color: #374850;
110 | border: 1px solid transparent;
111 | height: 35px;
112 | }
113 | .skin-blue .sidebar-form input[type="text"] {
114 | color: #666;
115 | border-top-left-radius: 2px;
116 | border-top-right-radius: 0;
117 | border-bottom-right-radius: 0;
118 | border-bottom-left-radius: 2px;
119 | }
120 | .skin-blue .sidebar-form input[type="text"]:focus,
121 | .skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
122 | background-color: #fff;
123 | color: #666;
124 | }
125 | .skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
126 | border-left-color: #fff;
127 | }
128 | .skin-blue .sidebar-form .btn {
129 | color: #999;
130 | border-top-left-radius: 0;
131 | border-top-right-radius: 2px;
132 | border-bottom-right-radius: 2px;
133 | border-bottom-left-radius: 0;
134 | }
135 | .skin-blue.layout-top-nav .main-header > .logo {
136 | background-color: #3c8dbc;
137 | color: #ffffff;
138 | border-bottom: 0 solid transparent;
139 | }
140 | .skin-blue.layout-top-nav .main-header > .logo:hover {
141 | background-color: #3b8ab8;
142 | }
143 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-blue.min.css:
--------------------------------------------------------------------------------
1 | .skin-blue .main-header .navbar{background-color:#3c8dbc}.skin-blue .main-header .navbar .nav>li>a{color:#fff}.skin-blue .main-header .navbar .nav>li>a:hover,.skin-blue .main-header .navbar .nav>li>a:active,.skin-blue .main-header .navbar .nav>li>a:focus,.skin-blue .main-header .navbar .nav .open>a,.skin-blue .main-header .navbar .nav .open>a:hover,.skin-blue .main-header .navbar .nav .open>a:focus,.skin-blue .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue .main-header .logo{background-color:#367fa9;color:#fff;border-bottom:0 solid transparent}.skin-blue .main-header .logo:hover{background-color:#357ca5}.skin-blue .main-header li.user-header{background-color:#3c8dbc}.skin-blue .content-header{background:transparent}.skin-blue .wrapper,.skin-blue .main-sidebar,.skin-blue .left-side{background-color:#222d32}.skin-blue .user-panel>.info,.skin-blue .user-panel>.info>a{color:#fff}.skin-blue .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-blue .sidebar-menu>li>a{border-left:3px solid transparent}.skin-blue .sidebar-menu>li:hover>a,.skin-blue .sidebar-menu>li.active>a,.skin-blue .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-blue .sidebar-menu>li.active>a{border-left-color:#3c8dbc}.skin-blue .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-blue .sidebar a{color:#b8c7ce}.skin-blue .sidebar a:hover{text-decoration:none}.skin-blue .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-blue .sidebar-menu .treeview-menu>li.active>a,.skin-blue .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-blue .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-blue .sidebar-form input[type="text"],.skin-blue .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-blue .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue .sidebar-form input[type="text"]:focus,.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-green-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Green
3 | * -----------
4 | */
5 | .skin-green-light .main-header .navbar {
6 | background-color: #00a65a;
7 | }
8 | .skin-green-light .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-green-light .main-header .navbar .nav > li > a:hover,
12 | .skin-green-light .main-header .navbar .nav > li > a:active,
13 | .skin-green-light .main-header .navbar .nav > li > a:focus,
14 | .skin-green-light .main-header .navbar .nav .open > a,
15 | .skin-green-light .main-header .navbar .nav .open > a:hover,
16 | .skin-green-light .main-header .navbar .nav .open > a:focus,
17 | .skin-green-light .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-green-light .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-green-light .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-green-light .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-green-light .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #008d4c;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-green-light .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-green-light .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-green-light .main-header .navbar .dropdown-menu li a:hover {
42 | background: #008d4c;
43 | }
44 | }
45 | .skin-green-light .main-header .logo {
46 | background-color: #00a65a;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-green-light .main-header .logo:hover {
51 | background-color: #00a157;
52 | }
53 | .skin-green-light .main-header li.user-header {
54 | background-color: #00a65a;
55 | }
56 | .skin-green-light .content-header {
57 | background: transparent;
58 | }
59 | .skin-green-light .wrapper,
60 | .skin-green-light .main-sidebar,
61 | .skin-green-light .left-side {
62 | background-color: #f9fafc;
63 | }
64 | .skin-green-light .main-sidebar {
65 | border-right: 1px solid #d2d6de;
66 | }
67 | .skin-green-light .user-panel > .info,
68 | .skin-green-light .user-panel > .info > a {
69 | color: #444444;
70 | }
71 | .skin-green-light .sidebar-menu > li {
72 | -webkit-transition: border-left-color 0.3s ease;
73 | -o-transition: border-left-color 0.3s ease;
74 | transition: border-left-color 0.3s ease;
75 | }
76 | .skin-green-light .sidebar-menu > li.header {
77 | color: #848484;
78 | background: #f9fafc;
79 | }
80 | .skin-green-light .sidebar-menu > li > a {
81 | border-left: 3px solid transparent;
82 | font-weight: 600;
83 | }
84 | .skin-green-light .sidebar-menu > li:hover > a,
85 | .skin-green-light .sidebar-menu > li.active > a {
86 | color: #000000;
87 | background: #f4f4f5;
88 | }
89 | .skin-green-light .sidebar-menu > li.active {
90 | border-left-color: #00a65a;
91 | }
92 | .skin-green-light .sidebar-menu > li.active > a {
93 | font-weight: 600;
94 | }
95 | .skin-green-light .sidebar-menu > li > .treeview-menu {
96 | background: #f4f4f5;
97 | }
98 | .skin-green-light .sidebar a {
99 | color: #444444;
100 | }
101 | .skin-green-light .sidebar a:hover {
102 | text-decoration: none;
103 | }
104 | .skin-green-light .sidebar-menu .treeview-menu > li > a {
105 | color: #777777;
106 | }
107 | .skin-green-light .sidebar-menu .treeview-menu > li.active > a,
108 | .skin-green-light .sidebar-menu .treeview-menu > li > a:hover {
109 | color: #000000;
110 | }
111 | .skin-green-light .sidebar-menu .treeview-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-green-light .sidebar-form {
115 | border-radius: 3px;
116 | border: 1px solid #d2d6de;
117 | margin: 10px 10px;
118 | }
119 | .skin-green-light .sidebar-form input[type="text"],
120 | .skin-green-light .sidebar-form .btn {
121 | box-shadow: none;
122 | background-color: #fff;
123 | border: 1px solid transparent;
124 | height: 35px;
125 | }
126 | .skin-green-light .sidebar-form input[type="text"] {
127 | color: #666;
128 | border-top-left-radius: 2px;
129 | border-top-right-radius: 0;
130 | border-bottom-right-radius: 0;
131 | border-bottom-left-radius: 2px;
132 | }
133 | .skin-green-light .sidebar-form input[type="text"]:focus,
134 | .skin-green-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
135 | background-color: #fff;
136 | color: #666;
137 | }
138 | .skin-green-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
139 | border-left-color: #fff;
140 | }
141 | .skin-green-light .sidebar-form .btn {
142 | color: #999;
143 | border-top-left-radius: 0;
144 | border-top-right-radius: 2px;
145 | border-bottom-right-radius: 2px;
146 | border-bottom-left-radius: 0;
147 | }
148 | @media (min-width: 768px) {
149 | .skin-green-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
150 | border-left: 1px solid #d2d6de;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-green-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-green-light .main-header .navbar{background-color:#00a65a}.skin-green-light .main-header .navbar .nav>li>a{color:#fff}.skin-green-light .main-header .navbar .nav>li>a:hover,.skin-green-light .main-header .navbar .nav>li>a:active,.skin-green-light .main-header .navbar .nav>li>a:focus,.skin-green-light .main-header .navbar .nav .open>a,.skin-green-light .main-header .navbar .nav .open>a:hover,.skin-green-light .main-header .navbar .nav .open>a:focus,.skin-green-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-green-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-green-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-green-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-green-light .main-header .navbar .sidebar-toggle:hover{background-color:#008d4c}@media (max-width:767px){.skin-green-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-green-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-green-light .main-header .navbar .dropdown-menu li a:hover{background:#008d4c}}.skin-green-light .main-header .logo{background-color:#00a65a;color:#fff;border-bottom:0 solid transparent}.skin-green-light .main-header .logo:hover{background-color:#00a157}.skin-green-light .main-header li.user-header{background-color:#00a65a}.skin-green-light .content-header{background:transparent}.skin-green-light .wrapper,.skin-green-light .main-sidebar,.skin-green-light .left-side{background-color:#f9fafc}.skin-green-light .main-sidebar{border-right:1px solid #d2d6de}.skin-green-light .user-panel>.info,.skin-green-light .user-panel>.info>a{color:#444}.skin-green-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-green-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-green-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-green-light .sidebar-menu>li:hover>a,.skin-green-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-green-light .sidebar-menu>li.active{border-left-color:#00a65a}.skin-green-light .sidebar-menu>li.active>a{font-weight:600}.skin-green-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-green-light .sidebar a{color:#444}.skin-green-light .sidebar a:hover{text-decoration:none}.skin-green-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-green-light .sidebar-menu .treeview-menu>li.active>a,.skin-green-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-green-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-green-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-green-light .sidebar-form input[type="text"],.skin-green-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-green-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-green-light .sidebar-form input[type="text"]:focus,.skin-green-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-green-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-green-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-green-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-green.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Green
3 | * -----------
4 | */
5 | .skin-green .main-header .navbar {
6 | background-color: #00a65a;
7 | }
8 | .skin-green .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-green .main-header .navbar .nav > li > a:hover,
12 | .skin-green .main-header .navbar .nav > li > a:active,
13 | .skin-green .main-header .navbar .nav > li > a:focus,
14 | .skin-green .main-header .navbar .nav .open > a,
15 | .skin-green .main-header .navbar .nav .open > a:hover,
16 | .skin-green .main-header .navbar .nav .open > a:focus,
17 | .skin-green .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-green .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-green .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-green .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-green .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #008d4c;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-green .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-green .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-green .main-header .navbar .dropdown-menu li a:hover {
42 | background: #008d4c;
43 | }
44 | }
45 | .skin-green .main-header .logo {
46 | background-color: #008d4c;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-green .main-header .logo:hover {
51 | background-color: #008749;
52 | }
53 | .skin-green .main-header li.user-header {
54 | background-color: #00a65a;
55 | }
56 | .skin-green .content-header {
57 | background: transparent;
58 | }
59 | .skin-green .wrapper,
60 | .skin-green .main-sidebar,
61 | .skin-green .left-side {
62 | background-color: #222d32;
63 | }
64 | .skin-green .user-panel > .info,
65 | .skin-green .user-panel > .info > a {
66 | color: #fff;
67 | }
68 | .skin-green .sidebar-menu > li.header {
69 | color: #4b646f;
70 | background: #1a2226;
71 | }
72 | .skin-green .sidebar-menu > li > a {
73 | border-left: 3px solid transparent;
74 | }
75 | .skin-green .sidebar-menu > li:hover > a,
76 | .skin-green .sidebar-menu > li.active > a,
77 | .skin-green .sidebar-menu > li.menu-open > a {
78 | color: #ffffff;
79 | background: #1e282c;
80 | }
81 | .skin-green .sidebar-menu > li.active > a {
82 | border-left-color: #00a65a;
83 | }
84 | .skin-green .sidebar-menu > li > .treeview-menu {
85 | margin: 0 1px;
86 | background: #2c3b41;
87 | }
88 | .skin-green .sidebar a {
89 | color: #b8c7ce;
90 | }
91 | .skin-green .sidebar a:hover {
92 | text-decoration: none;
93 | }
94 | .skin-green .sidebar-menu .treeview-menu > li > a {
95 | color: #8aa4af;
96 | }
97 | .skin-green .sidebar-menu .treeview-menu > li.active > a,
98 | .skin-green .sidebar-menu .treeview-menu > li > a:hover {
99 | color: #ffffff;
100 | }
101 | .skin-green .sidebar-form {
102 | border-radius: 3px;
103 | border: 1px solid #374850;
104 | margin: 10px 10px;
105 | }
106 | .skin-green .sidebar-form input[type="text"],
107 | .skin-green .sidebar-form .btn {
108 | box-shadow: none;
109 | background-color: #374850;
110 | border: 1px solid transparent;
111 | height: 35px;
112 | }
113 | .skin-green .sidebar-form input[type="text"] {
114 | color: #666;
115 | border-top-left-radius: 2px;
116 | border-top-right-radius: 0;
117 | border-bottom-right-radius: 0;
118 | border-bottom-left-radius: 2px;
119 | }
120 | .skin-green .sidebar-form input[type="text"]:focus,
121 | .skin-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
122 | background-color: #fff;
123 | color: #666;
124 | }
125 | .skin-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
126 | border-left-color: #fff;
127 | }
128 | .skin-green .sidebar-form .btn {
129 | color: #999;
130 | border-top-left-radius: 0;
131 | border-top-right-radius: 2px;
132 | border-bottom-right-radius: 2px;
133 | border-bottom-left-radius: 0;
134 | }
135 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-green.min.css:
--------------------------------------------------------------------------------
1 | .skin-green .main-header .navbar{background-color:#00a65a}.skin-green .main-header .navbar .nav>li>a{color:#fff}.skin-green .main-header .navbar .nav>li>a:hover,.skin-green .main-header .navbar .nav>li>a:active,.skin-green .main-header .navbar .nav>li>a:focus,.skin-green .main-header .navbar .nav .open>a,.skin-green .main-header .navbar .nav .open>a:hover,.skin-green .main-header .navbar .nav .open>a:focus,.skin-green .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{background-color:#008d4c}@media (max-width:767px){.skin-green .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-green .main-header .navbar .dropdown-menu li a{color:#fff}.skin-green .main-header .navbar .dropdown-menu li a:hover{background:#008d4c}}.skin-green .main-header .logo{background-color:#008d4c;color:#fff;border-bottom:0 solid transparent}.skin-green .main-header .logo:hover{background-color:#008749}.skin-green .main-header li.user-header{background-color:#00a65a}.skin-green .content-header{background:transparent}.skin-green .wrapper,.skin-green .main-sidebar,.skin-green .left-side{background-color:#222d32}.skin-green .user-panel>.info,.skin-green .user-panel>.info>a{color:#fff}.skin-green .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-green .sidebar-menu>li>a{border-left:3px solid transparent}.skin-green .sidebar-menu>li:hover>a,.skin-green .sidebar-menu>li.active>a,.skin-green .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-green .sidebar-menu>li.active>a{border-left-color:#00a65a}.skin-green .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-green .sidebar a{color:#b8c7ce}.skin-green .sidebar a:hover{text-decoration:none}.skin-green .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-green .sidebar-menu .treeview-menu>li.active>a,.skin-green .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-green .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-green .sidebar-form input[type="text"],.skin-green .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-green .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-green .sidebar-form input[type="text"]:focus,.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-green .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-purple-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Purple
3 | * ------------
4 | */
5 | .skin-purple-light .main-header .navbar {
6 | background-color: #605ca8;
7 | }
8 | .skin-purple-light .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-purple-light .main-header .navbar .nav > li > a:hover,
12 | .skin-purple-light .main-header .navbar .nav > li > a:active,
13 | .skin-purple-light .main-header .navbar .nav > li > a:focus,
14 | .skin-purple-light .main-header .navbar .nav .open > a,
15 | .skin-purple-light .main-header .navbar .nav .open > a:hover,
16 | .skin-purple-light .main-header .navbar .nav .open > a:focus,
17 | .skin-purple-light .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-purple-light .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-purple-light .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-purple-light .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-purple-light .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #555299;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-purple-light .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-purple-light .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-purple-light .main-header .navbar .dropdown-menu li a:hover {
42 | background: #555299;
43 | }
44 | }
45 | .skin-purple-light .main-header .logo {
46 | background-color: #605ca8;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-purple-light .main-header .logo:hover {
51 | background-color: #5d59a6;
52 | }
53 | .skin-purple-light .main-header li.user-header {
54 | background-color: #605ca8;
55 | }
56 | .skin-purple-light .content-header {
57 | background: transparent;
58 | }
59 | .skin-purple-light .wrapper,
60 | .skin-purple-light .main-sidebar,
61 | .skin-purple-light .left-side {
62 | background-color: #f9fafc;
63 | }
64 | .skin-purple-light .main-sidebar {
65 | border-right: 1px solid #d2d6de;
66 | }
67 | .skin-purple-light .user-panel > .info,
68 | .skin-purple-light .user-panel > .info > a {
69 | color: #444444;
70 | }
71 | .skin-purple-light .sidebar-menu > li {
72 | -webkit-transition: border-left-color 0.3s ease;
73 | -o-transition: border-left-color 0.3s ease;
74 | transition: border-left-color 0.3s ease;
75 | }
76 | .skin-purple-light .sidebar-menu > li.header {
77 | color: #848484;
78 | background: #f9fafc;
79 | }
80 | .skin-purple-light .sidebar-menu > li > a {
81 | border-left: 3px solid transparent;
82 | font-weight: 600;
83 | }
84 | .skin-purple-light .sidebar-menu > li:hover > a,
85 | .skin-purple-light .sidebar-menu > li.active > a {
86 | color: #000000;
87 | background: #f4f4f5;
88 | }
89 | .skin-purple-light .sidebar-menu > li.active {
90 | border-left-color: #605ca8;
91 | }
92 | .skin-purple-light .sidebar-menu > li.active > a {
93 | font-weight: 600;
94 | }
95 | .skin-purple-light .sidebar-menu > li > .treeview-menu {
96 | background: #f4f4f5;
97 | }
98 | .skin-purple-light .sidebar a {
99 | color: #444444;
100 | }
101 | .skin-purple-light .sidebar a:hover {
102 | text-decoration: none;
103 | }
104 | .skin-purple-light .sidebar-menu .treeview-menu > li > a {
105 | color: #777777;
106 | }
107 | .skin-purple-light .sidebar-menu .treeview-menu > li.active > a,
108 | .skin-purple-light .sidebar-menu .treeview-menu > li > a:hover {
109 | color: #000000;
110 | }
111 | .skin-purple-light .sidebar-menu .treeview-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-purple-light .sidebar-form {
115 | border-radius: 3px;
116 | border: 1px solid #d2d6de;
117 | margin: 10px 10px;
118 | }
119 | .skin-purple-light .sidebar-form input[type="text"],
120 | .skin-purple-light .sidebar-form .btn {
121 | box-shadow: none;
122 | background-color: #fff;
123 | border: 1px solid transparent;
124 | height: 35px;
125 | }
126 | .skin-purple-light .sidebar-form input[type="text"] {
127 | color: #666;
128 | border-top-left-radius: 2px;
129 | border-top-right-radius: 0;
130 | border-bottom-right-radius: 0;
131 | border-bottom-left-radius: 2px;
132 | }
133 | .skin-purple-light .sidebar-form input[type="text"]:focus,
134 | .skin-purple-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
135 | background-color: #fff;
136 | color: #666;
137 | }
138 | .skin-purple-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
139 | border-left-color: #fff;
140 | }
141 | .skin-purple-light .sidebar-form .btn {
142 | color: #999;
143 | border-top-left-radius: 0;
144 | border-top-right-radius: 2px;
145 | border-bottom-right-radius: 2px;
146 | border-bottom-left-radius: 0;
147 | }
148 | @media (min-width: 768px) {
149 | .skin-purple-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
150 | border-left: 1px solid #d2d6de;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-purple-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-purple-light .main-header .navbar{background-color:#605ca8}.skin-purple-light .main-header .navbar .nav>li>a{color:#fff}.skin-purple-light .main-header .navbar .nav>li>a:hover,.skin-purple-light .main-header .navbar .nav>li>a:active,.skin-purple-light .main-header .navbar .nav>li>a:focus,.skin-purple-light .main-header .navbar .nav .open>a,.skin-purple-light .main-header .navbar .nav .open>a:hover,.skin-purple-light .main-header .navbar .nav .open>a:focus,.skin-purple-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-purple-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-purple-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple-light .main-header .navbar .sidebar-toggle:hover{background-color:#555299}@media (max-width:767px){.skin-purple-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-purple-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-purple-light .main-header .navbar .dropdown-menu li a:hover{background:#555299}}.skin-purple-light .main-header .logo{background-color:#605ca8;color:#fff;border-bottom:0 solid transparent}.skin-purple-light .main-header .logo:hover{background-color:#5d59a6}.skin-purple-light .main-header li.user-header{background-color:#605ca8}.skin-purple-light .content-header{background:transparent}.skin-purple-light .wrapper,.skin-purple-light .main-sidebar,.skin-purple-light .left-side{background-color:#f9fafc}.skin-purple-light .main-sidebar{border-right:1px solid #d2d6de}.skin-purple-light .user-panel>.info,.skin-purple-light .user-panel>.info>a{color:#444}.skin-purple-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-purple-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-purple-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-purple-light .sidebar-menu>li:hover>a,.skin-purple-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-purple-light .sidebar-menu>li.active{border-left-color:#605ca8}.skin-purple-light .sidebar-menu>li.active>a{font-weight:600}.skin-purple-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-purple-light .sidebar a{color:#444}.skin-purple-light .sidebar a:hover{text-decoration:none}.skin-purple-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-purple-light .sidebar-menu .treeview-menu>li.active>a,.skin-purple-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-purple-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-purple-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-purple-light .sidebar-form input[type="text"],.skin-purple-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-purple-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-purple-light .sidebar-form input[type="text"]:focus,.skin-purple-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-purple-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-purple-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-purple-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-purple.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Purple
3 | * ------------
4 | */
5 | .skin-purple .main-header .navbar {
6 | background-color: #605ca8;
7 | }
8 | .skin-purple .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-purple .main-header .navbar .nav > li > a:hover,
12 | .skin-purple .main-header .navbar .nav > li > a:active,
13 | .skin-purple .main-header .navbar .nav > li > a:focus,
14 | .skin-purple .main-header .navbar .nav .open > a,
15 | .skin-purple .main-header .navbar .nav .open > a:hover,
16 | .skin-purple .main-header .navbar .nav .open > a:focus,
17 | .skin-purple .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-purple .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-purple .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-purple .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-purple .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #555299;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-purple .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-purple .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-purple .main-header .navbar .dropdown-menu li a:hover {
42 | background: #555299;
43 | }
44 | }
45 | .skin-purple .main-header .logo {
46 | background-color: #555299;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-purple .main-header .logo:hover {
51 | background-color: #545096;
52 | }
53 | .skin-purple .main-header li.user-header {
54 | background-color: #605ca8;
55 | }
56 | .skin-purple .content-header {
57 | background: transparent;
58 | }
59 | .skin-purple .wrapper,
60 | .skin-purple .main-sidebar,
61 | .skin-purple .left-side {
62 | background-color: #222d32;
63 | }
64 | .skin-purple .user-panel > .info,
65 | .skin-purple .user-panel > .info > a {
66 | color: #fff;
67 | }
68 | .skin-purple .sidebar-menu > li.header {
69 | color: #4b646f;
70 | background: #1a2226;
71 | }
72 | .skin-purple .sidebar-menu > li > a {
73 | border-left: 3px solid transparent;
74 | }
75 | .skin-purple .sidebar-menu > li:hover > a,
76 | .skin-purple .sidebar-menu > li.active > a,
77 | .skin-purple .sidebar-menu > li.menu-open > a {
78 | color: #ffffff;
79 | background: #1e282c;
80 | }
81 | .skin-purple .sidebar-menu > li.active > a {
82 | border-left-color: #605ca8;
83 | }
84 | .skin-purple .sidebar-menu > li > .treeview-menu {
85 | margin: 0 1px;
86 | background: #2c3b41;
87 | }
88 | .skin-purple .sidebar a {
89 | color: #b8c7ce;
90 | }
91 | .skin-purple .sidebar a:hover {
92 | text-decoration: none;
93 | }
94 | .skin-purple .sidebar-menu .treeview-menu > li > a {
95 | color: #8aa4af;
96 | }
97 | .skin-purple .sidebar-menu .treeview-menu > li.active > a,
98 | .skin-purple .sidebar-menu .treeview-menu > li > a:hover {
99 | color: #ffffff;
100 | }
101 | .skin-purple .sidebar-form {
102 | border-radius: 3px;
103 | border: 1px solid #374850;
104 | margin: 10px 10px;
105 | }
106 | .skin-purple .sidebar-form input[type="text"],
107 | .skin-purple .sidebar-form .btn {
108 | box-shadow: none;
109 | background-color: #374850;
110 | border: 1px solid transparent;
111 | height: 35px;
112 | }
113 | .skin-purple .sidebar-form input[type="text"] {
114 | color: #666;
115 | border-top-left-radius: 2px;
116 | border-top-right-radius: 0;
117 | border-bottom-right-radius: 0;
118 | border-bottom-left-radius: 2px;
119 | }
120 | .skin-purple .sidebar-form input[type="text"]:focus,
121 | .skin-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
122 | background-color: #fff;
123 | color: #666;
124 | }
125 | .skin-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
126 | border-left-color: #fff;
127 | }
128 | .skin-purple .sidebar-form .btn {
129 | color: #999;
130 | border-top-left-radius: 0;
131 | border-top-right-radius: 2px;
132 | border-bottom-right-radius: 2px;
133 | border-bottom-left-radius: 0;
134 | }
135 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-purple.min.css:
--------------------------------------------------------------------------------
1 | .skin-purple .main-header .navbar{background-color:#605ca8}.skin-purple .main-header .navbar .nav>li>a{color:#fff}.skin-purple .main-header .navbar .nav>li>a:hover,.skin-purple .main-header .navbar .nav>li>a:active,.skin-purple .main-header .navbar .nav>li>a:focus,.skin-purple .main-header .navbar .nav .open>a,.skin-purple .main-header .navbar .nav .open>a:hover,.skin-purple .main-header .navbar .nav .open>a:focus,.skin-purple .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{background-color:#555299}@media (max-width:767px){.skin-purple .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-purple .main-header .navbar .dropdown-menu li a{color:#fff}.skin-purple .main-header .navbar .dropdown-menu li a:hover{background:#555299}}.skin-purple .main-header .logo{background-color:#555299;color:#fff;border-bottom:0 solid transparent}.skin-purple .main-header .logo:hover{background-color:#545096}.skin-purple .main-header li.user-header{background-color:#605ca8}.skin-purple .content-header{background:transparent}.skin-purple .wrapper,.skin-purple .main-sidebar,.skin-purple .left-side{background-color:#222d32}.skin-purple .user-panel>.info,.skin-purple .user-panel>.info>a{color:#fff}.skin-purple .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-purple .sidebar-menu>li>a{border-left:3px solid transparent}.skin-purple .sidebar-menu>li:hover>a,.skin-purple .sidebar-menu>li.active>a,.skin-purple .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-purple .sidebar-menu>li.active>a{border-left-color:#605ca8}.skin-purple .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-purple .sidebar a{color:#b8c7ce}.skin-purple .sidebar a:hover{text-decoration:none}.skin-purple .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-purple .sidebar-menu .treeview-menu>li.active>a,.skin-purple .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-purple .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-purple .sidebar-form input[type="text"],.skin-purple .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-purple .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-purple .sidebar-form input[type="text"]:focus,.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-purple .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-red-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Red
3 | * ---------
4 | */
5 | .skin-red-light .main-header .navbar {
6 | background-color: #dd4b39;
7 | }
8 | .skin-red-light .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-red-light .main-header .navbar .nav > li > a:hover,
12 | .skin-red-light .main-header .navbar .nav > li > a:active,
13 | .skin-red-light .main-header .navbar .nav > li > a:focus,
14 | .skin-red-light .main-header .navbar .nav .open > a,
15 | .skin-red-light .main-header .navbar .nav .open > a:hover,
16 | .skin-red-light .main-header .navbar .nav .open > a:focus,
17 | .skin-red-light .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-red-light .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-red-light .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-red-light .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-red-light .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #d73925;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-red-light .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-red-light .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-red-light .main-header .navbar .dropdown-menu li a:hover {
42 | background: #d73925;
43 | }
44 | }
45 | .skin-red-light .main-header .logo {
46 | background-color: #dd4b39;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-red-light .main-header .logo:hover {
51 | background-color: #dc4735;
52 | }
53 | .skin-red-light .main-header li.user-header {
54 | background-color: #dd4b39;
55 | }
56 | .skin-red-light .content-header {
57 | background: transparent;
58 | }
59 | .skin-red-light .wrapper,
60 | .skin-red-light .main-sidebar,
61 | .skin-red-light .left-side {
62 | background-color: #f9fafc;
63 | }
64 | .skin-red-light .main-sidebar {
65 | border-right: 1px solid #d2d6de;
66 | }
67 | .skin-red-light .user-panel > .info,
68 | .skin-red-light .user-panel > .info > a {
69 | color: #444444;
70 | }
71 | .skin-red-light .sidebar-menu > li {
72 | -webkit-transition: border-left-color 0.3s ease;
73 | -o-transition: border-left-color 0.3s ease;
74 | transition: border-left-color 0.3s ease;
75 | }
76 | .skin-red-light .sidebar-menu > li.header {
77 | color: #848484;
78 | background: #f9fafc;
79 | }
80 | .skin-red-light .sidebar-menu > li > a {
81 | border-left: 3px solid transparent;
82 | font-weight: 600;
83 | }
84 | .skin-red-light .sidebar-menu > li:hover > a,
85 | .skin-red-light .sidebar-menu > li.active > a {
86 | color: #000000;
87 | background: #f4f4f5;
88 | }
89 | .skin-red-light .sidebar-menu > li.active {
90 | border-left-color: #dd4b39;
91 | }
92 | .skin-red-light .sidebar-menu > li.active > a {
93 | font-weight: 600;
94 | }
95 | .skin-red-light .sidebar-menu > li > .treeview-menu {
96 | background: #f4f4f5;
97 | }
98 | .skin-red-light .sidebar a {
99 | color: #444444;
100 | }
101 | .skin-red-light .sidebar a:hover {
102 | text-decoration: none;
103 | }
104 | .skin-red-light .sidebar-menu .treeview-menu > li > a {
105 | color: #777777;
106 | }
107 | .skin-red-light .sidebar-menu .treeview-menu > li.active > a,
108 | .skin-red-light .sidebar-menu .treeview-menu > li > a:hover {
109 | color: #000000;
110 | }
111 | .skin-red-light .sidebar-menu .treeview-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-red-light .sidebar-form {
115 | border-radius: 3px;
116 | border: 1px solid #d2d6de;
117 | margin: 10px 10px;
118 | }
119 | .skin-red-light .sidebar-form input[type="text"],
120 | .skin-red-light .sidebar-form .btn {
121 | box-shadow: none;
122 | background-color: #fff;
123 | border: 1px solid transparent;
124 | height: 35px;
125 | }
126 | .skin-red-light .sidebar-form input[type="text"] {
127 | color: #666;
128 | border-top-left-radius: 2px;
129 | border-top-right-radius: 0;
130 | border-bottom-right-radius: 0;
131 | border-bottom-left-radius: 2px;
132 | }
133 | .skin-red-light .sidebar-form input[type="text"]:focus,
134 | .skin-red-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
135 | background-color: #fff;
136 | color: #666;
137 | }
138 | .skin-red-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
139 | border-left-color: #fff;
140 | }
141 | .skin-red-light .sidebar-form .btn {
142 | color: #999;
143 | border-top-left-radius: 0;
144 | border-top-right-radius: 2px;
145 | border-bottom-right-radius: 2px;
146 | border-bottom-left-radius: 0;
147 | }
148 | @media (min-width: 768px) {
149 | .skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
150 | border-left: 1px solid #d2d6de;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-red-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-red-light .main-header .navbar{background-color:#dd4b39}.skin-red-light .main-header .navbar .nav>li>a{color:#fff}.skin-red-light .main-header .navbar .nav>li>a:hover,.skin-red-light .main-header .navbar .nav>li>a:active,.skin-red-light .main-header .navbar .nav>li>a:focus,.skin-red-light .main-header .navbar .nav .open>a,.skin-red-light .main-header .navbar .nav .open>a:hover,.skin-red-light .main-header .navbar .nav .open>a:focus,.skin-red-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red-light .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red-light .main-header .logo{background-color:#dd4b39;color:#fff;border-bottom:0 solid transparent}.skin-red-light .main-header .logo:hover{background-color:#dc4735}.skin-red-light .main-header li.user-header{background-color:#dd4b39}.skin-red-light .content-header{background:transparent}.skin-red-light .wrapper,.skin-red-light .main-sidebar,.skin-red-light .left-side{background-color:#f9fafc}.skin-red-light .main-sidebar{border-right:1px solid #d2d6de}.skin-red-light .user-panel>.info,.skin-red-light .user-panel>.info>a{color:#444}.skin-red-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-red-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-red-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-red-light .sidebar-menu>li:hover>a,.skin-red-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-red-light .sidebar-menu>li.active{border-left-color:#dd4b39}.skin-red-light .sidebar-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-red-light .sidebar a{color:#444}.skin-red-light .sidebar a:hover{text-decoration:none}.skin-red-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-red-light .sidebar-menu .treeview-menu>li.active>a,.skin-red-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-red-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-red-light .sidebar-form input[type="text"],.skin-red-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-red-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red-light .sidebar-form input[type="text"]:focus,.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-red.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Red
3 | * ---------
4 | */
5 | .skin-red .main-header .navbar {
6 | background-color: #dd4b39;
7 | }
8 | .skin-red .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-red .main-header .navbar .nav > li > a:hover,
12 | .skin-red .main-header .navbar .nav > li > a:active,
13 | .skin-red .main-header .navbar .nav > li > a:focus,
14 | .skin-red .main-header .navbar .nav .open > a,
15 | .skin-red .main-header .navbar .nav .open > a:hover,
16 | .skin-red .main-header .navbar .nav .open > a:focus,
17 | .skin-red .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-red .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-red .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-red .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-red .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #d73925;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-red .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-red .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-red .main-header .navbar .dropdown-menu li a:hover {
42 | background: #d73925;
43 | }
44 | }
45 | .skin-red .main-header .logo {
46 | background-color: #d73925;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-red .main-header .logo:hover {
51 | background-color: #d33724;
52 | }
53 | .skin-red .main-header li.user-header {
54 | background-color: #dd4b39;
55 | }
56 | .skin-red .content-header {
57 | background: transparent;
58 | }
59 | .skin-red .wrapper,
60 | .skin-red .main-sidebar,
61 | .skin-red .left-side {
62 | background-color: #222d32;
63 | }
64 | .skin-red .user-panel > .info,
65 | .skin-red .user-panel > .info > a {
66 | color: #fff;
67 | }
68 | .skin-red .sidebar-menu > li.header {
69 | color: #4b646f;
70 | background: #1a2226;
71 | }
72 | .skin-red .sidebar-menu > li > a {
73 | border-left: 3px solid transparent;
74 | }
75 | .skin-red .sidebar-menu > li:hover > a,
76 | .skin-red .sidebar-menu > li.active > a,
77 | .skin-red .sidebar-menu > li.menu-open > a {
78 | color: #ffffff;
79 | background: #1e282c;
80 | }
81 | .skin-red .sidebar-menu > li.active > a {
82 | border-left-color: #dd4b39;
83 | }
84 | .skin-red .sidebar-menu > li > .treeview-menu {
85 | margin: 0 1px;
86 | background: #2c3b41;
87 | }
88 | .skin-red .sidebar a {
89 | color: #b8c7ce;
90 | }
91 | .skin-red .sidebar a:hover {
92 | text-decoration: none;
93 | }
94 | .skin-red .sidebar-menu .treeview-menu > li > a {
95 | color: #8aa4af;
96 | }
97 | .skin-red .sidebar-menu .treeview-menu > li.active > a,
98 | .skin-red .sidebar-menu .treeview-menu > li > a:hover {
99 | color: #ffffff;
100 | }
101 | .skin-red .sidebar-form {
102 | border-radius: 3px;
103 | border: 1px solid #374850;
104 | margin: 10px 10px;
105 | }
106 | .skin-red .sidebar-form input[type="text"],
107 | .skin-red .sidebar-form .btn {
108 | box-shadow: none;
109 | background-color: #374850;
110 | border: 1px solid transparent;
111 | height: 35px;
112 | }
113 | .skin-red .sidebar-form input[type="text"] {
114 | color: #666;
115 | border-top-left-radius: 2px;
116 | border-top-right-radius: 0;
117 | border-bottom-right-radius: 0;
118 | border-bottom-left-radius: 2px;
119 | }
120 | .skin-red .sidebar-form input[type="text"]:focus,
121 | .skin-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
122 | background-color: #fff;
123 | color: #666;
124 | }
125 | .skin-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
126 | border-left-color: #fff;
127 | }
128 | .skin-red .sidebar-form .btn {
129 | color: #999;
130 | border-top-left-radius: 0;
131 | border-top-right-radius: 2px;
132 | border-bottom-right-radius: 2px;
133 | border-bottom-left-radius: 0;
134 | }
135 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-red.min.css:
--------------------------------------------------------------------------------
1 | .skin-red .main-header .navbar{background-color:#dd4b39}.skin-red .main-header .navbar .nav>li>a{color:#fff}.skin-red .main-header .navbar .nav>li>a:hover,.skin-red .main-header .navbar .nav>li>a:active,.skin-red .main-header .navbar .nav>li>a:focus,.skin-red .main-header .navbar .nav .open>a,.skin-red .main-header .navbar .nav .open>a:hover,.skin-red .main-header .navbar .nav .open>a:focus,.skin-red .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red .main-header .logo{background-color:#d73925;color:#fff;border-bottom:0 solid transparent}.skin-red .main-header .logo:hover{background-color:#d33724}.skin-red .main-header li.user-header{background-color:#dd4b39}.skin-red .content-header{background:transparent}.skin-red .wrapper,.skin-red .main-sidebar,.skin-red .left-side{background-color:#222d32}.skin-red .user-panel>.info,.skin-red .user-panel>.info>a{color:#fff}.skin-red .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-red .sidebar-menu>li>a{border-left:3px solid transparent}.skin-red .sidebar-menu>li:hover>a,.skin-red .sidebar-menu>li.active>a,.skin-red .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-red .sidebar-menu>li.active>a{border-left-color:#dd4b39}.skin-red .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-red .sidebar a{color:#b8c7ce}.skin-red .sidebar a:hover{text-decoration:none}.skin-red .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-red .sidebar-menu .treeview-menu>li.active>a,.skin-red .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-red .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-red .sidebar-form input[type="text"],.skin-red .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-red .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red .sidebar-form input[type="text"]:focus,.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-yellow-light.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Yellow
3 | * ------------
4 | */
5 | .skin-yellow-light .main-header .navbar {
6 | background-color: #f39c12;
7 | }
8 | .skin-yellow-light .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-yellow-light .main-header .navbar .nav > li > a:hover,
12 | .skin-yellow-light .main-header .navbar .nav > li > a:active,
13 | .skin-yellow-light .main-header .navbar .nav > li > a:focus,
14 | .skin-yellow-light .main-header .navbar .nav .open > a,
15 | .skin-yellow-light .main-header .navbar .nav .open > a:hover,
16 | .skin-yellow-light .main-header .navbar .nav .open > a:focus,
17 | .skin-yellow-light .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-yellow-light .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-yellow-light .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-yellow-light .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-yellow-light .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #e08e0b;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-yellow-light .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-yellow-light .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-yellow-light .main-header .navbar .dropdown-menu li a:hover {
42 | background: #e08e0b;
43 | }
44 | }
45 | .skin-yellow-light .main-header .logo {
46 | background-color: #f39c12;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-yellow-light .main-header .logo:hover {
51 | background-color: #f39a0d;
52 | }
53 | .skin-yellow-light .main-header li.user-header {
54 | background-color: #f39c12;
55 | }
56 | .skin-yellow-light .content-header {
57 | background: transparent;
58 | }
59 | .skin-yellow-light .wrapper,
60 | .skin-yellow-light .main-sidebar,
61 | .skin-yellow-light .left-side {
62 | background-color: #f9fafc;
63 | }
64 | .skin-yellow-light .main-sidebar {
65 | border-right: 1px solid #d2d6de;
66 | }
67 | .skin-yellow-light .user-panel > .info,
68 | .skin-yellow-light .user-panel > .info > a {
69 | color: #444444;
70 | }
71 | .skin-yellow-light .sidebar-menu > li {
72 | -webkit-transition: border-left-color 0.3s ease;
73 | -o-transition: border-left-color 0.3s ease;
74 | transition: border-left-color 0.3s ease;
75 | }
76 | .skin-yellow-light .sidebar-menu > li.header {
77 | color: #848484;
78 | background: #f9fafc;
79 | }
80 | .skin-yellow-light .sidebar-menu > li > a {
81 | border-left: 3px solid transparent;
82 | font-weight: 600;
83 | }
84 | .skin-yellow-light .sidebar-menu > li:hover > a,
85 | .skin-yellow-light .sidebar-menu > li.active > a {
86 | color: #000000;
87 | background: #f4f4f5;
88 | }
89 | .skin-yellow-light .sidebar-menu > li.active {
90 | border-left-color: #f39c12;
91 | }
92 | .skin-yellow-light .sidebar-menu > li.active > a {
93 | font-weight: 600;
94 | }
95 | .skin-yellow-light .sidebar-menu > li > .treeview-menu {
96 | background: #f4f4f5;
97 | }
98 | .skin-yellow-light .sidebar a {
99 | color: #444444;
100 | }
101 | .skin-yellow-light .sidebar a:hover {
102 | text-decoration: none;
103 | }
104 | .skin-yellow-light .sidebar-menu .treeview-menu > li > a {
105 | color: #777777;
106 | }
107 | .skin-yellow-light .sidebar-menu .treeview-menu > li.active > a,
108 | .skin-yellow-light .sidebar-menu .treeview-menu > li > a:hover {
109 | color: #000000;
110 | }
111 | .skin-yellow-light .sidebar-menu .treeview-menu > li.active > a {
112 | font-weight: 600;
113 | }
114 | .skin-yellow-light .sidebar-form {
115 | border-radius: 3px;
116 | border: 1px solid #d2d6de;
117 | margin: 10px 10px;
118 | }
119 | .skin-yellow-light .sidebar-form input[type="text"],
120 | .skin-yellow-light .sidebar-form .btn {
121 | box-shadow: none;
122 | background-color: #fff;
123 | border: 1px solid transparent;
124 | height: 35px;
125 | }
126 | .skin-yellow-light .sidebar-form input[type="text"] {
127 | color: #666;
128 | border-top-left-radius: 2px;
129 | border-top-right-radius: 0;
130 | border-bottom-right-radius: 0;
131 | border-bottom-left-radius: 2px;
132 | }
133 | .skin-yellow-light .sidebar-form input[type="text"]:focus,
134 | .skin-yellow-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
135 | background-color: #fff;
136 | color: #666;
137 | }
138 | .skin-yellow-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
139 | border-left-color: #fff;
140 | }
141 | .skin-yellow-light .sidebar-form .btn {
142 | color: #999;
143 | border-top-left-radius: 0;
144 | border-top-right-radius: 2px;
145 | border-bottom-right-radius: 2px;
146 | border-bottom-left-radius: 0;
147 | }
148 | @media (min-width: 768px) {
149 | .skin-yellow-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
150 | border-left: 1px solid #d2d6de;
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-yellow-light.min.css:
--------------------------------------------------------------------------------
1 | .skin-yellow-light .main-header .navbar{background-color:#f39c12}.skin-yellow-light .main-header .navbar .nav>li>a{color:#fff}.skin-yellow-light .main-header .navbar .nav>li>a:hover,.skin-yellow-light .main-header .navbar .nav>li>a:active,.skin-yellow-light .main-header .navbar .nav>li>a:focus,.skin-yellow-light .main-header .navbar .nav .open>a,.skin-yellow-light .main-header .navbar .nav .open>a:hover,.skin-yellow-light .main-header .navbar .nav .open>a:focus,.skin-yellow-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-yellow-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-yellow-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow-light .main-header .navbar .sidebar-toggle:hover{background-color:#e08e0b}@media (max-width:767px){.skin-yellow-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-yellow-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-yellow-light .main-header .navbar .dropdown-menu li a:hover{background:#e08e0b}}.skin-yellow-light .main-header .logo{background-color:#f39c12;color:#fff;border-bottom:0 solid transparent}.skin-yellow-light .main-header .logo:hover{background-color:#f39a0d}.skin-yellow-light .main-header li.user-header{background-color:#f39c12}.skin-yellow-light .content-header{background:transparent}.skin-yellow-light .wrapper,.skin-yellow-light .main-sidebar,.skin-yellow-light .left-side{background-color:#f9fafc}.skin-yellow-light .main-sidebar{border-right:1px solid #d2d6de}.skin-yellow-light .user-panel>.info,.skin-yellow-light .user-panel>.info>a{color:#444}.skin-yellow-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-yellow-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-yellow-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-yellow-light .sidebar-menu>li:hover>a,.skin-yellow-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-yellow-light .sidebar-menu>li.active{border-left-color:#f39c12}.skin-yellow-light .sidebar-menu>li.active>a{font-weight:600}.skin-yellow-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-yellow-light .sidebar a{color:#444}.skin-yellow-light .sidebar a:hover{text-decoration:none}.skin-yellow-light .sidebar-menu .treeview-menu>li>a{color:#777}.skin-yellow-light .sidebar-menu .treeview-menu>li.active>a,.skin-yellow-light .sidebar-menu .treeview-menu>li>a:hover{color:#000}.skin-yellow-light .sidebar-menu .treeview-menu>li.active>a{font-weight:600}.skin-yellow-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-yellow-light .sidebar-form input[type="text"],.skin-yellow-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px}.skin-yellow-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-yellow-light .sidebar-form input[type="text"]:focus,.skin-yellow-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-yellow-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-yellow-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-yellow-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-yellow.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Skin: Yellow
3 | * ------------
4 | */
5 | .skin-yellow .main-header .navbar {
6 | background-color: #f39c12;
7 | }
8 | .skin-yellow .main-header .navbar .nav > li > a {
9 | color: #ffffff;
10 | }
11 | .skin-yellow .main-header .navbar .nav > li > a:hover,
12 | .skin-yellow .main-header .navbar .nav > li > a:active,
13 | .skin-yellow .main-header .navbar .nav > li > a:focus,
14 | .skin-yellow .main-header .navbar .nav .open > a,
15 | .skin-yellow .main-header .navbar .nav .open > a:hover,
16 | .skin-yellow .main-header .navbar .nav .open > a:focus,
17 | .skin-yellow .main-header .navbar .nav > .active > a {
18 | background: rgba(0, 0, 0, 0.1);
19 | color: #f6f6f6;
20 | }
21 | .skin-yellow .main-header .navbar .sidebar-toggle {
22 | color: #ffffff;
23 | }
24 | .skin-yellow .main-header .navbar .sidebar-toggle:hover {
25 | color: #f6f6f6;
26 | background: rgba(0, 0, 0, 0.1);
27 | }
28 | .skin-yellow .main-header .navbar .sidebar-toggle {
29 | color: #fff;
30 | }
31 | .skin-yellow .main-header .navbar .sidebar-toggle:hover {
32 | background-color: #e08e0b;
33 | }
34 | @media (max-width: 767px) {
35 | .skin-yellow .main-header .navbar .dropdown-menu li.divider {
36 | background-color: rgba(255, 255, 255, 0.1);
37 | }
38 | .skin-yellow .main-header .navbar .dropdown-menu li a {
39 | color: #fff;
40 | }
41 | .skin-yellow .main-header .navbar .dropdown-menu li a:hover {
42 | background: #e08e0b;
43 | }
44 | }
45 | .skin-yellow .main-header .logo {
46 | background-color: #e08e0b;
47 | color: #ffffff;
48 | border-bottom: 0 solid transparent;
49 | }
50 | .skin-yellow .main-header .logo:hover {
51 | background-color: #db8b0b;
52 | }
53 | .skin-yellow .main-header li.user-header {
54 | background-color: #f39c12;
55 | }
56 | .skin-yellow .content-header {
57 | background: transparent;
58 | }
59 | .skin-yellow .wrapper,
60 | .skin-yellow .main-sidebar,
61 | .skin-yellow .left-side {
62 | background-color: #222d32;
63 | }
64 | .skin-yellow .user-panel > .info,
65 | .skin-yellow .user-panel > .info > a {
66 | color: #fff;
67 | }
68 | .skin-yellow .sidebar-menu > li.header {
69 | color: #4b646f;
70 | background: #1a2226;
71 | }
72 | .skin-yellow .sidebar-menu > li > a {
73 | border-left: 3px solid transparent;
74 | }
75 | .skin-yellow .sidebar-menu > li:hover > a,
76 | .skin-yellow .sidebar-menu > li.active > a,
77 | .skin-yellow .sidebar-menu > li.menu-open > a {
78 | color: #ffffff;
79 | background: #1e282c;
80 | }
81 | .skin-yellow .sidebar-menu > li.active > a {
82 | border-left-color: #f39c12;
83 | }
84 | .skin-yellow .sidebar-menu > li > .treeview-menu {
85 | margin: 0 1px;
86 | background: #2c3b41;
87 | }
88 | .skin-yellow .sidebar a {
89 | color: #b8c7ce;
90 | }
91 | .skin-yellow .sidebar a:hover {
92 | text-decoration: none;
93 | }
94 | .skin-yellow .sidebar-menu .treeview-menu > li > a {
95 | color: #8aa4af;
96 | }
97 | .skin-yellow .sidebar-menu .treeview-menu > li.active > a,
98 | .skin-yellow .sidebar-menu .treeview-menu > li > a:hover {
99 | color: #ffffff;
100 | }
101 | .skin-yellow .sidebar-form {
102 | border-radius: 3px;
103 | border: 1px solid #374850;
104 | margin: 10px 10px;
105 | }
106 | .skin-yellow .sidebar-form input[type="text"],
107 | .skin-yellow .sidebar-form .btn {
108 | box-shadow: none;
109 | background-color: #374850;
110 | border: 1px solid transparent;
111 | height: 35px;
112 | }
113 | .skin-yellow .sidebar-form input[type="text"] {
114 | color: #666;
115 | border-top-left-radius: 2px;
116 | border-top-right-radius: 0;
117 | border-bottom-right-radius: 0;
118 | border-bottom-left-radius: 2px;
119 | }
120 | .skin-yellow .sidebar-form input[type="text"]:focus,
121 | .skin-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
122 | background-color: #fff;
123 | color: #666;
124 | }
125 | .skin-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
126 | border-left-color: #fff;
127 | }
128 | .skin-yellow .sidebar-form .btn {
129 | color: #999;
130 | border-top-left-radius: 0;
131 | border-top-right-radius: 2px;
132 | border-bottom-right-radius: 2px;
133 | border-bottom-left-radius: 0;
134 | }
135 |
--------------------------------------------------------------------------------
/static/css/plugin/skins/skin-yellow.min.css:
--------------------------------------------------------------------------------
1 | .skin-yellow .main-header .navbar{background-color:#f39c12}.skin-yellow .main-header .navbar .nav>li>a{color:#fff}.skin-yellow .main-header .navbar .nav>li>a:hover,.skin-yellow .main-header .navbar .nav>li>a:active,.skin-yellow .main-header .navbar .nav>li>a:focus,.skin-yellow .main-header .navbar .nav .open>a,.skin-yellow .main-header .navbar .nav .open>a:hover,.skin-yellow .main-header .navbar .nav .open>a:focus,.skin-yellow .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{background-color:#e08e0b}@media (max-width:767px){.skin-yellow .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-yellow .main-header .navbar .dropdown-menu li a{color:#fff}.skin-yellow .main-header .navbar .dropdown-menu li a:hover{background:#e08e0b}}.skin-yellow .main-header .logo{background-color:#e08e0b;color:#fff;border-bottom:0 solid transparent}.skin-yellow .main-header .logo:hover{background-color:#db8b0b}.skin-yellow .main-header li.user-header{background-color:#f39c12}.skin-yellow .content-header{background:transparent}.skin-yellow .wrapper,.skin-yellow .main-sidebar,.skin-yellow .left-side{background-color:#222d32}.skin-yellow .user-panel>.info,.skin-yellow .user-panel>.info>a{color:#fff}.skin-yellow .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-yellow .sidebar-menu>li>a{border-left:3px solid transparent}.skin-yellow .sidebar-menu>li:hover>a,.skin-yellow .sidebar-menu>li.active>a,.skin-yellow .sidebar-menu>li.menu-open>a{color:#fff;background:#1e282c}.skin-yellow .sidebar-menu>li.active>a{border-left-color:#f39c12}.skin-yellow .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-yellow .sidebar a{color:#b8c7ce}.skin-yellow .sidebar a:hover{text-decoration:none}.skin-yellow .sidebar-menu .treeview-menu>li>a{color:#8aa4af}.skin-yellow .sidebar-menu .treeview-menu>li.active>a,.skin-yellow .sidebar-menu .treeview-menu>li>a:hover{color:#fff}.skin-yellow .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-yellow .sidebar-form input[type="text"],.skin-yellow .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px}.skin-yellow .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-yellow .sidebar-form input[type="text"]:focus,.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-yellow .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}
--------------------------------------------------------------------------------
/static/js/plugin/datatables/i18n/English.lang:
--------------------------------------------------------------------------------
1 | /**
2 | * English - this is the default DataTables ships with
3 | * @name English
4 | * @anchor English
5 | * @author Allan Jardine
6 | */
7 |
8 | {
9 | "sEmptyTable": "No data available in table",
10 | "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11 | "sInfoEmpty": "Showing 0 to 0 of 0 entries",
12 | "sInfoFiltered": "(filtered from _MAX_ total entries)",
13 | "sInfoPostFix": "",
14 | "sInfoThousands": ",",
15 | "sLengthMenu": "Show _MENU_ entries",
16 | "sLoadingRecords": "Loading...",
17 | "sProcessing": "Processing...",
18 | "sSearch": "Search:",
19 | "sZeroRecords": "No matching records found",
20 | "oPaginate": {
21 | "sFirst": "First",
22 | "sLast": "Last",
23 | "sNext": "Next",
24 | "sPrevious": "Previous"
25 | },
26 | "oAria": {
27 | "sSortAscending": ": activate to sort column ascending",
28 | "sSortDescending": ": activate to sort column descending"
29 | }
30 | }
--------------------------------------------------------------------------------
/static/js/plugin/datatables/i18n/zh-hans.json:
--------------------------------------------------------------------------------
1 | {
2 | "sProcessing": "处理中...",
3 | "sLengthMenu": "显示 _MENU_ 项结果",
4 | "sZeroRecords": "没有匹配结果",
5 | "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
6 | "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
7 | "sInfoFiltered": "(由 _MAX_ 项结果过滤)",
8 | "sInfoPostFix": "",
9 | "sSearch": "搜索:",
10 | "sUrl": "",
11 | "sEmptyTable": "表中数据为空",
12 | "sLoadingRecords": "载入中...",
13 | "sInfoThousands": ",",
14 | "oPaginate": {
15 | "sFirst": "首页",
16 | "sPrevious": "上页",
17 | "sNext": "下页",
18 | "sLast": "末页"
19 | },
20 | "oAria": {
21 | "sSortAscending": ": 以升序排列此列",
22 | "sSortDescending": ": 以降序排列此列"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/static/js/plugin/datatables/pdfmake.min.js.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/static/js/plugin/datatables/pdfmake.min.js.map
--------------------------------------------------------------------------------
/static/js/plugin/select2/select2.i18n.cn.js:
--------------------------------------------------------------------------------
1 | /*! Select2 4.0.3 | https://github.com/select2/select2/blob/master/LICENSE.md */
2 |
3 | (function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})();
--------------------------------------------------------------------------------
/static/js/plugin/toastr/toastr.min.js:
--------------------------------------------------------------------------------
1 | !function(e){e(["jquery"],function(e){return function(){function t(e,t,n){return g({type:O.error,iconClass:m().iconClasses.error,message:e,optionsOverride:n,title:t})}function n(t,n){return t||(t=m()),v=e("#"+t.containerId),v.length?v:(n&&(v=d(t)),v)}function o(e,t,n){return g({type:O.info,iconClass:m().iconClasses.info,message:e,optionsOverride:n,title:t})}function s(e){C=e}function i(e,t,n){return g({type:O.success,iconClass:m().iconClasses.success,message:e,optionsOverride:n,title:t})}function a(e,t,n){return g({type:O.warning,iconClass:m().iconClasses.warning,message:e,optionsOverride:n,title:t})}function r(e,t){var o=m();v||n(o),u(e,o,t)||l(o)}function c(t){var o=m();return v||n(o),t&&0===e(":focus",t).length?void h(t):void(v.children().length&&v.remove())}function l(t){for(var n=v.children(),o=n.length-1;o>=0;o--)u(e(n[o]),t)}function u(t,n,o){var s=!(!o||!o.force)&&o.force;return!(!t||!s&&0!==e(":focus",t).length)&&(t[n.hideMethod]({duration:n.hideDuration,easing:n.hideEasing,complete:function(){h(t)}}),!0)}function d(t){return v=e("").attr("id",t.containerId).addClass(t.positionClass),v.appendTo(e(t.target)),v}function p(){return{tapToDismiss:!0,toastClass:"toast",containerId:"toast-container",debug:!1,showMethod:"fadeIn",showDuration:300,showEasing:"swing",onShown:void 0,hideMethod:"fadeOut",hideDuration:1e3,hideEasing:"swing",onHidden:void 0,closeMethod:!1,closeDuration:!1,closeEasing:!1,closeOnHover:!0,extendedTimeOut:1e3,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},iconClass:"toast-info",positionClass:"toast-top-right",timeOut:5e3,titleClass:"toast-title",messageClass:"toast-message",escapeHtml:!1,target:"body",closeHtml:'',closeClass:"toast-close-button",newestOnTop:!0,preventDuplicates:!1,progressBar:!1,progressClass:"toast-progress",rtl:!1}}function f(e){C&&C(e)}function g(t){function o(e){return null==e&&(e=""),e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}function s(){c(),u(),d(),p(),g(),C(),l(),i()}function i(){var e="";switch(t.iconClass){case"toast-success":case"toast-info":e="polite";break;default:e="assertive"}I.attr("aria-live",e)}function a(){E.closeOnHover&&I.hover(H,D),!E.onclick&&E.tapToDismiss&&I.click(b),E.closeButton&&j&&j.click(function(e){e.stopPropagation?e.stopPropagation():void 0!==e.cancelBubble&&e.cancelBubble!==!0&&(e.cancelBubble=!0),E.onCloseClick&&E.onCloseClick(e),b(!0)}),E.onclick&&I.click(function(e){E.onclick(e),b()})}function r(){I.hide(),I[E.showMethod]({duration:E.showDuration,easing:E.showEasing,complete:E.onShown}),E.timeOut>0&&(k=setTimeout(b,E.timeOut),F.maxHideTime=parseFloat(E.timeOut),F.hideEta=(new Date).getTime()+F.maxHideTime,E.progressBar&&(F.intervalId=setInterval(x,10)))}function c(){t.iconClass&&I.addClass(E.toastClass).addClass(y)}function l(){E.newestOnTop?v.prepend(I):v.append(I)}function u(){if(t.title){var e=t.title;E.escapeHtml&&(e=o(t.title)),M.append(e).addClass(E.titleClass),I.append(M)}}function d(){if(t.message){var e=t.message;E.escapeHtml&&(e=o(t.message)),B.append(e).addClass(E.messageClass),I.append(B)}}function p(){E.closeButton&&(j.addClass(E.closeClass).attr("role","button"),I.prepend(j))}function g(){E.progressBar&&(q.addClass(E.progressClass),I.prepend(q))}function C(){E.rtl&&I.addClass("rtl")}function O(e,t){if(e.preventDuplicates){if(t.message===w)return!0;w=t.message}return!1}function b(t){var n=t&&E.closeMethod!==!1?E.closeMethod:E.hideMethod,o=t&&E.closeDuration!==!1?E.closeDuration:E.hideDuration,s=t&&E.closeEasing!==!1?E.closeEasing:E.hideEasing;if(!e(":focus",I).length||t)return clearTimeout(F.intervalId),I[n]({duration:o,easing:s,complete:function(){h(I),clearTimeout(k),E.onHidden&&"hidden"!==P.state&&E.onHidden(),P.state="hidden",P.endTime=new Date,f(P)}})}function D(){(E.timeOut>0||E.extendedTimeOut>0)&&(k=setTimeout(b,E.extendedTimeOut),F.maxHideTime=parseFloat(E.extendedTimeOut),F.hideEta=(new Date).getTime()+F.maxHideTime)}function H(){clearTimeout(k),F.hideEta=0,I.stop(!0,!0)[E.showMethod]({duration:E.showDuration,easing:E.showEasing})}function x(){var e=(F.hideEta-(new Date).getTime())/F.maxHideTime*100;q.width(e+"%")}var E=m(),y=t.iconClass||E.iconClass;if("undefined"!=typeof t.optionsOverride&&(E=e.extend(E,t.optionsOverride),y=t.optionsOverride.iconClass||y),!O(E,t)){T++,v=n(E,!0);var k=null,I=e(""),M=e(""),B=e(""),q=e(""),j=e(E.closeHtml),F={intervalId:null,hideEta:null,maxHideTime:null},P={toastId:T,state:"visible",startTime:new Date,options:E,map:t};return s(),r(),a(),f(P),E.debug&&console&&console.log(P),I}}function m(){return e.extend({},p(),b.options)}function h(e){v||(v=n()),e.is(":visible")||(e.remove(),e=null,0===v.children().length&&(v.remove(),w=void 0))}var v,C,w,T=0,O={error:"error",info:"info",success:"success",warning:"warning"},b={clear:r,remove:c,error:t,getContainer:n,info:o,options:{},subscribe:s,success:i,version:"2.1.3",warning:a};return b}()})}("function"==typeof define&&define.amd?define:function(e,t){"undefined"!=typeof module&&module.exports?module.exports=t(require("jquery")):window.toastr=t(window.jQuery)});
2 |
--------------------------------------------------------------------------------
/support/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/support/.gitkeep
--------------------------------------------------------------------------------
/support/supervisord/cert_manage.ini:
--------------------------------------------------------------------------------
1 | [program:cert_manage]
2 | directory=/opt/cert_manage
3 | environment=PATH="/opt/py3/bin:%(ENV_PATH)s"
4 | command=/opt/py3/bin/python run_server.py all
5 | pidfile=/opt/cert_manage/cert_manage.pid
6 | autostart=true
7 | autorestart=true
8 | stdout_logfile=/opt/cert_manage/logs/cert_manage.log
9 | stderr_logfile=/opt/cert_manage/logs/cert_manage_error.log
--------------------------------------------------------------------------------
/templates/_base.html:
--------------------------------------------------------------------------------
1 | {% load static i18n %}
2 |
4 |
5 |
6 | {% load staticfiles %}
7 |
8 | 证书管理系统
9 | {% include '_head_css_js.html' %}
10 | {% block custom_head_css_js %}
11 | {% endblock %}
12 |
13 |
14 |
15 |
16 |
17 |
68 |
69 | {% block content %}
70 | {% endblock %}
71 |
72 |
73 |
74 | {% include '_foot_js.html' %}
75 | {% block custom_foot_js %}
76 | {% endblock %}
77 |
--------------------------------------------------------------------------------
/templates/_copyright.html:
--------------------------------------------------------------------------------
1 | Copyright 上海XXX网络技术有限公司 © 2015-2019
--------------------------------------------------------------------------------
/templates/_foot_js.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% load static %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/templates/_head_css_js.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% load static %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/templates/flash_message_standalone.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 证书管理系统
10 |
11 | {% include '_head_css_js.html' %}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
证书管理系统
22 |
23 | {% if errors %}
24 |
25 |
26 | {{ errors }}
27 |
28 |
29 | {% endif %}
30 |
31 | {% if messages %}
32 |
33 |
34 | {{ messages|safe }}
35 |
36 |
37 | {% endif %}
38 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {% include '_copyright.html' %}
50 |
51 |
52 |
53 |
54 |
76 |
77 |
--------------------------------------------------------------------------------
/templates/index.html:
--------------------------------------------------------------------------------
1 | {% extends '_base.html' %}
2 | {% block content %}
3 | 欢迎登录证书管理系统
4 | {% endblock %}
--------------------------------------------------------------------------------
/tmp/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/tmp/.gitkeep
--------------------------------------------------------------------------------
/users/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/users/__init__.py
--------------------------------------------------------------------------------
/users/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from users.models import User, UserGroup
4 |
5 |
6 | # Register your models here.
7 |
8 | class userExtAdmin(admin.ModelAdmin):
9 | list_display = (
10 | 'name', 'username', 'email', 'phone', 'role', 'date_expired', 'is_active', 'date_joined')
11 |
12 |
13 | class userGroupExtAdmin(admin.ModelAdmin):
14 | list_display = ('name', 'date_created')
15 |
16 |
17 | admin.site.register(User, userExtAdmin)
18 | admin.site.register(UserGroup, userGroupExtAdmin)
19 |
--------------------------------------------------------------------------------
/users/api.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:16
6 | # @Version : 1.0
7 | # @File : api
8 | # @Software : PyCharm
9 |
10 |
11 | from rest_framework.pagination import LimitOffsetPagination
12 | from rest_framework_bulk import BulkModelViewSet
13 |
14 | from users.serializers import UserSerializer, UserGroupSerializer
15 |
16 | from users.models import User, UserGroup
17 | from users.permissions import IsSuperUser
18 | from users.mixins import IDInFilterMixin
19 |
20 |
21 | class UserViewSet(IDInFilterMixin, BulkModelViewSet):
22 | '''
23 | 用户的操作接口
24 | '''
25 | queryset = User.objects.all()
26 | serializer_class = UserSerializer
27 | pagination_class = LimitOffsetPagination
28 | permission_classes = (IsSuperUser,)
29 | filter_fields = ('username', 'email', 'name', 'phone', 'date_expired')
30 | search_fields = filter_fields
31 |
32 |
33 | class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
34 | '''
35 | 用户组的操作接口
36 | '''
37 | queryset = UserGroup.objects.all()
38 | serializer_class = UserGroupSerializer
39 | pagination_class = LimitOffsetPagination
40 | permission_classes = (IsSuperUser,)
41 | search_fields = ('name', 'comment')
42 |
--------------------------------------------------------------------------------
/users/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class UsersConfig(AppConfig):
5 | name = 'users'
6 |
7 | def ready(self):
8 | super().ready()
9 |
--------------------------------------------------------------------------------
/users/forms.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 下午2:53
6 | # @Version : 1.0
7 | # @File : forms
8 | # @Software : PyCharm
9 |
10 |
11 | from django import forms
12 | from captcha.fields import CaptchaField
13 | from django.contrib.auth.forms import AuthenticationForm
14 | from django.utils.translation import gettext_lazy as _
15 |
16 |
17 | class UserLoginForm(AuthenticationForm):
18 | username = forms.CharField(label=_('Username'), max_length=100)
19 | password = forms.CharField(
20 | label=_('Password'), widget=forms.PasswordInput,
21 | max_length=128, strip=False
22 | )
23 |
24 |
25 | class UserLoginCaptchaForm(AuthenticationForm):
26 | username = forms.CharField(label=_('Username'), max_length=100)
27 | password = forms.CharField(
28 | label=_('Password'), widget=forms.PasswordInput,
29 | max_length=128, strip=False
30 | )
31 | captcha = CaptchaField()
32 |
--------------------------------------------------------------------------------
/users/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1 on 2019-09-18 14:24
2 |
3 | from django.conf import settings
4 | import django.contrib.auth.models
5 | from django.db import migrations, models
6 | import django.db.models.deletion
7 | import django.utils.timezone
8 | import users.utils
9 | import uuid
10 |
11 |
12 | class Migration(migrations.Migration):
13 |
14 | initial = True
15 |
16 | dependencies = [
17 | ('auth', '0009_alter_user_last_name_max_length'),
18 | ]
19 |
20 | operations = [
21 | migrations.CreateModel(
22 | name='User',
23 | fields=[
24 | ('password', models.CharField(max_length=128, verbose_name='password')),
25 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
26 | ('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
27 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
28 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
29 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
30 | ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
31 | ('username', models.CharField(max_length=128, unique=True, verbose_name='Username')),
32 | ('name', models.CharField(max_length=128, verbose_name='Name')),
33 | ('email', models.EmailField(max_length=128, unique=True, verbose_name='Email')),
34 | ('role', models.CharField(blank=True, choices=[('Admin', 'Administrator'), ('User', 'User')], default='User', max_length=36, verbose_name='Role')),
35 | ('phone', models.CharField(blank=True, max_length=20, null=True, verbose_name='Phone')),
36 | ('otp_level', models.SmallIntegerField(choices=[(0, 'Disable'), (1, 'Enable'), (2, 'Force enable')], default=0, verbose_name='MFA')),
37 | ('date_expired', models.DateTimeField(blank=True, default=users.utils.date_expired_default, null=True, verbose_name='Date expired')),
38 | ('comment', models.TextField(blank=True, max_length=200, verbose_name='Comment')),
39 | ],
40 | options={
41 | 'verbose_name': 'User',
42 | 'ordering': ['username'],
43 | },
44 | managers=[
45 | ('objects', django.contrib.auth.models.UserManager()),
46 | ],
47 | ),
48 | migrations.CreateModel(
49 | name='AccessKey',
50 | fields=[
51 | ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='AccessKeyID')),
52 | ('secret', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='AccessKeySecret')),
53 | ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='access_key', to=settings.AUTH_USER_MODEL, verbose_name='User')),
54 | ],
55 | ),
56 | migrations.CreateModel(
57 | name='PrivateToken',
58 | fields=[
59 | ('key', models.CharField(max_length=40, primary_key=True, serialize=False, verbose_name='Key')),
60 | ('created', models.DateTimeField(auto_now_add=True, verbose_name='Created')),
61 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='auth_token', to=settings.AUTH_USER_MODEL, verbose_name='User')),
62 | ],
63 | options={
64 | 'verbose_name': 'Private Token',
65 | },
66 | ),
67 | migrations.CreateModel(
68 | name='UserGroup',
69 | fields=[
70 | ('is_discard', models.BooleanField(default=False, verbose_name='is discard')),
71 | ('discard_time', models.DateTimeField(blank=True, null=True, verbose_name='discard time')),
72 | ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
73 | ('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
74 | ('comment', models.TextField(blank=True, verbose_name='Comment')),
75 | ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
76 | ('created_by', models.CharField(blank=True, max_length=100, null=True)),
77 | ],
78 | options={
79 | 'verbose_name': 'User group',
80 | 'ordering': ['name'],
81 | },
82 | ),
83 | migrations.AddField(
84 | model_name='user',
85 | name='groups',
86 | field=models.ManyToManyField(blank=True, related_name='users', to='users.UserGroup', verbose_name='User group'),
87 | ),
88 | migrations.AddField(
89 | model_name='user',
90 | name='user_permissions',
91 | field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'),
92 | ),
93 | ]
94 |
--------------------------------------------------------------------------------
/users/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itnotebooks/cert_manage/965d62cbcbc06df4105b14847955eef30343ec7c/users/migrations/__init__.py
--------------------------------------------------------------------------------
/users/mixins.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午6:49
6 | # @Version : 1.0
7 | # @File : mixins
8 | # @Software : PyCharm
9 |
10 | from django.db import models
11 | from django.utils import timezone
12 | from rest_framework.exceptions import ValidationError
13 | from django.utils.translation import ugettext_lazy as _
14 |
15 |
16 | class NoDeleteQuerySet(models.query.QuerySet):
17 |
18 | def delete(self):
19 | return self.update(is_discard=True, discard_time=timezone.now())
20 |
21 |
22 | class NoDeleteManager(models.Manager):
23 |
24 | def get_all(self):
25 | return NoDeleteQuerySet(self.model, using=self._db)
26 |
27 | def get_queryset(self):
28 | return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=False)
29 |
30 | def get_deleted(self):
31 | return NoDeleteQuerySet(self.model, using=self._db).filter(is_discard=True)
32 |
33 |
34 | class NoDeleteModelMixin(models.Model):
35 | is_discard = models.BooleanField(verbose_name=_("is discard"), default=False)
36 | discard_time = models.DateTimeField(verbose_name=_("discard time"), null=True, blank=True)
37 |
38 | objects = NoDeleteManager()
39 |
40 | class Meta:
41 | abstract = True
42 |
43 | def delete(self):
44 | self.is_discard = True
45 | self.discard_time = timezone.now()
46 | return self.save()
47 |
48 |
49 | class IDInFilterMixin(object):
50 | def filter_queryset(self, queryset):
51 |
52 | queryset = super(IDInFilterMixin, self).filter_queryset(queryset)
53 | id_list = self.request.query_params.get('id__in')
54 | if id_list:
55 | import json
56 | try:
57 | ids = json.loads(id_list)
58 | except Exception as e:
59 | return queryset
60 | if isinstance(ids, list):
61 | queryset = queryset.filter(id__in=ids)
62 | return queryset
63 |
64 |
65 | class BulkSerializerMixin(object):
66 | """
67 | Become rest_framework_bulk not support uuid as a primary key
68 | so rewrite it. https://github.com/miki725/django-rest-framework-bulk/issues/66
69 | """
70 |
71 | def to_internal_value(self, data):
72 | from rest_framework_bulk import BulkListSerializer
73 |
74 | try:
75 | ret = super(BulkSerializerMixin, self).to_internal_value(data)
76 | except ValidationError as e:
77 | error = {}
78 | error['msg'] = e.detail
79 | error['code'] = 10400
80 | raise ValidationError(error)
81 |
82 | id_attr = getattr(self.Meta, 'update_lookup_field', 'id')
83 | request_method = getattr(getattr(self.context.get('view'), 'request'), 'method', '')
84 | # add update_lookup_field field back to validated data
85 | # since super by default strips out read-only fields
86 | # hence id will no longer be present in validated_data
87 | if all((isinstance(self.root, BulkListSerializer),
88 | id_attr,
89 | request_method in ('PUT', 'PATCH'))):
90 | id_field = self.fields[id_attr]
91 | if data.get("id"):
92 | id_value = id_field.to_internal_value(data.get("id"))
93 | else:
94 | id_value = id_field.to_internal_value(data.get("pk"))
95 | ret[id_attr] = id_value
96 | return ret
97 |
--------------------------------------------------------------------------------
/users/models/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 下午4:24
6 | # @Version : 1.0
7 | # @File : __init__.py
8 | # @Software : PyCharm
9 |
10 | from .user import UserGroup, User
11 | from .authentication import *
12 |
--------------------------------------------------------------------------------
/users/models/authentication.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 下午4:25
6 | # @Version : 1.0
7 | # @File : authentication
8 | # @Software : PyCharm
9 |
10 |
11 | import uuid
12 | from django.db import models
13 | from django.utils.translation import ugettext_lazy as _
14 | from rest_framework import authentication
15 | from rest_framework.authtoken.models import Token
16 |
17 | from .user import User
18 |
19 |
20 | class AccessKey(models.Model):
21 | id = models.UUIDField(verbose_name='AccessKeyID', primary_key=True,
22 | default=uuid.uuid4, editable=False)
23 | secret = models.UUIDField(verbose_name='AccessKeySecret',
24 | default=uuid.uuid4, editable=False)
25 | user = models.ForeignKey(User, verbose_name='User',
26 | on_delete=models.CASCADE, related_name='access_key')
27 |
28 | def get_id(self):
29 | return str(self.id)
30 |
31 | def get_secret(self):
32 | return str(self.secret)
33 |
34 | def __str__(self):
35 | return str(self.id)
36 |
37 |
38 | class PrivateToken(Token):
39 | """Inherit from auth token, otherwise migration is boring"""
40 |
41 | class Meta:
42 | verbose_name = _('Private Token')
43 |
--------------------------------------------------------------------------------
/users/permissions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午9:25
6 | # @Version : 1.0
7 | # @File : permissions
8 | # @Software : PyCharm
9 |
10 |
11 | from rest_framework import permissions
12 |
13 |
14 | class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
15 | """Allows access to valid user, is active and not expired"""
16 |
17 | def has_permission(self, request, view):
18 | return super(IsValidUser, self).has_permission(request, view) \
19 | and request.user.is_valid
20 |
21 |
22 | class IsSuperUser(IsValidUser):
23 | """Allows access only to superuser"""
24 |
25 | def has_permission(self, request, view):
26 | return super(IsSuperUser, self).has_permission(request, view) \
27 | and request.user.is_superuser
28 |
--------------------------------------------------------------------------------
/users/serializers.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午9:37
6 | # @Version : 1.0
7 | # @File : serializers
8 | # @Software : PyCharm
9 |
10 |
11 | from rest_framework import serializers
12 |
13 | from rest_framework_bulk import BulkListSerializer
14 | from users.mixins import BulkSerializerMixin
15 | from users.models import User, UserGroup
16 |
17 |
18 | class UserGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
19 | class Meta:
20 | model = UserGroup
21 | list_serializer_class = BulkListSerializer
22 | fields = '__all__'
23 |
24 |
25 | class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
26 | groups = UserGroupSerializer(many=True)
27 |
28 | class Meta:
29 | model = User
30 | list_serializer_class = BulkListSerializer
31 | fields = ['id', 'name', 'username', 'first_name', 'last_name', 'role', 'phone', 'groups', 'is_active', 'email',
32 | 'date_expired']
33 |
--------------------------------------------------------------------------------
/users/signals.py:
--------------------------------------------------------------------------------
1 | from django.dispatch import Signal
2 |
3 |
4 | post_user_create = Signal(providing_args=('user',))
5 |
6 |
--------------------------------------------------------------------------------
/users/templates/users/login.html:
--------------------------------------------------------------------------------
1 | {% load static %}
2 | {% load i18n %}
3 |
4 |
5 |
6 |
7 |
8 |
9 | 证书管理系统
10 | {% include '_head_css_js.html' %}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {% trans 'Login' %}
25 |
26 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | {% include '_copyright.html' %}
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/users/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/users/urls/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:14
6 | # @Version : 1.0
7 | # @File : __init__.py
8 | # @Software : PyCharm
9 |
--------------------------------------------------------------------------------
/users/urls/api_urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:14
6 | # @Version : 1.0
7 | # @File : api_urls
8 | # @Software : PyCharm
9 |
10 |
11 | from __future__ import absolute_import
12 |
13 | from django.conf.urls import url
14 | from rest_framework_bulk.routes import BulkRouter
15 | from users import api
16 |
17 | app_name = 'users'
18 |
19 | router = BulkRouter()
20 | router.register(r'v1/users', api.UserViewSet, 'user')
21 | router.register(r'v1/groups', api.UserGroupViewSet, 'user-group')
22 |
23 | urlpatterns = []
24 |
25 | urlpatterns += router.urls
26 |
--------------------------------------------------------------------------------
/users/urls/views_urls.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午7:15
6 | # @Version : 1.0
7 | # @File : views_urls
8 | # @Software : PyCharm
9 |
10 | from __future__ import absolute_import
11 |
12 | from django.conf.urls import url
13 |
14 | from users import views
15 |
16 | app_name = 'users'
17 |
18 | urlpatterns = [
19 | # Login view
20 | url(r'^login$', views.UserLoginView.as_view(), name='login'),
21 | url(r'^logout$', views.UserLogoutView.as_view(), name='logout')
22 | ]
23 |
--------------------------------------------------------------------------------
/users/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # @Author : Eric Winn
4 | # @Email : eng.eric.winn@gmail.com
5 | # @Time : 19-9-3 上午6:41
6 | # @Version : 1.0
7 | # @File : utils
8 | # @Software : PyCharm
9 |
10 | from django.conf import settings
11 |
12 | from django.utils.translation import ugettext as _
13 | from django.http import Http404
14 | from django.urls import reverse
15 | from django.utils import timezone
16 | from django.core.cache import cache
17 |
18 |
19 | def date_expired_default():
20 | try:
21 | years = int(settings.DEFAULT_EXPIRED_YEARS)
22 | except TypeError:
23 | years = 70
24 | return timezone.now() + timezone.timedelta(days=365 * years)
25 |
26 |
27 | def get_tmp_user_from_cache(request):
28 | if not request.session.session_key:
29 | return None
30 | user = cache.get(request.session.session_key + 'user')
31 | return user
32 |
33 |
34 | def set_tmp_user_to_cache(request, user):
35 | cache.set(request.session.session_key + 'user', user, 600)
36 |
37 |
38 | def get_user_or_tmp_user(request):
39 | user = request.user
40 | tmp_user = get_tmp_user_from_cache(request)
41 | if user.is_authenticated:
42 | return user
43 | elif tmp_user:
44 | return tmp_user
45 | else:
46 | raise Http404("Not found this user")
47 |
48 |
49 | def redirect_user_first_login_or_index(request, redirect_field_name):
50 | return request.POST.get(
51 | redirect_field_name,
52 | request.GET.get(redirect_field_name, reverse('index')))
53 |
54 |
55 | def get_login_ip(request):
56 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')
57 | if x_forwarded_for and x_forwarded_for[0]:
58 | login_ip = x_forwarded_for[0]
59 | else:
60 | login_ip = request.META.get('REMOTE_ADDR', '')
61 | return login_ip
62 |
63 |
64 | create_success_msg = _("%(name)s was created successfully")
65 | update_success_msg = _("%(name)s was updated successfully")
66 |
67 |
68 | def refresh_token(token, user, expiration=settings.TOKEN_EXPIRATION or 3600):
69 | cache.set(token, user.id, expiration)
70 |
--------------------------------------------------------------------------------
/users/views.py:
--------------------------------------------------------------------------------
1 | from django.http import HttpResponse
2 | from django.shortcuts import redirect
3 | from django.core.cache import cache
4 | from django.contrib.auth import login as auth_login, logout as auth_logout
5 | from django.urls import reverse
6 |
7 | from django.utils.decorators import method_decorator
8 |
9 | from django.utils.translation import ugettext as _
10 |
11 | from django.views.decorators.cache import never_cache
12 | from django.views.decorators.csrf import csrf_protect
13 | from django.views.decorators.debug import sensitive_post_parameters
14 | from django.views.generic import FormView, TemplateView
15 |
16 | from users import forms
17 | from users.utils import redirect_user_first_login_or_index, set_tmp_user_to_cache, get_login_ip, get_user_or_tmp_user
18 |
19 |
20 | # Create your views here.
21 |
22 | @method_decorator(sensitive_post_parameters(), name='dispatch')
23 | @method_decorator(csrf_protect, name='dispatch')
24 | @method_decorator(never_cache, name='dispatch')
25 | class UserLoginView(FormView):
26 | template_name = 'users/login.html'
27 | form_class = forms.UserLoginForm
28 | form_class_captcha = forms.UserLoginCaptchaForm
29 | redirect_field_name = 'next'
30 | key_prefix = "_LOGIN_INVALID_{}"
31 |
32 | def get(self, request, *args, **kwargs):
33 | if request.user.is_staff:
34 | return redirect(self.get_success_url())
35 | request.session.set_test_cookie()
36 | return super().get(request, *args, **kwargs)
37 |
38 | def form_valid(self, form):
39 | if not self.request.session.test_cookie_worked():
40 | return HttpResponse(_("Please enable cookies and try again."))
41 |
42 | set_tmp_user_to_cache(self.request, form.get_user())
43 | return redirect(self.get_success_url())
44 |
45 | def form_invalid(self, form):
46 | ip = get_login_ip(self.request)
47 | cache.set(self.key_prefix.format(ip), 1, 3600)
48 | old_form = form
49 | form = self.form_class_captcha(data=form.data)
50 | form._errors = old_form.errors
51 | return super().form_invalid(form)
52 |
53 | def get_form_class(self):
54 | ip = get_login_ip(self.request)
55 | if cache.get(self.key_prefix.format(ip)):
56 | return self.form_class_captcha
57 | else:
58 | return self.form_class
59 |
60 | def get_success_url(self):
61 | user = get_user_or_tmp_user(self.request)
62 | auth_login(self.request, user)
63 | return redirect_user_first_login_or_index(self.request, self.redirect_field_name)
64 |
65 | def get_context_data(self, **kwargs):
66 | context = {
67 | }
68 | kwargs.update(context)
69 | return super().get_context_data(**kwargs)
70 |
71 |
72 | @method_decorator(never_cache, name='dispatch')
73 | class UserLogoutView(TemplateView):
74 | template_name = 'flash_message_standalone.html'
75 |
76 | def get(self, request, *args, **kwargs):
77 | auth_logout(request)
78 | response = super().get(request, *args, **kwargs)
79 | return response
80 |
81 | def get_context_data(self, **kwargs):
82 | context = {
83 | 'title': _('Logout success'),
84 | 'messages': _('Logout success, return login page'),
85 | 'interval': 5,
86 | 'redirect_url': reverse('index'),
87 | 'auto_redirect': True,
88 | }
89 | kwargs.update(context)
90 | return super().get_context_data(**kwargs)
91 |
--------------------------------------------------------------------------------