├── .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('
'+b.addText+"
");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('
'+b.deleteText+"
");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 | --------------------------------------------------------------------------------