├── .gitignore
├── LICENSE
├── README.md
├── archer
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
├── debug.bat
├── debug.sh
├── manage.py
├── patch
└── django_1.8.17_admin_secure_archer.patch
├── requirements.txt
├── sql
├── __init__.py
├── admin.py
├── aes_decryptor.py
├── aliyun_api.py
├── aliyun_function.py
├── check_login_middleware.py
├── const.py
├── dao.py
├── data_masking.py
├── exception_logging_middleware.py
├── extend_json_encoder.py
├── inception.py
├── jobs.py
├── models.py
├── permission.py
├── processor.py
├── query.py
├── sendmail.py
├── sqlreview.py
├── static
│ ├── ace
│ │ ├── ace.js
│ │ ├── ace_init.js
│ │ ├── ext-language_tools.js
│ │ ├── mode-sql.js
│ │ ├── snippets
│ │ │ └── sql.js
│ │ ├── theme-github.js
│ │ └── theme-textmate.js
│ ├── admin
│ │ ├── css
│ │ │ ├── base.css
│ │ │ ├── changelists.css
│ │ │ ├── dashboard.css
│ │ │ ├── forms.css
│ │ │ ├── ie.css
│ │ │ ├── login.css
│ │ │ ├── rtl.css
│ │ │ └── widgets.css
│ │ ├── img
│ │ │ ├── changelist-bg.gif
│ │ │ ├── changelist-bg_rtl.gif
│ │ │ ├── default-bg-reverse.gif
│ │ │ ├── default-bg.gif
│ │ │ ├── deleted-overlay.gif
│ │ │ ├── gis
│ │ │ │ ├── move_vertex_off.png
│ │ │ │ └── move_vertex_on.png
│ │ │ ├── icon-no.gif
│ │ │ ├── icon-unknown.gif
│ │ │ ├── icon-yes.gif
│ │ │ ├── icon_addlink.gif
│ │ │ ├── icon_alert.gif
│ │ │ ├── icon_calendar.gif
│ │ │ ├── icon_changelink.gif
│ │ │ ├── icon_clock.gif
│ │ │ ├── icon_deletelink.gif
│ │ │ ├── icon_error.gif
│ │ │ ├── icon_searchbox.png
│ │ │ ├── icon_success.gif
│ │ │ ├── inline-delete-8bit.png
│ │ │ ├── inline-delete.png
│ │ │ ├── inline-restore-8bit.png
│ │ │ ├── inline-restore.png
│ │ │ ├── inline-splitter-bg.gif
│ │ │ ├── nav-bg-grabber.gif
│ │ │ ├── nav-bg-reverse.gif
│ │ │ ├── nav-bg-selected.gif
│ │ │ ├── nav-bg.gif
│ │ │ ├── selector-icons.gif
│ │ │ ├── selector-search.gif
│ │ │ ├── sorting-icons.gif
│ │ │ ├── tooltag-add.png
│ │ │ └── tooltag-arrowright.png
│ │ └── js
│ │ │ ├── LICENSE-JQUERY.txt
│ │ │ ├── SelectBox.js
│ │ │ ├── SelectFilter2.js
│ │ │ ├── actions.js
│ │ │ ├── actions.min.js
│ │ │ ├── admin
│ │ │ ├── DateTimeShortcuts.js
│ │ │ └── RelatedObjectLookups.js
│ │ │ ├── calendar.js
│ │ │ ├── collapse.js
│ │ │ ├── collapse.min.js
│ │ │ ├── core.js
│ │ │ ├── inlines.js
│ │ │ ├── inlines.min.js
│ │ │ ├── jquery.init.js
│ │ │ ├── jquery.js
│ │ │ ├── jquery.min.js
│ │ │ ├── prepopulate.js
│ │ │ ├── prepopulate.min.js
│ │ │ ├── related-widget-wrapper.js
│ │ │ ├── timeparse.js
│ │ │ └── urlify.js
│ ├── base.html
│ ├── bootstrap-3.3.7-dist
│ │ ├── css
│ │ │ ├── bootstrap-theme.css
│ │ │ ├── bootstrap-theme.css.map
│ │ │ ├── bootstrap-theme.min.css
│ │ │ ├── bootstrap-theme.min.css.map
│ │ │ ├── bootstrap.css
│ │ │ ├── bootstrap.css.map
│ │ │ ├── bootstrap.min.css
│ │ │ ├── bootstrap.min.css.map
│ │ │ └── dashboard.css
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ │ └── js
│ │ │ ├── bootstrap.js
│ │ │ ├── bootstrap.min.js
│ │ │ └── npm.js
│ ├── bootstrap-table
│ │ ├── css
│ │ │ └── bootstrap-table.min.css
│ │ └── js
│ │ │ ├── bootstrap-table-export.min.js
│ │ │ ├── bootstrap-table-zh-CN.min.js
│ │ │ ├── bootstrap-table.min.js
│ │ │ └── tableExport.min.js
│ ├── charts.html
│ ├── daterangepicker
│ │ ├── css
│ │ │ └── daterangepicker.css
│ │ └── js
│ │ │ ├── daterangepicker.js
│ │ │ └── moment.min.js
│ ├── datetimepicker
│ │ ├── css
│ │ │ ├── bootstrap-datetimepicker.css
│ │ │ ├── daterangepicker-bs2.css
│ │ │ └── daterangepicker-bs3.css
│ │ └── js
│ │ │ ├── bootstrap-datetimepicker.js
│ │ │ └── bootstrap-datetimepicker.zh-CN.js
│ ├── dbaprinciples.html
│ ├── detail.html
│ ├── diagnosis.html
│ ├── dist
│ │ ├── css
│ │ │ ├── bootstrap-select.css
│ │ │ ├── bootstrap-select.css.map
│ │ │ └── bootstrap-select.min.css
│ │ └── js
│ │ │ ├── bootstrap-select.js
│ │ │ ├── bootstrap-select.js.map
│ │ │ ├── bootstrap-select.min.js
│ │ │ ├── i18n
│ │ │ ├── defaults-bg_BG.js
│ │ │ ├── defaults-bg_BG.min.js
│ │ │ ├── defaults-cs_CZ.js
│ │ │ ├── defaults-cs_CZ.min.js
│ │ │ ├── defaults-da_DK.js
│ │ │ ├── defaults-da_DK.min.js
│ │ │ ├── defaults-de_DE.js
│ │ │ ├── defaults-de_DE.min.js
│ │ │ ├── defaults-en_US.js
│ │ │ ├── defaults-en_US.min.js
│ │ │ ├── defaults-es_CL.js
│ │ │ ├── defaults-es_CL.min.js
│ │ │ ├── defaults-eu.js
│ │ │ ├── defaults-eu.min.js
│ │ │ ├── defaults-fa_IR.js
│ │ │ ├── defaults-fa_IR.min.js
│ │ │ ├── defaults-fr_FR.js
│ │ │ ├── defaults-fr_FR.min.js
│ │ │ ├── defaults-hu_HU.js
│ │ │ ├── defaults-hu_HU.min.js
│ │ │ ├── defaults-it_IT.js
│ │ │ ├── defaults-it_IT.min.js
│ │ │ ├── defaults-ko_KR.js
│ │ │ ├── defaults-ko_KR.min.js
│ │ │ ├── defaults-nl_NL.js
│ │ │ ├── defaults-nl_NL.min.js
│ │ │ ├── defaults-pl_PL.js
│ │ │ ├── defaults-pl_PL.min.js
│ │ │ ├── defaults-pt_BR.js
│ │ │ ├── defaults-pt_BR.min.js
│ │ │ ├── defaults-pt_PT.js
│ │ │ ├── defaults-pt_PT.min.js
│ │ │ ├── defaults-ro_RO.js
│ │ │ ├── defaults-ro_RO.min.js
│ │ │ ├── defaults-ru_RU.js
│ │ │ ├── defaults-ru_RU.min.js
│ │ │ ├── defaults-sk_SK.js
│ │ │ ├── defaults-sk_SK.min.js
│ │ │ ├── defaults-sl_SI.js
│ │ │ ├── defaults-sl_SI.min.js
│ │ │ ├── defaults-sv_SE.js
│ │ │ ├── defaults-sv_SE.min.js
│ │ │ ├── defaults-tr_TR.js
│ │ │ ├── defaults-tr_TR.min.js
│ │ │ ├── defaults-ua_UA.js
│ │ │ ├── defaults-ua_UA.min.js
│ │ │ ├── defaults-zh_CN.js
│ │ │ ├── defaults-zh_CN.min.js
│ │ │ ├── defaults-zh_TW.js
│ │ │ └── defaults-zh_TW.min.js
│ │ │ └── sql-formatter.min.js
│ ├── error.html
│ ├── fileinput
│ │ ├── css
│ │ │ └── fileinput.min.css
│ │ ├── img
│ │ │ └── loading.gif
│ │ └── js
│ │ │ ├── fileinput.min.js
│ │ │ └── locales
│ │ │ └── zh.js
│ ├── highcharts
│ │ └── Chart.min.js
│ ├── jquery
│ │ └── jquery.min.js
│ ├── login.html
│ ├── queryapplydetail.html
│ ├── queryapplylist.html
│ ├── queryuserprivileges.html
│ ├── rollback.html
│ ├── slowquery.html
│ ├── sqladvisor.html
│ ├── sqlquery.html
│ ├── sqlworkflow.html
│ ├── submitSql.html
│ ├── user
│ │ ├── css
│ │ │ └── user1.css
│ │ └── js
│ │ │ ├── autoreview.js
│ │ │ ├── charts.js
│ │ │ ├── formatter.js
│ │ │ ├── login.js
│ │ │ └── rollback.js
│ └── workflow.html
├── templatetags
│ ├── __init__.py
│ └── format_tags.py
├── tests.py
├── urls.py
├── views.py
├── views_ajax.py
└── workflow.py
├── src
├── docker
│ ├── Dockerfile
│ ├── nginx.conf
│ ├── pymysql
│ │ ├── connections.py
│ │ └── cursors.py
│ ├── requirements.txt
│ └── startup.sh
├── docs
│ ├── mysql_db_design_guide.docx
│ └── mysql_db_design_guide.md
├── init_sql
│ ├── master->v2.0.sql
│ └── v1.1.1->v2.0.sql
├── screenshots
│ ├── admin.png
│ ├── allworkflow.png
│ ├── applyforprivileges.png
│ ├── autoreview.png
│ ├── bugs
│ │ ├── bug1.png
│ │ ├── bug2.png
│ │ └── bug3.png
│ ├── charts.png
│ ├── datamasking.png
│ ├── datamaskingcolumns.png
│ ├── datamaskingrules.png
│ ├── finish.png
│ ├── login.png
│ ├── manageprivileges.png
│ ├── osc_progress.png
│ ├── process.png
│ ├── pymysql.png
│ ├── query.png
│ ├── querylog.png
│ ├── rollback.png
│ ├── slowquery.png
│ ├── slowquerylog.png
│ ├── sqladvisor.png
│ ├── submitsql.png
│ ├── waitingforme.png
│ └── workflowconfig.png
└── script
│ ├── analysis_slow_query.sh
│ ├── centos7_install.sh
│ └── mysql_slow_query_review.sql
├── startup.sh
└── stop.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.swp
3 | *.lock
4 | *.log
5 | .idea/
6 | .DS_Store
7 | archer/settings.py.github
8 | archer/settings.py.dev
9 | sql/migrations/
10 |
--------------------------------------------------------------------------------
/archer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/archer/__init__.py
--------------------------------------------------------------------------------
/archer/urls.py:
--------------------------------------------------------------------------------
1 | """archer URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/1.8/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: url(r'^$', 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: url(r'^$', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
14 | """
15 | from django.conf.urls import include, url
16 | from django.contrib import admin
17 |
18 | urlpatterns = [
19 | url(r'^admin/', include(admin.site.urls)),
20 | url(r'^', include('sql.urls', namespace="sql")),
21 | ]
22 |
--------------------------------------------------------------------------------
/archer/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for archer 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/1.8/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", "archer.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/debug.bat:
--------------------------------------------------------------------------------
1 | python3 manage.py runserver 0.0.0.0:9123
--------------------------------------------------------------------------------
/debug.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | python3 manage.py runserver 0.0.0.0:9123 --insecure
4 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "archer.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/patch/django_1.8.17_admin_secure_archer.patch:
--------------------------------------------------------------------------------
1 | --- views.py 2018-01-23 11:53:00.179201491 +0800
2 | +++ python/site-packages/django/contrib/auth/views.py 2018-01-23 11:58:10.668286140 +0800
3 | @@ -24,7 +24,14 @@
4 | from django.views.decorators.cache import never_cache
5 | from django.views.decorators.csrf import csrf_protect
6 | from django.views.decorators.debug import sensitive_post_parameters
7 | -
8 | +# 账户锁定
9 | +from django.conf import settings
10 | +from sql.sendmail import MailSender
11 | +import datetime
12 | +import logging
13 | +logger = logging.getLogger('default')
14 | +login_failure_counter = {}
15 | +# 账户锁定end
16 |
17 | @sensitive_post_parameters()
18 | @csrf_protect
19 | @@ -41,8 +48,22 @@
20 |
21 | if request.method == "POST":
22 | form = authentication_form(request, data=request.POST)
23 | - if form.is_valid():
24 | -
25 | +
26 | + # 增加账户锁定
27 | + failed_cnt = settings.LOCK_CNT_THRESHOLD
28 | + locking_time = settings.LOCK_TIME_THRESHOLD
29 | + username = request.POST['username']
30 | + mailSender = MailSender()
31 | + now_time = datetime.datetime.now()
32 | + mail_title = 'login inception admin'
33 | + login_failed_message = ''
34 | +
35 | + if username in login_failure_counter and login_failure_counter[username]['cnt'] >= failed_cnt and (now_time - login_failure_counter[username]["last_failure_time"]).seconds <= locking_time:
36 | + login_failed_message = 'user:{},login /admin failed, account locking...'.format(username)
37 | + logger.warning(login_failed_message)
38 | + mailSender.sendEmail(mail_title, login_failed_message, getattr(settings, 'MAIL_REVIEW_SECURE_ADDR'))
39 | + elif form.is_valid():
40 | + logger.info('user:{},login /admin success'.format(username))
41 | # Ensure the user-originating redirection url is safe.
42 | if not is_safe_url(url=redirect_to, host=request.get_host()):
43 | redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
44 | @@ -51,6 +72,15 @@
45 | auth_login(request, form.get_user())
46 |
47 | return HttpResponseRedirect(redirect_to)
48 | + else:
49 | + if username in login_failure_counter and (now_time - login_failure_counter[username]["last_failure_time"]).seconds <= locking_time:
50 | + login_failure_counter[username]["cnt"] += 1
51 | + else:
52 | + login_failure_counter[username] = {"cnt":1, "last_failure_time": datetime.datetime.now()}
53 | + login_failed_message = 'user:{},login /admin failed, fail count:{}'.format(username, login_failure_counter[username]["cnt"])
54 | + logger.warning(login_failed_message)
55 | + mailSender.sendEmail(mail_title, login_failed_message, getattr(settings, 'MAIL_REVIEW_SECURE_ADDR'))
56 | + #账户锁定end
57 | else:
58 | form = authentication_form(request)
59 |
60 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2022.12.7
2 | chardet==3.0.4
3 | Django==2.2.28
4 | idna==2.6
5 | Naked==0.1.31
6 | pycrypto==2.6.1
7 | PyMySQL==0.7.11
8 | PyYAML==5.4
9 | requests==2.20.0
10 | shellescape==3.4.1
11 | simplejson==3.14.0
12 | urllib3==1.26.5
13 | django-admin-bootstrapped==2.5.7
14 | django-apscheduler==0.2.8
15 |
--------------------------------------------------------------------------------
/sql/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/__init__.py
--------------------------------------------------------------------------------
/sql/admin.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | from django.contrib import admin
3 | from django.contrib.auth.admin import UserAdmin
4 | from django.contrib.auth.forms import UserCreationForm, UserChangeForm
5 |
6 | # Register your models here.
7 | from archer import settings
8 | from .models import users, master_config, slave_config, workflow, WorkflowAudit, WorkflowAuditSetting, \
9 | DataMaskingColumns, DataMaskingRules, AliyunAccessKey, AliyunRdsConfig
10 |
11 |
12 | # 主库配置管理
13 | @admin.register(master_config)
14 | class master_configAdmin(admin.ModelAdmin):
15 | list_display = ('id', 'cluster_name', 'master_host', 'master_port', 'master_user', 'create_time')
16 | search_fields = ['id', 'cluster_name', 'master_host', 'master_port', 'master_user', 'master_password',
17 | 'create_time', 'update_time']
18 |
19 |
20 | # SQL工单管理
21 | @admin.register(workflow)
22 | class workflowAdmin(admin.ModelAdmin):
23 | list_display = ('id', 'workflow_name', 'cluster_name', 'engineer', 'create_time', 'status', 'is_backup')
24 | search_fields = ['id', 'workflow_name', 'engineer', 'review_man', 'sql_content']
25 | exclude = ('is_manual',)
26 |
27 | @admin.register(users)
28 | class usersAdmin(UserAdmin):
29 | def __init__(self, *args, **kwargs):
30 | super(UserAdmin, self).__init__(*args, **kwargs)
31 | self.list_display = ('id', 'username', 'display', 'role', 'email', 'is_superuser', 'is_staff', 'is_active')
32 | self.search_fields = ('id', 'username', 'display', 'role', 'email')
33 | # 以上的属性都可以在django源码的UserAdmin类中找到,我们做以覆盖
34 |
35 | def changelist_view(self, request, extra_context=None):
36 | # 这个方法在源码的admin/options.py文件的ModelAdmin这个类中定义,我们要重新定义它,以达到不同权限的用户,返回的表单内容不同
37 | if request.user.is_superuser:
38 | # 此字段定义UserChangeForm表单中的具体显示内容,并可以分类显示
39 | self.fieldsets = (
40 | (('认证信息'), {'fields': ('username', 'password')}),
41 | (('个人信息'), {'fields': ('display', 'role', 'email')}),
42 | (('权限信息'), {'fields': ('is_active', 'is_staff')}),
43 | # (('Important dates'), {'fields': ('last_login', 'date_joined')}),
44 | )
45 | # 此字段定义UserCreationForm表单中的具体显示内容
46 | self.add_fieldsets = ((None, {'classes': ('wide',),
47 | 'fields': ('username', 'display', 'role', 'email', 'password1', 'password2'),
48 | }),
49 | )
50 | return super(UserAdmin, self).changelist_view(request, extra_context)
51 |
52 |
53 | if settings.QUERY:
54 | # 查询从库配置
55 | @admin.register(slave_config)
56 | class WorkflowAuditAdmin(admin.ModelAdmin):
57 | list_display = (
58 | 'id', 'cluster_name', 'slave_host', 'slave_port', 'slave_user', 'create_time', 'update_time')
59 | search_fields = ['id', 'cluster_name', 'slave_host', 'slave_port', 'slave_user', 'slave_password', ]
60 |
61 |
62 | # 工作流审核配置
63 | @admin.register(WorkflowAuditSetting)
64 | class WorkflowAuditSettingAdmin(admin.ModelAdmin):
65 | list_display = ('audit_setting_id', 'workflow_type', 'audit_users',)
66 |
67 | if settings.DATA_MASKING_ON_OFF:
68 | # 脱敏字段页面定义
69 | @admin.register(DataMaskingColumns)
70 | class DataMaskingColumnsAdmin(admin.ModelAdmin):
71 | list_display = (
72 | 'column_id', 'rule_type', 'active', 'cluster_name', 'table_schema', 'table_name', 'column_name',
73 | 'create_time',)
74 | search_fields = ['cluster_name', 'table_schema', 'table_name', 'column_name']
75 |
76 |
77 | # 脱敏规则页面定义
78 | @admin.register(DataMaskingRules)
79 | class DataMaskingRulesAdmin(admin.ModelAdmin):
80 | list_display = (
81 | 'rule_type', 'rule_regex', 'hide_group', 'rule_desc', 'sys_time',)
82 |
83 | if settings.ALIYUN_RDS_MANAGE:
84 | # 阿里云的认证信息
85 | @admin.register(AliyunAccessKey)
86 | class AliyunAccessKeyAdmin(admin.ModelAdmin):
87 | list_display = ('ak', 'secret', 'is_enable', 'remark',)
88 |
89 |
90 | # 阿里云集群配置信息
91 | @admin.register(AliyunRdsConfig)
92 | class AliyunRdsConfigAdmin(admin.ModelAdmin):
93 | list_display = ('cluster_name', 'rds_dbinstanceid',)
94 |
--------------------------------------------------------------------------------
/sql/aes_decryptor.py:
--------------------------------------------------------------------------------
1 | from Crypto.Cipher import AES
2 | from binascii import b2a_hex, a2b_hex
3 |
4 | class Prpcrypt():
5 | def __init__(self):
6 | self.key = 'eCcGFZQj6PNoSSma31LR39rTzTbLkU8E'.encode('utf-8')
7 | self.mode = AES.MODE_CBC
8 |
9 | #加密函数,如果text不足16位就用空格补足为16位,
10 | #如果大于16当时不是16的倍数,那就补足为16的倍数。
11 | def encrypt(self,text):
12 | cryptor = AES.new(self.key,self.mode,b'0000000000000000')
13 | #这里密钥key 长度必须为16(AES-128),
14 | #24(AES-192),或者32 (AES-256)Bytes 长度
15 | #目前AES-128 足够目前使用
16 | length = 16
17 | count = len(text)
18 | if count < length:
19 | add = (length-count)
20 | #\0 backspace
21 | text = text + ('\0' * add)
22 | elif count > length:
23 | add = (length-(count % length))
24 | text = text + ('\0' * add)
25 | self.ciphertext = cryptor.encrypt(text.encode('utf-8'))
26 | #因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
27 | #所以这里统一把加密后的字符串转化为16进制字符串
28 | return b2a_hex(self.ciphertext).decode(encoding='utf-8')
29 |
30 | #解密后,去掉补足的空格用strip() 去掉
31 | def decrypt(self,text):
32 | cryptor = AES.new(self.key,self.mode,b'0000000000000000')
33 | plain_text = cryptor.decrypt(a2b_hex(text))
34 | return plain_text.decode().rstrip('\0')
35 |
36 | if __name__ == '__main__':
37 | pc = Prpcrypt() #初始化密钥
38 | e = pc.encrypt('123456') #加密
39 | d = pc.decrypt(e) #解密
40 | print("加密:",str(e))
41 | print("解密:",str(d))
42 |
--------------------------------------------------------------------------------
/sql/aliyun_api.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import datetime
3 | from aliyunsdkcore import client
4 | from aliyunsdkrds.request.v20140815 import DescribeSlowLogsRequest, DescribeSlowLogRecordsRequest, \
5 | RequestServiceOfCloudDBARequest
6 | import simplejson as json
7 | from .models import AliyunAccessKey
8 | from .aes_decryptor import Prpcrypt
9 | import logging
10 |
11 | logger = logging.getLogger('default')
12 |
13 | class Aliyun(object):
14 | def __init__(self):
15 | try:
16 | auth = AliyunAccessKey.objects.filter(is_enable=1)
17 | prpCryptor = Prpcrypt()
18 | ak = prpCryptor.decrypt(auth[0].ak)
19 | secret = prpCryptor.decrypt(auth[0].secret)
20 | except Exception:
21 | logger.error('没有找到有效的ak信息!')
22 | else:
23 | self.clt = client.AcsClient(
24 | ak=ak,
25 | secret=secret)
26 | def request_api(self, request, *values):
27 | if values:
28 | for value in values:
29 | for k, v in value.items():
30 | request.add_query_param(k, v)
31 | request.set_accept_format('json')
32 | result = self.clt.do_action_with_exception(request)
33 | return json.dumps(json.loads(result.decode('utf-8')), indent=4, sort_keys=False, ensure_ascii=False)
34 |
35 | # 阿里云2017-12-10T16:00:00Z时间加上8小时时区显示
36 | def aliyun_time_format(self, str_time):
37 | if 'T' in str_time:
38 | Ymd = str_time.split('T')[0]
39 | HMS = str_time.split('T')[1].split('Z')[0]
40 | str_time = '%s %s' % (Ymd, HMS)
41 | time = datetime.datetime.strptime(str_time, "%Y-%m-%d %H:%M:%S")
42 | format_time = time + datetime.timedelta(hours=8)
43 | elif 'Z' in str_time:
44 | Ymd = str_time.split('Z')[0]
45 | format_time = '%s' % Ymd
46 | else:
47 | format_time = str_time
48 | return format_time
49 |
50 | def DescribeSlowLogs(self, DBInstanceId, StartTime, EndTime, **kwargs):
51 | '''获取集群慢日志列表
52 | DBName,SortKey、PageSize、PageNumber'''
53 | request = DescribeSlowLogsRequest.DescribeSlowLogsRequest()
54 | values = {"action_name": "DescribeSlowLogs", "DBInstanceId": DBInstanceId,
55 | "StartTime": StartTime, "EndTime": EndTime, "SortKey": "TotalExecutionCounts"}
56 | values = dict(values, **kwargs)
57 | result = self.request_api(request, values)
58 | return result
59 |
60 | def DescribeSlowLogRecords(self, DBInstanceId, StartTime, EndTime, **kwargs):
61 | '''查看慢日志明细
62 | SQLId,DBName、PageSize、PageNumber'''
63 | request = DescribeSlowLogRecordsRequest.DescribeSlowLogRecordsRequest()
64 | values = {"action_name": "DescribeSlowLogRecords", "DBInstanceId": DBInstanceId,
65 | "StartTime": StartTime, "EndTime": EndTime}
66 | values = dict(values, **kwargs)
67 | result = self.request_api(request, values)
68 | return result
69 |
70 | def RequestServiceOfCloudDBA(self, DBInstanceId, ServiceRequestType, ServiceRequestParam, **kwargs):
71 | '''
72 | 获取统计信息:'GetTimedMonData',{"Language":"zh","KeyGroup":"mem_cpu_usage","KeyName":"","StartTime":"2018-01-15T04:03:26Z","EndTime":"2018-01-15T05:03:26Z"}
73 | mem_cpu_usage、iops_usage、detailed_disk_space
74 | 获取process信息:'ShowProcessList',{"Language":"zh","Command":"Query"} -- Not Sleep , All
75 | 终止进程:'ConfirmKillSessionRequest',{"Language":"zh","SQLRequestID":75865,"SQLStatement":"kill 34022786;"}
76 | 获取表空间信息:'GetSpaceStatForTables',{"Language": "zh", "OrderType": "Data"}
77 | 获取资源利用信息:'GetResourceUsage',{"Language":"zh"}
78 | '''
79 | request = RequestServiceOfCloudDBARequest.RequestServiceOfCloudDBARequest()
80 | values = {"action_name": "RequestServiceOfCloudDBA", "DBInstanceId": DBInstanceId,
81 | "ServiceRequestType": ServiceRequestType, "ServiceRequestParam": ServiceRequestParam}
82 | values = dict(values, **kwargs)
83 | result = self.request_api(request, values)
84 | return result
85 |
--------------------------------------------------------------------------------
/sql/check_login_middleware.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import re
3 | from django.http import HttpResponseRedirect
4 |
5 | class CheckLoginMiddleware(object):
6 | def process_request(self, request):
7 | """
8 | 该函数在每个函数之前检查是否登录,若未登录,则重定向到/login/
9 | """
10 | if request.session.get('login_username', False) in (False, '匿名用户'):
11 | #以下是不用跳转到login页面的url白名单
12 | if request.path not in ('/login/', '/authenticate/') and re.match(r"/admin/\w*", request.path) is None:
13 | return HttpResponseRedirect('/login/')
14 |
--------------------------------------------------------------------------------
/sql/const.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 |
3 | class Const(object):
4 | workflowStatus = {
5 | 'finish': '已正常结束',
6 | 'abort': '人工终止流程',
7 | 'autoreviewing': '自动审核中',
8 | 'manreviewing': '等待审核人审核',
9 | 'pass': '审核通过',
10 | 'timingtask': '定时执行',
11 | 'executing': '执行中',
12 | 'autoreviewwrong': '自动审核不通过',
13 | 'exception': '执行有异常',
14 | }
15 | # 定时任务id的前缀
16 | workflowJobprefix = {
17 | 'query': 'query',
18 | 'sqlreview': 'sqlreview',
19 | }
20 |
21 |
22 | class WorkflowDict:
23 | # 工作流申请类型,1.query
24 | workflow_type = {
25 | 'query': 1,
26 | 'query_display': '查询权限申请',
27 | }
28 |
29 | # 工作流状态,0.待审核 1.审核通过 2.审核不通过 3.审核取消
30 | workflow_status = {
31 | 'audit_wait': 0,
32 | 'audit_wait_display': '待审核',
33 | 'audit_success': 1,
34 | 'audit_success_display': '审核通过',
35 | 'audit_reject': 2,
36 | 'audit_reject_display': '审核不通过',
37 | 'audit_abort': 3,
38 | 'audit_abort_display': '审核取消',
39 | }
40 |
--------------------------------------------------------------------------------
/sql/exception_logging_middleware.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import logging
3 |
4 | logger = logging.getLogger('default')
5 |
6 |
7 | class ExceptionLoggingMiddleware(object):
8 | def process_exception(self, request, exception):
9 | import traceback
10 | logger.error(traceback.format_exc())
11 |
--------------------------------------------------------------------------------
/sql/extend_json_encoder.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import simplejson as json
3 |
4 | from datetime import datetime, date, timedelta
5 | from decimal import Decimal
6 | from functools import singledispatch
7 |
8 |
9 | class MyClass:
10 | def __init__(self, value):
11 | self._value = value
12 |
13 | def get_value(self):
14 | return self._value
15 |
16 |
17 | # 创建非内置类型的实例
18 | mc = MyClass('i am class MyClass ')
19 | dm = Decimal('11.11')
20 | dt = datetime.now()
21 | dat = date.today()
22 |
23 |
24 | @singledispatch
25 | def convert(o):
26 | raise TypeError('can not convert type')
27 |
28 |
29 | @convert.register(datetime)
30 | def _(o):
31 | return o.strftime('%Y-%m-%d %H:%M:%S')
32 |
33 |
34 | @convert.register(date)
35 | def _(o):
36 | return o.strftime('%Y-%m-%d')
37 |
38 |
39 | @convert.register(timedelta)
40 | def _(o):
41 | return o.total_seconds()
42 |
43 | # @convert.register(Decimal)
44 | # def _(o):
45 | # return float(o)
46 |
47 |
48 | @convert.register(MyClass)
49 | def _(o):
50 | return o.get_value()
51 |
52 |
53 | class ExtendJSONEncoder(json.JSONEncoder):
54 | def default(self, obj):
55 | try:
56 | return convert(obj)
57 | except TypeError:
58 | return super(ExtendJSONEncoder, self).default(obj)
59 |
60 |
61 | data = {
62 | 'mc': mc,
63 | 'dm': dm,
64 | 'dt': dt,
65 | 'dat': dat,
66 | 'tl': timedelta(minutes=30),
67 | 'bigint': 988983860501598208
68 | }
69 |
70 | # print(json.dumps(data, cls=ExtendJSONEncoder, bigint_as_string=True))
71 | # print(json.dumps(data, cls=ExtendJSONEncoder, bigint_as_string=True, default=str))
72 |
--------------------------------------------------------------------------------
/sql/jobs.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | import datetime
3 | import time
4 |
5 | from apscheduler.schedulers.background import BackgroundScheduler
6 | from apscheduler.schedulers import SchedulerAlreadyRunningError, SchedulerNotRunningError
7 | from django.core.urlresolvers import reverse
8 | from django.http import HttpResponseRedirect
9 | from django.shortcuts import render
10 | from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
11 |
12 | from sql.const import Const
13 | from sql.models import workflow
14 | from .sqlreview import execute_job, getDetailUrl
15 |
16 | import logging
17 |
18 | logging.basicConfig()
19 | logging.getLogger('apscheduler').setLevel(logging.DEBUG)
20 |
21 | logger = logging.getLogger('default')
22 |
23 | # 初始化scheduler
24 | scheduler = BackgroundScheduler()
25 | scheduler.add_jobstore(DjangoJobStore(), "default")
26 | register_events(scheduler)
27 | try:
28 | scheduler.start()
29 | logger.debug("Scheduler started!")
30 | except SchedulerAlreadyRunningError:
31 | logger.debug("Scheduler is already running!")
32 |
33 |
34 | # 添加/修改sql执行任务
35 | def add_sqlcronjob(job_id, run_date, workflowId, url):
36 | scheduler = BackgroundScheduler()
37 | scheduler.add_jobstore(DjangoJobStore(), "default")
38 | scheduler.add_job(execute_job, 'date', run_date=run_date, args=[workflowId, url], id=job_id,
39 | replace_existing=True)
40 | register_events(scheduler)
41 | try:
42 | scheduler.start()
43 | logger.debug("Scheduler started!")
44 | except SchedulerAlreadyRunningError:
45 | logger.debug("Scheduler is already running!")
46 | logger.debug('add_sqlcronjob:' + job_id + " run_date:" + run_date.strftime('%Y-%m-%d %H:%M:%S'))
47 |
48 |
49 | # 删除sql执行任务
50 | def del_sqlcronjob(job_id):
51 | logger.debug('del_sqlcronjob:' + job_id)
52 | return scheduler.remove_job(job_id)
53 |
54 |
55 | # 获取任务详情
56 | def job_info(job_id):
57 | return scheduler.get_job(job_id)
58 |
--------------------------------------------------------------------------------
/sql/permission.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import simplejson as json
3 | from django.shortcuts import render
4 | from django.http import HttpResponse
5 | from .models import users
6 |
7 |
8 | # 管理员操作权限验证
9 | def superuser_required(func):
10 | def wrapper(request, *args, **kw):
11 | # 获取用户信息,权限验证
12 | loginUser = request.session.get('login_username', False)
13 | loginUserOb = users.objects.get(username=loginUser)
14 |
15 | if loginUserOb.is_superuser is False:
16 | if request.is_ajax():
17 | finalResult = {'status': 1, 'msg': '您无权操作,请联系管理员', 'data': []}
18 | return HttpResponse(json.dumps(finalResult), content_type='application/json')
19 | else:
20 | context = {'errMsg': "您无权操作,请联系管理员"}
21 | return render(request, "error.html", context)
22 |
23 | return func(request, *args, **kw)
24 |
25 | return wrapper
26 |
27 |
28 | # 角色操作权限验证
29 | def role_required(roles=()):
30 | def _deco(func):
31 | def wrapper(request, *args, **kw):
32 | # 获取用户信息,权限验证
33 | loginUser = request.session.get('login_username', False)
34 | loginUserOb = users.objects.get(username=loginUser)
35 | loginrole = loginUserOb.role
36 |
37 | if loginrole not in roles and loginUserOb.is_superuser is False:
38 | if request.is_ajax():
39 | finalResult = {'status': 1, 'msg': '您无权操作,请联系管理员', 'data': []}
40 | return HttpResponse(json.dumps(finalResult), content_type='application/json')
41 | else:
42 | context = {'errMsg': "您无权操作,请联系管理员"}
43 | return render(request, "error.html", context)
44 |
45 | return func(request, *args, **kw)
46 |
47 | return wrapper
48 |
49 | return _deco
50 |
--------------------------------------------------------------------------------
/sql/processor.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | from sql.workflow import Workflow
3 | from .models import users
4 | from django.conf import settings
5 |
6 | leftMenuBtnsCommon = (
7 | {'key': 'allworkflow', 'name': 'SQL上线工单', 'url': '/allworkflow/', 'class': 'glyphicon glyphicon-home',
8 | 'display': True},
9 | {'key': 'sqlquery', 'name': 'SQL在线查询', 'url': '/sqlquery/', 'class': 'glyphicon glyphicon-search',
10 | 'display': settings.QUERY},
11 | {'key': 'slowquery', 'name': 'SQL慢查日志', 'url': '/slowquery/', 'class': 'glyphicon glyphicon-align-right',
12 | 'display': settings.SLOWQUERY},
13 | {'key': 'sqladvisor', 'name': 'SQL优化工具', 'url': '/sqladvisor/', 'class': 'glyphicon glyphicon-wrench',
14 | 'display': settings.SQLADVISOR},
15 | {'key': 'queryapply', 'name': '查询权限管理', 'url': '/queryapplylist/', 'class': 'glyphicon glyphicon-eye-open',
16 | 'display': settings.QUERY}
17 | )
18 |
19 | leftMenuBtnsSuper = (
20 | {'key': 'diagnosis', 'name': '主库会话管理', 'url': '/diagnosis_process/', 'class': 'glyphicon glyphicon-scissors',
21 | 'display': True},
22 | {'key': 'admin', 'name': '后台数据管理', 'url': '/admin/sql/', 'class': 'glyphicon glyphicon-list', 'display': True},
23 | )
24 |
25 | leftMenuBtnsDoc = (
26 | {'key': 'dbaprinciples', 'name': 'SQL审核必读', 'url': '/dbaprinciples/', 'class': 'glyphicon glyphicon-book',
27 | 'display': True},
28 | {'key': 'charts', 'name': '统计图表展示', 'url': '/charts/', 'class': 'glyphicon glyphicon-file', 'display': True},
29 | )
30 |
31 |
32 | def global_info(request):
33 | """存放用户,会话信息等."""
34 | loginUser = request.session.get('login_username', None)
35 | if loginUser is not None:
36 | user = users.objects.get(username=loginUser)
37 | UserDisplay = user.display
38 | if UserDisplay == '':
39 | UserDisplay = loginUser
40 | if user.is_superuser:
41 | leftMenuBtns = leftMenuBtnsCommon + leftMenuBtnsSuper + leftMenuBtnsDoc
42 | else:
43 | leftMenuBtns = leftMenuBtnsCommon + leftMenuBtnsDoc
44 | # 获取代办数量
45 | try:
46 | todo = Workflow().auditlist(user, 0, 0, 1)['data']['auditlistCount']
47 | except Exception:
48 | todo = 0
49 | else:
50 | leftMenuBtns = ()
51 | UserDisplay = ''
52 | todo = 0
53 |
54 | return {
55 | 'loginUser': loginUser,
56 | 'leftMenuBtns': leftMenuBtns,
57 | 'UserDisplay': UserDisplay,
58 | 'todo': todo
59 | }
60 |
--------------------------------------------------------------------------------
/sql/sendmail.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import traceback
3 | from multiprocessing import Process
4 | import email
5 | from email import encoders
6 | from email.header import Header
7 | from email.mime.text import MIMEText
8 | from email.utils import parseaddr, formataddr
9 | import smtplib
10 |
11 | from django.conf import settings
12 | import logging
13 |
14 | logger = logging.getLogger('default')
15 |
16 |
17 | class MailSender(object):
18 |
19 | def __init__(self):
20 | try:
21 | self.MAIL_REVIEW_SMTP_SERVER = getattr(settings, 'MAIL_REVIEW_SMTP_SERVER')
22 | self.MAIL_REVIEW_SMTP_PORT = int(getattr(settings, 'MAIL_REVIEW_SMTP_PORT'))
23 | self.MAIL_REVIEW_FROM_ADDR = getattr(settings, 'MAIL_REVIEW_FROM_ADDR')
24 | self.MAIL_REVIEW_FROM_PASSWORD = getattr(settings, 'MAIL_REVIEW_FROM_PASSWORD')
25 | self.SSL = getattr(settings, 'MAIL_SSL')
26 |
27 | except AttributeError as a:
28 | print("Error: %s" % a)
29 | except ValueError as v:
30 | print("Error: %s" % v)
31 |
32 | def _format_addr(self, s):
33 | name, addr = parseaddr(s)
34 | return formataddr((Header(name, 'utf-8').encode(), addr))
35 |
36 | def _add_attachment(self, filename):
37 | '''''
38 | 添加附件
39 | '''
40 | file_msg = email.mime.base.MIMEBase('application', 'octet-stream')
41 | file_msg.set_payload(open(filename, 'rb').read())
42 | # 附件如果有中文会出现乱码问题,加入gbk
43 | file_msg.add_header('Content-Disposition', 'attachment', filename=('gbk', '', filename.split('/')[-1]))
44 | encoders.encode_base64(file_msg)
45 |
46 | return file_msg
47 |
48 | def _send(self, strTitle, strContent, listToAddr, **kwargs):
49 | '''''
50 | 发送邮件
51 | '''
52 | # 构造MIMEMultipart对象做为根容器
53 | main_msg = email.mime.multipart.MIMEMultipart()
54 |
55 | # 添加文本内容
56 | text_msg = email.mime.text.MIMEText(strContent, 'plain', 'utf-8')
57 | main_msg.attach(text_msg)
58 |
59 | # 添加附件
60 | filename_list = kwargs.get('filename_list')
61 | if filename_list:
62 | for filename in kwargs['filename_list']:
63 | file_msg = self._add_attachment(filename)
64 | main_msg.attach(file_msg)
65 |
66 | # 收发件人地址和邮件标题:
67 | main_msg['From'] = formataddr(["archer 通知", self.MAIL_REVIEW_FROM_ADDR])
68 | main_msg['To'] = ','.join(listToAddr)
69 | listCcAddr = kwargs.get('listCcAddr')
70 | if listCcAddr:
71 | main_msg['Cc'] = ', '.join(kwargs['listCcAddr'])
72 | listAddr = listToAddr + listCcAddr
73 | else:
74 | listAddr = listToAddr
75 | main_msg['Subject'] = Header(strTitle, "utf-8").encode()
76 | main_msg['Date'] = email.utils.formatdate()
77 |
78 | if self.SSL:
79 | server = smtplib.SMTP_SSL(self.MAIL_REVIEW_SMTP_SERVER, self.MAIL_REVIEW_SMTP_PORT) # SMTP协议默认SSL端口是465
80 | else:
81 | server = smtplib.SMTP(self.MAIL_REVIEW_SMTP_SERVER, self.MAIL_REVIEW_SMTP_PORT) # SMTP协议默认端口是25
82 | # server.set_debuglevel(1)
83 |
84 | # 如果提供的密码为空,则不需要登录SMTP server
85 | if self.MAIL_REVIEW_FROM_PASSWORD != '':
86 | server.login(self.MAIL_REVIEW_FROM_ADDR, self.MAIL_REVIEW_FROM_PASSWORD)
87 | sendResult = server.sendmail(self.MAIL_REVIEW_FROM_ADDR, listAddr, main_msg.as_string())
88 | server.quit()
89 |
90 | # 调用方应该调用此方法,采用子进程方式异步阻塞地发送邮件,避免邮件服务挂掉影响archer主服务
91 | def sendEmail(self, strTitle, strContent, listToAddr, **kwargs):
92 | try:
93 | p = Process(target=self._send, args=(strTitle, strContent, listToAddr), kwargs=kwargs)
94 | p.start()
95 | except Exception:
96 | logger.error(traceback.format_exc())
97 |
--------------------------------------------------------------------------------
/sql/sqlreview.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import simplejson as json
3 |
4 | import time
5 | from threading import Thread
6 |
7 | from django.db import connection
8 | from django.utils import timezone
9 | from django.conf import settings
10 |
11 | from .dao import Dao
12 | from .const import Const, WorkflowDict
13 | from .sendmail import MailSender
14 | from .inception import InceptionDao
15 | from .aes_decryptor import Prpcrypt
16 | from .models import users, workflow, master_config
17 | from .workflow import Workflow
18 | from .permission import role_required, superuser_required
19 | import logging
20 |
21 | logger = logging.getLogger('default')
22 |
23 | dao = Dao()
24 | inceptionDao = InceptionDao()
25 | mailSender = MailSender()
26 | prpCryptor = Prpcrypt()
27 | workflowOb = Workflow()
28 |
29 |
30 | # 获取当前请求url
31 | def getDetailUrl(request):
32 | scheme = request.scheme
33 | host = request.META['HTTP_HOST']
34 | return "%s://%s/detail/" % (scheme, host)
35 |
36 |
37 | # 根据实例名获取主库连接字符串,并封装成一个dict
38 | def getMasterConnStr(clusterName):
39 | listMasters = master_config.objects.filter(cluster_name=clusterName)
40 |
41 | masterHost = listMasters[0].master_host
42 | masterPort = listMasters[0].master_port
43 | masterUser = listMasters[0].master_user
44 | masterPassword = prpCryptor.decrypt(listMasters[0].master_password)
45 | dictConn = {'masterHost': masterHost, 'masterPort': masterPort, 'masterUser': masterUser,
46 | 'masterPassword': masterPassword}
47 | return dictConn
48 |
49 |
50 | # SQL工单执行回调
51 | def execute_call_back(workflowId, clusterName, url):
52 | workflowDetail = workflow.objects.get(id=workflowId)
53 | # 获取审核人
54 | try:
55 | listAllReviewMen = json.loads(workflowDetail.review_man)
56 | except ValueError:
57 | listAllReviewMen = (workflowDetail.review_man,)
58 |
59 | dictConn = getMasterConnStr(clusterName)
60 | try:
61 | # 交给inception先split,再执行
62 | logger.debug('execute_call_back:' + str(workflowId) + ' executing')
63 | (finalStatus, finalList) = inceptionDao.executeFinal(workflowDetail, dictConn)
64 |
65 | # 封装成JSON格式存进数据库字段里
66 | strJsonResult = json.dumps(finalList)
67 | workflowDetail = workflow.objects.get(id=workflowId)
68 | workflowDetail.execute_result = strJsonResult
69 | workflowDetail.finish_time = timezone.now()
70 | workflowDetail.status = finalStatus
71 | workflowDetail.is_manual = 0
72 | workflowDetail.audit_remark = ''
73 | # 重新获取连接,防止超时
74 | connection.close()
75 | workflowDetail.save()
76 | logger.debug('execute_call_back:' + str(workflowId) + ' finish')
77 | except Exception as e:
78 | logger.error(e)
79 |
80 | # 如果执行完毕了,则根据settings.py里的配置决定是否给提交者和DBA一封邮件提醒.DBA需要知晓审核并执行过的单子
81 | if hasattr(settings, 'MAIL_ON_OFF') == True:
82 | if getattr(settings, 'MAIL_ON_OFF') == "on":
83 | # 给主、副审核人,申请人,DBA各发一封邮件
84 | engineer = workflowDetail.engineer
85 | reviewMen = workflowDetail.review_man
86 | workflowStatus = workflowDetail.status
87 | workflowName = workflowDetail.workflow_name
88 | objEngineer = users.objects.get(username=engineer)
89 | strTitle = "SQL上线工单执行完毕 # " + str(workflowId)
90 | strContent = "发起人:" + engineer + "\n审核人:" + reviewMen + "\n工单地址:" + url + "\n工单名称: " + workflowName + "\n执行结果:" + workflowStatus
91 | reviewManAddr = [email['email'] for email in
92 | users.objects.filter(username__in=listAllReviewMen).values('email')]
93 | dbaAddr = [email['email'] for email in users.objects.filter(role='DBA').values('email')]
94 | listCcAddr = reviewManAddr + dbaAddr
95 | mailSender.sendEmail(strTitle, strContent, [objEngineer.email], listCcAddr=listCcAddr)
96 |
97 |
98 | # 给定时任务执行sql
99 | def execute_job(workflowId, url):
100 | job_id = Const.workflowJobprefix['sqlreview'] + '-' + str(workflowId)
101 | logger.debug('execute_job:' + job_id + ' start')
102 | workflowDetail = workflow.objects.get(id=workflowId)
103 | clusterName = workflowDetail.cluster_name
104 |
105 | # 服务器端二次验证,当前工单状态必须为定时执行过状态
106 | if workflowDetail.status != Const.workflowStatus['timingtask']:
107 | raise Exception('工单不是定时执行状态')
108 |
109 | # 将流程状态修改为执行中,并更新reviewok_time字段
110 | workflowDetail.status = Const.workflowStatus['executing']
111 | workflowDetail.reviewok_time = timezone.now()
112 | try:
113 | workflowDetail.save()
114 | except Exception:
115 | # 关闭后重新获取连接,防止超时
116 | connection.close()
117 | workflowDetail.save()
118 | logger.debug('execute_job:' + job_id + ' executing')
119 | # 执行之前重新split并check一遍,更新SHA1缓存;因为如果在执行中,其他进程去做这一步操作的话,会导致inception core dump挂掉
120 | splitReviewResult = inceptionDao.sqlautoReview(workflowDetail.sql_content, workflowDetail.cluster_name,
121 | isSplit='yes')
122 | workflowDetail.review_content = json.dumps(splitReviewResult)
123 | try:
124 | workflowDetail.save()
125 | except Exception:
126 | # 关闭后重新获取连接,防止超时
127 | connection.close()
128 | workflowDetail.save()
129 |
130 | # 采取异步回调的方式执行语句,防止出现持续执行中的异常
131 | t = Thread(target=execute_call_back, args=(workflowId, clusterName, url))
132 | t.start()
133 |
--------------------------------------------------------------------------------
/sql/static/ace/snippets/sql.js:
--------------------------------------------------------------------------------
1 | define("ace/snippets/sql",["require","exports","module"], function(require, exports, module) {
2 | "use strict";
3 |
4 | exports.snippetText = "snippet tbl\n\
5 | create table ${1:table} (\n\
6 | ${2:columns}\n\
7 | );\n\
8 | snippet col\n\
9 | ${1:name} ${2:type} ${3:default ''} ${4:not null}\n\
10 | snippet ccol\n\
11 | ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\n\
12 | snippet ncol\n\
13 | ${1:name} number ${3:default 0} ${4:not null}\n\
14 | snippet dcol\n\
15 | ${1:name} date ${3:default sysdate} ${4:not null}\n\
16 | snippet ind\n\
17 | create index ${3:$1_$2} on ${1:table}(${2:column});\n\
18 | snippet uind\n\
19 | create unique index ${1:name} on ${2:table}(${3:column});\n\
20 | snippet tblcom\n\
21 | comment on table ${1:table} is '${2:comment}';\n\
22 | snippet colcom\n\
23 | comment on column ${1:table}.${2:column} is '${3:comment}';\n\
24 | snippet addcol\n\
25 | alter table ${1:table} add (${2:column} ${3:type});\n\
26 | snippet seq\n\
27 | create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\n\
28 | snippet s*\n\
29 | select * from ${1:table}\n\
30 | ";
31 | exports.scope = "sql";
32 |
33 | });
34 |
--------------------------------------------------------------------------------
/sql/static/ace/theme-github.js:
--------------------------------------------------------------------------------
1 | define("ace/theme/github",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
2 |
3 | exports.isDark = false;
4 | exports.cssClass = "ace-github";
5 | exports.cssText = "\
6 | .ace-github .ace_gutter {\
7 | background: #e8e8e8;\
8 | color: #AAA;\
9 | }\
10 | .ace-github {\
11 | background: #fff;\
12 | color: #000;\
13 | }\
14 | .ace-github .ace_keyword {\
15 | font-weight: bold;\
16 | }\
17 | .ace-github .ace_string {\
18 | color: #D14;\
19 | }\
20 | .ace-github .ace_variable.ace_class {\
21 | color: teal;\
22 | }\
23 | .ace-github .ace_constant.ace_numeric {\
24 | color: #099;\
25 | }\
26 | .ace-github .ace_constant.ace_buildin {\
27 | color: #0086B3;\
28 | }\
29 | .ace-github .ace_support.ace_function {\
30 | color: #0086B3;\
31 | }\
32 | .ace-github .ace_comment {\
33 | color: #998;\
34 | font-style: italic;\
35 | }\
36 | .ace-github .ace_variable.ace_language {\
37 | color: #0086B3;\
38 | }\
39 | .ace-github .ace_paren {\
40 | font-weight: bold;\
41 | }\
42 | .ace-github .ace_boolean {\
43 | font-weight: bold;\
44 | }\
45 | .ace-github .ace_string.ace_regexp {\
46 | color: #009926;\
47 | font-weight: normal;\
48 | }\
49 | .ace-github .ace_variable.ace_instance {\
50 | color: teal;\
51 | }\
52 | .ace-github .ace_constant.ace_language {\
53 | font-weight: bold;\
54 | }\
55 | .ace-github .ace_cursor {\
56 | color: black;\
57 | }\
58 | .ace-github.ace_focus .ace_marker-layer .ace_active-line {\
59 | background: rgb(255, 255, 204);\
60 | }\
61 | .ace-github .ace_marker-layer .ace_active-line {\
62 | background: rgb(245, 245, 245);\
63 | }\
64 | .ace-github .ace_marker-layer .ace_selection {\
65 | background: rgb(181, 213, 255);\
66 | }\
67 | .ace-github.ace_multiselect .ace_selection.ace_start {\
68 | box-shadow: 0 0 3px 0px white;\
69 | }\
70 | .ace-github.ace_nobold .ace_line > span {\
71 | font-weight: normal !important;\
72 | }\
73 | .ace-github .ace_marker-layer .ace_step {\
74 | background: rgb(252, 255, 0);\
75 | }\
76 | .ace-github .ace_marker-layer .ace_stack {\
77 | background: rgb(164, 229, 101);\
78 | }\
79 | .ace-github .ace_marker-layer .ace_bracket {\
80 | margin: -1px 0 0 -1px;\
81 | border: 1px solid rgb(192, 192, 192);\
82 | }\
83 | .ace-github .ace_gutter-active-line {\
84 | background-color : rgba(0, 0, 0, 0.07);\
85 | }\
86 | .ace-github .ace_marker-layer .ace_selected-word {\
87 | background: rgb(250, 250, 255);\
88 | border: 1px solid rgb(200, 200, 250);\
89 | }\
90 | .ace-github .ace_invisible {\
91 | color: #BFBFBF\
92 | }\
93 | .ace-github .ace_print-margin {\
94 | width: 1px;\
95 | background: #e8e8e8;\
96 | }\
97 | .ace-github .ace_indent-guide {\
98 | background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
99 | }";
100 |
101 | var dom = require("../lib/dom");
102 | dom.importCssString(exports.cssText, exports.cssClass);
103 | });
104 |
--------------------------------------------------------------------------------
/sql/static/ace/theme-textmate.js:
--------------------------------------------------------------------------------
1 | define("ace/theme/textmate",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
2 | "use strict";
3 |
4 | exports.isDark = false;
5 | exports.cssClass = "ace-tm";
6 | exports.cssText = ".ace-tm .ace_gutter {\
7 | background: #f0f0f0;\
8 | color: #333;\
9 | }\
10 | .ace-tm .ace_print-margin {\
11 | width: 1px;\
12 | background: #e8e8e8;\
13 | }\
14 | .ace-tm .ace_fold {\
15 | background-color: #6B72E6;\
16 | }\
17 | .ace-tm {\
18 | background-color: #FFFFFF;\
19 | color: black;\
20 | }\
21 | .ace-tm .ace_cursor {\
22 | color: black;\
23 | }\
24 | .ace-tm .ace_invisible {\
25 | color: rgb(191, 191, 191);\
26 | }\
27 | .ace-tm .ace_storage,\
28 | .ace-tm .ace_keyword {\
29 | color: blue;\
30 | }\
31 | .ace-tm .ace_constant {\
32 | color: rgb(197, 6, 11);\
33 | }\
34 | .ace-tm .ace_constant.ace_buildin {\
35 | color: rgb(88, 72, 246);\
36 | }\
37 | .ace-tm .ace_constant.ace_language {\
38 | color: rgb(88, 92, 246);\
39 | }\
40 | .ace-tm .ace_constant.ace_library {\
41 | color: rgb(6, 150, 14);\
42 | }\
43 | .ace-tm .ace_invalid {\
44 | background-color: rgba(255, 0, 0, 0.1);\
45 | color: red;\
46 | }\
47 | .ace-tm .ace_support.ace_function {\
48 | color: rgb(60, 76, 114);\
49 | }\
50 | .ace-tm .ace_support.ace_constant {\
51 | color: rgb(6, 150, 14);\
52 | }\
53 | .ace-tm .ace_support.ace_type,\
54 | .ace-tm .ace_support.ace_class {\
55 | color: rgb(109, 121, 222);\
56 | }\
57 | .ace-tm .ace_keyword.ace_operator {\
58 | color: rgb(104, 118, 135);\
59 | }\
60 | .ace-tm .ace_string {\
61 | color: rgb(3, 106, 7);\
62 | }\
63 | .ace-tm .ace_comment {\
64 | color: rgb(76, 136, 107);\
65 | }\
66 | .ace-tm .ace_comment.ace_doc {\
67 | color: rgb(0, 102, 255);\
68 | }\
69 | .ace-tm .ace_comment.ace_doc.ace_tag {\
70 | color: rgb(128, 159, 191);\
71 | }\
72 | .ace-tm .ace_constant.ace_numeric {\
73 | color: rgb(0, 0, 205);\
74 | }\
75 | .ace-tm .ace_variable {\
76 | color: rgb(49, 132, 149);\
77 | }\
78 | .ace-tm .ace_xml-pe {\
79 | color: rgb(104, 104, 91);\
80 | }\
81 | .ace-tm .ace_entity.ace_name.ace_function {\
82 | color: #0000A2;\
83 | }\
84 | .ace-tm .ace_heading {\
85 | color: rgb(12, 7, 255);\
86 | }\
87 | .ace-tm .ace_list {\
88 | color:rgb(185, 6, 144);\
89 | }\
90 | .ace-tm .ace_meta.ace_tag {\
91 | color:rgb(0, 22, 142);\
92 | }\
93 | .ace-tm .ace_string.ace_regex {\
94 | color: rgb(255, 0, 0)\
95 | }\
96 | .ace-tm .ace_marker-layer .ace_selection {\
97 | background: rgb(181, 213, 255);\
98 | }\
99 | .ace-tm.ace_multiselect .ace_selection.ace_start {\
100 | box-shadow: 0 0 3px 0px white;\
101 | }\
102 | .ace-tm .ace_marker-layer .ace_step {\
103 | background: rgb(252, 255, 0);\
104 | }\
105 | .ace-tm .ace_marker-layer .ace_stack {\
106 | background: rgb(164, 229, 101);\
107 | }\
108 | .ace-tm .ace_marker-layer .ace_bracket {\
109 | margin: -1px 0 0 -1px;\
110 | border: 1px solid rgb(192, 192, 192);\
111 | }\
112 | .ace-tm .ace_marker-layer .ace_active-line {\
113 | background: rgba(0, 0, 0, 0.07);\
114 | }\
115 | .ace-tm .ace_gutter-active-line {\
116 | background-color : #dcdcdc;\
117 | }\
118 | .ace-tm .ace_marker-layer .ace_selected-word {\
119 | background: rgb(250, 250, 255);\
120 | border: 1px solid rgb(200, 200, 250);\
121 | }\
122 | .ace-tm .ace_indent-guide {\
123 | background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y;\
124 | }\
125 | ";
126 |
127 | var dom = require("../lib/dom");
128 | dom.importCssString(exports.cssText, exports.cssClass);
129 | });
130 |
--------------------------------------------------------------------------------
/sql/static/admin/css/dashboard.css:
--------------------------------------------------------------------------------
1 | /* DASHBOARD */
2 |
3 | .dashboard .module table th {
4 | width: 100%;
5 | }
6 |
7 | .dashboard .module table td {
8 | white-space: nowrap;
9 | }
10 |
11 | .dashboard .module table td a {
12 | display: block;
13 | padding-right: .6em;
14 | }
15 |
16 | /* RECENT ACTIONS MODULE */
17 |
18 | .module ul.actionlist {
19 | margin-left: 0;
20 | }
21 |
22 | ul.actionlist li {
23 | list-style-type: none;
24 | }
25 |
26 | ul.actionlist li {
27 | overflow: hidden;
28 | text-overflow: ellipsis;
29 | -o-text-overflow: ellipsis;
30 | }
31 |
--------------------------------------------------------------------------------
/sql/static/admin/css/ie.css:
--------------------------------------------------------------------------------
1 | /* IE 6 & 7 */
2 |
3 | /* Proper fixed width for dashboard in IE6 */
4 |
5 | .dashboard #content {
6 | *width: 768px;
7 | }
8 |
9 | .dashboard #content-main {
10 | *width: 535px;
11 | }
12 |
13 | /* IE 6 ONLY */
14 |
15 | /* Keep header from flowing off the page */
16 |
17 | #container {
18 | _position: static;
19 | }
20 |
21 | /* Put the right sidebars back on the page */
22 |
23 | .colMS #content-related {
24 | _margin-right: 0;
25 | _margin-left: 10px;
26 | _position: static;
27 | }
28 |
29 | /* Put the left sidebars back on the page */
30 |
31 | .colSM #content-related {
32 | _margin-right: 10px;
33 | _margin-left: -115px;
34 | _position: static;
35 | }
36 |
37 | .form-row {
38 | _height: 1%;
39 | }
40 |
41 | /* Fix right margin for changelist filters in IE6 */
42 |
43 | #changelist-filter ul {
44 | _margin-right: -10px;
45 | }
46 |
47 | /* IE ignores min-height, but treats height as if it were min-height */
48 |
49 | .change-list .filtered {
50 | _height: 400px;
51 | }
52 |
53 | /* IE doesn't know alpha transparency in PNGs */
54 |
55 | .inline-deletelink {
56 | background: transparent url(../img/inline-delete-8bit.png) no-repeat;
57 | }
58 |
59 | /* IE7 doesn't support inline-block */
60 | .change-list ul.toplinks li {
61 | zoom: 1;
62 | *display: inline;
63 | }
64 |
--------------------------------------------------------------------------------
/sql/static/admin/css/login.css:
--------------------------------------------------------------------------------
1 | /* LOGIN FORM */
2 |
3 | body.login {
4 | background: #eee;
5 | }
6 |
7 | .login #container {
8 | background: white;
9 | border: 1px solid #ccc;
10 | width: 28em;
11 | min-width: 300px;
12 | margin-left: auto;
13 | margin-right: auto;
14 | margin-top: 100px;
15 | }
16 |
17 | .login #content-main {
18 | width: 100%;
19 | }
20 |
21 | .login form {
22 | margin-top: 1em;
23 | }
24 |
25 | .login .form-row {
26 | padding: 4px 0;
27 | float: left;
28 | width: 100%;
29 | }
30 |
31 | .login .form-row label {
32 | padding-right: 0.5em;
33 | line-height: 2em;
34 | font-size: 1em;
35 | clear: both;
36 | color: #333;
37 | }
38 |
39 | .login .form-row #id_username, .login .form-row #id_password {
40 | clear: both;
41 | padding: 6px;
42 | width: 100%;
43 | -webkit-box-sizing: border-box;
44 | -moz-box-sizing: border-box;
45 | box-sizing: border-box;
46 | }
47 |
48 | .login span.help {
49 | font-size: 10px;
50 | display: block;
51 | }
52 |
53 | .login .submit-row {
54 | clear: both;
55 | padding: 1em 0 0 9.4em;
56 | }
57 |
58 | .login .password-reset-link {
59 | text-align: center;
60 | }
61 |
--------------------------------------------------------------------------------
/sql/static/admin/css/rtl.css:
--------------------------------------------------------------------------------
1 | body {
2 | direction: rtl;
3 | }
4 |
5 | /* LOGIN */
6 |
7 | .login .form-row {
8 | float: right;
9 | }
10 |
11 | .login .form-row label {
12 | float: right;
13 | padding-left: 0.5em;
14 | padding-right: 0;
15 | text-align: left;
16 | }
17 |
18 | .login .submit-row {
19 | clear: both;
20 | padding: 1em 9.4em 0 0;
21 | }
22 |
23 | /* GLOBAL */
24 |
25 | th {
26 | text-align: right;
27 | }
28 |
29 | .module h2, .module caption {
30 | text-align: right;
31 | }
32 |
33 | .addlink, .changelink {
34 | padding-left: 0px;
35 | padding-right: 12px;
36 | background-position: 100% 0.2em;
37 | }
38 |
39 | .deletelink {
40 | padding-left: 0px;
41 | padding-right: 12px;
42 | background-position: 100% 0.25em;
43 | }
44 |
45 | .object-tools {
46 | float: left;
47 | }
48 |
49 | thead th:first-child,
50 | tfoot td:first-child {
51 | border-left: 1px solid #ddd !important;
52 | }
53 |
54 | /* LAYOUT */
55 |
56 | #user-tools {
57 | right: auto;
58 | left: 0;
59 | text-align: left;
60 | }
61 |
62 | div.breadcrumbs {
63 | text-align: right;
64 | }
65 |
66 | #content-main {
67 | float: right;
68 | }
69 |
70 | #content-related {
71 | float: left;
72 | margin-left: -19em;
73 | margin-right: auto;
74 | }
75 |
76 | .colMS {
77 | margin-left: 20em !important;
78 | margin-right: 10px !important;
79 | }
80 |
81 | /* SORTABLE TABLES */
82 |
83 | table thead th.sorted .sortoptions {
84 | float: left;
85 | }
86 |
87 | thead th.sorted .text {
88 | padding-right: 0;
89 | padding-left: 42px;
90 | }
91 |
92 | /* dashboard styles */
93 |
94 | .dashboard .module table td a {
95 | padding-left: .6em;
96 | padding-right: 12px;
97 | }
98 |
99 | /* changelists styles */
100 |
101 | .change-list .filtered {
102 | background: white url(../img/changelist-bg_rtl.gif) top left repeat-y !important;
103 | }
104 |
105 | .change-list .filtered table {
106 | border-left: 1px solid #ddd;
107 | border-right: 0px none;
108 | }
109 |
110 | #changelist-filter {
111 | right: auto;
112 | left: 0;
113 | border-left: 0px none;
114 | border-right: 1px solid #ddd;
115 | }
116 |
117 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull {
118 | margin-right: 0px !important;
119 | margin-left: 160px !important;
120 | }
121 |
122 | #changelist-filter li.selected {
123 | border-left: 0px none;
124 | padding-left: 0px;
125 | margin-left: 0;
126 | border-right: 5px solid #ccc;
127 | padding-right: 5px;
128 | margin-right: -10px;
129 | }
130 |
131 | .filtered .actions {
132 | border-left:1px solid #DDDDDD;
133 | margin-left:160px !important;
134 | border-right: 0 none;
135 | margin-right:0 !important;
136 | }
137 |
138 | #changelist table tbody td:first-child, #changelist table tbody th:first-child {
139 | border-right: 0;
140 | border-left: 1px solid #ddd;
141 | }
142 |
143 | /* FORMS */
144 |
145 | .aligned label {
146 | padding: 0 0 3px 1em;
147 | float: right;
148 | }
149 |
150 | .submit-row {
151 | text-align: left
152 | }
153 |
154 | .submit-row p.deletelink-box {
155 | float: right;
156 | }
157 |
158 | .submit-row .deletelink {
159 | background: url(../img/icon_deletelink.gif) 0 50% no-repeat;
160 | padding-right: 14px;
161 | }
162 |
163 | .vDateField, .vTimeField {
164 | margin-left: 2px;
165 | }
166 |
167 | form ul.inline li {
168 | float: right;
169 | padding-right: 0;
170 | padding-left: 7px;
171 | }
172 |
173 | input[type=submit].default, .submit-row input.default {
174 | float: left;
175 | }
176 |
177 | fieldset .field-box {
178 | float: right;
179 | margin-left: 20px;
180 | margin-right: 0;
181 | }
182 |
183 | .errorlist li {
184 | background-position: 100% .3em;
185 | padding: 4px 25px 4px 5px;
186 | }
187 |
188 | .errornote {
189 | background-position: 100% .3em;
190 | padding: 4px 25px 4px 5px;
191 | }
192 |
193 | /* WIDGETS */
194 |
195 | .calendarnav-previous {
196 | top: 0;
197 | left: auto;
198 | right: 0;
199 | }
200 |
201 | .calendarnav-next {
202 | top: 0;
203 | right: auto;
204 | left: 0;
205 | }
206 |
207 | .calendar caption, .calendarbox h2 {
208 | text-align: center;
209 | }
210 |
211 | .selector {
212 | float: right;
213 | }
214 |
215 | .selector .selector-filter {
216 | text-align: right;
217 | }
218 |
219 | .inline-deletelink {
220 | float: left;
221 | }
222 |
223 | /* MISC */
224 |
225 | .inline-related h2, .inline-group h2 {
226 | text-align: right
227 | }
228 |
229 | .inline-related h3 span.delete {
230 | padding-right: 20px;
231 | padding-left: inherit;
232 | left: 10px;
233 | right: inherit;
234 | float:left;
235 | }
236 |
237 | .inline-related h3 span.delete label {
238 | margin-left: inherit;
239 | margin-right: 2px;
240 | }
241 |
242 | /* IE7 specific bug fixes */
243 |
244 | div.colM {
245 | position: relative;
246 | }
247 |
248 | .submit-row input {
249 | float: left;
250 | }
251 |
--------------------------------------------------------------------------------
/sql/static/admin/img/changelist-bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/changelist-bg.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/changelist-bg_rtl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/changelist-bg_rtl.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/default-bg-reverse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/default-bg-reverse.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/default-bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/default-bg.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/deleted-overlay.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/deleted-overlay.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/gis/move_vertex_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/gis/move_vertex_off.png
--------------------------------------------------------------------------------
/sql/static/admin/img/gis/move_vertex_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/gis/move_vertex_on.png
--------------------------------------------------------------------------------
/sql/static/admin/img/icon-no.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon-no.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon-unknown.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon-unknown.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon-yes.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon-yes.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_addlink.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_addlink.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_alert.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_alert.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_calendar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_calendar.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_changelink.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_changelink.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_clock.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_clock.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_deletelink.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_deletelink.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_error.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_error.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_searchbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_searchbox.png
--------------------------------------------------------------------------------
/sql/static/admin/img/icon_success.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/icon_success.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/inline-delete-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/inline-delete-8bit.png
--------------------------------------------------------------------------------
/sql/static/admin/img/inline-delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/inline-delete.png
--------------------------------------------------------------------------------
/sql/static/admin/img/inline-restore-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/inline-restore-8bit.png
--------------------------------------------------------------------------------
/sql/static/admin/img/inline-restore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/inline-restore.png
--------------------------------------------------------------------------------
/sql/static/admin/img/inline-splitter-bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/inline-splitter-bg.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/nav-bg-grabber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/nav-bg-grabber.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/nav-bg-reverse.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/nav-bg-reverse.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/nav-bg-selected.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/nav-bg-selected.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/nav-bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/nav-bg.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/selector-icons.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/selector-icons.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/selector-search.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/selector-search.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/sorting-icons.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/sorting-icons.gif
--------------------------------------------------------------------------------
/sql/static/admin/img/tooltag-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/tooltag-add.png
--------------------------------------------------------------------------------
/sql/static/admin/img/tooltag-arrowright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/admin/img/tooltag-arrowright.png
--------------------------------------------------------------------------------
/sql/static/admin/js/LICENSE-JQUERY.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 John Resig, http://jquery.com/
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/sql/static/admin/js/SelectBox.js:
--------------------------------------------------------------------------------
1 | var SelectBox = {
2 | cache: new Object(),
3 | init: function(id) {
4 | var box = document.getElementById(id);
5 | var node;
6 | SelectBox.cache[id] = new Array();
7 | var cache = SelectBox.cache[id];
8 | for (var i = 0; (node = box.options[i]); i++) {
9 | cache.push({value: node.value, text: node.text, displayed: 1});
10 | }
11 | },
12 | redisplay: function(id) {
13 | // Repopulate HTML select box from cache
14 | var box = document.getElementById(id);
15 | box.options.length = 0; // clear all options
16 | for (var i = 0, j = SelectBox.cache[id].length; i < j; i++) {
17 | var node = SelectBox.cache[id][i];
18 | if (node.displayed) {
19 | var new_option = new Option(node.text, node.value, false, false);
20 | // Shows a tooltip when hovering over the option
21 | new_option.setAttribute("title", node.text);
22 | box.options[box.options.length] = new_option;
23 | }
24 | }
25 | },
26 | filter: function(id, text) {
27 | // Redisplay the HTML select box, displaying only the choices containing ALL
28 | // the words in text. (It's an AND search.)
29 | var tokens = text.toLowerCase().split(/\s+/);
30 | var node, token;
31 | for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
32 | node.displayed = 1;
33 | for (var j = 0; (token = tokens[j]); j++) {
34 | if (node.text.toLowerCase().indexOf(token) == -1) {
35 | node.displayed = 0;
36 | }
37 | }
38 | }
39 | SelectBox.redisplay(id);
40 | },
41 | delete_from_cache: function(id, value) {
42 | var node, delete_index = null;
43 | for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
44 | if (node.value == value) {
45 | delete_index = i;
46 | break;
47 | }
48 | }
49 | var j = SelectBox.cache[id].length - 1;
50 | for (var i = delete_index; i < j; i++) {
51 | SelectBox.cache[id][i] = SelectBox.cache[id][i+1];
52 | }
53 | SelectBox.cache[id].length--;
54 | },
55 | add_to_cache: function(id, option) {
56 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1});
57 | },
58 | cache_contains: function(id, value) {
59 | // Check if an item is contained in the cache
60 | var node;
61 | for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
62 | if (node.value == value) {
63 | return true;
64 | }
65 | }
66 | return false;
67 | },
68 | move: function(from, to) {
69 | var from_box = document.getElementById(from);
70 | var to_box = document.getElementById(to);
71 | var option;
72 | for (var i = 0; (option = from_box.options[i]); i++) {
73 | if (option.selected && SelectBox.cache_contains(from, option.value)) {
74 | SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1});
75 | SelectBox.delete_from_cache(from, option.value);
76 | }
77 | }
78 | SelectBox.redisplay(from);
79 | SelectBox.redisplay(to);
80 | },
81 | move_all: function(from, to) {
82 | var from_box = document.getElementById(from);
83 | var to_box = document.getElementById(to);
84 | var option;
85 | for (var i = 0; (option = from_box.options[i]); i++) {
86 | if (SelectBox.cache_contains(from, option.value)) {
87 | SelectBox.add_to_cache(to, {value: option.value, text: option.text, displayed: 1});
88 | SelectBox.delete_from_cache(from, option.value);
89 | }
90 | }
91 | SelectBox.redisplay(from);
92 | SelectBox.redisplay(to);
93 | },
94 | sort: function(id) {
95 | SelectBox.cache[id].sort( function(a, b) {
96 | a = a.text.toLowerCase();
97 | b = b.text.toLowerCase();
98 | try {
99 | if (a > b) return 1;
100 | if (a < b) return -1;
101 | }
102 | catch (e) {
103 | // silently fail on IE 'unknown' exception
104 | }
105 | return 0;
106 | } );
107 | },
108 | select_all: function(id) {
109 | var box = document.getElementById(id);
110 | for (var i = 0; i < box.options.length; i++) {
111 | box.options[i].selected = 'selected';
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/sql/static/admin/js/actions.min.js:
--------------------------------------------------------------------------------
1 | (function(a){var f;a.fn.actions=function(q){var b=a.extend({},a.fn.actions.defaults,q),g=a(this),e=!1,m=function(c){c?k():l();a(g).prop("checked",c).parent().parent().toggleClass(b.selectedClass,c)},h=function(){var c=a(g).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).prop("checked",function(){var a;c==g.length?(a=!0,k()):(a=!1,n());return a})},k=function(){a(b.acrossClears).hide();
2 | a(b.acrossQuestions).show();a(b.allContainer).hide()},p=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},l=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},n=function(){l();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};a(b.counterContainer).show();a(this).filter(":checked").each(function(c){a(this).parent().parent().toggleClass(b.selectedClass);
3 | h();1==a(b.acrossInput).val()&&p()});a(b.allToggle).show().click(function(){m(a(this).prop("checked"));h()});a("a",b.acrossQuestions).click(function(c){c.preventDefault();a(b.acrossInput).val(1);p()});a("a",b.acrossClears).click(function(c){c.preventDefault();a(b.allToggle).prop("checked",!1);n();m(0);h()});f=null;a(g).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(f&&a.data(f)!=a.data(d)&&!0===c.shiftKey){var e=!1;a(f).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,
4 | d.checked);a(g).each(function(){if(a.data(this)==a.data(f)||a.data(this)==a.data(d))e=e?!1:!0;e&&a(this).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);f=d;h()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(a){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});
5 | a('form#changelist-form input[name="_save"]').click(function(c){var d=!1;a("select option:selected",b.actionContainer).each(function(){a(this).val()&&(d=!0)});if(d)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};
6 | a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
7 |
--------------------------------------------------------------------------------
/sql/static/admin/js/admin/RelatedObjectLookups.js:
--------------------------------------------------------------------------------
1 | // Handles related-objects functionality: lookup link for raw_id_fields
2 | // and Add Another links.
3 |
4 | function html_unescape(text) {
5 | // Unescape a string that was escaped using django.utils.html.escape.
6 | text = text.replace(/</g, '<');
7 | text = text.replace(/>/g, '>');
8 | text = text.replace(/"/g, '"');
9 | text = text.replace(/'/g, "'");
10 | text = text.replace(/&/g, '&');
11 | return text;
12 | }
13 |
14 | // IE doesn't accept periods or dashes in the window name, but the element IDs
15 | // we use to generate popup window names may contain them, therefore we map them
16 | // to allowed characters in a reversible way so that we can locate the correct
17 | // element when the popup window is dismissed.
18 | function id_to_windowname(text) {
19 | text = text.replace(/\./g, '__dot__');
20 | text = text.replace(/\-/g, '__dash__');
21 | return text;
22 | }
23 |
24 | function windowname_to_id(text) {
25 | text = text.replace(/__dot__/g, '.');
26 | text = text.replace(/__dash__/g, '-');
27 | return text;
28 | }
29 |
30 | function showAdminPopup(triggeringLink, name_regexp) {
31 | var name = triggeringLink.id.replace(name_regexp, '');
32 | name = id_to_windowname(name);
33 | var href = triggeringLink.href;
34 | if (href.indexOf('?') == -1) {
35 | href += '?_popup=1';
36 | } else {
37 | href += '&_popup=1';
38 | }
39 | var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
40 | win.focus();
41 | return false;
42 | }
43 |
44 | function showRelatedObjectLookupPopup(triggeringLink) {
45 | return showAdminPopup(triggeringLink, /^lookup_/);
46 | }
47 |
48 | function dismissRelatedLookupPopup(win, chosenId) {
49 | var name = windowname_to_id(win.name);
50 | var elem = document.getElementById(name);
51 | if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
52 | elem.value += ',' + chosenId;
53 | } else {
54 | document.getElementById(name).value = chosenId;
55 | }
56 | win.close();
57 | }
58 |
59 | function showRelatedObjectPopup(triggeringLink) {
60 | var name = triggeringLink.id.replace(/^(change|add|delete)_/, '');
61 | name = id_to_windowname(name);
62 | var href = triggeringLink.href;
63 | var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
64 | win.focus();
65 | return false;
66 | }
67 |
68 | function dismissAddRelatedObjectPopup(win, newId, newRepr) {
69 | // newId and newRepr are expected to have previously been escaped by
70 | // django.utils.html.escape.
71 | newId = html_unescape(newId);
72 | newRepr = html_unescape(newRepr);
73 | var name = windowname_to_id(win.name);
74 | var elem = document.getElementById(name);
75 | var o;
76 | if (elem) {
77 | var elemName = elem.nodeName.toUpperCase();
78 | if (elemName == 'SELECT') {
79 | o = new Option(newRepr, newId);
80 | elem.options[elem.options.length] = o;
81 | o.selected = true;
82 | } else if (elemName == 'INPUT') {
83 | if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
84 | elem.value += ',' + newId;
85 | } else {
86 | elem.value = newId;
87 | }
88 | }
89 | // Trigger a change event to update related links if required.
90 | django.jQuery(elem).trigger('change');
91 | } else {
92 | var toId = name + "_to";
93 | o = new Option(newRepr, newId);
94 | SelectBox.add_to_cache(toId, o);
95 | SelectBox.redisplay(toId);
96 | }
97 | win.close();
98 | }
99 |
100 | function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
101 | objId = html_unescape(objId);
102 | newRepr = html_unescape(newRepr);
103 | var id = windowname_to_id(win.name).replace(/^edit_/, '');
104 | var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
105 | var selects = django.jQuery(selectsSelector);
106 | selects.find('option').each(function() {
107 | if (this.value == objId) {
108 | this.textContent = newRepr;
109 | this.value = newId;
110 | }
111 | });
112 | win.close();
113 | };
114 |
115 | function dismissDeleteRelatedObjectPopup(win, objId) {
116 | objId = html_unescape(objId);
117 | var id = windowname_to_id(win.name).replace(/^delete_/, '');
118 | var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
119 | var selects = django.jQuery(selectsSelector);
120 | selects.find('option').each(function() {
121 | if (this.value == objId) {
122 | django.jQuery(this).remove();
123 | }
124 | }).trigger('change');
125 | win.close();
126 | };
127 |
128 | // Kept for backward compatibility
129 | showAddAnotherPopup = showRelatedObjectPopup;
130 | dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
131 |
132 | django.jQuery(function($){
133 | $(document).ready(function() {
134 | $('.related-lookup').click(function(e) {
135 | e.preventDefault();
136 | showRelatedObjectLookupPopup(this);
137 | });
138 | });
139 | });
140 |
--------------------------------------------------------------------------------
/sql/static/admin/js/collapse.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | $(document).ready(function() {
3 | // Add anchor tag for Show/Hide link
4 | $("fieldset.collapse").each(function(i, elem) {
5 | // Don't hide if fields in this fieldset have errors
6 | if ($(elem).find("div.errors").length == 0) {
7 | $(elem).addClass("collapsed").find("h2").first().append(' (' + gettext("Show") +
9 | ')');
10 | }
11 | });
12 | // Add toggle to anchor tag
13 | $("fieldset.collapse a.collapse-toggle").click(function(ev) {
14 | if ($(this).closest("fieldset").hasClass("collapsed")) {
15 | // Show
16 | $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]);
17 | } else {
18 | // Hide
19 | $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]);
20 | }
21 | return false;
22 | });
23 | });
24 | })(django.jQuery);
25 |
--------------------------------------------------------------------------------
/sql/static/admin/js/collapse.min.js:
--------------------------------------------------------------------------------
1 | (function(a){a(document).ready(function(){a("fieldset.collapse").each(function(c,b){a(b).find("div.errors").length==0&&a(b).addClass("collapsed").find("h2").first().append(' ('+gettext("Show")+")")});a("fieldset.collapse a.collapse-toggle").click(function(){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset",
2 | [a(this).attr("id")]);return false})})})(django.jQuery);
3 |
--------------------------------------------------------------------------------
/sql/static/admin/js/inlines.min.js:
--------------------------------------------------------------------------------
1 | (function(a){a.fn.formset=function(g){var b=a.extend({},a.fn.formset.defaults,g),i=a(this);g=i.parent();var m=function(e,k,h){var j=RegExp("("+k+"-(\\d+|__prefix__))");k=k+"-"+h;a(e).prop("for")&&a(e).prop("for",a(e).prop("for").replace(j,k));if(e.id)e.id=e.id.replace(j,k);if(e.name)e.name=e.name.replace(j,k)},l=a("#id_"+b.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),d=parseInt(l.val(),10),c=a("#id_"+b.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off");l=c.val()===""||c.val()-l.val()>0;i.each(function(){a(this).not("."+
2 | b.emptyCssClass).addClass(b.formCssClass)});if(i.length&&l){var f;if(i.prop("tagName")=="TR"){i=this.eq(-1).children().length;g.append('
'+b.addText+" |
");f=g.find("tr:last a")}else{i.filter(":last").after('");f=i.filter(":last").next().find("a")}f.click(function(e){e.preventDefault();var k=a("#id_"+b.prefix+"-TOTAL_FORMS");e=a("#"+
3 | b.prefix+"-empty");var h=e.clone(true);h.removeClass(b.emptyCssClass).addClass(b.formCssClass).attr("id",b.prefix+"-"+d);if(h.is("tr"))h.children(":last").append('");else h.is("ul")||h.is("ol")?h.append(''+b.deleteText+""):h.children(":first").append(''+b.deleteText+"");
4 | h.find("*").each(function(){m(this,b.prefix,k.val())});h.insertBefore(a(e));a(k).val(parseInt(k.val(),10)+1);d+=1;c.val()!==""&&c.val()-k.val()<=0&&f.parent().hide();h.find("a."+b.deleteCssClass).click(function(j){j.preventDefault();j=a(this).parents("."+b.formCssClass);j.remove();d-=1;b.removed&&b.removed(j);j=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(j.length);if(c.val()===""||c.val()-j.length>0)f.parent().show();for(var n=0,o=j.length;n 0) {
23 | values.push(field.val());
24 | }
25 | });
26 | prepopulatedField.val(URLify(values.join(' '), maxLength));
27 | };
28 |
29 | prepopulatedField.data('_changed', false);
30 | prepopulatedField.change(function() {
31 | prepopulatedField.data('_changed', true);
32 | });
33 |
34 | if (!prepopulatedField.val()) {
35 | $(dependencies.join(',')).keyup(populate).change(populate).focus(populate);
36 | }
37 | });
38 | };
39 | })(django.jQuery);
40 |
--------------------------------------------------------------------------------
/sql/static/admin/js/prepopulate.min.js:
--------------------------------------------------------------------------------
1 | (function(b){b.fn.prepopulate=function(e,g){return this.each(function(){var a=b(this),d=function(){if(!a.data("_changed")){var f=[];b.each(e,function(h,c){c=b(c);c.val().length>0&&f.push(c.val())});a.val(URLify(f.join(" "),g))}};a.data("_changed",false);a.change(function(){a.data("_changed",true)});a.val()||b(e.join(",")).keyup(d).change(d).focus(d)})}})(django.jQuery);
2 |
--------------------------------------------------------------------------------
/sql/static/admin/js/related-widget-wrapper.js:
--------------------------------------------------------------------------------
1 | django.jQuery(function($){
2 | function updateLinks() {
3 | var $this = $(this);
4 | var siblings = $this.nextAll('.change-related, .delete-related');
5 | if (!siblings.length) return;
6 | var value = $this.val();
7 | if (value) {
8 | siblings.each(function(){
9 | var elm = $(this);
10 | elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
11 | });
12 | } else siblings.removeAttr('href');
13 | }
14 | var container = $(document);
15 | container.on('change', '.related-widget-wrapper select', updateLinks);
16 | container.find('.related-widget-wrapper select').each(updateLinks);
17 | container.on('click', '.related-widget-wrapper-link', function(event){
18 | if (this.href) {
19 | showRelatedObjectPopup(this);
20 | }
21 | event.preventDefault();
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/sql/static/admin/js/timeparse.js:
--------------------------------------------------------------------------------
1 | var timeParsePatterns = [
2 | // 9
3 | { re: /^\d{1,2}$/i,
4 | handler: function(bits) {
5 | if (bits[0].length == 1) {
6 | return '0' + bits[0] + ':00';
7 | } else {
8 | return bits[0] + ':00';
9 | }
10 | }
11 | },
12 | // 13:00
13 | { re: /^\d{2}[:.]\d{2}$/i,
14 | handler: function(bits) {
15 | return bits[0].replace('.', ':');
16 | }
17 | },
18 | // 9:00
19 | { re: /^\d[:.]\d{2}$/i,
20 | handler: function(bits) {
21 | return '0' + bits[0].replace('.', ':');
22 | }
23 | },
24 | // 3 am / 3 a.m. / 3am
25 | { re: /^(\d+)\s*([ap])(?:.?m.?)?$/i,
26 | handler: function(bits) {
27 | var hour = parseInt(bits[1]);
28 | if (hour == 12) {
29 | hour = 0;
30 | }
31 | if (bits[2].toLowerCase() == 'p') {
32 | if (hour == 12) {
33 | hour = 0;
34 | }
35 | return (hour + 12) + ':00';
36 | } else {
37 | if (hour < 10) {
38 | return '0' + hour + ':00';
39 | } else {
40 | return hour + ':00';
41 | }
42 | }
43 | }
44 | },
45 | // 3.30 am / 3:15 a.m. / 3.00am
46 | { re: /^(\d+)[.:](\d{2})\s*([ap]).?m.?$/i,
47 | handler: function(bits) {
48 | var hour = parseInt(bits[1]);
49 | var mins = parseInt(bits[2]);
50 | if (mins < 10) {
51 | mins = '0' + mins;
52 | }
53 | if (hour == 12) {
54 | hour = 0;
55 | }
56 | if (bits[3].toLowerCase() == 'p') {
57 | if (hour == 12) {
58 | hour = 0;
59 | }
60 | return (hour + 12) + ':' + mins;
61 | } else {
62 | if (hour < 10) {
63 | return '0' + hour + ':' + mins;
64 | } else {
65 | return hour + ':' + mins;
66 | }
67 | }
68 | }
69 | },
70 | // noon
71 | { re: /^no/i,
72 | handler: function(bits) {
73 | return '12:00';
74 | }
75 | },
76 | // midnight
77 | { re: /^mid/i,
78 | handler: function(bits) {
79 | return '00:00';
80 | }
81 | }
82 | ];
83 |
84 | function parseTimeString(s) {
85 | for (var i = 0; i < timeParsePatterns.length; i++) {
86 | var re = timeParsePatterns[i].re;
87 | var handler = timeParsePatterns[i].handler;
88 | var bits = re.exec(s);
89 | if (bits) {
90 | return handler(bits);
91 | }
92 | }
93 | return s;
94 | }
95 |
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/css/dashboard.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Base structure
3 | */
4 |
5 | /* Move down content because we have a fixed navbar that is 50px tall */
6 | body {
7 | padding-top: 50px;
8 | }
9 |
10 |
11 | /*
12 | * Global add-ons
13 | */
14 |
15 | .sub-header {
16 | padding-bottom: 10px;
17 | border-bottom: 1px solid #eee;
18 | }
19 |
20 | /*
21 | * Top navigation
22 | * Hide default border to remove 1px line.
23 | */
24 | .navbar-fixed-top {
25 | border: 0;
26 | }
27 |
28 | /*
29 | * Sidebar
30 | */
31 |
32 | /* Hide for mobile, show later */
33 | .sidebar {
34 | display: none;
35 | }
36 | @media (min-width: 768px) {
37 | .sidebar {
38 | position: fixed;
39 | top: 51px;
40 | bottom: 0;
41 | left: 0;
42 | z-index: 1000;
43 | display: block;
44 | padding: 20px;
45 | overflow-x: hidden;
46 | overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
47 | background-color: #f5f5f5;
48 | border-right: 1px solid #eee;
49 | }
50 | }
51 |
52 | /* Sidebar navigation */
53 | .nav-sidebar {
54 | margin-right: -21px; /* 20px padding + 1px border */
55 | margin-bottom: 20px;
56 | margin-left: -20px;
57 | }
58 | .nav-sidebar > li > a {
59 | padding-right: 20px;
60 | padding-left: 20px;
61 | }
62 | .nav-sidebar > .active > a,
63 | .nav-sidebar > .active > a:hover,
64 | .nav-sidebar > .active > a:focus {
65 | color: #fff;
66 | background-color: #428bca;
67 | }
68 |
69 |
70 | /*
71 | * Main content
72 | */
73 |
74 | .main {
75 | padding: 20px;
76 | }
77 | @media (min-width: 768px) {
78 | .main {
79 | padding-right: 40px;
80 | padding-left: 40px;
81 | }
82 | }
83 | .main .page-header {
84 | margin-top: 0;
85 | }
86 |
87 |
88 | /*
89 | * Placeholder dashboard ideas
90 | */
91 |
92 | .placeholders {
93 | margin-bottom: 30px;
94 | text-align: center;
95 | }
96 | .placeholders h4 {
97 | margin-bottom: 0;
98 | }
99 | .placeholder {
100 | margin-bottom: 20px;
101 | }
102 | .placeholder img {
103 | display: inline-block;
104 | border-radius: 50%;
105 | }
106 |
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/sql/static/bootstrap-3.3.7-dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/sql/static/bootstrap-table/css/bootstrap-table.min.css:
--------------------------------------------------------------------------------
1 | .fixed-table-container .bs-checkbox,.fixed-table-container .no-records-found{text-align:center}.fixed-table-body thead th .th-inner,.table td,.table th{box-sizing:border-box}.bootstrap-table .table{margin-bottom:0!important;border-bottom:1px solid #ddd;border-collapse:collapse!important;border-radius:1px}.bootstrap-table .table:not(.table-condensed),.bootstrap-table .table:not(.table-condensed)>tbody>tr>td,.bootstrap-table .table:not(.table-condensed)>tbody>tr>th,.bootstrap-table .table:not(.table-condensed)>tfoot>tr>td,.bootstrap-table .table:not(.table-condensed)>tfoot>tr>th,.bootstrap-table .table:not(.table-condensed)>thead>tr>td{padding:8px}.bootstrap-table .table.table-no-bordered>tbody>tr>td,.bootstrap-table .table.table-no-bordered>thead>tr>th{border-right:2px solid transparent}.bootstrap-table .table.table-no-bordered>tbody>tr>td:last-child{border-right:none}.fixed-table-container{position:relative;clear:both;border:1px solid #ddd;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px}.fixed-table-container.table-no-bordered{border:1px solid transparent}.fixed-table-footer,.fixed-table-header{overflow:hidden}.fixed-table-footer{border-top:1px solid #ddd}.fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.fixed-table-container table{width:100%}.fixed-table-container thead th{height:0;padding:0;margin:0;border-left:1px solid #ddd}.fixed-table-container thead th:focus{outline:transparent solid 0}.fixed-table-container thead th:first-child{border-left:none;border-top-left-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fixed-table-container tbody td .th-inner,.fixed-table-container thead th .th-inner{padding:8px;line-height:24px;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fixed-table-container thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px}.fixed-table-container thead th .both{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC')}.fixed-table-container thead th .asc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==)}.fixed-table-container thead th .desc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=)}.fixed-table-container th.detail{width:30px}.fixed-table-container tbody td{border-left:1px solid #ddd}.fixed-table-container tbody tr:first-child td{border-top:none}.fixed-table-container tbody td:first-child{border-left:none}.fixed-table-container tbody .selected td{background-color:#f5f5f5}.fixed-table-container .bs-checkbox .th-inner{padding:8px 0}.fixed-table-container input[type=radio],.fixed-table-container input[type=checkbox]{margin:0 auto!important}.fixed-table-pagination .pagination-detail,.fixed-table-pagination div.pagination{margin-top:10px;margin-bottom:10px}.fixed-table-pagination div.pagination .pagination{margin:0}.fixed-table-pagination .pagination a{padding:6px 12px;line-height:1.428571429}.fixed-table-pagination .pagination-info{line-height:34px;margin-right:5px}.fixed-table-pagination .btn-group{position:relative;display:inline-block;vertical-align:middle}.fixed-table-pagination .dropup .dropdown-menu{margin-bottom:0}.fixed-table-pagination .page-list{display:inline-block}.fixed-table-toolbar .columns-left{margin-right:5px}.fixed-table-toolbar .columns-right{margin-left:5px}.fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429}.fixed-table-toolbar .bs-bars,.fixed-table-toolbar .columns,.fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px;line-height:34px}.fixed-table-pagination li.disabled a{pointer-events:none;cursor:default}.fixed-table-loading{display:none;position:absolute;top:42px;right:0;bottom:0;left:0;z-index:99;background-color:#fff;text-align:center}.fixed-table-body .card-view .title{font-weight:700;display:inline-block;min-width:30%;text-align:left!important}.table td,.table th{vertical-align:middle}.fixed-table-toolbar .dropdown-menu{text-align:left;max-height:300px;overflow:auto}.fixed-table-toolbar .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.fixed-table-toolbar .btn-group>.btn-group>.btn{border-radius:0}.fixed-table-toolbar .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.fixed-table-toolbar .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .table>thead>tr>th{vertical-align:bottom;border-bottom:1px solid #ddd}.bootstrap-table .table thead>tr>th{padding:0;margin:0}.bootstrap-table .fixed-table-footer tbody>tr>td{padding:0!important}.bootstrap-table .fixed-table-footer .table{border-bottom:none;border-radius:0;padding:0!important}.pull-right .dropdown-menu{right:0;left:auto}p.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}
--------------------------------------------------------------------------------
/sql/static/bootstrap-table/js/bootstrap-table-export.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-table - v1.11.1 - 2017-02-22
3 | * https://github.com/wenzhixin/bootstrap-table
4 | * Copyright (c) 2017 zhixin wen
5 | * Licensed MIT License
6 | */
7 | !function(a){"use strict";var b=a.fn.bootstrapTable.utils.sprintf,c={json:"JSON",xml:"XML",png:"PNG",csv:"CSV",txt:"TXT",sql:"SQL",doc:"MS-Word",excel:"MS-Excel",xlsx:"MS-Excel (OpenXML)",powerpoint:"MS-Powerpoint",pdf:"PDF"};a.extend(a.fn.bootstrapTable.defaults,{showExport:!1,exportDataType:"basic",exportTypes:["json","xml","csv","txt","sql","excel"],exportOptions:{}}),a.extend(a.fn.bootstrapTable.defaults.icons,{"export":"glyphicon-export icon-share"}),a.extend(a.fn.bootstrapTable.locales,{formatExport:function(){return"Export data"}}),a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales);var d=a.fn.bootstrapTable.Constructor,e=d.prototype.initToolbar;d.prototype.initToolbar=function(){if(this.showToolbar=this.options.showExport,e.apply(this,Array.prototype.slice.apply(arguments)),this.options.showExport){var d=this,f=this.$toolbar.find(">.btn-group"),g=f.find("div.export");if(!g.length){g=a(['','",'","
"].join("")).appendTo(f);var h=g.find(".dropdown-menu"),i=this.options.exportTypes;if("string"==typeof this.options.exportTypes){var j=this.options.exportTypes.slice(1,-1).replace(/ /g,"").split(",");i=[],a.each(j,function(a,b){i.push(b.slice(1,-1))})}a.each(i,function(a,b){c.hasOwnProperty(b)&&h.append(['','',c[b],"",""].join(""))}),h.find("li").click(function(){var b=a(this).data("type"),c=function(){d.$el.tableExport(a.extend({},d.options.exportOptions,{type:b,escape:!1}))};if("all"===d.options.exportDataType&&d.options.pagination)d.$el.one("server"===d.options.sidePagination?"post-body.bs.table":"page-change.bs.table",function(){c(),d.togglePagination()}),d.togglePagination();else if("selected"===d.options.exportDataType){var e=d.getData(),f=d.getAllSelections();"server"===d.options.sidePagination&&(e={total:d.options.totalRows},e[d.options.dataField]=d.getData(),f={total:d.options.totalRows},f[d.options.dataField]=d.getAllSelections()),d.load(f),c(),d.load(e)}else c()})}}}}(jQuery);
--------------------------------------------------------------------------------
/sql/static/bootstrap-table/js/bootstrap-table-zh-CN.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * bootstrap-table - v1.11.0 - 2016-07-02
3 | * https://github.com/wenzhixin/bootstrap-table
4 | * Copyright (c) 2016 zhixin wen
5 | * Licensed MIT License
6 | */
7 | !function(a){"use strict";a.fn.bootstrapTable.locales["zh-CN"]={formatLoadingMessage:function(){return"正在努力地加载数据中,请稍候……"},formatRecordsPerPage:function(a){return"每页显示 "+a+" 条记录"},formatShowingRows:function(a,b,c){return"显示第 "+a+" 到第 "+b+" 条记录,总共 "+c+" 条记录"},formatSearch:function(){return"搜索"},formatNoMatches:function(){return"没有找到匹配的记录"},formatPaginationSwitch:function(){return"隐藏/显示分页"},formatRefresh:function(){return"刷新"},formatToggle:function(){return"切换"},formatColumns:function(){return"列"},formatExport:function(){return"导出数据"},formatClearFilters:function(){return"清空过滤"}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales["zh-CN"])}(jQuery);
--------------------------------------------------------------------------------
/sql/static/charts.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
7 |
8 |
9 | {% endblock content %}
10 |
11 | {% block js %}
12 | {% load staticfiles %}
13 |
14 |
15 | {% endblock %}
16 |
17 |
18 |
--------------------------------------------------------------------------------
/sql/static/datetimepicker/js/bootstrap-datetimepicker.zh-CN.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Simplified Chinese translation for bootstrap-datetimepicker
3 | * Yuan Cheung
4 | */
5 | ;(function($){
6 | $.fn.datetimepicker.dates['zh-CN'] = {
7 | days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
8 | daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六", "周日"],
9 | daysMin: ["日", "一", "二", "三", "四", "五", "六", "日"],
10 | months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
11 | monthsShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
12 | today: "今天",
13 | suffix: [],
14 | meridiem: ["上午", "下午"]
15 | };
16 | }(jQuery));
17 |
--------------------------------------------------------------------------------
/sql/static/dist/css/bootstrap-select.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */.bootstrap-select{width:220px \0}.bootstrap-select>.dropdown-toggle{width:100%;padding-right:25px}.error .bootstrap-select .dropdown-toggle,.has-error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select.fit-width{width:auto!important}.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn){width:220px}.bootstrap-select .dropdown-toggle:focus{outline:thin dotted #333!important;outline:5px auto -webkit-focus-ring-color!important;outline-offset:-2px}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:none}.bootstrap-select.form-control:not([class*=col-]){width:100%}.bootstrap-select.form-control.input-group-btn{z-index:auto}.bootstrap-select.btn-group:not(.input-group-btn),.bootstrap-select.btn-group[class*=col-]{float:none;display:inline-block;margin-left:0}.bootstrap-select.btn-group.dropdown-menu-right,.bootstrap-select.btn-group[class*=col-].dropdown-menu-right,.row .bootstrap-select.btn-group[class*=col-].dropdown-menu-right{float:right}.form-group .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group{margin-bottom:0}.form-group-lg .bootstrap-select.btn-group.form-control,.form-group-sm .bootstrap-select.btn-group.form-control{padding:0}.form-inline .bootstrap-select.btn-group .form-control{width:100%}.bootstrap-select.btn-group.disabled,.bootstrap-select.btn-group>.disabled{cursor:not-allowed}.bootstrap-select.btn-group.disabled:focus,.bootstrap-select.btn-group>.disabled:focus{outline:0!important}.bootstrap-select.btn-group .dropdown-toggle .filter-option{display:inline-block;overflow:hidden;width:100%;text-align:left}.bootstrap-select.btn-group .dropdown-toggle .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group[class*=col-] .dropdown-toggle{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;z-index:1035;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;float:none;border:0;padding:0;margin:0;border-radius:0;-webkit-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li.active small{color:#fff}.bootstrap-select.btn-group .dropdown-menu li.disabled a{cursor:not-allowed}.bootstrap-select.btn-group .dropdown-menu li a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li a.opt{position:relative;padding-left:2.25em}.bootstrap-select.btn-group .dropdown-menu li a span.check-mark{display:none}.bootstrap-select.btn-group .dropdown-menu li a span.text{display:inline-block}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:.5em}.bootstrap-select.btn-group .dropdown-menu .notify{position:absolute;bottom:5px;width:96%;margin:0 2%;min-height:26px;padding:3px 5px;background:#f5f5f5;border:1px solid #e3e3e3;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .no-results{padding:3px;background:#f5f5f5;margin:0 5px;white-space:nowrap}.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option{position:static}.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret{position:static;top:auto;margin-top:-1px}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark{position:absolute;display:inline-block;right:15px;margin-top:5px}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle{z-index:1036}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid rgba(204,204,204,.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid rgba(204,204,204,.2);border-bottom:0}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #fff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before{display:block}.bs-actionsbox,.bs-donebutton,.bs-searchbox{padding:4px 8px}.bs-actionsbox{float:left;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-actionsbox .btn-group button{width:50%}.bs-donebutton{float:left;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-donebutton .btn-group button{width:100%}.bs-searchbox+.bs-actionsbox{padding:0 8px 4px}.bs-searchbox .form-control{margin-bottom:0;width:100%}select.bs-select-hidden,select.selectpicker{display:none!important}select.mobile-device{position:absolute!important;top:0;left:0;display:block!important;width:100%;height:100%!important;opacity:0}
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-bg_BG.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Нищо избрано',
27 | noneResultsText: 'Няма резултат за {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected == 1) ? "{0} избран елемент" : "{0} избрани елемента";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | (numAll == 1) ? 'Лимита е достигнат ({n} елемент максимум)' : 'Лимита е достигнат ({n} елемента максимум)',
34 | (numGroup == 1) ? 'Груповия лимит е достигнат ({n} елемент максимум)' : 'Груповия лимит е достигнат ({n} елемента максимум)'
35 | ];
36 | },
37 | selectAllText: 'Избери всички',
38 | deselectAllText: 'Размаркирай всички',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-bg_BG.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Нищо избрано",noneResultsText:"Няма резултат за {0}",countSelectedText:function(a,b){return 1==a?"{0} избран елемент":"{0} избрани елемента"},maxOptionsText:function(a,b){return[1==a?"Лимита е достигнат ({n} елемент максимум)":"Лимита е достигнат ({n} елемента максимум)",1==b?"Груповия лимит е достигнат ({n} елемент максимум)":"Груповия лимит е достигнат ({n} елемента максимум)"]},selectAllText:"Избери всички",deselectAllText:"Размаркирай всички",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-cs_CZ.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nic není vybráno',
27 | noneResultsText: 'Žádné výsledky {0}',
28 | countSelectedText: 'Označeno {0} z {1}',
29 | maxOptionsText: ['Limit překročen ({n} {var} max)', 'Limit skupiny překročen ({n} {var} max)', ['položek', 'položka']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-cs_CZ.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nic není vybráno",noneResultsText:"Žádné výsledky {0}",countSelectedText:"Označeno {0} z {1}",maxOptionsText:["Limit překročen ({n} {var} max)","Limit skupiny překročen ({n} {var} max)",["položek","položka"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-da_DK.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Intet valgt',
27 | noneResultsText: 'Ingen resultater fundet {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected == 1) ? "{0} valgt" : "{0} valgt";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | (numAll == 1) ? 'Begrænsning nået (max {n} valgt)' : 'Begrænsning nået (max {n} valgte)',
34 | (numGroup == 1) ? 'Gruppe-begrænsning nået (max {n} valgt)' : 'Gruppe-begrænsning nået (max {n} valgte)'
35 | ];
36 | },
37 | selectAllText: 'Markér alle',
38 | deselectAllText: 'Afmarkér alle',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-da_DK.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Intet valgt",noneResultsText:"Ingen resultater fundet {0}",countSelectedText:function(a,b){return"{0} valgt"},maxOptionsText:function(a,b){return[1==a?"Begrænsning nået (max {n} valgt)":"Begrænsning nået (max {n} valgte)",1==b?"Gruppe-begrænsning nået (max {n} valgt)":"Gruppe-begrænsning nået (max {n} valgte)"]},selectAllText:"Markér alle",deselectAllText:"Afmarkér alle",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-de_DE.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Bitte wählen...',
27 | noneResultsText: 'Keine Ergebnisse für {0}',
28 | countSelectedText: '{0} von {1} ausgewählt',
29 | maxOptionsText: ['Limit erreicht ({n} {var} max.)', 'Gruppen-Limit erreicht ({n} {var} max.)', ['Eintrag', 'Einträge']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-de_DE.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Bitte wählen...",noneResultsText:"Keine Ergebnisse für {0}",countSelectedText:"{0} von {1} ausgewählt",maxOptionsText:["Limit erreicht ({n} {var} max.)","Gruppen-Limit erreicht ({n} {var} max.)",["Eintrag","Einträge"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-en_US.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nothing selected',
27 | noneResultsText: 'No results match {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected == 1) ? "{0} item selected" : "{0} items selected";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
34 | (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
35 | ];
36 | },
37 | selectAllText: 'Select All',
38 | deselectAllText: 'Deselect All',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-en_US.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nothing selected",noneResultsText:"No results match {0}",countSelectedText:function(a,b){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){return[1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==b?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)"]},selectAllText:"Select All",deselectAllText:"Deselect All",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-es_CL.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'No hay selección',
27 | noneResultsText: 'No hay resultados {0}',
28 | countSelectedText: 'Seleccionados {0} de {1}',
29 | maxOptionsText: ['Límite alcanzado ({n} {var} max)', 'Límite del grupo alcanzado({n} {var} max)', ['elementos', 'element']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-es_CL.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"No hay selección",noneResultsText:"No hay resultados {0}",countSelectedText:"Seleccionados {0} de {1}",maxOptionsText:["Límite alcanzado ({n} {var} max)","Límite del grupo alcanzado({n} {var} max)",["elementos","element"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-eu.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Hautapenik ez',
27 | noneResultsText: 'Emaitzarik ez {0}',
28 | countSelectedText: '{1}(e)tik {0} hautatuta',
29 | maxOptionsText: ['Mugara iritsita ({n} {var} gehienez)', 'Taldearen mugara iritsita ({n} {var} gehienez)', ['elementu', 'elementu']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-eu.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Hautapenik ez",noneResultsText:"Emaitzarik ez {0}",countSelectedText:"{1}(e)tik {0} hautatuta",maxOptionsText:["Mugara iritsita ({n} {var} gehienez)","Taldearen mugara iritsita ({n} {var} gehienez)",["elementu","elementu"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-fa_IR.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'چیزی انتخاب نشده است',
27 | noneResultsText: 'هیج مشابهی برای {0} پیدا نشد',
28 | countSelectedText: "{0} از {1} مورد انتخاب شده",
29 | maxOptionsText: ['بیشتر ممکن نیست {حداکثر {n} عدد}', 'بیشتر ممکن نیست {حداکثر {n} عدد}'],
30 | selectAllText: 'انتخاب همه',
31 | deselectAllText: 'انتخاب هیچ کدام',
32 | multipleSeparator: ', '
33 | };
34 | })(jQuery);
35 |
36 |
37 | }));
38 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-fa_IR.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"چیزی انتخاب نشده است",noneResultsText:"هیج مشابهی برای {0} پیدا نشد",countSelectedText:"{0} از {1} مورد انتخاب شده",maxOptionsText:["بیشتر ممکن نیست {حداکثر {n} عدد}","بیشتر ممکن نیست {حداکثر {n} عدد}"],selectAllText:"انتخاب همه",deselectAllText:"انتخاب هیچ کدام",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-fr_FR.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Aucune sélection',
27 | noneResultsText: 'Aucun résultat pour {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected > 1) ? "{0} éléments sélectionnés" : "{0} élément sélectionné";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | (numAll > 1) ? 'Limite atteinte ({n} éléments max)' : 'Limite atteinte ({n} élément max)',
34 | (numGroup > 1) ? 'Limite du groupe atteinte ({n} éléments max)' : 'Limite du groupe atteinte ({n} élément max)'
35 | ];
36 | },
37 | multipleSeparator: ', '
38 | };
39 | })(jQuery);
40 |
41 |
42 | }));
43 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-fr_FR.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Aucune sélection",noneResultsText:"Aucun résultat pour {0}",countSelectedText:function(a,b){return a>1?"{0} éléments sélectionnés":"{0} élément sélectionné"},maxOptionsText:function(a,b){return[a>1?"Limite atteinte ({n} éléments max)":"Limite atteinte ({n} élément max)",b>1?"Limite du groupe atteinte ({n} éléments max)":"Limite du groupe atteinte ({n} élément max)"]},multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-hu_HU.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Válasszon!',
27 | noneResultsText: 'Nincs találat {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return '{n} elem kiválasztva';
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | 'Legfeljebb {n} elem választható',
34 | 'A csoportban legfeljebb {n} elem választható'
35 | ];
36 | },
37 | selectAllText: 'Mind',
38 | deselectAllText: 'Egyik sem',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-hu_HU.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Válasszon!",noneResultsText:"Nincs találat {0}",countSelectedText:function(a,b){return"{n} elem kiválasztva"},maxOptionsText:function(a,b){return["Legfeljebb {n} elem választható","A csoportban legfeljebb {n} elem választható"]},selectAllText:"Mind",deselectAllText:"Egyik sem",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-it_IT.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nessuna selezione',
27 | noneResultsText: 'Nessun risultato per {0}',
28 | countSelectedText: 'Selezionati {0} di {1}',
29 | maxOptionsText: ['Limite raggiunto ({n} {var} max)', 'Limite del gruppo raggiunto ({n} {var} max)', ['elementi', 'elemento']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-it_IT.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nessuna selezione",noneResultsText:"Nessun risultato per {0}",countSelectedText:"Selezionati {0} di {1}",maxOptionsText:["Limite raggiunto ({n} {var} max)","Limite del gruppo raggiunto ({n} {var} max)",["elementi","elemento"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ko_KR.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: '항목을 선택해주세요',
27 | noneResultsText: '{0} 검색 결과가 없습니다',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return "{0}개를 선택하였습니다";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | '{n}개까지 선택 가능합니다',
34 | '해당 그룹은 {n}개까지 선택 가능합니다'
35 | ];
36 | },
37 | selectAllText: '전체선택',
38 | deselectAllText: '전체해제',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ko_KR.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"항목을 선택해주세요",noneResultsText:"{0} 검색 결과가 없습니다",countSelectedText:function(a,b){return"{0}개를 선택하였습니다"},maxOptionsText:function(a,b){return["{n}개까지 선택 가능합니다","해당 그룹은 {n}개까지 선택 가능합니다"]},selectAllText:"전체선택",deselectAllText:"전체해제",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-nl_NL.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Niets geselecteerd',
27 | noneResultsText: 'Geen resultaten gevonden voor {0}',
28 | countSelectedText: '{0} van {1} geselecteerd',
29 | maxOptionsText: ['Limiet bereikt ({n} {var} max)', 'Groep limiet bereikt ({n} {var} max)', ['items', 'item']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-nl_NL.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Niets geselecteerd",noneResultsText:"Geen resultaten gevonden voor {0}",countSelectedText:"{0} van {1} geselecteerd",maxOptionsText:["Limiet bereikt ({n} {var} max)","Groep limiet bereikt ({n} {var} max)",["items","item"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pl_PL.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nic nie zaznaczono',
27 | noneResultsText: 'Brak wyników wyszukiwania {0}',
28 | countSelectedText: 'Zaznaczono {0} z {1}',
29 | maxOptionsText: ['Osiągnięto limit ({n} {var} max)', 'Limit grupy osiągnięty ({n} {var} max)', ['elementy', 'element']],
30 | selectAll: 'Zaznacz wszystkie',
31 | deselectAll: 'Odznacz wszystkie',
32 | multipleSeparator: ', '
33 | };
34 | })(jQuery);
35 |
36 |
37 | }));
38 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pl_PL.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nic nie zaznaczono",noneResultsText:"Brak wyników wyszukiwania {0}",countSelectedText:"Zaznaczono {0} z {1}",maxOptionsText:["Osiągnięto limit ({n} {var} max)","Limit grupy osiągnięty ({n} {var} max)",["elementy","element"]],selectAll:"Zaznacz wszystkie",deselectAll:"Odznacz wszystkie",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pt_BR.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nada selecionado',
27 | noneResultsText: 'Nada encontrado contendo {0}',
28 | countSelectedText: 'Selecionado {0} de {1}',
29 | maxOptionsText: ['Limite excedido (máx. {n} {var})', 'Limite do grupo excedido (máx. {n} {var})', ['itens', 'item']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pt_BR.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nada selecionado",noneResultsText:"Nada encontrado contendo {0}",countSelectedText:"Selecionado {0} de {1}",maxOptionsText:["Limite excedido (máx. {n} {var})","Limite do grupo excedido (máx. {n} {var})",["itens","item"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pt_PT.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nenhum seleccionado',
27 | noneResultsText: 'Sem resultados contendo {0}',
28 | countSelectedText: 'Selecionado {0} de {1}',
29 | maxOptionsText: ['Limite ultrapassado (máx. {n} {var})', 'Limite de seleções ultrapassado (máx. {n} {var})', ['itens', 'item']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-pt_PT.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nenhum seleccionado",noneResultsText:"Sem resultados contendo {0}",countSelectedText:"Selecionado {0} de {1}",maxOptionsText:["Limite ultrapassado (máx. {n} {var})","Limite de seleções ultrapassado (máx. {n} {var})",["itens","item"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ro_RO.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nu a fost selectat nimic',
27 | noneResultsText: 'Nu exista niciun rezultat {0}',
28 | countSelectedText: '{0} din {1} selectat(e)',
29 | maxOptionsText: ['Limita a fost atinsa ({n} {var} max)', 'Limita de grup a fost atinsa ({n} {var} max)', ['iteme', 'item']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ro_RO.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nu a fost selectat nimic",noneResultsText:"Nu exista niciun rezultat {0}",countSelectedText:"{0} din {1} selectat(e)",maxOptionsText:["Limita a fost atinsa ({n} {var} max)","Limita de grup a fost atinsa ({n} {var} max)",["iteme","item"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ru_RU.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Ничего не выбрано',
27 | noneResultsText: 'Совпадений не найдено {0}',
28 | countSelectedText: 'Выбрано {0} из {1}',
29 | maxOptionsText: ['Достигнут предел ({n} {var} максимум)', 'Достигнут предел в группе ({n} {var} максимум)', ['items', 'item']],
30 | doneButtonText: 'Закрыть',
31 | multipleSeparator: ', '
32 | };
33 | })(jQuery);
34 |
35 |
36 | }));
37 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ru_RU.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Ничего не выбрано",noneResultsText:"Совпадений не найдено {0}",countSelectedText:"Выбрано {0} из {1}",maxOptionsText:["Достигнут предел ({n} {var} максимум)","Достигнут предел в группе ({n} {var} максимум)",["items","item"]],doneButtonText:"Закрыть",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sk_SK.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Vyberte zo zoznamu',
27 | noneResultsText: 'Pre výraz {0} neboli nájdené žiadne výsledky',
28 | countSelectedText: 'Vybrané {0} z {1}',
29 | maxOptionsText: ['Limit prekročený ({n} {var} max)', 'Limit skupiny prekročený ({n} {var} max)', ['položiek', 'položka']],
30 | selectAllText: 'Vybrať všetky',
31 | deselectAllText: 'Zrušiť výber',
32 | multipleSeparator: ', '
33 | };
34 | })(jQuery);
35 |
36 |
37 | }));
38 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sk_SK.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Vyberte zo zoznamu",noneResultsText:"Pre výraz {0} neboli nájdené žiadne výsledky",countSelectedText:"Vybrané {0} z {1}",maxOptionsText:["Limit prekročený ({n} {var} max)","Limit skupiny prekročený ({n} {var} max)",["položiek","položka"]],selectAllText:"Vybrať všetky",deselectAllText:"Zrušiť výber",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sl_SI.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Nič izbranega',
27 | noneResultsText: 'Ni zadetkov za {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | "Število izbranih: {0}";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | 'Omejitev dosežena (max. izbranih: {n})',
34 | 'Omejitev skupine dosežena (max. izbranih: {n})'
35 | ];
36 | },
37 | selectAllText: 'Izberi vse',
38 | deselectAllText: 'Počisti izbor',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sl_SI.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Nič izbranega",noneResultsText:"Ni zadetkov za {0}",countSelectedText:function(a,b){"Število izbranih: {0}"},maxOptionsText:function(a,b){return["Omejitev dosežena (max. izbranih: {n})","Omejitev skupine dosežena (max. izbranih: {n})"]},selectAllText:"Izberi vse",deselectAllText:"Počisti izbor",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sv_SE.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Inget valt',
27 | noneResultsText: 'Inget sökresultat matchar {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected === 1) ? "{0} alternativ valt" : "{0} alternativ valda";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | 'Gräns uppnåd (max {n} alternativ)',
34 | 'Gräns uppnåd (max {n} gruppalternativ)'
35 | ];
36 | },
37 | selectAllText: 'Markera alla',
38 | deselectAllText: 'Avmarkera alla',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-sv_SE.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Inget valt",noneResultsText:"Inget sökresultat matchar {0}",countSelectedText:function(a,b){return 1===a?"{0} alternativ valt":"{0} alternativ valda"},maxOptionsText:function(a,b){return["Gräns uppnåd (max {n} alternativ)","Gräns uppnåd (max {n} gruppalternativ)"]},selectAllText:"Markera alla",deselectAllText:"Avmarkera alla",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-tr_TR.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Hiçbiri seçilmedi',
27 | noneResultsText: 'Hiçbir sonuç bulunamadı {0}',
28 | countSelectedText: function (numSelected, numTotal) {
29 | return (numSelected == 1) ? "{0} öğe seçildi" : "{0} öğe seçildi";
30 | },
31 | maxOptionsText: function (numAll, numGroup) {
32 | return [
33 | (numAll == 1) ? 'Limit aşıldı (maksimum {n} sayıda öğe )' : 'Limit aşıldı (maksimum {n} sayıda öğe)',
34 | (numGroup == 1) ? 'Grup limiti aşıldı (maksimum {n} sayıda öğe)' : 'Grup limiti aşıldı (maksimum {n} sayıda öğe)'
35 | ];
36 | },
37 | selectAllText: 'Tümünü Seç',
38 | deselectAllText: 'Seçiniz',
39 | multipleSeparator: ', '
40 | };
41 | })(jQuery);
42 |
43 |
44 | }));
45 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-tr_TR.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Hiçbiri seçilmedi",noneResultsText:"Hiçbir sonuç bulunamadı {0}",countSelectedText:function(a,b){return"{0} öğe seçildi"},maxOptionsText:function(a,b){return[1==a?"Limit aşıldı (maksimum {n} sayıda öğe )":"Limit aşıldı (maksimum {n} sayıda öğe)","Grup limiti aşıldı (maksimum {n} sayıda öğe)"]},selectAllText:"Tümünü Seç",deselectAllText:"Seçiniz",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ua_UA.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: 'Нічого не вибрано',
27 | noneResultsText: 'Збігів не знайдено {0}',
28 | countSelectedText: 'Вибрано {0} із {1}',
29 | maxOptionsText: ['Досягнута межа ({n} {var} максимум)', 'Досягнута межа в групі ({n} {var} максимум)', ['items', 'item']],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-ua_UA.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"Нічого не вибрано",noneResultsText:"Збігів не знайдено {0}",countSelectedText:"Вибрано {0} із {1}",maxOptionsText:["Досягнута межа ({n} {var} максимум)","Досягнута межа в групі ({n} {var} максимум)",["items","item"]],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-zh_CN.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: '没有选中任何项',
27 | noneResultsText: '没有找到匹配项',
28 | countSelectedText: '选中{1}中的{0}项',
29 | maxOptionsText: ['超出限制 (最多选择{n}项)', '组选择超出限制(最多选择{n}组)'],
30 | multipleSeparator: ', '
31 | };
32 | })(jQuery);
33 |
34 |
35 | }));
36 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-zh_CN.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"没有选中任何项",noneResultsText:"没有找到匹配项",countSelectedText:"选中{1}中的{0}项",maxOptionsText:["超出限制 (最多选择{n}项)","组选择超出限制(最多选择{n}组)"],multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-zh_TW.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 |
8 | (function (root, factory) {
9 | if (typeof define === 'function' && define.amd) {
10 | // AMD. Register as an anonymous module unless amdModuleId is set
11 | define(["jquery"], function (a0) {
12 | return (factory(a0));
13 | });
14 | } else if (typeof exports === 'object') {
15 | // Node. Does not work with strict CommonJS, but
16 | // only CommonJS-like environments that support module.exports,
17 | // like Node.
18 | module.exports = factory(require("jquery"));
19 | } else {
20 | factory(jQuery);
21 | }
22 | }(this, function () {
23 |
24 | (function ($) {
25 | $.fn.selectpicker.defaults = {
26 | noneSelectedText: '沒有選取任何項目',
27 | noneResultsText: '沒有找到符合的結果',
28 | countSelectedText: '已經選取{0}個項目',
29 | maxOptionsText: ['超過限制 (最多選擇{n}項)', '超過限制(最多選擇{n}組)'],
30 | selectAllText: '選取全部',
31 | deselectAllText: '全部取消',
32 | multipleSeparator: ', '
33 | };
34 | })(jQuery);
35 |
36 |
37 | }));
38 |
--------------------------------------------------------------------------------
/sql/static/dist/js/i18n/defaults-zh_TW.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)
3 | *
4 | * Copyright 2013-2015 bootstrap-select
5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
6 | */
7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(){!function(a){a.fn.selectpicker.defaults={noneSelectedText:"沒有選取任何項目",noneResultsText:"沒有找到符合的結果",countSelectedText:"已經選取{0}個項目",maxOptionsText:["超過限制 (最多選擇{n}項)","超過限制(最多選擇{n}組)"],selectAllText:"選取全部",deselectAllText:"全部取消",multipleSeparator:", "}}(jQuery)});
--------------------------------------------------------------------------------
/sql/static/error.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {{errMsg}}
5 | {% endblock content %}
6 |
--------------------------------------------------------------------------------
/sql/static/fileinput/img/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/static/fileinput/img/loading.gif
--------------------------------------------------------------------------------
/sql/static/fileinput/js/locales/zh.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * FileInput Chinese Translations
3 | *
4 | * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
5 | * any HTML markup tags in the messages must not be converted or translated.
6 | *
7 | * @see http://github.com/kartik-v/bootstrap-fileinput
8 | * @author kangqf
9 | *
10 | * NOTE: this file must be saved in UTF-8 encoding.
11 | */
12 | (function ($) {
13 | "use strict";
14 |
15 | $.fn.fileinputLocales['zh'] = {
16 | fileSingle: '文件',
17 | filePlural: '个文件',
18 | browseLabel: '选择 …',
19 | removeLabel: '移除',
20 | removeTitle: '清除选中文件',
21 | cancelLabel: '取消',
22 | cancelTitle: '取消进行中的上传',
23 | uploadLabel: '上传',
24 | uploadTitle: '上传选中文件',
25 | msgNo: '没有',
26 | msgNoFilesSelected: '',
27 | msgCancelled: '取消',
28 | msgZoomModalHeading: '详细预览',
29 | msgFileRequired: '必须选择一个文件上传.',
30 | msgSizeTooSmall: '文件 "{name}" ({size} KB) 必须大于限定大小 {minSize} KB.',
31 | msgSizeTooLarge: '文件 "{name}" ({size} KB) 超过了允许大小 {maxSize} KB.',
32 | msgFilesTooLess: '你必须选择最少 {n} {files} 来上传. ',
33 | msgFilesTooMany: '选择的上传文件个数 ({n}) 超出最大文件的限制个数 {m}.',
34 | msgFileNotFound: '文件 "{name}" 未找到!',
35 | msgFileSecured: '安全限制,为了防止读取文件 "{name}".',
36 | msgFileNotReadable: '文件 "{name}" 不可读.',
37 | msgFilePreviewAborted: '取消 "{name}" 的预览.',
38 | msgFilePreviewError: '读取 "{name}" 时出现了一个错误.',
39 | msgInvalidFileName: '文件名 "{name}" 包含非法字符.',
40 | msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
41 | msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
42 | msgFileTypes: {
43 | 'image': 'image',
44 | 'html': 'HTML',
45 | 'text': 'text',
46 | 'video': 'video',
47 | 'audio': 'audio',
48 | 'flash': 'flash',
49 | 'pdf': 'PDF',
50 | 'object': 'object'
51 | },
52 | msgUploadAborted: '该文件上传被中止',
53 | msgUploadThreshold: '处理中...',
54 | msgUploadBegin: '正在初始化...',
55 | msgUploadEnd: '完成',
56 | msgUploadEmpty: '无效的文件上传.',
57 | msgUploadError: 'Error',
58 | msgValidationError: '验证错误',
59 | msgLoading: '加载第 {index} 文件 共 {files} …',
60 | msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',
61 | msgSelected: '{n} {files} 选中',
62 | msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',
63 | msgImageWidthSmall: '图像文件的"{name}"的宽度必须是至少{size}像素.',
64 | msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.',
65 | msgImageWidthLarge: '图像文件"{name}"的宽度不能超过{size}像素.',
66 | msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.',
67 | msgImageResizeError: '无法获取的图像尺寸调整。',
68 | msgImageResizeException: '调整图像大小时发生错误。{errors}
',
69 | msgAjaxError: '{operation} 发生错误. 请重试!',
70 | msgAjaxProgressError: '{operation} 失败',
71 | ajaxOperations: {
72 | deleteThumb: '删除文件',
73 | uploadThumb: '上传文件',
74 | uploadBatch: '批量上传',
75 | uploadExtra: '表单数据上传'
76 | },
77 | dropZoneTitle: '拖拽文件到这里 …
支持多文件同时上传',
78 | dropZoneClickTitle: '
(或点击{files}按钮选择文件)',
79 | fileActionSettings: {
80 | removeTitle: '删除文件',
81 | uploadTitle: '上传文件',
82 | uploadRetryTitle: 'Retry upload',
83 | zoomTitle: '查看详情',
84 | dragTitle: '移动 / 重置',
85 | indicatorNewTitle: '没有上传',
86 | indicatorSuccessTitle: '上传',
87 | indicatorErrorTitle: '上传错误',
88 | indicatorLoadingTitle: '上传 ...'
89 | },
90 | previewZoomButtonTitles: {
91 | prev: '预览上一个文件',
92 | next: '预览下一个文件',
93 | toggleheader: '缩放',
94 | fullscreen: '全屏',
95 | borderless: '无边界模式',
96 | close: '关闭当前预览'
97 | }
98 | };
99 | })(window.jQuery);
100 |
--------------------------------------------------------------------------------
/sql/static/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 自动化运维平台
5 | {% load staticfiles %}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
36 |
37 |
38 |
57 |
58 |
59 |
60 |
自动化运维平台. Developed by OP.
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
75 |
76 |
--------------------------------------------------------------------------------
/sql/static/rollback.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 | {% csrf_token %}
7 |
9 |
10 |
11 |
12 |
13 |
14 |
提交回滚请求
15 |
16 |
17 |
18 |
19 |
20 | {% endblock content %}
21 |
22 | {% block js %}
23 | {% load staticfiles %}
24 |
25 |
94 | {% endblock %}
95 |
96 |
--------------------------------------------------------------------------------
/sql/static/user/css/user1.css:
--------------------------------------------------------------------------------
1 | .user-bottom-div {
2 | display:block;
3 | text-align:center;
4 | background-color:#ddd;
5 | position:fixed;
6 | bottom:0;
7 | width:100%;
8 | height:50px;
9 | line-height:50px;
10 | }
11 |
12 | .user-center-div-col-md-10 {
13 | margin-bottom:50px;
14 | }
15 |
16 | .login-div-center {
17 | position: absolute;
18 | top: 45%;
19 | left: 50%;
20 | width: 500px;
21 | border-radius: 4px;
22 | box-shadow: 0 0 0 1px rgba(0,0,0,0.07);
23 | transform: translate(-50%, -50%);
24 | background-color: #f6f7f8;
25 | }
26 |
27 | .lsb-login {
28 | display: flex;
29 | justify-content: center;
30 | align-items: center;
31 | height: 90vh;
32 | }
33 |
34 | .mypanalbox {
35 | background-color: #FFF;
36 | border-radius: 8px;
37 | box-shadow: 3px 3px 3px;
38 | }
39 |
40 | .login-form {
41 | margin: 20px;
42 | }
43 |
44 | .sidebar {
45 | position: fixed;
46 | top: 51px;
47 | bottom: 0;
48 | left: 0;
49 | #z-index: 1000;
50 | display: block;
51 | padding: 20px;
52 | overflow-x: hidden;
53 | overflow-y: auto;
54 | background-color: #f5f5f5;
55 | border-right: 1px solid #eee;
56 | }
57 |
--------------------------------------------------------------------------------
/sql/static/user/js/charts.js:
--------------------------------------------------------------------------------
1 | var personDataSummary = null;
2 | var personCorlor = [
3 | 'rgba(255, 99, 132, 0.9)',
4 | 'rgba(54, 162, 235, 0.8)',
5 | 'rgba(255, 206, 86, 0.7)',
6 | 'rgba(75, 192, 192, 0.8)',
7 | 'rgba(153, 102, 255, 0.9)']
8 |
9 | $(document).ready(function() {
10 | var isCharts = window.location.pathname.indexOf("charts");
11 | if (isCharts != -1) {
12 | getPersonWork()
13 | getMonthWork()
14 | }
15 | });
16 |
17 | function getPersonWork(){
18 | $.ajax({
19 | type: 'get',
20 | url: '/getPersonCharts/',
21 | success: function(data) {
22 | var data_person = new Array();
23 | var lb_person = new Array();
24 | var bg_corlor = new Array()
25 | for (var i=0; i" + sqlworkflowStatus.finish + ""
34 | }
35 | else if (value === sqlworkflowStatus.abort) {
36 | return "" + sqlworkflowStatus.abort + ""
37 | }
38 | else if (value === sqlworkflowStatus.autoreviewing) {
39 | return "" + sqlworkflowStatus.autoreviewing + ""
40 | }
41 | else if (value === sqlworkflowStatus.manreviewing) {
42 | return "" + sqlworkflowStatus.manreviewing + ""
43 | }
44 | else if (value === sqlworkflowStatus.pass) {
45 | return "" + sqlworkflowStatus.pass + ""
46 | }
47 | else if (value === sqlworkflowStatus.timingtask) {
48 | return "" + sqlworkflowStatus.timingtask + ""
49 | }
50 | else if (value === sqlworkflowStatus.executing) {
51 | return "" + sqlworkflowStatus.executing + ""
52 | }
53 | else if (value === sqlworkflowStatus.autoreviewwrong) {
54 | return "" + sqlworkflowStatus.autoreviewwrong + ""
55 | }
56 | else if (value === sqlworkflowStatus.exception) {
57 | return "" + sqlworkflowStatus.exception + ""
58 | }
59 | else {
60 | return "" + '未知状态' + ""
61 | }
62 | }
63 |
64 | function workflow_type_formatter(value) {
65 | if (value === workflow_type.query) {
66 | return workflow_type.query_display
67 | }
68 | else {
69 | return '未知状态'
70 | }
71 | }
72 |
73 | function workflow_status_formatter(value) {
74 | if (value === workflow_status.audit_wait) {
75 | return "" + workflow_status.audit_wait_display + " "
76 | }
77 | else if (value === workflow_status.audit_success) {
78 | return " " + workflow_status.audit_success_display + " "
79 | }
80 | else if (value === workflow_status.audit_reject) {
81 | return "" + workflow_status.audit_reject_display + " "
82 | }
83 | else if (value === workflow_status.audit_abort) {
84 | return "" + workflow_status.audit_abort_display + " "
85 | }
86 | else {
87 | return "" + '未知状态' + ""
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/sql/static/user/js/login.js:
--------------------------------------------------------------------------------
1 | //回车键提交表单登录
2 | $(document).ready(function() {
3 | $(document).keydown(function(event) {
4 | //keycode==13为回车键
5 | if (event.keyCode == 13) {
6 | $('#btnLogin').addClass('disabled');
7 | $('#btnLogin').prop('disabled', true);
8 | authenticateUser();
9 | }
10 | });
11 | });
12 |
13 | $('#btnLogin').click(function(){
14 | $('#btnLogin').addClass('disabled');
15 | $('#btnLogin').prop('disabled', true);
16 | authenticateUser();
17 | });
18 |
19 | function authenticateUser() {
20 | var inputUsername = $('#inputUsername');
21 | var inputPassword = $('#inputPassword');
22 | $.ajax({
23 | type: "post",
24 | url: "/authenticate/",
25 | dataType: "json",
26 | data: {
27 | username: inputUsername.val(),
28 | password: inputPassword.val()
29 | },
30 | complete: function () {
31 | $('#btnLogin').removeClass('disabled');
32 | $('#btnLogin').prop('disabled', false);
33 | },
34 | success: function (data) {
35 | if (data.status == 0) {
36 | $(location).attr('href','/allworkflow/');
37 | } else {
38 | $('#wrongpwd-modal-body').html(data.msg);
39 | $('#wrongpwd-modal').modal({
40 | keyboard: true
41 | });
42 | }
43 | },
44 | error: function (XMLHttpRequest, textStatus, errorThrown) {
45 | alert(errorThrown);
46 | }
47 | });
48 | };
49 |
--------------------------------------------------------------------------------
/sql/static/user/js/rollback.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function () {
2 | var isRollback = window.location.pathname.indexOf("rollback");
3 | if (isRollback != -1) {
4 | $("#btnSubmitRollback").click(function () {
5 | $(this).button('loading').delay(2500).queue(function () {
6 | $(this).button('reset');
7 | $(this).dequeue();
8 | });
9 | var editWorkflowNname = $("#editWorkflowNname").val();
10 | var editSqlContent = $("#editSqlContent").val();
11 | var editClustername = $("#editClustername").val();
12 | var editIsbackup = $("#editIsbackup").val();
13 | var editReviewman = $("#editReviewman").val();
14 | var editSubReviewman = $("#editSubReviewman").val();
15 | sessionStorage.removeItem('editWorkflowDetailId');
16 | sessionStorage.setItem('editWorkflowNname', editWorkflowNname);
17 | sessionStorage.setItem('editSqlContent', editSqlContent);
18 | sessionStorage.setItem('editClustername', editClustername);
19 | sessionStorage.setItem('editIsbackup', editIsbackup);
20 | sessionStorage.setItem('editReviewman', editReviewman);
21 | sessionStorage.setItem('editSubReviewman', editSubReviewman);
22 | });
23 | }
24 | ;
25 | });
26 |
--------------------------------------------------------------------------------
/sql/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/sql/templatetags/__init__.py
--------------------------------------------------------------------------------
/sql/templatetags/format_tags.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | from django import template
3 | from django.utils.safestring import mark_safe
4 |
5 | register = template.Library()
6 |
7 |
8 | # 替换换行符
9 | @register.simple_tag
10 | def format_str(str):
11 | # 换行
12 | return mark_safe(str.replace(',', '
'))
13 |
--------------------------------------------------------------------------------
/sql/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/sql/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 |
3 | from django.conf.urls import url, include
4 | from . import views, views_ajax, query, jobs
5 | from django.conf import settings
6 |
7 | urlpatterns = [
8 | url(r'^$', views.sqlworkflow, name='sqlworkflow'),
9 | url(r'^index/$', views.sqlworkflow, name='sqlworkflow'),
10 | url(r'^login/$', views.login, name='login'),
11 | url(r'^logout/$', views.logout, name='logout'),
12 | url(r'^submitsql/$', views.submitSql, name='submitSql'),
13 | url(r'^editsql/$', views.submitSql, name='editsql'),
14 | url(r'^allworkflow/$', views.sqlworkflow, name='sqlworkflow'),
15 |
16 | url(r'^autoreview/$', views.autoreview, name='autoreview'),
17 | url(r'^detail/(?P[0-9]+)/$', views.detail, name='detail'),
18 | url(r'^passed/$', views.passed, name='passed'),
19 | url(r'^execute/$', views.execute, name='execute'),
20 | url(r'^timingtask/$', views.timingtask, name='timingtask'),
21 | url(r'^cancel/$', views.cancel, name='cancel'),
22 | url(r'^rollback/$', views.rollback, name='rollback'),
23 | url(r'^sqlquery/$', views.sqlquery, name='sqlquery'),
24 | url(r'^slowquery/$', views.slowquery, name='slowquery'),
25 | url(r'^sqladvisor/$', views.sqladvisor, name='sqladvisor'),
26 | url(r'^slowquery_advisor/$', views.sqladvisor, name='slowquery_advisor'),
27 | url(r'^queryapplylist/$', views.queryapplylist, name='queryapplylist'),
28 | url(r'^queryapplydetail/(?P[0-9]+)/$', views.queryapplydetail, name='queryapplydetail'),
29 | url(r'^queryuserprivileges/$', views.queryuserprivileges, name='queryuserprivileges'),
30 | url(r'^diagnosis_process/$', views.diagnosis_process, name='diagnosis_process'),
31 | url(r'^diagnosis_sapce/$', views.diagnosis_sapce, name='diagnosis_sapce'),
32 | url(r'^workflow/$', views.workflows, name='workflows'),
33 | url(r'^workflowdetail/(?P[0-9]+)/$', views.workflowsdetail, name='workflowsdetail'),
34 | url(r'^dbaprinciples/$', views.dbaprinciples, name='dbaprinciples'),
35 | url(r'^charts/$', views.charts, name='charts'),
36 |
37 | url(r'^authenticate/$', views_ajax.authenticateEntry, name='authenticate'),
38 | url(r'^sqlworkflow/$', views_ajax.sqlworkflow, name='sqlworkflow'),
39 | url(r'^simplecheck/$', views_ajax.simplecheck, name='simplecheck'),
40 | url(r'^getMonthCharts/$', views_ajax.getMonthCharts, name='getMonthCharts'),
41 | url(r'^getPersonCharts/$', views_ajax.getPersonCharts, name='getPersonCharts'),
42 | url(r'^getOscPercent/$', views_ajax.getOscPercent, name='getOscPercent'),
43 | url(r'^getWorkflowStatus/$', views_ajax.getWorkflowStatus, name='getWorkflowStatus'),
44 | url(r'^stopOscProgress/$', views_ajax.stopOscProgress, name='stopOscProgress'),
45 | url(r'^sqladvisorcheck/$', views_ajax.sqladvisorcheck, name='sqladvisorcheck'),
46 | url(r'^workflowlist/$', views_ajax.workflowlist, name='workflowlist'),
47 |
48 | url(r'^getClusterList/$', query.getClusterList, name='getClusterList'),
49 | url(r'^getdbNameList/$', query.getdbNameList, name='getdbNameList'),
50 | url(r'^getTableNameList/$', query.getTableNameList, name='getTableNameList'),
51 | url(r'^getColumnNameList/$', query.getColumnNameList, name='getColumnNameList'),
52 | url(r'^getqueryapplylist/$', query.getqueryapplylist, name='getqueryapplylist'),
53 | url(r'^getuserprivileges/$', query.getuserprivileges, name='getuserprivileges'),
54 | url(r'^applyforprivileges/$', query.applyforprivileges, name='applyforprivileges'),
55 | url(r'^modifyqueryprivileges/$', query.modifyqueryprivileges, name='modifyqueryprivileges'),
56 | url(r'^queryprivaudit/$', query.queryprivaudit, name='queryprivaudit'),
57 | url(r'^query/$', query.query, name='query'),
58 | url(r'^querylog/$', query.querylog, name='querylog'),
59 | url(r'^explain/$', query.explain, name='explain'),
60 | url(r'^slowquery_review/$', query.slowquery_review, name='slowquery_review'),
61 | url(r'^slowquery_review_history/$', query.slowquery_review_history, name='slowquery_review_history'),
62 | url(r'^process_status/$', views_ajax.process_status, name='process_status'),
63 | url(r'^create_kill_session/$', views_ajax.create_kill_session,name='create_kill_session'),
64 | url(r'^kill_session/$', views_ajax.kill_session, name='kill_session'),
65 | url(r'^sapce_status/$', views_ajax.tablesapce, name='tablesapce'),
66 | url(r'^del_sqlcronjob/$', jobs.del_sqlcronjob, name='del_sqlcronjob'),
67 | ]
68 |
69 |
--------------------------------------------------------------------------------
/src/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/centos
2 |
3 | #archer
4 | RUN yum -y install unzip git gcc gcc-c++ make cmake bison openssl-devel mysql-devel openldap-devel \
5 | && yum -y install epel-release \
6 | && yum -y install python34 python34-pip python34-devel.x86_64 \
7 | && cd /opt \
8 | && pip3 install virtualenv -i https://mirrors.ustc.edu.cn/pypi/web/simple/ \
9 | && virtualenv venv4archer --python=python3.4 \
10 | && source venv4archer/bin/activate \
11 | && git clone https://github.com/hhyo/archer.git \
12 | && pip3 install -r /opt/archer/src/docker/requirements.txt -i https://mirrors.ustc.edu.cn/pypi/web/simple/ \
13 | && cp /opt/archer/src/docker/pymysql/connections.py /opt/venv4archer/lib/python3.4/site-packages/pymysql/ \
14 | && cp /opt/archer/src/docker/pymysql/cursors.py /opt/venv4archer/lib/python3.4/site-packages/pymysql/ \
15 | && yum -y install nginx \
16 | && cp /opt/archer/src/docker/nginx.conf /etc/nginx/ \
17 | && nginx \
18 | #sqladvisor
19 | && yum -y install libaio-devel libffi-devel glib2 glib2-devel \
20 | && yum -y install http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm \
21 | && yum -y install Percona-Server-devel-56.x86_64 Percona-Server-shared-56.x86_64 Percona-Server-client-56.x86_64 \
22 | && git clone https://github.com/Meituan-Dianping/SQLAdvisor.git \
23 | && cd /opt/SQLAdvisor/ \
24 | && yum -y install make \
25 | && cmake -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=debug -DCMAKE_INSTALL_PREFIX=/usr/local/sqlparser ./ \
26 | && make && make install \
27 | && cd sqladvisor/ \
28 | && cmake -DCMAKE_BUILD_TYPE=debug ./ \
29 | && make \
30 | #修改中文支持
31 | && rm -rf /etc/localtime && ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
32 | && yum -y install kde-l10n-Chinese && yum -y reinstall glibc-common \
33 | && localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
34 |
35 | ENV LANG en_US.UTF-8
36 | ENV LC_ALL zh_CN.utf8
37 |
38 | #port
39 | EXPOSE 9123
40 |
41 | #start service
42 | ENTRYPOINT bash /opt/archer/src/docker/startup.sh && bash
43 |
--------------------------------------------------------------------------------
/src/docker/nginx.conf:
--------------------------------------------------------------------------------
1 | # For more information on configuration, see:
2 | # * Official English Documentation: http://nginx.org/en/docs/
3 | # * Official Russian Documentation: http://nginx.org/ru/docs/
4 |
5 | user nginx;
6 | worker_processes auto;
7 | error_log /var/log/nginx/error.log;
8 | pid /run/nginx.pid;
9 |
10 | # Load dynamic modules. See /usr/share/nginx/README.dynamic.
11 | include /usr/share/nginx/modules/*.conf;
12 |
13 | events {
14 | worker_connections 1024;
15 | }
16 |
17 | http {
18 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
19 | '$status $body_bytes_sent "$http_referer" '
20 | '"$http_user_agent" "$http_x_forwarded_for"';
21 |
22 | access_log /var/log/nginx/access.log main;
23 |
24 | access_log on;
25 | sendfile on;
26 | tcp_nopush on;
27 | tcp_nodelay on;
28 | keepalive_timeout 65;
29 | types_hash_max_size 2048;
30 |
31 | include /etc/nginx/mime.types;
32 | default_type application/octet-stream;
33 |
34 | # Load modular configuration files from the /etc/nginx/conf.d directory.
35 | # See http://nginx.org/en/docs/ngx_core_module.html#include
36 | # for more information.
37 | include /etc/nginx/conf.d/*.conf;
38 |
39 | server{
40 | listen 9123; #监听的端口
41 | server_name archer;
42 | proxy_read_timeout 600s; #超时时间与gunicorn超时时间设置一致
43 |
44 | location / {
45 | proxy_pass http://127.0.0.1:8888;
46 | proxy_set_header Host $host;
47 | proxy_set_header X-Forwarded-Host $host:nginx_port;
48 | proxy_set_header X-Real-IP $remote_addr;
49 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
50 | proxy_set_header X-Forwarded-Proto $scheme;
51 | }
52 |
53 | location /static {
54 | alias /opt/archer/static;
55 | }
56 |
57 | error_page 404 /404.html;
58 | location = /40x.html {
59 | }
60 |
61 | error_page 500 502 503 504 /50x.html;
62 | location = /50x.html {
63 | }
64 | }
65 |
66 | # Settings for a TLS enabled server.
67 | #
68 | # server {
69 | # listen 443 ssl http2 default_server;
70 | # listen [::]:443 ssl http2 default_server;
71 | # server_name _;
72 | # root /usr/share/nginx/html;
73 | #
74 | # ssl_certificate "/etc/pki/nginx/server.crt";
75 | # ssl_certificate_key "/etc/pki/nginx/private/server.key";
76 | # ssl_session_cache shared:SSL:1m;
77 | # ssl_session_timeout 10m;
78 | # ssl_ciphers HIGH:!aNULL:!MD5;
79 | # ssl_prefer_server_ciphers on;
80 | #
81 | # # Load configuration files for the default server block.
82 | # include /etc/nginx/default.d/*.conf;
83 | #
84 | # location / {
85 | # }
86 | #
87 | # error_page 404 /404.html;
88 | # location = /40x.html {
89 | # }
90 | #
91 | # error_page 500 502 503 504 /50x.html;
92 | # location = /50x.html {
93 | # }
94 | # }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/docker/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2022.12.7
2 | chardet==3.0.4
3 | Django==2.2.28
4 | idna==2.6
5 | Naked==0.1.31
6 | pycrypto==2.6.1
7 | PyMySQL==0.7.11
8 | PyYAML==5.4
9 | requests==2.18.4
10 | shellescape==3.4.1
11 | simplejson==3.14.0
12 | urllib3==1.26.5
13 | django-admin-bootstrapped==2.5.7
14 | django-apscheduler==0.2.8
15 | gunicorn==19.7.1
16 | django-auth-ldap==1.3.0
17 | aliyun-python-sdk-core==2.3.5
18 | aliyun-python-sdk-core-v3==2.5.3
19 | aliyun-python-sdk-rds==2.1.1
20 |
--------------------------------------------------------------------------------
/src/docker/startup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | cd /opt/archer
4 | #切换python运行环境
5 | source /opt/venv4archer/bin/activate
6 | #修改重定向端口,启动ngnix
7 | sed -i "s/nginx_port/$NGINX_PORT/g" /etc/nginx/nginx.conf
8 | /usr/sbin/nginx
9 |
10 | #收集所有的静态文件到STATIC_ROOT
11 | python3 manage.py collectstatic -v0 --noinput
12 |
13 | settings=${1:-"archer.settings"}
14 | ip=${2:-"127.0.0.1"}
15 | port=${3:-8888}
16 |
17 | gunicorn -w 2 --env DJANGO_SETTINGS_MODULE=${settings} --error-logfile=/tmp/archer.err -b ${ip}:${port} --timeout 600 archer.wsgi:application
18 |
--------------------------------------------------------------------------------
/src/docs/mysql_db_design_guide.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/docs/mysql_db_design_guide.docx
--------------------------------------------------------------------------------
/src/init_sql/master->v2.0.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE `aliyun_access_key` (
2 | `id` INT(11) NOT NULL AUTO_INCREMENT,
3 | `ak` VARCHAR(50) NOT NULL,
4 | `secret` VARCHAR(100) NOT NULL,
5 | `is_enable` INT(11) NOT NULL,
6 | `remark` VARCHAR(50) NOT NULL,
7 | PRIMARY KEY (`id`)
8 | )
9 | ENGINE = InnoDB
10 | DEFAULT CHARSET = utf8;
11 |
12 | CREATE TABLE `aliyun_rds_config` (
13 | `id` INT(11) NOT NULL AUTO_INCREMENT,
14 | `rds_dbinstanceid` VARCHAR(100) NOT NULL,
15 | `cluster_name` VARCHAR(50) NOT NULL,
16 | PRIMARY KEY (`id`),
17 | UNIQUE KEY `uniq_cluster_name` (`cluster_name`)
18 | )
19 | ENGINE = InnoDB
20 | DEFAULT CHARSET = utf8;
21 |
22 | ALTER TABLE `data_masking_columns`
23 | DROP COLUMN `cluster_id`,
24 | ADD INDEX `idx_cluster_name` (`cluster_name`);
25 |
26 | ALTER TABLE `data_masking_rules`
27 | ADD COLUMN `hide_group` INT(11) NOT NULL
28 | AFTER `rule_regex`,
29 | ADD UNIQUE INDEX `uniq_rule_type` (`rule_type`);
30 |
31 | ALTER TABLE `query_log`
32 | DROP COLUMN `cluster_id`;
33 |
34 | ALTER TABLE `query_privileges`
35 | ADD COLUMN `priv_type` INT(11) NOT NULL
36 | AFTER `limit_num`,
37 | DROP COLUMN `cluster_id`,
38 | MODIFY COLUMN `valid_date` DATE NOT NULL
39 | AFTER `table_name`;
40 |
41 | ALTER TABLE `query_privileges_apply`
42 | ADD COLUMN `db_list` LONGTEXT NOT NULL
43 | AFTER `user_name`,
44 | ADD COLUMN `priv_type` INT(11) NOT NULL
45 | AFTER `limit_num`,
46 | DROP COLUMN `cluster_id`,
47 | DROP COLUMN `db_name`,
48 | MODIFY COLUMN `valid_date` DATE NOT NULL
49 | AFTER `table_list`;
50 |
51 | ALTER TABLE `sql_master_config`
52 | ADD UNIQUE INDEX `uniq_cluster_name` (`cluster_name`);
53 |
54 | ALTER TABLE `sql_slave_config`
55 | DROP COLUMN `cluster_id`,
56 | ADD UNIQUE INDEX `uniq_cluster_name` (`cluster_name`);
57 |
58 | ALTER TABLE `sql_workflow`
59 | ADD COLUMN `is_manual` INT(11) NOT NULL
60 | AFTER `execute_result`,
61 | ADD COLUMN `audit_remark` LONGTEXT NULL
62 | AFTER `is_manual`;
63 |
64 | ALTER TABLE `workflow_audit`
65 | ADD UNIQUE INDEX `idx_workflow_id_type` (`workflow_id`, `workflow_type`);
66 |
67 | ALTER TABLE `workflow_audit_setting`
68 | ADD UNIQUE INDEX `uniq_workflow_type` (`workflow_type`);
69 |
--------------------------------------------------------------------------------
/src/screenshots/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/admin.png
--------------------------------------------------------------------------------
/src/screenshots/allworkflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/allworkflow.png
--------------------------------------------------------------------------------
/src/screenshots/applyforprivileges.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/applyforprivileges.png
--------------------------------------------------------------------------------
/src/screenshots/autoreview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/autoreview.png
--------------------------------------------------------------------------------
/src/screenshots/bugs/bug1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/bugs/bug1.png
--------------------------------------------------------------------------------
/src/screenshots/bugs/bug2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/bugs/bug2.png
--------------------------------------------------------------------------------
/src/screenshots/bugs/bug3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/bugs/bug3.png
--------------------------------------------------------------------------------
/src/screenshots/charts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/charts.png
--------------------------------------------------------------------------------
/src/screenshots/datamasking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/datamasking.png
--------------------------------------------------------------------------------
/src/screenshots/datamaskingcolumns.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/datamaskingcolumns.png
--------------------------------------------------------------------------------
/src/screenshots/datamaskingrules.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/datamaskingrules.png
--------------------------------------------------------------------------------
/src/screenshots/finish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/finish.png
--------------------------------------------------------------------------------
/src/screenshots/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/login.png
--------------------------------------------------------------------------------
/src/screenshots/manageprivileges.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/manageprivileges.png
--------------------------------------------------------------------------------
/src/screenshots/osc_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/osc_progress.png
--------------------------------------------------------------------------------
/src/screenshots/process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/process.png
--------------------------------------------------------------------------------
/src/screenshots/pymysql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/pymysql.png
--------------------------------------------------------------------------------
/src/screenshots/query.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/query.png
--------------------------------------------------------------------------------
/src/screenshots/querylog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/querylog.png
--------------------------------------------------------------------------------
/src/screenshots/rollback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/rollback.png
--------------------------------------------------------------------------------
/src/screenshots/slowquery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/slowquery.png
--------------------------------------------------------------------------------
/src/screenshots/slowquerylog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/slowquerylog.png
--------------------------------------------------------------------------------
/src/screenshots/sqladvisor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/sqladvisor.png
--------------------------------------------------------------------------------
/src/screenshots/submitsql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/submitsql.png
--------------------------------------------------------------------------------
/src/screenshots/waitingforme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/waitingforme.png
--------------------------------------------------------------------------------
/src/screenshots/workflowconfig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jly8866/archer/e208c195f969637e3e2c6d110db7153092f04c8f/src/screenshots/workflowconfig.png
--------------------------------------------------------------------------------
/src/script/analysis_slow_query.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | DIR="$( cd "$( dirname "$0" )" && pwd )"
3 | cd $DIR
4 |
5 | #配置archer数据库的连接地址
6 | monitor_db_host="127.0.0.1"
7 | monitor_db_port=3306
8 | monitor_db_user="root"
9 | monitor_db_password="123456"
10 | monitor_db_database="archer"
11 |
12 | #被监控机慢日志位置
13 | slowquery_file="/home/mysql/log_slow.log"
14 | pt_query_digest="/usr/bin/pt-query-digest"
15 |
16 | #被监控机连接信息
17 | hostname=mysql_host:mysql_port # 被监控机连接信息,和archer主库配置内容保持一致,用于archer做筛选
18 |
19 | #获取上次分析时间,初始化时请删除last_analysis_time_$hostname文件,可分析全部日志数据
20 | if [ -s last_analysis_time_$hostname ]; then
21 | last_analysis_time=`cat last_analysis_time_$hostname`
22 | else
23 | last_analysis_time='1000-01-01 00:00:00'
24 | fi
25 |
26 | #收集日志
27 | #RDS需要增加--no-version-check选项
28 | $pt_query_digest \
29 | --user=$monitor_db_user --password=$monitor_db_password --port=$monitor_db_port \
30 | --review h=$monitor_db_host,D=$monitor_db_database,t=mysql_slow_query_review \
31 | --history h=$monitor_db_host,D=$monitor_db_database,t=mysql_slow_query_review_history \
32 | --no-report --limit=100% --charset=utf8 \
33 | --since "$last_analysis_time" \
34 | --filter="\$event->{Bytes} = length(\$event->{arg}) and \$event->{hostname}=\"$hostname\" and \$event->{client}=\$event->{ip} " \
35 | $slowquery_file > /tmp/analysis_slow_query.log
36 |
37 | echo `date +"%Y-%m-%d %H:%M:%S"`>last_analysis_time_$hostname
--------------------------------------------------------------------------------
/src/script/centos7_install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | DIR="$( cd "$( dirname "$0" )" && pwd )"
3 | cd $DIR
4 | git clone -b archer-2.0 https://github.com/jly8866/archer.git \
5 | && yum -y install gcc gcc-c++ make cmake bison openssl-devel mysql-devel \
6 | && yum -y install epel-release \
7 | && yum -y install python34 python34-pip python34-devel.x86_64 \
8 | && pip3 install virtualenv -i https://mirrors.ustc.edu.cn/pypi/web/simple/ \
9 | && virtualenv venv4archer --python=python3.4 \
10 | && source venv4archer/bin/activate \
11 | && pip3 install -r archer/requirements.txt -i https://mirrors.ustc.edu.cn/pypi/web/simple/ \
12 | && cp archer/src/docker/pymysql/connections.py venv4archer/lib/python3.4/site-packages/pymysql/ \
13 | && cp archer/src/docker/pymysql/cursors.py venv4archer/lib/python3.4/site-packages/pymysql/ \
14 |
--------------------------------------------------------------------------------
/src/script/mysql_slow_query_review.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE `mysql_slow_query_review` (
2 | `checksum` CHAR(32) NOT NULL,
3 | `fingerprint` longtext NOT NULL,
4 | `sample` longtext NOT NULL,
5 | `first_seen` datetime(6) DEFAULT NULL,
6 | `last_seen` datetime(6) DEFAULT NULL,
7 | `reviewed_by` varchar(20) DEFAULT NULL,
8 | `reviewed_on` datetime(6) DEFAULT NULL,
9 | `comments` longtext,
10 | `reviewed_status` varchar(24) DEFAULT NULL,
11 | PRIMARY KEY (`checksum`),
12 | KEY `idx_last_seen` (`last_seen`)
13 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
14 |
15 | CREATE TABLE `mysql_slow_query_review_history` (
16 | `id` int(11) NOT NULL AUTO_INCREMENT,
17 | `hostname_max` varchar(64) NOT NULL,
18 | `client_max` varchar(64) DEFAULT NULL,
19 | `user_max` varchar(64) NOT NULL,
20 | `db_max` varchar(64) DEFAULT NULL,
21 | `checksum` CHAR(32) NOT NULL,
22 | `sample` longtext NOT NULL,
23 | `ts_min` datetime(6) NOT NULL,
24 | `ts_max` datetime(6) NOT NULL,
25 | `ts_cnt` float DEFAULT NULL,
26 | `Query_time_sum` float DEFAULT NULL,
27 | `Query_time_min` float DEFAULT NULL,
28 | `Query_time_max` float DEFAULT NULL,
29 | `Query_time_pct_95` float DEFAULT NULL,
30 | `Query_time_stddev` float DEFAULT NULL,
31 | `Query_time_median` float DEFAULT NULL,
32 | `Lock_time_sum` float DEFAULT NULL,
33 | `Lock_time_min` float DEFAULT NULL,
34 | `Lock_time_max` float DEFAULT NULL,
35 | `Lock_time_pct_95` float DEFAULT NULL,
36 | `Lock_time_stddev` float DEFAULT NULL,
37 | `Lock_time_median` float DEFAULT NULL,
38 | `Rows_sent_sum` float DEFAULT NULL,
39 | `Rows_sent_min` float DEFAULT NULL,
40 | `Rows_sent_max` float DEFAULT NULL,
41 | `Rows_sent_pct_95` float DEFAULT NULL,
42 | `Rows_sent_stddev` float DEFAULT NULL,
43 | `Rows_sent_median` float DEFAULT NULL,
44 | `Rows_examined_sum` float DEFAULT NULL,
45 | `Rows_examined_min` float DEFAULT NULL,
46 | `Rows_examined_max` float DEFAULT NULL,
47 | `Rows_examined_pct_95` float DEFAULT NULL,
48 | `Rows_examined_stddev` float DEFAULT NULL,
49 | `Rows_examined_median` float DEFAULT NULL,
50 | `Rows_affected_sum` float DEFAULT NULL,
51 | `Rows_affected_min` float DEFAULT NULL,
52 | `Rows_affected_max` float DEFAULT NULL,
53 | `Rows_affected_pct_95` float DEFAULT NULL,
54 | `Rows_affected_stddev` float DEFAULT NULL,
55 | `Rows_affected_median` float DEFAULT NULL,
56 | `Rows_read_sum` float DEFAULT NULL,
57 | `Rows_read_min` float DEFAULT NULL,
58 | `Rows_read_max` float DEFAULT NULL,
59 | `Rows_read_pct_95` float DEFAULT NULL,
60 | `Rows_read_stddev` float DEFAULT NULL,
61 | `Rows_read_median` float DEFAULT NULL,
62 | `Merge_passes_sum` float DEFAULT NULL,
63 | `Merge_passes_min` float DEFAULT NULL,
64 | `Merge_passes_max` float DEFAULT NULL,
65 | `Merge_passes_pct_95` float DEFAULT NULL,
66 | `Merge_passes_stddev` float DEFAULT NULL,
67 | `Merge_passes_median` float DEFAULT NULL,
68 | `InnoDB_IO_r_ops_min` float DEFAULT NULL,
69 | `InnoDB_IO_r_ops_max` float DEFAULT NULL,
70 | `InnoDB_IO_r_ops_pct_95` float DEFAULT NULL,
71 | `InnoDB_IO_r_ops_stddev` float DEFAULT NULL,
72 | `InnoDB_IO_r_ops_median` float DEFAULT NULL,
73 | `InnoDB_IO_r_bytes_min` float DEFAULT NULL,
74 | `InnoDB_IO_r_bytes_max` float DEFAULT NULL,
75 | `InnoDB_IO_r_bytes_pct_95` float DEFAULT NULL,
76 | `InnoDB_IO_r_bytes_stddev` float DEFAULT NULL,
77 | `InnoDB_IO_r_bytes_median` float DEFAULT NULL,
78 | `InnoDB_IO_r_wait_min` float DEFAULT NULL,
79 | `InnoDB_IO_r_wait_max` float DEFAULT NULL,
80 | `InnoDB_IO_r_wait_pct_95` float DEFAULT NULL,
81 | `InnoDB_IO_r_wait_stddev` float DEFAULT NULL,
82 | `InnoDB_IO_r_wait_median` float DEFAULT NULL,
83 | `InnoDB_rec_lock_wait_min` float DEFAULT NULL,
84 | `InnoDB_rec_lock_wait_max` float DEFAULT NULL,
85 | `InnoDB_rec_lock_wait_pct_95` float DEFAULT NULL,
86 | `InnoDB_rec_lock_wait_stddev` float DEFAULT NULL,
87 | `InnoDB_rec_lock_wait_median` float DEFAULT NULL,
88 | `InnoDB_queue_wait_min` float DEFAULT NULL,
89 | `InnoDB_queue_wait_max` float DEFAULT NULL,
90 | `InnoDB_queue_wait_pct_95` float DEFAULT NULL,
91 | `InnoDB_queue_wait_stddev` float DEFAULT NULL,
92 | `InnoDB_queue_wait_median` float DEFAULT NULL,
93 | `InnoDB_pages_distinct_min` float DEFAULT NULL,
94 | `InnoDB_pages_distinct_max` float DEFAULT NULL,
95 | `InnoDB_pages_distinct_pct_95` float DEFAULT NULL,
96 | `InnoDB_pages_distinct_stddev` float DEFAULT NULL,
97 | `InnoDB_pages_distinct_median` float DEFAULT NULL,
98 | `QC_Hit_cnt` float DEFAULT NULL,
99 | `QC_Hit_sum` float DEFAULT NULL,
100 | `Full_scan_cnt` float DEFAULT NULL,
101 | `Full_scan_sum` float DEFAULT NULL,
102 | `Full_join_cnt` float DEFAULT NULL,
103 | `Full_join_sum` float DEFAULT NULL,
104 | `Tmp_table_cnt` float DEFAULT NULL,
105 | `Tmp_table_sum` float DEFAULT NULL,
106 | `Tmp_table_on_disk_cnt` float DEFAULT NULL,
107 | `Tmp_table_on_disk_sum` float DEFAULT NULL,
108 | `Filesort_cnt` float DEFAULT NULL,
109 | `Filesort_sum` float DEFAULT NULL,
110 | `Filesort_on_disk_cnt` float DEFAULT NULL,
111 | `Filesort_on_disk_sum` float DEFAULT NULL,
112 | `Bytes_sum` float DEFAULT NULL,
113 | `Bytes_min` float DEFAULT NULL,
114 | `Bytes_max` float DEFAULT NULL,
115 | `Bytes_pct_95` float DEFAULT NULL,
116 | `Bytes_stddev` float DEFAULT NULL,
117 | `Bytes_median` float DEFAULT NULL,
118 | PRIMARY KEY (`id`),
119 | KEY `idx_hostname_max_ts_min` (`hostname_max`,`ts_min`),
120 | KEY `idx_checksum` (`checksum`)
121 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--------------------------------------------------------------------------------
/startup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #收集所有的静态文件到STATIC_ROOT
4 | python3 manage.py collectstatic -v0 --noinput
5 |
6 | settings=${1:-"archer.settings"}
7 | ip=${2:-"0.0.0.0"}
8 | port=${3:-8888}
9 |
10 | gunicorn -w 2 --env DJANGO_SETTINGS_MODULE=${settings} --error-logfile=/tmp/archer.err -b ${ip}:${port} --timeout 600 --daemon archer.wsgi:application
11 |
--------------------------------------------------------------------------------
/stop.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | port=${1:-8888}
4 | ps -ef|grep gunicorn|grep ${port}|awk '{print $2}'|xargs kill -15
5 |
--------------------------------------------------------------------------------