├── .gitattributes ├── .idea ├── ApiCaseSystem.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── ApiCaseSystem ├── .settings.py.swp ├── __init__.py ├── __init__.pyc ├── celery.py ├── celery.pyc ├── hostspage.py ├── settings.py ├── settings.pyc ├── urls.py ├── urls.pyc ├── wsgi.py └── wsgi.pyc ├── PBS_Dynamic ├── DataCenter.py ├── DataCenter.pyc ├── __init__.py ├── __init__.pyc ├── admin.py ├── admin.pyc ├── apps.py ├── apps.pyc ├── log_obj.py ├── log_obj.pyc ├── media │ └── introduce_img │ │ ├── log.gif │ │ └── wapi.gif ├── migrations │ ├── __init__.py │ └── __init__.pyc ├── models.py ├── models.pyc ├── static │ └── WEB_API │ │ ├── css │ │ ├── common │ │ │ ├── datetimepicker.css │ │ │ ├── jquery-ui-1.10.4.custom.css │ │ │ ├── jquery-ui-1.10.4.custom.min.css │ │ │ ├── jquery-ui.css │ │ │ ├── jquery-ui.min.css │ │ │ ├── jquery-ui.structure.css │ │ │ ├── jquery-ui.structure.min.css │ │ │ ├── jquery-ui.theme.css │ │ │ ├── jquery-ui.theme.min.css │ │ │ └── paging.css │ │ ├── log │ │ │ └── check_log.css │ │ └── wapi_bootstrap │ │ │ └── bootstrap.min.css │ │ └── js │ │ ├── common │ │ ├── datetimepicker.js │ │ ├── jquery-1.10.2.js │ │ ├── jquery-ui-1.10.4.custom.js │ │ ├── jquery-ui-1.10.4.custom.min.js │ │ ├── jquery-ui.js │ │ ├── jquery-ui.min.js │ │ ├── jquery.min.js │ │ ├── paging.js │ │ └── paging.min.js │ │ ├── log │ │ └── check_log.js │ │ └── wapi_bootstrap │ │ ├── bootstrap.min.js │ │ └── popper.min.js ├── tasks.py ├── templates │ └── WEB_API │ │ ├── log │ │ ├── check_log.html │ │ └── tmp.html │ │ └── report │ │ ├── index_ignite.html │ │ └── report.html ├── tests.py ├── views.py ├── views.pyc ├── web_api_forms.py ├── web_api_forms.pyc ├── web_api_paging.py └── web_api_paging.pyc ├── README.md ├── SOAP_API ├── __init__.py ├── __init__.pyc ├── admin.py ├── admin.pyc ├── apps.py ├── apps.pyc ├── migrations │ ├── __init__.py │ └── __init__.pyc ├── models.py ├── models.pyc ├── soap_api_forms.py ├── soap_api_forms.pyc ├── tests.py └── views.py ├── WingOn ├── .idea │ ├── WingOn.iml │ ├── inspectionProfiles │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── workspace.xml ├── FightDataAndloadCase │ ├── ProcessData.py │ ├── ProcessData.pyc │ ├── StructureData.py │ ├── StructureData.pyc │ ├── __init__.py │ └── __init__.pyc ├── Main.py ├── Main.pyc ├── __init__.py ├── __init__.pyc ├── generateReport │ ├── HtmlReport.py │ ├── HtmlReport.pyc │ ├── IgniteTemplateHtml.py │ ├── IgniteTemplateHtml.pyc │ ├── TemplateHtml.py │ ├── TemplateHtml.pyc │ ├── __init__.py │ ├── __init__.pyc │ └── clickA.js ├── methods │ ├── HttpEntity.py │ ├── HttpEntity.pyc │ ├── __init__.py │ └── __init__.pyc ├── reports │ ├── click.js │ ├── igniteReport │ │ └── ProdFBSFerry点火测试2017_12_28_08_30.html │ └── reportResult │ │ └── Prod2018_01_02_11_07.html └── requestBody │ ├── Check.py │ ├── Check.pyc │ ├── InterfaceCase.py │ ├── InterfaceCase.pyc │ ├── RMQ │ ├── RMQrecive.py │ ├── RMQsend.py │ ├── RMQsend.pyc │ ├── Rsa_encrypt │ │ ├── __init__.py │ │ ├── __init__.pyc │ │ ├── js.py │ │ ├── js.pyc │ │ └── rsa.js │ ├── __init__.py │ └── __init__.pyc │ ├── __init__.py │ ├── __init__.pyc │ └── rsa.js ├── celerybeat.pid ├── manage.py ├── requirements.txt ├── static ├── WEB_API │ ├── css │ │ ├── common │ │ │ ├── datetimepicker.css │ │ │ ├── jquery-ui-1.10.4.custom.css │ │ │ ├── jquery-ui-1.10.4.custom.min.css │ │ │ ├── jquery-ui.css │ │ │ ├── jquery-ui.min.css │ │ │ ├── jquery-ui.structure.css │ │ │ ├── jquery-ui.structure.min.css │ │ │ ├── jquery-ui.theme.css │ │ │ ├── jquery-ui.theme.min.css │ │ │ ├── paging.css │ │ │ └── paging.less │ │ ├── log │ │ │ ├── check_log.css │ │ │ ├── jquery-ui-1.10.4.custom.css │ │ │ ├── jquery-ui-1.10.4.custom.min.css │ │ │ ├── jquery-ui.css │ │ │ ├── jquery-ui.min.css │ │ │ ├── jquery-ui.structure.css │ │ │ ├── jquery-ui.structure.min.css │ │ │ ├── jquery-ui.theme.css │ │ │ └── jquery-ui.theme.min.css │ │ └── wapi_bootstrap │ │ │ └── bootstrap.min.css │ └── js │ │ ├── common │ │ ├── datetimepicker.js │ │ ├── jquery-1.10.2.js │ │ ├── jquery-ui-1.10.4.custom.js │ │ ├── jquery-ui-1.10.4.custom.min.js │ │ ├── jquery-ui.js │ │ ├── jquery-ui.min.js │ │ ├── jquery.min.js │ │ ├── paging.js │ │ └── paging.min.js │ │ ├── log │ │ ├── check_log.js │ │ ├── jquery-1.10.2.js │ │ ├── jquery-ui-1.10.4.custom.js │ │ ├── jquery-ui-1.10.4.custom.min.js │ │ ├── jquery-ui.js │ │ └── jquery-ui.min.js │ │ └── wapi_bootstrap │ │ ├── bootstrap.min.js │ │ └── popper.min.js ├── admin │ ├── css │ │ ├── base.css │ │ ├── changelists.css │ │ ├── dashboard.css │ │ ├── fonts.css │ │ ├── forms.css │ │ ├── login.css │ │ ├── rtl.css │ │ └── widgets.css │ ├── fonts │ │ ├── LICENSE.txt │ │ ├── README.txt │ │ ├── Roboto-Bold-webfont.woff │ │ ├── Roboto-Light-webfont.woff │ │ └── Roboto-Regular-webfont.woff │ ├── img │ │ ├── LICENSE │ │ ├── README.txt │ │ ├── calendar-icons.svg │ │ ├── gis │ │ │ ├── move_vertex_off.svg │ │ │ └── move_vertex_on.svg │ │ ├── icon-addlink.svg │ │ ├── icon-alert.svg │ │ ├── icon-calendar.svg │ │ ├── icon-changelink.svg │ │ ├── icon-clock.svg │ │ ├── icon-deletelink.svg │ │ ├── icon-no.svg │ │ ├── icon-unknown-alt.svg │ │ ├── icon-unknown.svg │ │ ├── icon-yes.svg │ │ ├── inline-delete.svg │ │ ├── search.svg │ │ ├── selector-icons.svg │ │ ├── sorting-icons.svg │ │ ├── tooltag-add.svg │ │ └── tooltag-arrowright.svg │ └── js │ │ ├── SelectBox.js │ │ ├── SelectFilter2.js │ │ ├── actions.js │ │ ├── actions.min.js │ │ ├── admin │ │ ├── DateTimeShortcuts.js │ │ └── RelatedObjectLookups.js │ │ ├── calendar.js │ │ ├── cancel.js │ │ ├── change_form.js │ │ ├── collapse.js │ │ ├── collapse.min.js │ │ ├── core.js │ │ ├── inlines.js │ │ ├── inlines.min.js │ │ ├── jquery.init.js │ │ ├── popup_response.js │ │ ├── prepopulate.js │ │ ├── prepopulate.min.js │ │ ├── prepopulate_init.js │ │ ├── timeparse.js │ │ ├── urlify.js │ │ └── vendor │ │ ├── jquery │ │ ├── LICENSE-JQUERY.txt │ │ ├── jquery.js │ │ └── jquery.min.js │ │ └── xregexp │ │ ├── LICENSE-XREGEXP.txt │ │ ├── xregexp.js │ │ └── xregexp.min.js └── djcelery │ └── style.css ├── templates └── hostconfig.html └── test_django.sql /.gitattributes: -------------------------------------------------------------------------------- 1 | *.css linguist-language=Python 2 | *.js linguist-language=Python 3 | *.html linguist-language=Python -------------------------------------------------------------------------------- /.idea/ApiCaseSystem.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ApiCaseSystem/.settings.py.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/.settings.py.swp -------------------------------------------------------------------------------- /ApiCaseSystem/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | # This will make sure the app is always imported when 4 | # Django starts so that shared_task will use this app. 5 | from .celery import app as celery_app 6 | 7 | __all__ = ['celery_app'] -------------------------------------------------------------------------------- /ApiCaseSystem/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/__init__.pyc -------------------------------------------------------------------------------- /ApiCaseSystem/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | import os 3 | from celery import Celery, platforms 4 | from django.conf import settings 5 | 6 | # set the default Django settings module for the 'celery' program. 7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ApiCaseSystem.settings') 8 | 9 | app = Celery('ApiCaseSystem') 10 | 11 | # Using a string here means the worker don't have to serialize 12 | # the configuration object to child processes. 13 | # - namespace='CELERY' means all celery-related configuration keys 14 | # should have a `CELERY_` prefix. 15 | app.config_from_object('django.conf:settings') 16 | 17 | # Load task modules from all registered Django app configs. 18 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 19 | 20 | platforms.C_FORCE_ROOT = True 21 | 22 | 23 | @app.task(bind=True) 24 | def debug_task(self): 25 | print('Request: {0!r}'.format(self.request)) 26 | -------------------------------------------------------------------------------- /ApiCaseSystem/celery.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/celery.pyc -------------------------------------------------------------------------------- /ApiCaseSystem/hostspage.py: -------------------------------------------------------------------------------- 1 | import time,platform,os 2 | from django.shortcuts import render_to_response 3 | from django.views.decorators.csrf import csrf_exempt 4 | 5 | hostsfile = '/etc/hosts' 6 | 7 | 8 | def basepage(request, issuccess=0): 9 | now = time.strftime('%Y-%m-%d %X', time.localtime()) 10 | with open(hostsfile) as f: 11 | hostsconent = f.read() 12 | return render_to_response('hostconfig.html', {'text': hostsconent, 'info': issuccess, 'now': now}) 13 | 14 | 15 | @csrf_exempt 16 | def hostupdate(request): 17 | if request.POST.has_key('save'): 18 | contents = request.POST['content'].encode('utf-8') 19 | with open(hostsfile,'w+') as f: 20 | f.write(contents.replace('\r', '')) 21 | issuccess = 1 22 | elif request.POST.has_key('saveandfresh'): 23 | contents = request.POST['content'].encode('utf-8') 24 | with open(hostsfile,'w+') as f: 25 | f.write(contents.replace('\r', '')) 26 | if platform.system() == 'Windows': 27 | os.system('ipconfig /flushdns') 28 | elif platform.system() == 'Linux': 29 | os.system('systemctl restart network') 30 | issuccess = 1 31 | else: 32 | issuccess = 0 33 | return basepage(request, issuccess) 34 | 35 | -------------------------------------------------------------------------------- /ApiCaseSystem/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for ApiCaseSystem project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | 13 | import os 14 | import platform 15 | 16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 18 | 19 | # DEFAULT_CHARSET = UTF-8 20 | 21 | # Quick-start development settings - unsuitable for production 22 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 23 | 24 | # SECURITY WARNING: keep the secret key used in production secret! 25 | SECRET_KEY = '^(8a(lacnu+)x-1%3^*zo(cy2!adsuq80xvy^+psz(ec(hkyij' 26 | 27 | # SECURITY WARNING: don't run with debug turned on in production! 28 | DEBUG = True 29 | 30 | ALLOWED_HOSTS = ['*'] 31 | 32 | # setting django 33 | BROKER_URL = 'django://localhost:8000//' 34 | CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler' 35 | 36 | if platform.system() == "Windows": 37 | DATABASES = { 38 | 'default': { 39 | 'ENGINE': 'django.db.backends.mysql', 40 | 'NAME': 'xxxxx', # config you database name 41 | 'USER': 'xxx', # database user name 42 | 'PASSWORD': 'xxx', # database pwd 43 | 'HOST': 'xxxx', # database host 44 | 'PORT': 'xxx', # database port 45 | 'OPTIONS': {'charset': 'utf8mb4'}, 46 | } 47 | } 48 | CELERY_TIMEZONE = 'UTC' # windows 49 | TIME_ZONE = 'UTC' # windows 50 | else: 51 | DATABASES = { 52 | 'default': { 53 | 'ENGINE': 'django.db.backends.mysql', 54 | 'NAME': 'xxxxx', # config you database name 55 | 'USER': 'xxx', # database user name 56 | 'PASSWORD': 'xxx', # database pwd 57 | 'HOST': 'xxxx', # database host 58 | 'PORT': 'xxx', # database port 59 | 'OPTIONS': {'charset': 'utf8mb4'}, 60 | } 61 | } 62 | CELERY_TIMEZONE = 'Asia/Shanghai' # 191 linux 63 | TIME_ZONE = 'Asia/Shanghai' # 191 LINUX 64 | 65 | 66 | # Application definition 67 | 68 | INSTALLED_APPS = [ 69 | # 'bootstrap_admin', 70 | 'django.contrib.admin', 71 | 'django.contrib.auth', 72 | 'django.contrib.contenttypes', 73 | 'django.contrib.sessions', 74 | 'django.contrib.messages', 75 | 'django.contrib.staticfiles', 76 | 'kombu.transport.django', 77 | 'djcelery.app.DjceleryConf', 78 | # 'djcelery', 79 | # 'djkombu', 80 | 'PBS_Dynamic', 81 | 'SOAP_API', 82 | # 'PBS_Dynamic.apps.PbsDynamicConfig', 83 | 84 | 85 | ] 86 | 87 | MIDDLEWARE = [ 88 | 'django.middleware.security.SecurityMiddleware', 89 | 'django.contrib.sessions.middleware.SessionMiddleware', 90 | 'django.middleware.common.CommonMiddleware', 91 | 'django.middleware.csrf.CsrfViewMiddleware', 92 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 93 | 'django.contrib.messages.middleware.MessageMiddleware', 94 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 95 | ] 96 | 97 | ROOT_URLCONF = 'ApiCaseSystem.urls' 98 | 99 | TEMPLATES = [ 100 | { 101 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 102 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 103 | 'APP_DIRS': True, 104 | 'OPTIONS': { 105 | 'context_processors': [ 106 | 'django.template.context_processors.debug', 107 | 'django.template.context_processors.request', 108 | 'django.contrib.auth.context_processors.auth', 109 | 'django.contrib.messages.context_processors.messages', 110 | ], 111 | }, 112 | }, 113 | ] 114 | 115 | WSGI_APPLICATION = 'ApiCaseSystem.wsgi.application' 116 | 117 | 118 | # Database 119 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 120 | 121 | # DATABASES = { 122 | # 'default': { 123 | # 'ENGINE': 'django.db.backends.sqlite3', 124 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 125 | # } 126 | # } 127 | 128 | # Password validation 129 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 130 | 131 | AUTH_PASSWORD_VALIDATORS = [ 132 | { 133 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 134 | }, 135 | { 136 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 137 | }, 138 | { 139 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 140 | }, 141 | { 142 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 143 | }, 144 | ] 145 | 146 | 147 | # Internationalization 148 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 149 | 150 | LANGUAGE_CODE = 'zh-Hans' 151 | 152 | # LANGUAGE_CODE = 'en-us' 153 | 154 | USE_I18N = True 155 | 156 | # USE_L10N = True 157 | USE_L10N = False 158 | DATETIME_FORMAT = 'Y-m-d H:i:s' 159 | DATE_FORMAT = 'Y-m-d' 160 | 161 | # USE_TZ = True 162 | USE_TZ = False 163 | 164 | 165 | # Static files (CSS, JavaScript, Images) 166 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 167 | 168 | STATIC_URL = '/static/' 169 | 170 | STATIC_ROOT = os.path.join(BASE_DIR, 'static') 171 | 172 | -------------------------------------------------------------------------------- /ApiCaseSystem/settings.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/settings.pyc -------------------------------------------------------------------------------- /ApiCaseSystem/urls.py: -------------------------------------------------------------------------------- 1 | """ApiCaseSystem URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/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. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | from PBS_Dynamic import views 19 | 20 | urlpatterns = [ 21 | url(r'^admin/', admin.site.urls), 22 | url(r'^log/$', views.log), 23 | # url('^hostupdate/$', hostupdate), 24 | ] 25 | -------------------------------------------------------------------------------- /ApiCaseSystem/urls.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/urls.pyc -------------------------------------------------------------------------------- /ApiCaseSystem/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ApiCaseSystem 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.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | # import sys 12 | 13 | from django.core.wsgi import get_wsgi_application 14 | 15 | # sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) 16 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ApiCaseSystem.settings") 17 | 18 | application = get_wsgi_application() 19 | -------------------------------------------------------------------------------- /ApiCaseSystem/wsgi.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/ApiCaseSystem/wsgi.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/DataCenter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class Common: 5 | """ 6 | 单执行Rest/Web Api用例字段信息等 7 | """ 8 | def __init__(self): 9 | self.list_id = [] 10 | self.start_time = None 11 | self.use_time = None 12 | self.user = None 13 | self.environment = None 14 | self.methods = 'test_case' 15 | self.suite_name = '' 16 | self.case_id_list = [] 17 | self.system_type = [] 18 | self.email_list = [] 19 | self.pattern_list = [] 20 | self.content_list = [] 21 | self.api_type_list = [] 22 | self.api_type = 0 23 | self.use_time_list = [] 24 | 25 | 26 | class SuiteDataCenter: 27 | """ 28 | 执行测试套件信息 29 | """ 30 | def __init__(self): 31 | self.list_id = [] 32 | self.start_time = None 33 | self.use_time = [] 34 | self.user = None 35 | self.environment = None 36 | self.methods = 'test_suite' 37 | self.suite_name = [] 38 | self.case_id_list = [] 39 | self.system_type = [] 40 | self.email_list = [] 41 | self.pattern_list = [] 42 | self.content_list = [] 43 | self.api_type_list = [] 44 | self.api_type = None 45 | self.use_time_list = [] 46 | 47 | 48 | class SoapDataCenter: 49 | """ 50 | 单执行Soap Api测试套件信息 51 | """ 52 | def __init__(self): 53 | self.list_id = [] 54 | self.start_time = None 55 | self.use_time = None 56 | self.user = None 57 | self.environment = None 58 | self.methods = 'test_case' 59 | self.suite_name = '' 60 | self.case_id_list = [] 61 | self.system_type = [] 62 | self.email_list = [] 63 | self.pattern_list = [] 64 | self.content_list = [] 65 | self.api_type_list = [] 66 | self.api_type = 1 67 | self.use_time_list = [] 68 | 69 | 70 | class IgniteDataCenter: 71 | """ 72 | 点火系统 信息 73 | """ 74 | def __init__(self): 75 | self.list_id = [] 76 | self.methods = 'ignite' 77 | self.environment = None 78 | self.environ = None 79 | self.system_type_list = [] 80 | self.system_name_list = [] 81 | self.start_time = None 82 | self.use_time = None 83 | self.user = None 84 | self.file_h = '.html' 85 | self.api_type = 0 86 | self.use_time_list = [] 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /PBS_Dynamic/DataCenter.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/DataCenter.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'PBS_Dynamic.apps.PbsDynamicConfig' 2 | -------------------------------------------------------------------------------- /PBS_Dynamic/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/__init__.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/admin.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/admin.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class PbsDynamicConfig(AppConfig): 8 | name = u'PBS_Dynamic' 9 | verbose_name = 'WEB/REST接口测试用例管理系统' 10 | -------------------------------------------------------------------------------- /PBS_Dynamic/apps.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/apps.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/log_obj.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | 4 | class LogObj(object): 5 | 6 | def __init__(self): 7 | self.check_result = None 8 | self.case_type = 0 9 | self.case_id = '' 10 | self.sub_case_id = '' 11 | self.click_time = None 12 | self.end_time = None 13 | self.system = '' 14 | self.environment = '' 15 | self.click_time = None 16 | self.end_time = None 17 | self.start_index = 0 18 | self.end_index = 15 19 | self.token = None 20 | self.page_url = None 21 | self.api_type = None 22 | self.soap_system = '' 23 | 24 | # def start_indexa(self): 25 | # start_index = self.start_index 26 | # return start_index 27 | # 28 | # def end_indexa(self): 29 | # end_index = self.end_index 30 | # return end_index 31 | # 32 | # def check_resultzz(self): 33 | # check_result = self.check_result 34 | # return check_result 35 | # 36 | # def page_urlz(self): 37 | # page_url = self.page_url 38 | # return page_url 39 | # 40 | # def click_times(self): 41 | # click_time = self.click_time 42 | # return click_time 43 | # 44 | # def end_times(self): 45 | # end_time = self.click_time 46 | # return end_time -------------------------------------------------------------------------------- /PBS_Dynamic/log_obj.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/log_obj.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/media/introduce_img/log.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/media/introduce_img/log.gif -------------------------------------------------------------------------------- /PBS_Dynamic/media/introduce_img/wapi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/media/introduce_img/wapi.gif -------------------------------------------------------------------------------- /PBS_Dynamic/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/migrations/__init__.py -------------------------------------------------------------------------------- /PBS_Dynamic/migrations/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/migrations/__init__.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/models.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/models.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/static/WEB_API/css/common/paging.css: -------------------------------------------------------------------------------- 1 | #box{list-style:none;margin:0;padding:0;margin-left:2%;margin-top:1%;} 2 | #box li { 3 | color: #0084F3; 4 | text-align: center; 5 | width: 60px; 6 | height: 40px; 7 | border: 1px solid #ebebeb; 8 | line-height: 40px; 9 | box-sizing: border-box; 10 | cursor: pointer; 11 | float: left; 12 | } 13 | #box li a{ 14 | display:block; 15 | width: 60px; 16 | height: 40px; 17 | line-height: 40px; 18 | } 19 | #box .active{background: #0084F3} 20 | #box .active a{color: white;} 21 | #box li a{text-decoration:none;} 22 | #box span{margin-left: 20px;height: 40px;line-height: 40px;} -------------------------------------------------------------------------------- /PBS_Dynamic/static/WEB_API/css/log/check_log.css: -------------------------------------------------------------------------------- 1 | #loading{width:100%;height:100%;background:#000;opacity:0; 2 | position:absolute;top:0px;color:white;z-index:50; 3 | font-size:36px;font-family:'微软雅黑';text-align:center;padding-top:25%; 4 | -webkit-transition:all 2s;display:none;} 5 | #mainview{ 6 | width: 90%;margin-top: 1%;margin-left:5%; 7 | -moz-box-shadow: 0 0 5px;/*firefox*/ 8 | -webkit-box-shadow: 0 0 5px;/*webkit*/ 9 | box-shadow: 0 0 5px;/*opera或ie9*/ 10 | -moz-border-radius:5px; 11 | -webkit-border-radius:5px; 12 | border-radius: 5px; 13 | padding: 5px;} 14 | #tarTop{ 15 | text-align: center; background: #0084F3; 16 | height: 3%; 17 | font-family: '微软雅黑';font-size: 24px;font-weight: bold;line-height: 40px;color: white; 18 | -moz-box-shadow: 0 0 3px; 19 | -webkit-box-shadow: 0 0 3px; 20 | box-shadow: 0 0 3px; 21 | -moz-border-radius: 5px; 22 | -webkit-border-radius: 5px; 23 | border-radius: 5px; } 24 | /*40px=3%*/ 25 | #oform{ margin-top: 1.5%; } 26 | #input_div{margin-left:1%;width: 98%;} 27 | #sel{width: 10%;} 28 | #click_time{width: 12%;} 29 | #end_time{width: 12%;} 30 | /*restapi 系统选择*/ 31 | #systemcode{width: 15%;font-size: 18px;} 32 | /*soapapi 系统选择*/ 33 | #soap_system_code{width: 15.7%;font-size: 16px;} 34 | 35 | #enviorment{width: 10%;} 36 | #case_id{width: 8%;height: 37px;} 37 | #sub_case_id{width: 8%;} 38 | #submit_btn{width:5%;background:#0084F3;color:white;margin-left:5%} 39 | #submit_btn:hover{opacity:0.6;} 40 | 41 | 42 | 43 | #search_thread{margin: 0 auto;margin-top: 2%;height:40px;background: #11A0FF; color: white; font-weight: bold; border-radius: 5px;} 44 | #search_thread table{width:97%; height:100%;text-align: left;margin-left: 2%;border-collapse: separate;} 45 | /*#search_thread table tr td{background: red} 46 | .div_title table tr td{background: black;}*/ 47 | /*开始执行时间*/ 48 | #search_thread .ClickExecutionTime2{width:15.5%;} 49 | /*接口名称*/ 50 | #search_thread .testCase__ApiName2{width: 33%;} 51 | /*描述*/ 52 | #search_thread .testCase__Description2{width: 21.6%;} 53 | /*ID*/ 54 | #search_thread .testCase_id2{width: 5%;} 55 | /*执行步骤*/ 56 | #search_thread .testCase__SetupStep2{width: 11%;} 57 | /*环境*/ 58 | #search_thread .Environment2{width: 5%;} 59 | /*结果*/ 60 | #search_thread .Status2{width: 9%;} 61 | /*子用例使用样式 ID 步骤类型*/ 62 | #search_thread .SubCaseID_id2{width: 8%;} 63 | #search_thread .SubCaseID__SetupType2{width: 8%;} 64 | 65 | /* soap 用例样式 testCase_id2*/ 66 | #search_thread .soapTestCase_id2{width: 8%;} 67 | #search_thread .soapTestCase__SetupStep2{width: 8%;} 68 | #search_thread .soapSubCase_id2{width: 5%;} 69 | 70 | 71 | /*log内容样式*/ 72 | #accordion{--webkit-box-shadow: 0 0 5px; margin-top: 0.5%;} 73 | #accordion div:nth-child(even){display:none;padding:25px;text-align:left;background:#F7F7F7;word-break: break-all;word-wrap:break-word;}; 74 | #accordion div:nth-child(odd){height:40px;}; 75 | .div_title{border-radius:10px;box-shadow: 0 0 5px #CCCCCC;} 76 | .div_title table{height:40px;border-bottom:1px solid #DDD;width: 97%;margin-left:2%;table-layout: fixed; text-align: left;border-collapse: separate;word-break: break-all; word-wrap: break-word;} 77 | .div_title table tr td{overflow: hidden;text-overflow:ellipsis;white-space: nowrap;} 78 | /*开始执行时间*/ 79 | .div_title .ClickExecutionTime{width: 15.5%;} 80 | /*接口名称*/ 81 | .div_title .testCase__ApiName,.SubCaseID__ApiName{width: 33%;} 82 | /*描述*/ 83 | .div_title .testCase__Description,.SubCaseID__Description{width: 21.6%;} 84 | /*ID*/ 85 | .div_title .testCase_id,.SubCaseID_id{width: 5%;} 86 | .div_title .SubCaseID_id{width: 8%;} 87 | /*执行步骤||步骤类型*/ 88 | .div_title .testCase__SetupStep,.SubCaseID__SetupType{width: 11%;} 89 | .div_title .SubCaseID__SetupType{width: 8%;} 90 | /*环境*/ 91 | .div_title .Environment{width: 5%;} 92 | /*结果状态*/ 93 | .div_title .Status{ width: 9%; color:#6c6; font-weight:bold;} 94 | 95 | /* soap 主用例样式 testCase_id2*/ 96 | .div_title .soapSubCase_id{width: 5%;} 97 | .div_title .soapTestCase_id{width: 8%;} 98 | 99 | .div_title .soapTestCase__Description,.soapSubCase__Description{width: 21.6%;} 100 | .div_title .soapTestCase__SetupStep,.soapSubCase__SetupType{width: 8%;} 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /PBS_Dynamic/static/WEB_API/js/common/paging.min.js: -------------------------------------------------------------------------------- 1 | (function(d, c, a) { 2 | function b(f, e) { 3 | this.el = f; 4 | this.options = { pageNo: e.initPageNo || 1, totalPages: e.totalPages || 1, totalCount: e.totalCount || "", slideSpeed: e.slideSpeed || 0, jump: e.jump || false, callback: e.callback || function() {} }; 5 | this.init() 6 | } 7 | b.prototype = { 8 | constructor: b, 9 | init: function() { 10 | this.createDom(); 11 | this.bindEvents() 12 | }, 13 | createDom: function() { 14 | var k = this, 15 | m = "", 16 | e = "", 17 | j = "", 18 | g = 60, 19 | h = k.options.totalPages, 20 | l = 0; 21 | h > 5 ? l = 5 * g : l = h * g; 22 | for (var f = 1; f <= k.options.totalPages; f++) { f != 1 ? m += "
  • " + f + "
  • " : m += '
  • ' + f + "
  • " } 23 | k.options.jump ? e = '' : e = ""; 24 | j = '' + '' + '
    ' + '
    " + '' + '' + e + '

    共 ' + k.options.totalPages + " 页

    " + '

    ' + k.options.totalCount + "

    "; 25 | k.el.html(j) 26 | }, 27 | bindEvents: function() { 28 | var k = this, 29 | f = d("#pageSelect"), 30 | r = f.children(), 31 | n = r[0].offsetWidth, 32 | l = k.options.totalPages, 33 | g = k.options.pageNo, 34 | e = 0, 35 | o = d("#prePage"), 36 | m = d("#nextPage"), 37 | i = d("#firstPage"), 38 | j = d("#lastPage"), 39 | q = d("#jumpBtn"), 40 | h = d("#jumpText"); 41 | o.on("click", function() { 42 | g--; 43 | if (g < 1) { g = 1 } 44 | p(g) 45 | }); 46 | m.on("click", function() { 47 | g++; 48 | if (g > r.length) { g = r.length } 49 | p(g) 50 | }); 51 | i.on("click", function() { 52 | g = 1; 53 | p(g) 54 | }); 55 | j.on("click", function() { 56 | g = l; 57 | p(g) 58 | }); 59 | q.on("click", function() { 60 | var s = parseInt(h.val().replace(/\D/g, "")); 61 | if (s && s >= 1 && s <= l) { 62 | g = s; 63 | p(g); 64 | h.val(s) 65 | } 66 | }); 67 | r.on("click", function() { 68 | g = d(this).index() + 1; 69 | p(g) 70 | }); 71 | 72 | function p(s) { 73 | r.removeClass("sel-page").eq(s - 1).addClass("sel-page"); 74 | if (l <= 5) { k.options.callback(s); return false } 75 | if (s >= 3 && s <= l - 2) { e = (s - 3) * n } 76 | if (s == 2 || s == 1) { e = 0 } 77 | if (s > l - 2) { e = (l - 5) * n } 78 | f.css("transform", "translateX(" + (-e) + "px)"); 79 | s == 1 ? i.attr("disabled", true) : i.attr("disabled", false); 80 | s == 1 ? o.attr("disabled", true) : o.attr("disabled", false); 81 | s == l ? j.attr("disabled", true) : j.attr("disabled", false); 82 | s == l ? m.attr("disabled", true) : m.attr("disabled", false); 83 | k.options.callback(s) 84 | } 85 | p(k.options.pageNo) 86 | } 87 | }; 88 | d.fn.paging = function(e) { return new b(d(this), e) } 89 | })(jQuery, window, document); -------------------------------------------------------------------------------- /PBS_Dynamic/static/WEB_API/js/log/check_log.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $('#sub_case_id').attr("disabled","disabled"); 3 | $('#soap_system_code').css('display','none'); 4 | }); 5 | //主用例/子用例切换响应事件 6 | function chg(){ 7 | if(document.getElementById("sel").value=="0"){ 8 | 9 | $('#sub_case_id').attr("disabled","disabled"); 10 | $('#sub_case_id').val(''); 11 | } 12 | else{ 13 | $('#sub_case_id').removeAttr("disabled"); 14 | $('#sub_case_id').val(''); 15 | 16 | } 17 | }; 18 | 19 | //SoapAPI/RestAPI切换响应事件 20 | function changeType(){ 21 | if(document.getElementById("api_type").value=="SoapAPI"){ 22 | document.getElementById("soap_system_code").style.display=''; 23 | document.getElementById("system_code").style.display='none'; 24 | }else{ 25 | document.getElementById("soap_system_code").style.display='none'; 26 | document.getElementById("system_code").style.display=''; 27 | } 28 | } 29 | $(function() { 30 | $( "#click_time" ).datetimepicker({ 31 | format:'Y-m-d H:i:s', 32 | step:10 33 | }); 34 | $( "#end_time" ).datetimepicker({ 35 | format:'Y-m-d H:i:s', 36 | step:10 37 | }); 38 | }); 39 | 40 | 41 | //日志详情展开 方法 42 | function logSlideToggle(){ 43 | $(".div_title").click(function(){ 44 | $(this).next().slideToggle(); 45 | }); 46 | } 47 | //状态颜色 方法 48 | function statusColor(){ 49 | var table_content=$('.table_content'); 50 | var i=0; 51 | for( var i = 0; i < table_content.length; i++ ) { 52 | 53 | var result_td=table_content.eq(i).children("td:last-child"); 54 | if(result_td.html()=='Fail'){ 55 | result_td.css('color','#c60'); 56 | } 57 | else if(result_td.html()=='Error'){ 58 | result_td.css('color','#c00'); 59 | } 60 | else if(result_td.html()=='Success'){ 61 | result_td.css('color','#6c6'); 62 | }else{ 63 | ; 64 | } 65 | } 66 | } 67 | //分页链接 点击响应 方法 68 | function linkClick(){ 69 | $('a').click(function(){ 70 | var oLink=$(this).attr('href'); 71 | //alert(oLink); 72 | $.ajax({ 73 | url: oLink, 74 | success: function(result, statues, xml){ 75 | //alert('进入分页回调'); 76 | //alert(result); 77 | $("#response_result").html(result); 78 | logSlideToggle(); 79 | statusColor(); 80 | linkClick(); 81 | }, 82 | error: function(){ 83 | alert("false"); 84 | }, 85 | dataType: "html" 86 | }); 87 | return false; 88 | }); 89 | } 90 | //页面加载完成 方法 查询提交请求 91 | $(document).ready(function(){ 92 | $.ajaxSetup({ 93 | data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, 94 | }); 95 | //查询提交 get请求 96 | $('#submit_btn').click(function(){ 97 | //alert('进入submit'); 98 | var csrfmiddlewaretoken='{{ csrf_token }}'; 99 | var api_type = $("#api_type").val(); 100 | var case_type = $("#sel").val(); 101 | var click_time = $("#click_time").val(); 102 | var end_time = $("#end_time").val(); 103 | var system_code = $("#system_code").val(); 104 | var soap_system_code = $("#soap_system_code").val(); 105 | var environment = $("#environment").val(); 106 | var case_id = $("#case_id").val(); 107 | var sub_case_id = $("#sub_case_id").val(); 108 | //正整数正则表达式 1-9开头 109 | var reg=/^[1-9]\d*$|^0$/; 110 | if(click_time==''||end_time==''){ 111 | alert('开始时间和结束时间不能为空'); 112 | $("#click_time").focus(); 113 | return false; 114 | }else if(click_time>end_time){ 115 | alert('开始时间不能早于结束时间'); 116 | $("#click_time").focus(); 117 | return false; 118 | }else if(case_type=='1'&&(case_id&&!(sub_case_id)||(sub_case_id&&(!case_id)))){ 119 | if(case_id&&!(sub_case_id)){alert('有主用例ID时 必须输入子用例ID');$("#sub_case_id").focus();} 120 | else{alert('有子用例ID时 必须输入主用例ID');$("#case_id").focus();} 121 | return false; 122 | }else if(case_type=='1'&&!(!case_id&&!sub_case_id)&&(reg.test(case_id)==false||reg.test(sub_case_id)==false)){ 123 | alert('请输入正确的ID'); 124 | return false; 125 | }else if(case_type=='0'&&case_id&®.test(case_id)==false){ 126 | alert('请输入正确的主用例ID'); 127 | $("#case_id").focus(); 128 | return false; 129 | } 130 | else{ 131 | document.getElementById("loading").style.display='block'; 132 | document.getElementById("loading").style.opacity='0.6'; 133 | $.ajax({ 134 | type:"GET", 135 | data: {api_type:api_type,case_type:case_type,click_time:click_time, 136 | end_time:end_time,system_code:system_code,soap_system_code:soap_system_code, 137 | environment:environment,case_id:case_id,sub_case_id:sub_case_id}, 138 | url: "/log/", 139 | cache: false, 140 | dataType: "html", 141 | /*ajax成功时回调方法*/ 142 | success: function(result, statues, xml){ 143 | //关闭 loading 144 | document.getElementById("loading").style.display='none'; 145 | //局部刷新数据 146 | $("#response_result").html(result); 147 | //加载分页提交事件 148 | linkClick(); 149 | //加载数据下拉事件 150 | logSlideToggle(); 151 | //加载状态颜色事件 152 | statusColor(); 153 | }, 154 | error: function(){ 155 | alert("false"); 156 | } 157 | }); 158 | return false; 159 | } 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /PBS_Dynamic/templates/WEB_API/log/tmp.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | 5 | 6 | {% ifequal api_type 'RestAPI' %} 7 | 8 | {% ifequal case_type 1 %} 9 | 10 | 11 | 12 | {% else %} 13 | 14 | 15 | 16 | 17 | {% endifequal %} 18 | {% else %} 19 | {% ifequal case_type 1 %} 20 | 21 | 22 | 23 | {% else %} 24 | 25 | 26 | 27 | 28 | {% endifequal %} 29 | {% endifequal %} 30 | 31 | 32 |
    用例开始时间用例中文描述接口名称ID步骤类型环境ID子用例步骤环境结果ID步骤类型环境ID子用例步骤环境结果
    33 |
    34 |
    35 | 36 | {% for result_node in result %} 37 | {% ifequal api_type 'RestAPI' %} 38 | {% ifequal case_type 0 %} 39 |
    40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
    {{ result_node.ClickExecutionTime }}{{ result_node.testCase__Description }}{{ result_node.testCase__ApiName }}{{ result_node.testCase_id }}{{ result_node.testCase__SetupStep }}{{ result_node.Environment }}{{ result_node.Status }}
    52 |
    53 | {% else %} 54 |
    55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
    {{ result_node.ClickExecutionTime }}{{ result_node.SubCaseID__Description }}{{ result_node.SubCaseID__ApiName }}{{ result_node.SubCaseID_id }}{{ result_node.SubCaseID__SetupType }}{{ result_node.Environment }}
    65 |
    66 | {% endifequal %} 67 |
    68 |

    {{ result_node.APIResult }}

    69 | 70 |
    71 | {% else %} 72 | {% ifequal case_type 0 %} 73 |
    74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
    {{ result_node.ClickExecutionTime }}{{ result_node.soapTestCase__Description }}{{ result_node.soapTestCase_id }}{{ result_node.soapTestCase__SetupStep }}{{ result_node.Environment }}{{ result_node.Status }}
    86 |
    87 | {% else %} 88 |
    89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
    {{ result_node.ClickExecutionTime }}{{ result_node.soapSubCase__Description }}{{ result_node.soapSubCase_id }}{{ result_node.soapSubCase__SetupType }}{{ result_node.Environment }}
    99 |
    100 | {% endifequal %} 101 |
    102 |
    {{ result_node.APIResult }}
    103 |
    104 | 105 | 106 | {% endifequal %} 107 | {% endfor %} 108 |
    109 |
    {{ page_str|safe}}
    -------------------------------------------------------------------------------- /PBS_Dynamic/templates/WEB_API/report/index_ignite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 点火结果报告 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 42 | 43 | 44 | 45 | 46 | 65 | 66 | 67 |
    68 |
    69 |
    70 |
      71 |
    • API Automation Description
    • 72 |
    • User:xinglongwang
    • 73 |
    • StartTime:2017-11-22 09:37:49.427000
    • 74 |
    • UseTime:0:00:00.080000
    • 75 |
    • Success:与预期结果校验正确(ExpectResult)
    • 76 |
    • Fail:与预期结果校验错误(ExpectResult)
    • 77 |
    • Error:用例格式数据或输入错误
    • 78 |
    79 |
    80 | 81 |
    82 |
      83 |
    • Result Count
    • 84 |
    • Total:  0
    • 85 |
    • Status_200:  0
    • 86 |
    • Status_Other:  0
    • 87 |
    88 |
    89 |
    90 |
    91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
    IDSystemTypeApiNameMethodStatusExecutionTimeUseTime (S)
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Booking/MotoBack4Web/{ProductId}/{TempOrderId}/{PkgOrderNO}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post5002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    1PBSDynamicH5/Product/Theme/{ThemeID}post2002017-10-31 19:00:57.7292570.0177059173584
    175 |
    176 |
    177 |
    178 | 179 | -------------------------------------------------------------------------------- /PBS_Dynamic/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /PBS_Dynamic/views.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/views.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/web_api_forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .models import * 3 | from django import forms 4 | 5 | 6 | class TestCaseForm(forms.ModelForm): 7 | """ 8 | 定义主用例中的 字段规则, 9 | 默认是必填,required=False(选填) 10 | """ 11 | # Host = forms.ChoiceField(label=u'HOST环境路径') 12 | HostName = forms.CharField(label=u'Host环境名', required=False, widget=forms.TextInput( 13 | attrs={'readonly': 'true'})) 14 | Description = forms.CharField(label=u'测试用例描述', widget=forms.Textarea( 15 | attrs={'cols': '85', 'rows': '1'})) 16 | 17 | ApiName = forms.CharField(label=u'接口uri', widget=forms.Textarea( 18 | attrs={'cols': '85', 'rows': '1'})) 19 | 20 | Method = forms.ChoiceField(label=u'方法', choices=[('post', 'post'), ('get', 'get')]) 21 | 22 | SetupStep = forms.CharField(label=u'Setup步骤', required=False, widget=forms.Textarea( 23 | attrs={'cols': '85', 'rows': '1'})) 24 | 25 | UrlParameter = forms.CharField(label=u'Url参数', required=False, widget=forms.Textarea( 26 | attrs={'cols': '85', 'rows': '1'})) 27 | # Suite = forms.ChoiceField(label=u'测试套件', choices=[(i.id, i.Name) for i in TestSuite.objects.all()]) 28 | Expect = forms.CharField(label=u'预期值', widget=forms.Textarea( 29 | attrs={'cols': '85', 'rows': '1'})) 30 | APIResult = forms.CharField(label=u'API结果', required=False, widget=forms.Textarea( 31 | attrs={'readonly': 'true', 'cols': '85'})) 32 | Status = forms.CharField(label=u'状态', required=False, widget=forms.TextInput( 33 | attrs={'readonly': 'true', 'class': 'vTextField'})) 34 | UseTime = forms.CharField(label=u'接口消耗时间(s)', required=False, widget=forms.TextInput( 35 | attrs={'readonly': 'true', 'class': 'vTextField'})) 36 | ExecutionTime = forms.DateTimeField(label=u'用例执行时间', required=False, widget=forms.TextInput( 37 | attrs={'readonly': 'true', 'class': 'vTextField'})) 38 | 39 | # Suite = forms.ChoiceField(label=u'测试套件') 40 | 41 | # 动态加载下拉表单的数据 42 | def __init__(self, *args, **kwargs): 43 | super(TestCaseForm, self).__init__(*args, **kwargs) 44 | # self.fields['Suite'].choices = ((i.id, i.Name) for i in TestSuite.objects.all()) 45 | # self.fields['Host'].choices = ((host.Uri, host.Uri) for host in SystemHost.objects.all()) 46 | 47 | class Meta: 48 | forms.model = TestCase 49 | 50 | 51 | class SubTestCaseForm(forms.ModelForm): 52 | """ 53 | 定义子用例中的 字段规则, 54 | """ 55 | # Host = forms.ChoiceField(label=u'HOST环境路径', choices=[(host[1], host[1]) for host in host_list]) 56 | # Host = forms.ChoiceField(label=u'HOST环境路径') 57 | Method = forms.ChoiceField(label=u'方法', choices=[('post', 'post'), ('get', 'get'), ('put', 'put')]) 58 | DataBox = forms.CharField(label=u'数据值', widget=forms.Textarea( 59 | attrs={'cols': '72', 'rows': '1'})) 60 | APIResult = forms.CharField(label=u'API结果', required=False, widget=forms.Textarea( 61 | attrs={'readonly': 'true', 'cols': '72'})) 62 | UseTime = forms.CharField(label=u'接口消耗时间(s)', required=False, widget=forms.TextInput( 63 | attrs={'readonly': 'true', 'class': 'vTextField'})) 64 | 65 | HostName = forms.CharField(label=u'Host环境名', required=False, widget=forms.TextInput( 66 | attrs={'readonly': 'true'})) 67 | 68 | ExecutionTime = forms.DateTimeField(label=u'用例执行时间', required=False, widget=forms.TextInput( 69 | attrs={'readonly': 'true', 'class': 'vTextField'})) 70 | 71 | def __init__(self, *args, **kwargs): 72 | super(SubTestCaseForm, self).__init__(*args, **kwargs) 73 | self.fields['Host'].choices = ((host.Uri, host.Uri) for host in SystemHost.objects.all()) 74 | 75 | class Meta: 76 | forms.model = SubTestCase 77 | 78 | 79 | class TestSuiteForm(forms.ModelForm): 80 | """ 81 | 定义测试套件中 Name字段表单规则 82 | """ 83 | Name = forms.CharField(label=u'测试套件名称', validators=[validate_name], 84 | help_text=u'必须输入下划线!如 PBS_H5动态下单流程任务', 85 | widget=forms.Textarea(attrs={'cols': '85', 'rows': '1'}) 86 | ) 87 | 88 | Description = forms.CharField(label=u'主用例ID內容', validators=[validate_description], 89 | help_text=u'必須是一個 list 且內容是主用例ID 如 [12, 13]', 90 | widget=forms.Textarea(attrs={'cols': '85', 'rows': '10'}) 91 | ) 92 | # Pattern = forms.ChoiceField(label=u'模式', choices=[('0', '默认不对接'), ('1', '对接运维监控')],) 93 | ApiType = forms.ChoiceField(label=u'API类型', choices=[('REST API', 'REST API'), ('SOAP API', 'SOAP API')], 94 | help_text=u'如选REST API, 主用例ID內容 必须输入是REST API的') 95 | 96 | 97 | class SystemHostForm(forms.ModelForm): 98 | """ 99 | 环境系统表单字段规则 100 | """ 101 | Uri = forms.CharField(label=u'Host URI 地址', widget=forms.Textarea(attrs={'cols': '72'})) 102 | 103 | class Meta: 104 | forms.model = SystemHost 105 | 106 | 107 | class IgniteForm(forms.ModelForm): 108 | """ 109 | 点火中表单字段规则 110 | """ 111 | ExecutionTime = forms.DateTimeField(label=u'点火执行时间', required=False, widget=forms.TextInput( 112 | attrs={'readonly': 'true', 'class': 'vTextField'})) 113 | # Host = forms.CharField(label=u'执行状态', help_text='0:执行,1:不执行') 114 | 115 | 116 | class IgniteCommonForm(forms.ModelForm): 117 | """ 118 | 点火用例抽象基类表单字段规则 119 | """ 120 | SystemType = forms.ChoiceField(label=u'系统类别') 121 | Method = forms.ChoiceField(label=u'方法', choices=[('post', 'post'), ('get', 'get')]) 122 | Status = forms.CharField(label=u'状态', required=False, widget=forms.TextInput( 123 | attrs={'readonly': 'true', 'class': 'vTextField'})) 124 | UseTime = forms.CharField(label=u'接口消耗时间(s)', required=False, widget=forms.TextInput( 125 | attrs={'readonly': 'true', 'class': 'vTextField'})) 126 | ExecutionTime = forms.DateTimeField(label=u'执行时间', required=False, widget=forms.TextInput( 127 | attrs={'readonly': 'true', 'class': 'vTextField'})) 128 | ExecuteStatus = forms.CharField(label=u'执行状态', help_text='0:执行,1:不执行') 129 | 130 | def __init__(self, *args, **kwargs): 131 | super(IgniteCommonForm, self).__init__(*args, **kwargs) 132 | self.fields['SystemType'].choices = ((host.SystemType, host.SystemType) for host in SystemHost.objects.all()) 133 | 134 | 135 | class UpdateHostForm(forms.ModelForm): 136 | """ 137 | 更新Host表单字段规则 138 | """ 139 | Content = forms.CharField(label=u'Host配置内容', widget=forms.Textarea(attrs={'cols': '72', 'rows': '28'})) 140 | 141 | class Meta: 142 | forms.model = UpdateHost 143 | -------------------------------------------------------------------------------- /PBS_Dynamic/web_api_forms.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/web_api_forms.pyc -------------------------------------------------------------------------------- /PBS_Dynamic/web_api_paging.py: -------------------------------------------------------------------------------- 1 | # -*-coding:utf-8-*- 2 | # from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 3 | 4 | 5 | class Pagination(object): 6 | 7 | def __init__(self, total_count, current_page, page_url, per_page_item_num=15, max_page_num=12): 8 | """ 9 | :param total_count: Total data 10 | :param current_page: current page 11 | :param per_page_item_num: Number of pages per page 12 | :param max_page_num: Display the maximum number of pages 13 | """ 14 | # 数据总个数 15 | self.total_count = total_count 16 | # 当前页 17 | try: 18 | v = int(current_page) 19 | if v <= 0: 20 | v = 1 21 | self.current_page = v 22 | except Exception as e: 23 | self.current_page = 1 24 | # 每页显示的行数 25 | self.per_page_item_num = per_page_item_num 26 | # 最多显示页面 27 | self.max_page_num = max_page_num 28 | self.page_url = page_url 29 | 30 | def start(self): 31 | return (self.current_page-1) * self.per_page_item_num 32 | 33 | def end(self): 34 | return self.current_page * self.per_page_item_num 35 | 36 | @property 37 | def num_pages(self): 38 | 39 | a, b = divmod(self.total_count, self.per_page_item_num) 40 | if b == 0: 41 | return a 42 | return a+1 43 | 44 | def pager_num_range(self): 45 | 46 | if self.num_pages < self.max_page_num: 47 | return range(1, self.num_pages+1) 48 | # 总页数特别多 5 49 | part = int(self.max_page_num/2) 50 | if self.current_page <= part: 51 | return range(1, self.max_page_num+1) 52 | if (self.current_page + part) > self.num_pages: 53 | return range(self.num_pages-self.max_page_num+1, self.num_pages+1) 54 | return range(self.current_page-part, self.current_page+part+1) 55 | 56 | def page_str(self): 57 | 58 | page_list = [] 59 | 60 | first = "
  • 首页
  • " % self.page_url 61 | page_list.append(first) 62 | 63 | if self.current_page == 1: 64 | prev = "
  • 上一页
  • " 65 | else: 66 | prev = "
  • 上一页
  • " % (self.current_page-1, self.page_url) 67 | page_list.append(prev) 68 | for i in self.pager_num_range(): 69 | if i == self.current_page: 70 | temp = "
  • %s
  • " % (i, self.page_url, i) 71 | else: 72 | temp = "
  • %s
  • " % (i, self.page_url, i) 73 | page_list.append(temp) 74 | 75 | if self.current_page == self.num_pages: 76 | nex = "
  • 下一页
  • " 77 | else: 78 | nex = "
  • 下一页
  • " % (self.current_page + 1, self.page_url) 79 | page_list.append(nex) 80 | 81 | last = "
  • 尾页
  • " % (self.num_pages, self.page_url) 82 | page_list.append(last) 83 | page_msg = '第%s页/共%s页,合计%s条数据' % (self.current_page, self.num_pages, self.total_count) 84 | page_list.append(page_msg) 85 | return ''.join(page_list) 86 | -------------------------------------------------------------------------------- /PBS_Dynamic/web_api_paging.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/PBS_Dynamic/web_api_paging.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django admin WAPI 2 | The WAPI is an automation interface test platform 3 | developed based on the [Django admin](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/) framework. 4 | Mainly composed of 7 modules: 5 | 6 | - API use case management system (add/delete/view/search use cases) 7 | - API suite management system (in a single system or in a single version for a set of packages) 8 | - API Task management system (asynchronous Task) 9 | - Environment system configuration (environment domain name Host or system domain name Host) 10 | - Log system (query record API execution results) 11 | - Feedback system (after troubleshoot the wrong reasons) 12 | - Statistical system (statistical API/system robustness, etc.) 13 | 14 | At the moment, Is a ` Django admin ` as the main framework implementations, 15 | Later will use ` Django + the Bootstrap + JS + RESTful ` technology to realize the comprehensive transformation, 16 | Now we has achieved five big modules, then we will further develop. 17 | 18 | # Features 19 | * Supports HTTP, HTTPS and SOAP protocol interfaces. 20 | * Support request parameterization and data transfer of associated interfaces. 21 | * Support ignition test, smoke, business process test, single interface test and generate test report. 22 | * Support sending mail and support sending WeChat push messages. 23 | * Support queue service to perform Task tasks. 24 | * Support for configuring multiple environments host (DEV \TEST\PROD environment), etc. 25 | * Support logging query 26 | 27 | # Dependencies 28 | Use Python 2.7 and 29 | Dependent libraries in [requirements.txt](https://github.com/wangxinglong007/WAPI/blob/master/requirements.txt) 30 | * Django==1.11 31 | * django-celery==3.2.1 32 | * django-kombu==0.9.4 33 | * mysqlclient==1.3.12 34 | * requests==2.18.4 35 | * redis==2.10.5 36 | * bs4==0.0.1 37 | * lxml==3.8.0 38 | * kombu==3.0.37 39 | * pyOpenSSL==17.0.0 40 | * pyv8==1.0 41 | * BeautifulSoup==3.2.1 42 | * beautifulsoup4==4.5.3 43 | * celery==3.1.25 44 | 45 | 46 | # Install and Configuration 47 | * Run pip install -r requirements.txt 48 | * And configuration [settings.py](https://github.com/wangxinglong007/WAPI/blob/master/ApiCaseSystem/settings.py) 49 | 50 | 51 | Windows installation `mysqlclient` can have a lot of problems, and you need 52 | install some application (For example) 53 | 54 | * [mysqlclient](https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient) 55 | * [Microsoft Visual C++ Compiler for Python 2.7](https://www.microsoft.com/en-us/download/details.aspx?id=44266) 56 | * [mysql-connector-c-6.0.2-winx64.msi](https://dev.mysql.com/downloads/connector/c/6.0.html) 57 | 58 | # Database 59 | * Create a database. 60 | 61 | CREATE DATABASE `wapi_db` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ 62 | 63 | * Import tables. Download this [test_django.sql](https://github.com/wangxinglong007/WAPI/blob/master/test_django.sql) file and import form you databases. 64 | 65 | * If there are some files in the migrations folder. First, you just need **`__init__.py`** and delete other files. 66 | Next Create file in **migrations** such: 67 | 68 | 1. python manage.py makemigrations 69 | 70 | 2. python manage.py migrate --fake 71 | (--fake this parameter is very important.) 72 | 73 | # Running 74 | You can deploy on [Apache](https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/modwsgi/) or run in you PC. 75 | For example in my PC: 76 | 77 | python manage.py runserver 78 | And if you need tasks function, must be running [celery](http://docs.celeryproject.org/en/3.1/django/index.html). 79 | 80 | python manage.py celery worker -l info 81 | python manage.py celery beat 82 | 83 | # Problems with deployment 84 | There may be problems with execute `python manage.py makemigrations`. 85 | 1. The mysql version does not support this. such as: 86 | 87 | ```django.db.utils.OperationalError: (2019, "Can't initialize character set utf8m64 (path: /usr/local/mysql/share/mysql/charsets/)")``` 88 | 89 | Solution: 90 | 91 | **a.** Upgrade mysql to 5.5+ 92 | 93 | **b.** Set DataBase Character set: **utf8mb4 -- UTF-8 Unicode** and Set collation **utf8mb4_unicode_ci** 94 | ```mysql 95 | CREATE DATABASE `wapi_db` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ 96 | ``` 97 | 98 | 2. `djcelery.app.DjceleryConf ImportError: No module named DjceleryConf` 99 | 100 | Solution: Modify the code in `Python27\Lib\site-packages\djcelery\app.py` 101 | ```python 102 | # -*- coding: utf-8 -*- 103 | from __future__ import absolute_import, unicode_literals 104 | 105 | from celery import current_app 106 | from django.apps import AppConfig 107 | 108 | #: The Django-Celery app instance. 109 | app = current_app._get_current_object() 110 | 111 | class DjceleryConf(AppConfig): 112 | name = 'djcelery' 113 | verbose_name = u'Task' 114 | ``` 115 | 116 | 3. `(1146, "Table 'django_apisys.PBS_Dynamic_testcase' doesn't exist")` Because, the mysql table name is case-insensitive in Windows and case sensitive in Linux. 117 | 118 | Solution: There are two ways to solve the problem. 119 | 120 | **a.** Add **db_table** an attribute to `model.py`. For example: 121 | ```python 122 | class TestCase(APITestCaseComment): 123 | ..... 124 | User = models.CharField('user', max_length=32, null=True, blank=True) 125 | ..... 126 | 127 | class Meta: 128 | ...... 129 | db_table = 'PBS_Dynamic_testcase' 130 | ``` 131 | 132 | **b.** Change the table name pbs_dynamic_testcase to PBS_Dynamic_testcase. 133 | 134 | # Plan 135 | * Use the [Django REST Framework](http://www.django-rest-framework.org/) 136 | * Add performance test functionality [locust](https://docs.locust.io/en/latest/) 137 | * Add statistical function (API, subsystem success rate, failure rate, etc.) [highcharts](https://www.hcharts.cn/demo/highcharts) 138 | * Use the [django-bootstrap](https://github.com/zostera/django-bootstrap4) refactoring page 139 | * Feedback system And automatically bring bug 140 | 141 | # Show 142 | ![WAPI](https://github.com/wangxinglong007/WAPI/blob/master/PBS_Dynamic/media/introduce_img/wapi.gif) 143 | ![Log](https://github.com/wangxinglong007/WAPI/blob/master/PBS_Dynamic/media/introduce_img/log.gif) 144 | -------------------------------------------------------------------------------- /SOAP_API/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'SOAP_API.apps.SoapApiConfig' 2 | -------------------------------------------------------------------------------- /SOAP_API/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/__init__.pyc -------------------------------------------------------------------------------- /SOAP_API/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib import admin 5 | 6 | from .soap_api_forms import * 7 | import threading 8 | import datetime 9 | import re 10 | 11 | from WingOn import Main 12 | from PBS_Dynamic.DataCenter import * 13 | from WingOn.generateReport.HtmlReport import report 14 | 15 | 16 | def thread_func(some_result_list, common_data): 17 | """ 18 | 多线程执行用例 19 | :param some_result_list: 根据用例id或者套件id查询出的用例列表 20 | :param common_data: 实例数据 21 | :return: 如果是套件的则返回 使用时间列表 22 | """ 23 | suite_name = common_data.suite_name 24 | threads = [] 25 | use_time_list = [] 26 | 27 | for some_result in some_result_list: 28 | thd = threading.Thread(target=Main.run_main, args=(some_result, common_data)) 29 | threads.append(thd) 30 | 31 | if suite_name: 32 | for ths in threads: 33 | begin_time = datetime.datetime.now() 34 | ths.start() 35 | ths.join() 36 | end_time = datetime.datetime.now() 37 | use_time = str(end_time - begin_time) 38 | use_time_list.append(use_time) 39 | 40 | return use_time_list 41 | else: 42 | for ths in threads: 43 | ths.start() 44 | ths.join() 45 | 46 | 47 | class SOAPTestCasesAdmin(admin.ModelAdmin): 48 | 49 | fields = ['Host', 'HostName', 'Description', 'SetupStep', 'Method', 'Headers', 50 | 'BodyValues', 'Expect', 'APIResult', 'Status', 'ExecutionTime', 'UseTime', 'User', 51 | 'Editor'] # 字段排序 52 | list_display = ('Description', 'HostName', 'id', 'setup_step', 'Method', 'status', 53 | 'ExecutionTime', ) 54 | raw_id_fields = ("Host",) 55 | search_fields = ('id', 'Description') 56 | 57 | methods = 'test_case' 58 | suite_name = '' 59 | suite_system = '' 60 | case_id_list = [] 61 | email_list = [] 62 | pattern_list = [] 63 | 64 | list_per_page = 50 65 | form = SOAPTestCasesForm 66 | 67 | def save_model(self, request, obj, form, change): 68 | obj.Editor = str(request.user) 69 | obj.save() 70 | 71 | def run_test_case(self, request, queryset): 72 | soap_data_center = SoapDataCenter() 73 | soap_data_center.environment = 'Test' 74 | common_run_case(request, soap_data_center) 75 | 76 | run_test_case.short_description = '执行Test 的 主测试用例' 77 | 78 | def run_uat_case(self, request, queryset): 79 | soap_data_center = SoapDataCenter() 80 | soap_data_center.environment = 'Uat' 81 | common_run_case(request, soap_data_center) 82 | 83 | run_uat_case.short_description = '执行Uat 的 主测试用例' 84 | 85 | def run_prod_case(self, request, queryset): 86 | soap_data_center = SoapDataCenter() 87 | soap_data_center.environment = 'Prod' 88 | common_run_case(request, soap_data_center) 89 | 90 | run_prod_case.short_description = '执行Prod 的 主测试用例' 91 | 92 | actions = [run_test_case, run_uat_case, run_prod_case] 93 | 94 | 95 | class SOAPSubTestCaseAdmin(admin.ModelAdmin): 96 | """ 97 | 子用例表展示等 98 | copy_func 复制功能 99 | """ 100 | fields = ['Host', 'HostName', 'SetupType', 'Description', 'Method', 'Headers', 101 | 'BodyValues', 'DataBox', 'APIResult', 'ExecutionTime', 'UseTime'] 102 | 103 | list_display = ('Description', 'HostName', 'id', 'SetupType', 'Method', 'UseTime', 104 | 'ExecutionTime') 105 | search_fields = ('Description', 'id',) 106 | raw_id_fields = ("Host",) 107 | 108 | list_per_page = 50 109 | # list_filter = (HostListFilter,) 110 | form = SOAPSubTestCaseForm 111 | 112 | 113 | def common_run_case(request, soap_data_center): 114 | soap_data_center.methods = 'test_case' 115 | soap_data_center.user = str(request.user) 116 | 117 | soap_data_center.list_id = [i.replace('_selected_action=', '') for i in 118 | re.compile(r"(_[a-zA-Z]+_[a-zA-Z]+=\d+)").findall(request.body)] 119 | soap_data_center.start_time = datetime.datetime.now() 120 | some_result_list = [] 121 | for i in soap_data_center.list_id: 122 | some_results = SOAPTestCases.objects.filter(id=i).values() 123 | some_result_list.append(some_results) 124 | 125 | thread_func(some_result_list, soap_data_center) 126 | 127 | end_time = datetime.datetime.now() 128 | soap_data_center.use_time = str(end_time - soap_data_center.start_time) 129 | 130 | report(soap_data_center) 131 | 132 | admin.site.register(SOAPTestCases, SOAPTestCasesAdmin) 133 | admin.site.register(SOAPSubTestCases, SOAPSubTestCaseAdmin) 134 | 135 | -------------------------------------------------------------------------------- /SOAP_API/admin.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/admin.pyc -------------------------------------------------------------------------------- /SOAP_API/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class SoapApiConfig(AppConfig): 8 | name = 'SOAP_API' 9 | verbose_name = 'SOAP接口测试用例管理系统' -------------------------------------------------------------------------------- /SOAP_API/apps.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/apps.pyc -------------------------------------------------------------------------------- /SOAP_API/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/migrations/__init__.py -------------------------------------------------------------------------------- /SOAP_API/migrations/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/migrations/__init__.pyc -------------------------------------------------------------------------------- /SOAP_API/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models 5 | 6 | import sys 7 | from django import forms 8 | from django.utils.html import format_html 9 | 10 | sys.path.append("..") 11 | 12 | from PBS_Dynamic.models import SystemHost, ReportCommon 13 | 14 | 15 | # Create your models here. 16 | 17 | 18 | class SOAPTestCaseComment(models.Model): 19 | """ 20 | 公共基类模型 21 | 主用例 和 子用例继承 22 | """ 23 | Host = models.ForeignKey(SystemHost, verbose_name='HOST环境路径', max_length=256) 24 | HostName = models.CharField('系统', max_length=256, blank=True) 25 | Description = models.CharField('测试用例描述', max_length=256) 26 | Method = models.CharField('方法', max_length=10) 27 | Headers = models.TextField('信息头') 28 | BodyValues = models.TextField('Body值', null=True, blank=True) 29 | APIResult = models.TextField('API结果', null=True, blank=True) 30 | ExecutionTime = models.DateTimeField('用例执行时间', null=True, blank=True) 31 | CreateTime = models.DateTimeField('用例创建时间', auto_now_add=True, null=True) 32 | UseTime = models.CharField('接口消耗时间(s)', max_length=32, null=True, blank=True) 33 | 34 | class Meta: 35 | abstract = True 36 | 37 | 38 | class SOAPTestCases(SOAPTestCaseComment): 39 | objects = None 40 | SetupStep = models.CharField('Setup步骤', max_length=256, blank=True) 41 | Expect = models.CharField('预期值', max_length=2048) 42 | Status = models.CharField('状态', max_length=10, null=True, blank=True) 43 | User = models.CharField('执行者', max_length=32, null=True, blank=True) 44 | Editor = models.CharField('创建/编辑者', max_length=32, null=True, blank=True) 45 | 46 | def __str__(self): 47 | return self.HostName 48 | 49 | def save(self, *args, **kwargs): 50 | get_host = SystemHost.objects.filter(id=self.Host_id).values_list('id', 'HostName')[0] 51 | if not self.HostName: 52 | self.HostName = get_host[1] 53 | else: 54 | new_get_host = SystemHost.objects.filter(id=self.Host_id).values_list('id', 'HostName')[0] 55 | if self.HostName != new_get_host[1]: 56 | self.HostName = new_get_host[1] 57 | else: 58 | self.HostName = get_host[1] 59 | super(SOAPTestCases, self).save(*args, **kwargs) 60 | 61 | def setup_step(self): 62 | return format_html( 63 | '
    {1}
    ', 64 | self.SetupStep, 65 | self.SetupStep, 66 | ) 67 | 68 | def status(self): 69 | color = '' 70 | if self.Status == 'Success': 71 | color = '#6c6' 72 | elif self.Status == 'Fail': 73 | color = '#c60' 74 | elif self.Status == 'Error': 75 | color = '#c00' 76 | 77 | return format_html( 78 | '{1}', 79 | color, 80 | self.Status, 81 | ) 82 | 83 | setup_step.short_description = u'Setup步骤' 84 | status.short_description = u'状态' 85 | 86 | class Meta: 87 | verbose_name = 'SOAPTestCase' 88 | verbose_name_plural = '主测试用例' 89 | app_label = 'SOAP_API' 90 | 91 | 92 | class SOAPSubTestCases(SOAPTestCaseComment): 93 | objects = None 94 | SetupType = models.CharField('Setup类型', max_length=10) 95 | SetupIndex = models.CharField('关联主用例Setup步骤', max_length=32, blank=True) 96 | CaseID = models.CharField('关联主用例ID', max_length=32, blank=True) 97 | DataBox = models.CharField('数据值', max_length=1024, null=True, blank=True) 98 | 99 | def __str__(self): 100 | return self.HostName 101 | 102 | def save(self, *args, **kwargs): 103 | get_host = SystemHost.objects.filter(Uri=self.Host).values_list('HostName')[0] 104 | 105 | if not self.HostName: 106 | self.HostName = get_host[0] 107 | super(SOAPSubTestCases, self).save(*args, **kwargs) 108 | else: 109 | 110 | self.HostName = get_host[0] 111 | super(SOAPSubTestCases, self).save(*args, **kwargs) 112 | 113 | class Meta: 114 | verbose_name = 'SubTestCase' 115 | verbose_name_plural = u'子测试用例' 116 | 117 | 118 | class SoapReport(ReportCommon): 119 | """ 120 | 继承ReportCommon 主用例报告模型 121 | """ 122 | soapTestCase = models.ForeignKey(SOAPTestCases) 123 | Status = models.CharField('状态', max_length=10, null=True, blank=True) 124 | 125 | def __str__(self): 126 | return self.soapTestCase 127 | 128 | 129 | class SoapSubReport(ReportCommon): 130 | """ 131 | 继承ReportCommon 主用例报告模型 132 | """ 133 | soapSubCase = models.ForeignKey(SOAPSubTestCases) 134 | 135 | def __str__(self): 136 | return self.soapSubCase 137 | -------------------------------------------------------------------------------- /SOAP_API/models.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/models.pyc -------------------------------------------------------------------------------- /SOAP_API/soap_api_forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .models import * 3 | from django import forms 4 | 5 | 6 | class SOAPTestCasesForm(forms.ModelForm): 7 | """ 8 | 定义主用例中的 字段规则, 9 | 默认是必填,required=False(选填) 10 | """ 11 | # Host = forms.ChoiceField(label=u'HOST环境路径') 12 | HostName = forms.CharField(label=u'Host环境名', required=False, widget=forms.TextInput( 13 | attrs={'readonly': 'true'})) 14 | Description = forms.CharField(label=u'测试用例描述', widget=forms.Textarea( 15 | attrs={'cols': '85', 'rows': '1'})) 16 | 17 | Method = forms.ChoiceField(label=u'方法', choices=[('post', 'post'), ('get', 'get')]) 18 | 19 | SetupStep = forms.CharField(label=u'Setup步骤', required=False, widget=forms.Textarea( 20 | attrs={'cols': '85', 'rows': '1'})) 21 | 22 | Expect = forms.CharField(label=u'预期值', widget=forms.Textarea( 23 | attrs={'cols': '85', 'rows': '8'})) 24 | APIResult = forms.CharField(label=u'API结果', required=False, widget=forms.Textarea( 25 | attrs={'readonly': 'true', 'cols': '85'})) 26 | Status = forms.CharField(label=u'状态', required=False, widget=forms.TextInput( 27 | attrs={'readonly': 'true', 'class': 'vTextField'})) 28 | UseTime = forms.CharField(label=u'接口消耗时间(s)', required=False, widget=forms.TextInput( 29 | attrs={'readonly': 'true', 'class': 'vTextField'})) 30 | ExecutionTime = forms.DateTimeField(label=u'用例执行时间', required=False, widget=forms.TextInput( 31 | attrs={'readonly': 'true', 'class': 'vTextField'})) 32 | 33 | class Meta: 34 | forms.model = SOAPTestCases 35 | 36 | 37 | class SOAPSubTestCaseForm(forms.ModelForm): 38 | """ 39 | 定义子用例中的 字段规则, 40 | """ 41 | Method = forms.ChoiceField(label=u'方法', choices=[('post', 'post'), ('get', 'get'), ('put', 'put')]) 42 | DataBox = forms.CharField(label=u'数据值', widget=forms.Textarea( 43 | attrs={'cols': '85', 'rows': '8'})) 44 | APIResult = forms.CharField(label=u'API结果', required=False, widget=forms.Textarea( 45 | attrs={'readonly': 'true', 'cols': '85'})) 46 | UseTime = forms.CharField(label=u'接口消耗时间(s)', required=False, widget=forms.TextInput( 47 | attrs={'readonly': 'true', 'class': 'vTextField'})) 48 | 49 | HostName = forms.CharField(label=u'Host环境名', required=False, widget=forms.TextInput( 50 | attrs={'readonly': 'true'})) 51 | 52 | ExecutionTime = forms.DateTimeField(label=u'用例执行时间', required=False, widget=forms.TextInput( 53 | attrs={'readonly': 'true', 'class': 'vTextField'})) 54 | 55 | def __init__(self, *args, **kwargs): 56 | super(SOAPSubTestCaseForm, self).__init__(*args, **kwargs) 57 | self.fields['Host'].choices = ((host.Uri, host.Uri) for host in SystemHost.objects.all()) 58 | 59 | class Meta: 60 | forms.model = SOAPSubTestCases -------------------------------------------------------------------------------- /SOAP_API/soap_api_forms.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/SOAP_API/soap_api_forms.pyc -------------------------------------------------------------------------------- /SOAP_API/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /SOAP_API/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.shortcuts import render 5 | 6 | # Create your views here. 7 | -------------------------------------------------------------------------------- /WingOn/.idea/WingOn.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /WingOn/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /WingOn/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /WingOn/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WingOn/FightDataAndloadCase/ProcessData.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/FightDataAndloadCase/ProcessData.pyc -------------------------------------------------------------------------------- /WingOn/FightDataAndloadCase/StructureData.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # coding:utf-8 3 | 4 | 5 | class StructureData: 6 | """ 7 | 主用例结构体 8 | """ 9 | def __init__(self): 10 | self.case_id = 0 11 | self.api_name = '' 12 | self.case_desc = '' 13 | self.set_up = '' 14 | self.url_parameter = '' 15 | self.method = '' 16 | self.headers = '' 17 | self.body_value = '' 18 | self.expect = '' 19 | self.api_result = '' 20 | self.status = [] 21 | self.use_time = '' 22 | self.host = '' 23 | self.suite = '' 24 | self.execution_time = '' 25 | self.update_time = '' 26 | self.host_name = '' 27 | 28 | 29 | class SetUpStructureData: 30 | """ 31 | 子用例结构体 32 | """ 33 | def __init__(self): 34 | self.setup_index = '' 35 | self.case_id = '' 36 | self.api_name = '' 37 | self.description = '' 38 | self.url_parameter = '' 39 | self.method = '' 40 | self.headers = '' 41 | self.body_values = '' 42 | self.data_box = '' 43 | self.api_result = '' 44 | self.status = '' 45 | self.execution_time = '' 46 | self.use_time = '' 47 | self.id = '' 48 | self.host = '' 49 | self.host_name = '' 50 | self.set_up_type = '' 51 | self.expect = '' 52 | 53 | 54 | class SoapStructureData: 55 | """ 56 | SOAP 主用例结构体 57 | """ 58 | def __init__(self): 59 | self.case_id = 0 60 | self.api_name = '' 61 | self.case_desc = '' 62 | self.set_up = '' 63 | self.url_parameter = '' 64 | self.method = '' 65 | self.headers = '' 66 | self.body_value = '' 67 | self.expect = '' 68 | self.api_result = '' 69 | self.status = [] 70 | self.use_time = '' 71 | self.host = '' 72 | self.suite = '' 73 | self.execution_time = '' 74 | self.update_time = '' 75 | self.host_name = '' 76 | 77 | 78 | class SoapSetUpStructureData: 79 | """ 80 | 子用例结构体 81 | """ 82 | def __init__(self): 83 | self.setup_index = '' 84 | self.case_id = '' 85 | self.description = '' 86 | self.method = '' 87 | self.headers = '' 88 | self.body_values = '' 89 | self.data_box = '' 90 | self.api_result = '' 91 | self.status = '' 92 | self.execution_time = '' 93 | self.use_time = '' 94 | self.id = '' 95 | self.host = '' 96 | self.host_name = '' 97 | self.set_up_type = '' 98 | self.expect = '' 99 | -------------------------------------------------------------------------------- /WingOn/FightDataAndloadCase/StructureData.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/FightDataAndloadCase/StructureData.pyc -------------------------------------------------------------------------------- /WingOn/FightDataAndloadCase/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/FightDataAndloadCase/__init__.py -------------------------------------------------------------------------------- /WingOn/FightDataAndloadCase/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/FightDataAndloadCase/__init__.pyc -------------------------------------------------------------------------------- /WingOn/Main.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # coding:utf-8 3 | 4 | import sys 5 | 6 | from FightDataAndloadCase.ProcessData import ProcessData 7 | from WingOn.generateReport.HtmlReport import report, ignite_reports 8 | 9 | reload(sys) 10 | sys.setdefaultencoding('utf-8') 11 | 12 | 13 | def run_main(some_result, common_data): 14 | """ 15 | :param some_result: 执行时勾选的数据 16 | :param common_data: 实例 17 | types: 类型 0 为 rest_api 1 为 soap_api 18 | :return: 19 | """ 20 | 21 | # trans = ProcessData() 22 | if common_data.api_type == 0: 23 | ProcessData.process(some_result, common_data) 24 | elif common_data.api_type == 1: 25 | ProcessData.soap_process(some_result, common_data) 26 | 27 | # report(common_data) 28 | 29 | -------------------------------------------------------------------------------- /WingOn/Main.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/Main.pyc -------------------------------------------------------------------------------- /WingOn/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/__init__.py -------------------------------------------------------------------------------- /WingOn/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/__init__.pyc -------------------------------------------------------------------------------- /WingOn/generateReport/HtmlReport.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/generateReport/HtmlReport.pyc -------------------------------------------------------------------------------- /WingOn/generateReport/IgniteTemplateHtml.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/python 2 | # coding=utf-8 3 | 4 | 5 | class IgniteTemplateHtml: 6 | 7 | def __init__(self): 8 | pass 9 | 10 | @staticmethod 11 | def get_report_html(): 12 | report_html = """ 13 | 14 | 15 | 点火结果报告 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 41 | 42 | 43 | 44 | 45 | 64 | 65 | 66 |
    67 |
    68 |
    69 |
      70 |
    • API Automation Description
    • 71 |
    • User: {{ user }}
    • 72 |
    • StartTime: {{ start_time }}
    • 73 |
    • UseTime: {{ use_time }}
    • 74 |
    • Success: 与预期结果校验正确(ExpectResult)
    • 75 |
    • Fail: 与预期结果校验错误(ExpectResult)
    • 76 |
    • Error: 用例格式数据或输入错误
    • 77 |
    78 |
    79 | 80 |
    81 |
      82 |
    • Result Count
    • 83 |
    • Total: {{ counts.0 }}
    • 84 |
    • Status_200: {{ counts.1 }}
    • 85 |
    • Status_Other: {{ counts.2 }}
    • 86 |
    87 |
    88 |
    89 |
    90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | {% for result in result_list %} 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | {% endfor %} 111 | 112 |
    IDSystemTypeApiNameMethodStatusExecutionTimeUseTime (S)
    {{ result.0 }}{{ result.1 }}{{ result.2 }}{{ result.3 }}{{ result.4 }}{{ result.5 }}{{ result.6 }}
    113 |
    114 |
    115 |
    116 | 117 | """ 118 | return report_html 119 | -------------------------------------------------------------------------------- /WingOn/generateReport/IgniteTemplateHtml.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/generateReport/IgniteTemplateHtml.pyc -------------------------------------------------------------------------------- /WingOn/generateReport/TemplateHtml.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/generateReport/TemplateHtml.pyc -------------------------------------------------------------------------------- /WingOn/generateReport/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/generateReport/__init__.py -------------------------------------------------------------------------------- /WingOn/generateReport/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/generateReport/__init__.pyc -------------------------------------------------------------------------------- /WingOn/generateReport/clickA.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by xinglongwang on 2017/3/22. 3 | */ 4 | 5 | 6 | 7 | function display(d) 8 | { 9 | 10 | var ui = document.getElementById(d); 11 | if(ui.style.display=="block"){ 12 | ui.style.display="none"; 13 | } 14 | else{ 15 | ui.style.display="block"; 16 | } 17 | 18 | } 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /WingOn/methods/HttpEntity.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # coding:utf-8 3 | 4 | import json 5 | import requests 6 | import urllib 7 | import urllib2 8 | import ssl 9 | import time 10 | 11 | from PBS_Dynamic.DataCenter import * 12 | 13 | # 忽略https认证 14 | context = ssl._create_unverified_context() 15 | # requests.packages.urllib3.disable_warnings() 16 | ssl._create_default_https_context = ssl._create_unverified_context 17 | 18 | 19 | class HttpEntity: 20 | 21 | def __init__(self, host): 22 | self.host = host 23 | 24 | def post(self, api_name, headers, body, host_name, environment): 25 | """ 26 | 构造post请求体 27 | :param host_name: host地址 28 | :param api_name: uri 如 /Search/FareRemarks 29 | :param headers: 请求的信息头 30 | :param body: 请求的body 31 | :return: 返回请求的结果 32 | """ 33 | 34 | if 'https://' in api_name: 35 | url = api_name 36 | else: 37 | url = self.host + api_name 38 | 39 | data = json.dumps(body) 40 | # 进行旅客填写信息页面时,pbs系统会调用checkchange,api需要等待15s才返回结果 41 | if (host_name == 'PackageFHAPIDynamic' or host_name == 'PBSH5StaticL') and \ 42 | '/Booking/SaveInfomation4FH' in api_name: 43 | if environment == 'Test': 44 | result = requests.post(url, data=data, headers=headers, verify=False) 45 | else: 46 | result = requests.post(url, data=data, headers=headers) 47 | time.sleep(30) 48 | if int(json.loads(result.text)['data']['NoResultYet4Resouce']) != 0: 49 | if environment == 'Test': 50 | result = requests.post(url, data=data, headers=headers, verify=False) 51 | else: 52 | result = requests.post(url, data=data, headers=headers) 53 | 54 | else: 55 | if environment == 'Test': 56 | result = requests.post(url, data=data, headers=headers, verify=False) 57 | else: 58 | result = requests.post(url, data=data, headers=headers) 59 | return result.text 60 | 61 | def urllib_post(self, api_name, headers, body): 62 | """ 63 | 构造post请求体 (支付时 vco登录时用) 64 | :param api_name: uri 如 /Search/FareRemarks 65 | :param headers: 请求的信息头 66 | :param body: 请求的body 67 | :return: 返回请求的结果 68 | """ 69 | if 'https://' in api_name: 70 | url = api_name 71 | else: 72 | url = self.host + api_name 73 | 74 | body_value = urllib.urlencode(body) 75 | request = urllib2.Request(url, body_value, headers) 76 | 77 | response = urllib2.urlopen(request) 78 | result = response.read() 79 | 80 | return result 81 | 82 | def get(self, api_name, value, environment): 83 | """ 84 | 构造get 有参数的请求体 85 | :param api_name: uri 如 /Search/FareRemarks 86 | :param value: uri 后的参数 如 {"$top":1} 87 | :return: 返回请求的结果 88 | """ 89 | 90 | url = self.host + api_name 91 | data = urllib.urlencode(value) 92 | last_url = url + '?' + data 93 | # last_url = http://xxx/xx/xxx/xx/Zones?$top=1 94 | request = urllib2.Request(last_url) 95 | # response = urllib2.urlopen(request) 96 | if environment == 'Test': 97 | response = urllib2.urlopen(request, context=context) 98 | else: 99 | response = urllib2.urlopen(request) 100 | result = response.read() 101 | return result 102 | 103 | def get_no_param(self, api_name, environment): 104 | """ 105 | 构造get 无参数的请求体 106 | :param api_name: uri 如 /Search/FareRemarks 107 | :param environment: 环境 test https认证需要忽略 108 | :return: 返回请求的结果 109 | """ 110 | url = self.host + api_name 111 | request = urllib2.Request(url) 112 | # response = urllib2.urlopen(request) 113 | if environment == 'Test': 114 | response = urllib2.urlopen(request, context=context) 115 | else: 116 | response = urllib2.urlopen(request) 117 | result = response.read() 118 | return result 119 | 120 | def put(self, api_name, headers, body, environment): 121 | """ 122 | 构造put 请求体 123 | :param api_name: 接口uri 124 | :param headers: 信息头 125 | :param body: 请求内容 126 | :return: 返回的结果 127 | """ 128 | if 'https://' in api_name: 129 | url = api_name 130 | else: 131 | url = self.host + api_name 132 | 133 | data = json.dumps(body) 134 | if environment == 'Test': 135 | result = requests.put(url, data=data, headers=headers, verify=False) 136 | else: 137 | result = requests.put(url, data=data, headers=headers) 138 | 139 | return result.text 140 | 141 | @staticmethod 142 | def soap_post(host, body, headers, environment): 143 | """ 144 | 构造soap_post 请求体 145 | :param host: 146 | :param body: 147 | :param headers: 148 | :param environment: 149 | :return: 150 | """ 151 | if environment == 'Test': 152 | 153 | result = requests.post(host, body, headers=headers, verify=False, stream=False) 154 | else: 155 | result = requests.post(host, body, headers=headers, stream=False) 156 | 157 | return result.content 158 | 159 | 160 | class IgniteHttpEntity(object): 161 | """ 162 | 构造点火系统的请求 163 | requests (post、get、delete、put、options) 164 | urllib (urllib_methods) 165 | """ 166 | def __init__(self): 167 | pass 168 | 169 | @staticmethod 170 | def post(host_url): 171 | result = requests.post(host_url, verify=False) 172 | 173 | return result.status_code 174 | 175 | @staticmethod 176 | def get(host_url): 177 | result = requests.get(host_url, verify=False) 178 | 179 | return result.status_code 180 | 181 | @staticmethod 182 | def delete(host_url): 183 | result = requests.delete(host_url, verify=False) 184 | return result.status_code 185 | 186 | @staticmethod 187 | def put(host_url): 188 | result = requests.delete(host_url, verify=False) 189 | return result.status_code 190 | 191 | @staticmethod 192 | def options(host_url): 193 | result = requests.options(host_url, verify=False) 194 | return result.status_code 195 | 196 | @staticmethod 197 | def urllib_methods(host_url): 198 | request = urllib2.Request(host_url) 199 | response = urllib2.urlopen(request, context=context) 200 | return response.getcode() 201 | -------------------------------------------------------------------------------- /WingOn/methods/HttpEntity.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/methods/HttpEntity.pyc -------------------------------------------------------------------------------- /WingOn/methods/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/methods/__init__.py -------------------------------------------------------------------------------- /WingOn/methods/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/methods/__init__.pyc -------------------------------------------------------------------------------- /WingOn/reports/click.js: -------------------------------------------------------------------------------- 1 | function display(d) { 2 | var ui = document.getElementById(d); 3 | if(ui.style.display=="block"){ 4 | ui.style.display="none"; 5 | } 6 | else{ 7 | ui.style.display="block"; 8 | } 9 | } 10 | window.alert = alert; 11 | function alert(data) { 12 | var pup = document.createElement("div"), 13 | section = document.createElement("section") 14 | error_message = document.createElement("p"), 15 | btn = document.createElement("div"), 16 | error_title = document.createElement("div"), 17 | textNode = document.createTextNode(data ? data : ""), 18 | error_title_measage = document.createTextNode(""); 19 | btnText = document.createTextNode("Close"); 20 | // 控制样式 21 | css(pup, { 22 | "position" : "absolute", 23 | "left" : "20%", 24 | "right" : "20%", 25 | "top" : "10%", 26 | "bottom" : "30%", 27 | "margin" : "50px", 28 | "background-color" : "#FFFCEC", 29 | "text-align" : "left", 30 | //"width" : "auto", 31 | "overflow-x" : "auto", 32 | "overflow-y" : "auto" 33 | }); 34 | css(error_message, { 35 | "font-size" : "15px", 36 | }) 37 | css(btn, { 38 | "background" : "#999999", 39 | "text-align" : "right", 40 | "color" : "white", 41 | }) 42 | // 内部结构套入 43 | btn.appendChild(btnText); 44 | pup.appendChild(btn); 45 | 46 | error_title.appendChild(error_title_measage); 47 | pup.appendChild(error_title); 48 | 49 | error_message.appendChild(textNode); 50 | 51 | pup.appendChild(section); 52 | section.appendChild(error_message); 53 | 54 | 55 | // 整体显示到页面内 56 | document.getElementsByTagName("body")[0].appendChild(pup); 57 | // 点击关闭按钮 58 | btn.onclick = function() { 59 | pup.parentNode.removeChild(pup); 60 | } 61 | } 62 | function css(targetObj, cssObj) { 63 | var str = targetObj.getAttribute("style") ? targetObj.getAttribute("style") : ""; 64 | for(var i in cssObj) { 65 | str += i + ":" + cssObj[i] + ";"; 66 | } 67 | targetObj.style.cssText = str; 68 | } 69 | //alert(ui.innerHTML); 70 | 71 | function display(d) { 72 | var ui = document.getElementById(d); 73 | alert(ui.innerHTML); 74 | //如果以弹框的形式,那这个就不显示 75 | /*if (ui.style.display == "block") { 76 | ui.style.display = "none"; 77 | } else { 78 | ui.style.display = "block"; 79 | }*/ 80 | } 81 | -------------------------------------------------------------------------------- /WingOn/requestBody/Check.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # coding:utf-8 3 | 4 | import sys 5 | import re 6 | import json 7 | import random 8 | import traceback 9 | from bs4 import BeautifulSoup 10 | 11 | 12 | reload(sys) 13 | sys.setdefaultencoding("utf-8") 14 | 15 | rule = re.compile(r"(\[.*?\])") 16 | 17 | 18 | class Check: 19 | 20 | def __init__(self, test_data): 21 | self.test_data = test_data 22 | 23 | @staticmethod 24 | def get_verify_data(routes, dicta, k): 25 | """ 26 | 子用例数据值中的路径去获取dicta 中的 数据 27 | :param routes: 从子用例数据值中切出来的路径如head_errcode 28 | :param dicta: 子用例返回的结果 29 | :param k: 主用例中从verify中调用 返回结果 30 | :return: 31 | """ 32 | 33 | dicta = json.loads(dicta) 34 | 35 | for route in routes: 36 | # print route 37 | # route = str(route) 38 | 39 | if '[' in route: 40 | split_list = route.split('[') 41 | if split_list[0]: 42 | 43 | get_key = split_list[0] 44 | # len_get_key = len(get_key) 45 | else: 46 | get_key = int(split_list[1].replace(']', '')) 47 | 48 | length = dicta[get_key] 49 | id_ = rule.findall(route)[0].replace('[', '').replace(']', '') 50 | 51 | # id_ = int(rule.findall(route)[0].replace('[', '').replace(']', '')) 52 | id_ = eval(json.loads(json.dumps(id_))) 53 | if not route.split('[')[0]: 54 | dicta = dicta[id_] 55 | else: 56 | dicta = dicta.get(route.split('[')[0])[id_] 57 | 58 | elif '-' in route: 59 | route = route.replace('-', '_') 60 | dicta = dicta.get(route) 61 | else: 62 | dicta = dicta.get(route) 63 | 64 | if ('have keys' or 'no keys') in k: 65 | return route 66 | else: 67 | return dicta 68 | 69 | def verify(self, result, dict_parameter): 70 | """ 71 | 在主用例的期望字段的值切割,将值写入expect_result字典中,在调用verify_函数取值,最后检验值对不对或者字段存不存在 72 | :param result: 主用例的结果 73 | :param dict_parameter: 从子用例的数据值字段获取子用例结果添加到此字典中 74 | :return: 75 | """ 76 | expect_result = {} 77 | # user = Check(self.test_data) 78 | 79 | for i in self.test_data.expect.split(','): 80 | if 'dict_parameter' in i: 81 | if str(eval(i.split(':')[0])) == str(i.split(':')[1]): 82 | self.test_data.status.append('Success') 83 | else: 84 | self.test_data.status.append('Fail') 85 | else: 86 | expect_result[tuple(i.split(':')[0].split('_'))] = i.split(':')[1] 87 | 88 | for j, k in expect_result.items(): 89 | c = Check.get_verify_data(j, result, k) 90 | if 'have keys' in k: 91 | 92 | if c in result: 93 | self.test_data.status.append('Success') 94 | else: 95 | self.test_data.status.append('Fail') 96 | elif 'no keys' in k: 97 | 98 | if c not in result: 99 | self.test_data.status.append('Success') 100 | else: 101 | self.test_data.status.append('Fail') 102 | else: 103 | 104 | if str(c) == str(k): # assert 105 | self.test_data.status.append('Success') 106 | else: 107 | self.test_data.status.append('Fail') 108 | 109 | if 'Fail' in self.test_data.status: 110 | self.test_data.status = 'Fail' 111 | else: 112 | self.test_data.status = 'Success' 113 | 114 | @staticmethod 115 | def module_message(result, filter_string): 116 | filter_node = None 117 | try: 118 | soup = BeautifulSoup(result, "html.parser", from_encoding='utf-8') 119 | filter_list = filter_string.lower().split('_') 120 | result_list = soup.find_all('s:envelope') 121 | 122 | find_result = result_list[0] 123 | 124 | for filter_node in filter_list: 125 | 126 | result = find_result.find(filter_node) 127 | 128 | result_text = result.text 129 | 130 | except Exception as e: 131 | raise Exception(traceback.format_exc() + '请查看结果 或者 查看预期值{0}是否正确\n'.format(filter_node)) 132 | return result_text 133 | 134 | def verify_soap(self, result): 135 | check_list = self.test_data.expect.split(',') 136 | for check_node in check_list: 137 | check_left = Check.module_message(result, check_node.split('=')[0]) 138 | check_right = check_node.split('=')[1].replace('$', '') 139 | 140 | if str(check_left) == str(check_right): 141 | self.test_data.status.append('Success') 142 | else: 143 | self.test_data.status.append('Fail') 144 | 145 | if 'Fail' in self.test_data.status: 146 | self.test_data.status = 'Fail' 147 | else: 148 | self.test_data.status = 'Success' 149 | 150 | 151 | def randomLength(length): 152 | """ 153 | :param length: list的值 154 | :return: 随机返回接口中list的长度 155 | """ 156 | if len(length) == 0: 157 | raise Exception('此list为空,无法取到此列表的内容') 158 | else: 159 | return random.randint(0, len(length)-1) 160 | 161 | 162 | -------------------------------------------------------------------------------- /WingOn/requestBody/Check.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/Check.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/InterfaceCase.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/InterfaceCase.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/RMQrecive.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # coding:utf-8 3 | 4 | import pika 5 | import redis 6 | from Rsa_encrypt.js import rsa_encryption_data 7 | 8 | credentials = pika.PlainCredentials('admin', 'admin') 9 | parameters = pika.ConnectionParameters('xxxx', 'port', 'xxxxTest', credentials) 10 | connection = pika.BlockingConnection(parameters) 11 | channel = connection.channel() 12 | channel.queue_declare(queue='AutoPayQueue') 13 | print '[*] Waiting for messages. To exit press CTRL+C' 14 | r = redis.Redis(host='xxx', port=port) 15 | 16 | 17 | def callback(ch, method, properties, body): 18 | 19 | list_body = eval(body).items()[0] 20 | # print list_body[0], rsa_encryption_data(list_body[1]) 21 | r.set(list_body[0], rsa_encryption_data(list_body[1]), ex=1800) 22 | # channel.basic_consume(callback, queue = 'queue.abs.booking.searchflightlist' , no_ack = True ) 23 | channel.basic_consume(callback, queue='AutoPayQueue', no_ack=True) 24 | channel.start_consuming() 25 | 26 | -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/RMQsend.py: -------------------------------------------------------------------------------- 1 | import pika 2 | import time 3 | import uuid 4 | import json 5 | import redis 6 | # channel.queue_declare(queue='queue.abs.booking.searchflightlist') 7 | 8 | 9 | def send_to_rmq(org_data): 10 | credentials = pika.PlainCredentials('admin', 'admin') 11 | parameters = pika.ConnectionParameters('host', 'port', 'xxxxTest', credentials) 12 | connection = pika.BlockingConnection(parameters) 13 | channel = connection.channel() 14 | uuid_ = uuid.uuid4().__str__() 15 | body = str({uuid_: org_data}) 16 | channel.basic_publish(exchange='', 17 | # routing_key='queue.abs.booking.searchflightlist', 18 | routing_key='AutoPayQueue', 19 | body=body) 20 | # print " [x] Sent %s" %body 21 | connection.close() 22 | return uuid_ 23 | 24 | 25 | def uuid_get_data(uuid): 26 | r = redis.Redis(host='host', port='port') 27 | while r.get(uuid) is None: 28 | time.sleep(0.5) 29 | return r.get(uuid) 30 | 31 | 32 | def rsa_data(need_data): 33 | return eval(uuid_get_data(send_to_rmq(need_data))) 34 | 35 | 36 | -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/RMQsend.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/RMQ/RMQsend.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/Rsa_encrypt/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'c.ma' 2 | -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/Rsa_encrypt/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/RMQ/Rsa_encrypt/__init__.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/Rsa_encrypt/js.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | __author__ = 'c.ma' 3 | import PyV8 4 | # from bs4 import BeautifulSoup 5 | import json 6 | 7 | 8 | def rsa_encryption_data(need_data): 9 | str_need_data = ''.join(json.dumps(need_data)) 10 | with PyV8.JSContext() as ctxt: 11 | js_file = open(r'/var/www/html/ApiCaseSystem/WingOn/requestBody/RMQ/Rsa_encrypt/rsa.js', 'r') 12 | js_file_content = ''.join(js_file.readlines()) 13 | js_file.close() 14 | ctxt.eval(js_file_content) 15 | rsa_data_ = ctxt.locals.a 16 | return list(rsa_data_(str_need_data)) 17 | 18 | 19 | # def getCreditCardNumber(need_data): 20 | # str_need_data = str(need_data) 21 | # print str_need_data 22 | # # import PyV8 23 | # with PyV8.JSLocker() as ctxt: 24 | # ctxt = PyV8.JSContext() 25 | # ctxt.enter() 26 | # js_file = open(r'.\WingOn\requestBody\rsa.js', 'r') 27 | # js_file_content = ''.join(js_file.readlines()) 28 | # # js_file.close() 29 | # ctxt.eval(js_file_content) 30 | # rsa_func = ctxt.locals.a 31 | # rsa_data_ = list(rsa_func(str_need_data)) 32 | # ctxt.leave() 33 | # return rsa_data_ 34 | -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/Rsa_encrypt/js.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/RMQ/Rsa_encrypt/js.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'c.ma' 2 | -------------------------------------------------------------------------------- /WingOn/requestBody/RMQ/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/RMQ/__init__.pyc -------------------------------------------------------------------------------- /WingOn/requestBody/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/__init__.py -------------------------------------------------------------------------------- /WingOn/requestBody/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/WingOn/requestBody/__init__.pyc -------------------------------------------------------------------------------- /celerybeat.pid: -------------------------------------------------------------------------------- 1 | 14378 2 | -------------------------------------------------------------------------------- /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", "ApiCaseSystem.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.11 2 | django-celery==3.2.1 3 | django-kombu==0.9.4 4 | mysqlclient==1.3.12 5 | requests==2.18.4 6 | redis==2.10.5 7 | bs4==0.0.1 8 | lxml==3.8.0 9 | kombu==3.0.37 10 | pyOpenSSL==17.0.0 11 | pyv8==1.0 12 | BeautifulSoup==3.2.1 13 | beautifulsoup4==4.5.3 14 | celery==3.1.25 -------------------------------------------------------------------------------- /static/WEB_API/css/common/paging.css: -------------------------------------------------------------------------------- 1 | #box{list-style:none;margin:0;padding:0;margin-left:2%;margin-top:1%;} 2 | #box li { 3 | color: #0084F3; 4 | text-align: center; 5 | width: 60px; 6 | height: 40px; 7 | border: 1px solid #ebebeb; 8 | line-height: 40px; 9 | box-sizing: border-box; 10 | cursor: pointer; 11 | float: left; 12 | } 13 | #box li a{ 14 | display:block; 15 | width: 60px; 16 | height: 40px; 17 | line-height: 40px; 18 | } 19 | #box .active{background: #0084F3} 20 | #box .active a{color: white;} 21 | #box li a{text-decoration:none;} 22 | #box span{margin-left: 20px;height: 40px;line-height: 40px;} -------------------------------------------------------------------------------- /static/WEB_API/css/common/paging.less: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | list-style: none; 5 | } 6 | 7 | .fl { 8 | float: left; 9 | } 10 | 11 | .box { 12 | height: 40px; 13 | line-height: 40px; 14 | position: absolute; 15 | left: 50%; 16 | top: 50%; 17 | transform: translate(-50%, -50%); 18 | text-align: center; // 按钮 19 | button { 20 | padding: 0 10px; 21 | margin: 0 10px; 22 | height: 40px; 23 | .fl; 24 | cursor: pointer; 25 | border: 1px solid #ebebeb; 26 | background-color: #ffffff; 27 | } // 首页、尾页按钮 28 | .first-page, 29 | .last-page { 30 | margin: 0; 31 | } // 页码块 32 | .pageWrap { 33 | height: 40px; 34 | .fl; 35 | overflow: hidden; 36 | ul { 37 | width: 100000px; 38 | height: 40px; 39 | .fl; 40 | li { 41 | width: 60px; 42 | height: 40px; 43 | border: 1px solid #ebebeb; 44 | line-height: 40px; 45 | box-sizing: border-box; 46 | cursor: pointer; 47 | .fl; 48 | } // 选中页码 49 | .sel-page { 50 | background-color: yellow; //选中时的颜色 51 | } 52 | } 53 | } // 跳转页 54 | .jump-text { 55 | width: 60px; 56 | height: 40px; 57 | box-sizing: border-box; 58 | text-align: center; 59 | margin: 0 5px; 60 | .fl; 61 | } // 跳转按钮 62 | .jump-button { 63 | margin:0; 64 | .fl; 65 | } // 总页数,总条目数 66 | .total-pages, 67 | .total-count { 68 | margin-left: 10px; 69 | .fl; 70 | font-size: 14px; 71 | } 72 | } -------------------------------------------------------------------------------- /static/WEB_API/css/log/check_log.css: -------------------------------------------------------------------------------- 1 | #loading{width:100%;height:100%;background:#000;opacity:0; 2 | position:absolute;top:0px;color:white;z-index:50; 3 | font-size:36px;font-family:'微软雅黑';text-align:center;padding-top:25%; 4 | -webkit-transition:all 2s;display:none;} 5 | #mainview{ 6 | width: 90%;margin-top: 1%;margin-left:5%; 7 | -moz-box-shadow: 0 0 5px;/*firefox*/ 8 | -webkit-box-shadow: 0 0 5px;/*webkit*/ 9 | box-shadow: 0 0 5px;/*opera或ie9*/ 10 | -moz-border-radius:5px; 11 | -webkit-border-radius:5px; 12 | border-radius: 5px; 13 | padding: 5px;} 14 | #tarTop{ 15 | text-align: center; background: #0084F3; 16 | height: 3%; 17 | font-family: '微软雅黑';font-size: 24px;font-weight: bold;line-height: 40px;color: white; 18 | -moz-box-shadow: 0 0 3px; 19 | -webkit-box-shadow: 0 0 3px; 20 | box-shadow: 0 0 3px; 21 | -moz-border-radius: 5px; 22 | -webkit-border-radius: 5px; 23 | border-radius: 5px; } 24 | /*40px=3%*/ 25 | #oform{ margin-top: 1.5%; } 26 | #input_div{margin-left:1%;width: 98%;} 27 | #sel{width: 10%;} 28 | #click_time{width: 12%;} 29 | #end_time{width: 12%;} 30 | /*restapi 系统选择*/ 31 | #systemcode{width: 15%;font-size: 18px;} 32 | /*soapapi 系统选择*/ 33 | #soap_system_code{width: 15.7%;font-size: 16px;} 34 | 35 | #enviorment{width: 10%;} 36 | #case_id{width: 8%;height: 37px;} 37 | #sub_case_id{width: 8%;} 38 | #submit_btn{width:5%;background:#0084F3;color:white;margin-left:5%} 39 | #submit_btn:hover{opacity:0.6;} 40 | 41 | 42 | 43 | #search_thread{margin: 0 auto;margin-top: 2%;height:40px;background: #11A0FF; color: white; font-weight: bold; border-radius: 5px;} 44 | #search_thread table{width:97%; height:100%;text-align: left;margin-left: 2%;border-collapse: separate;} 45 | /*#search_thread table tr td{background: red} 46 | .div_title table tr td{background: black;}*/ 47 | /*开始执行时间*/ 48 | #search_thread .ClickExecutionTime2{width:15.5%;} 49 | /*接口名称*/ 50 | #search_thread .testCase__ApiName2{width: 33%;} 51 | /*描述*/ 52 | #search_thread .testCase__Description2{width: 21.6%;} 53 | /*ID*/ 54 | #search_thread .testCase_id2{width: 5%;} 55 | /*执行步骤*/ 56 | #search_thread .testCase__SetupStep2{width: 11%;} 57 | /*环境*/ 58 | #search_thread .Environment2{width: 5%;} 59 | /*结果*/ 60 | #search_thread .Status2{width: 9%;} 61 | /*子用例使用样式 ID 步骤类型*/ 62 | #search_thread .SubCaseID_id2{width: 8%;} 63 | #search_thread .SubCaseID__SetupType2{width: 8%;} 64 | 65 | /* soap 用例样式 testCase_id2*/ 66 | #search_thread .soapTestCase_id2{width: 8%;} 67 | #search_thread .soapTestCase__SetupStep2{width: 8%;} 68 | #search_thread .soapSubCase_id2{width: 5%;} 69 | 70 | 71 | /*log内容样式*/ 72 | #accordion{--webkit-box-shadow: 0 0 5px; margin-top: 0.5%;} 73 | #accordion div:nth-child(even){display:none;padding:25px;text-align:left;background:#F7F7F7;word-break: break-all;word-wrap:break-word;}; 74 | #accordion div:nth-child(odd){height:40px;}; 75 | .div_title{border-radius:10px;box-shadow: 0 0 5px #CCCCCC;} 76 | .div_title table{height:40px;border-bottom:1px solid #DDD;width: 97%;margin-left:2%;table-layout: fixed; text-align: left;border-collapse: separate;word-break: break-all; word-wrap: break-word;} 77 | .div_title table tr td{overflow: hidden;text-overflow:ellipsis;white-space: nowrap;} 78 | /*开始执行时间*/ 79 | .div_title .ClickExecutionTime{width: 15.5%;} 80 | /*接口名称*/ 81 | .div_title .testCase__ApiName,.SubCaseID__ApiName{width: 33%;} 82 | /*描述*/ 83 | .div_title .testCase__Description,.SubCaseID__Description{width: 21.6%;} 84 | /*ID*/ 85 | .div_title .testCase_id,.SubCaseID_id{width: 5%;} 86 | .div_title .SubCaseID_id{width: 8%;} 87 | /*执行步骤||步骤类型*/ 88 | .div_title .testCase__SetupStep,.SubCaseID__SetupType{width: 11%;} 89 | .div_title .SubCaseID__SetupType{width: 8%;} 90 | /*环境*/ 91 | .div_title .Environment{width: 5%;} 92 | /*结果状态*/ 93 | .div_title .Status{ width: 9%; color:#6c6; font-weight:bold;} 94 | 95 | /* soap 主用例样式 testCase_id2*/ 96 | .div_title .soapSubCase_id{width: 5%;} 97 | .div_title .soapTestCase_id{width: 8%;} 98 | 99 | .div_title .soapTestCase__Description,.soapSubCase__Description{width: 21.6%;} 100 | .div_title .soapTestCase__SetupStep,.soapSubCase__SetupType{width: 8%;} 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /static/WEB_API/js/common/paging.min.js: -------------------------------------------------------------------------------- 1 | (function(d, c, a) { 2 | function b(f, e) { 3 | this.el = f; 4 | this.options = { pageNo: e.initPageNo || 1, totalPages: e.totalPages || 1, totalCount: e.totalCount || "", slideSpeed: e.slideSpeed || 0, jump: e.jump || false, callback: e.callback || function() {} }; 5 | this.init() 6 | } 7 | b.prototype = { 8 | constructor: b, 9 | init: function() { 10 | this.createDom(); 11 | this.bindEvents() 12 | }, 13 | createDom: function() { 14 | var k = this, 15 | m = "", 16 | e = "", 17 | j = "", 18 | g = 60, 19 | h = k.options.totalPages, 20 | l = 0; 21 | h > 5 ? l = 5 * g : l = h * g; 22 | for (var f = 1; f <= k.options.totalPages; f++) { f != 1 ? m += "
  • " + f + "
  • " : m += '
  • ' + f + "
  • " } 23 | k.options.jump ? e = '' : e = ""; 24 | j = '' + '' + '
    ' + '
    " + '' + '' + e + '

    共 ' + k.options.totalPages + " 页

    " + '

    ' + k.options.totalCount + "

    "; 25 | k.el.html(j) 26 | }, 27 | bindEvents: function() { 28 | var k = this, 29 | f = d("#pageSelect"), 30 | r = f.children(), 31 | n = r[0].offsetWidth, 32 | l = k.options.totalPages, 33 | g = k.options.pageNo, 34 | e = 0, 35 | o = d("#prePage"), 36 | m = d("#nextPage"), 37 | i = d("#firstPage"), 38 | j = d("#lastPage"), 39 | q = d("#jumpBtn"), 40 | h = d("#jumpText"); 41 | o.on("click", function() { 42 | g--; 43 | if (g < 1) { g = 1 } 44 | p(g) 45 | }); 46 | m.on("click", function() { 47 | g++; 48 | if (g > r.length) { g = r.length } 49 | p(g) 50 | }); 51 | i.on("click", function() { 52 | g = 1; 53 | p(g) 54 | }); 55 | j.on("click", function() { 56 | g = l; 57 | p(g) 58 | }); 59 | q.on("click", function() { 60 | var s = parseInt(h.val().replace(/\D/g, "")); 61 | if (s && s >= 1 && s <= l) { 62 | g = s; 63 | p(g); 64 | h.val(s) 65 | } 66 | }); 67 | r.on("click", function() { 68 | g = d(this).index() + 1; 69 | p(g) 70 | }); 71 | 72 | function p(s) { 73 | r.removeClass("sel-page").eq(s - 1).addClass("sel-page"); 74 | if (l <= 5) { k.options.callback(s); return false } 75 | if (s >= 3 && s <= l - 2) { e = (s - 3) * n } 76 | if (s == 2 || s == 1) { e = 0 } 77 | if (s > l - 2) { e = (l - 5) * n } 78 | f.css("transform", "translateX(" + (-e) + "px)"); 79 | s == 1 ? i.attr("disabled", true) : i.attr("disabled", false); 80 | s == 1 ? o.attr("disabled", true) : o.attr("disabled", false); 81 | s == l ? j.attr("disabled", true) : j.attr("disabled", false); 82 | s == l ? m.attr("disabled", true) : m.attr("disabled", false); 83 | k.options.callback(s) 84 | } 85 | p(k.options.pageNo) 86 | } 87 | }; 88 | d.fn.paging = function(e) { return new b(d(this), e) } 89 | })(jQuery, window, document); -------------------------------------------------------------------------------- /static/WEB_API/js/log/check_log.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | $('#sub_case_id').attr("disabled","disabled"); 3 | $('#soap_system_code').css('display','none'); 4 | }); 5 | //主用例/子用例切换响应事件 6 | function chg(){ 7 | if(document.getElementById("sel").value=="0"){ 8 | 9 | $('#sub_case_id').attr("disabled","disabled"); 10 | $('#sub_case_id').val(''); 11 | } 12 | else{ 13 | $('#sub_case_id').removeAttr("disabled"); 14 | $('#sub_case_id').val(''); 15 | 16 | } 17 | }; 18 | 19 | //SoapAPI/RestAPI切换响应事件 20 | function changeType(){ 21 | if(document.getElementById("api_type").value=="SoapAPI"){ 22 | document.getElementById("soap_system_code").style.display=''; 23 | document.getElementById("system_code").style.display='none'; 24 | }else{ 25 | document.getElementById("soap_system_code").style.display='none'; 26 | document.getElementById("system_code").style.display=''; 27 | } 28 | } 29 | $(function() { 30 | $( "#click_time" ).datetimepicker({ 31 | format:'Y-m-d H:i:s', 32 | step:10 33 | }); 34 | $( "#end_time" ).datetimepicker({ 35 | format:'Y-m-d H:i:s', 36 | step:10 37 | }); 38 | }); 39 | 40 | 41 | //日志详情展开 方法 42 | function logSlideToggle(){ 43 | $(".div_title").click(function(){ 44 | $(this).next().slideToggle(); 45 | }); 46 | } 47 | //状态颜色 方法 48 | function statusColor(){ 49 | var table_content=$('.table_content'); 50 | var i=0; 51 | for( var i = 0; i < table_content.length; i++ ) { 52 | 53 | var result_td=table_content.eq(i).children("td:last-child"); 54 | if(result_td.html()=='Fail'){ 55 | result_td.css('color','#c60'); 56 | } 57 | else if(result_td.html()=='Error'){ 58 | result_td.css('color','#c00'); 59 | } 60 | else if(result_td.html()=='Success'){ 61 | result_td.css('color','#6c6'); 62 | }else{ 63 | ; 64 | } 65 | } 66 | } 67 | //分页链接 点击响应 方法 68 | function linkClick(){ 69 | $('a').click(function(){ 70 | var oLink=$(this).attr('href'); 71 | //alert(oLink); 72 | $.ajax({ 73 | url: oLink, 74 | success: function(result, statues, xml){ 75 | //alert('进入分页回调'); 76 | //alert(result); 77 | $("#response_result").html(result); 78 | logSlideToggle(); 79 | statusColor(); 80 | linkClick(); 81 | }, 82 | error: function(){ 83 | alert("false"); 84 | }, 85 | dataType: "html" 86 | }); 87 | return false; 88 | }); 89 | } 90 | //页面加载完成 方法 查询提交请求 91 | $(document).ready(function(){ 92 | $.ajaxSetup({ 93 | data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, 94 | }); 95 | //查询提交 get请求 96 | $('#submit_btn').click(function(){ 97 | //alert('进入submit'); 98 | var csrfmiddlewaretoken='{{ csrf_token }}'; 99 | var api_type = $("#api_type").val(); 100 | var case_type = $("#sel").val(); 101 | var click_time = $("#click_time").val(); 102 | var end_time = $("#end_time").val(); 103 | var system_code = $("#system_code").val(); 104 | var soap_system_code = $("#soap_system_code").val(); 105 | var environment = $("#environment").val(); 106 | var case_id = $("#case_id").val(); 107 | var sub_case_id = $("#sub_case_id").val(); 108 | //正整数正则表达式 1-9开头 109 | var reg=/^[1-9]\d*$|^0$/; 110 | if(click_time==''||end_time==''){ 111 | alert('开始时间和结束时间不能为空'); 112 | $("#click_time").focus(); 113 | return false; 114 | }else if(click_time>end_time){ 115 | alert('开始时间不能早于结束时间'); 116 | $("#click_time").focus(); 117 | return false; 118 | }else if(case_type=='1'&&(case_id&&!(sub_case_id)||(sub_case_id&&(!case_id)))){ 119 | if(case_id&&!(sub_case_id)){alert('有主用例ID时 必须输入子用例ID');$("#sub_case_id").focus();} 120 | else{alert('有子用例ID时 必须输入主用例ID');$("#case_id").focus();} 121 | return false; 122 | }else if(case_type=='1'&&!(!case_id&&!sub_case_id)&&(reg.test(case_id)==false||reg.test(sub_case_id)==false)){ 123 | alert('请输入正确的ID'); 124 | return false; 125 | }else if(case_type=='0'&&case_id&®.test(case_id)==false){ 126 | alert('请输入正确的主用例ID'); 127 | $("#case_id").focus(); 128 | return false; 129 | } 130 | else{ 131 | document.getElementById("loading").style.display='block'; 132 | document.getElementById("loading").style.opacity='0.6'; 133 | $.ajax({ 134 | type:"GET", 135 | data: {api_type:api_type,case_type:case_type,click_time:click_time, 136 | end_time:end_time,system_code:system_code,soap_system_code:soap_system_code, 137 | environment:environment,case_id:case_id,sub_case_id:sub_case_id}, 138 | url: "/log/", 139 | cache: false, 140 | dataType: "html", 141 | /*ajax成功时回调方法*/ 142 | success: function(result, statues, xml){ 143 | //关闭 loading 144 | document.getElementById("loading").style.display='none'; 145 | //局部刷新数据 146 | $("#response_result").html(result); 147 | //加载分页提交事件 148 | linkClick(); 149 | //加载数据下拉事件 150 | logSlideToggle(); 151 | //加载状态颜色事件 152 | statusColor(); 153 | }, 154 | error: function(){ 155 | alert("false"); 156 | } 157 | }); 158 | return false; 159 | } 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /static/admin/css/changelists.css: -------------------------------------------------------------------------------- 1 | /* CHANGELISTS */ 2 | 3 | #changelist { 4 | position: relative; 5 | width: 100%; 6 | } 7 | 8 | #changelist table { 9 | width: 100%; 10 | } 11 | 12 | .change-list .hiddenfields { display:none; } 13 | 14 | .change-list .filtered table { 15 | border-right: none; 16 | } 17 | 18 | .change-list .filtered { 19 | min-height: 400px; 20 | } 21 | 22 | .change-list .filtered .results, .change-list .filtered .paginator, 23 | .filtered #toolbar, .filtered div.xfull { 24 | margin-right: 280px; 25 | width: auto; 26 | } 27 | 28 | .change-list .filtered table tbody th { 29 | padding-right: 1em; 30 | } 31 | 32 | #changelist-form .results { 33 | overflow-x: auto; 34 | } 35 | 36 | #changelist .toplinks { 37 | border-bottom: 1px solid #ddd; 38 | } 39 | 40 | #changelist .paginator { 41 | color: #666; 42 | border-bottom: 1px solid #eee; 43 | background: #fff; 44 | overflow: hidden; 45 | } 46 | 47 | /* CHANGELIST TABLES */ 48 | 49 | #changelist table thead th { 50 | padding: 0; 51 | white-space: nowrap; 52 | vertical-align: middle; 53 | } 54 | 55 | #changelist table thead th.action-checkbox-column { 56 | width: 1.5em; 57 | text-align: center; 58 | } 59 | 60 | #changelist table tbody td.action-checkbox { 61 | text-align: center; 62 | } 63 | 64 | #changelist table tfoot { 65 | color: #666; 66 | } 67 | 68 | /* TOOLBAR */ 69 | 70 | #changelist #toolbar { 71 | padding: 8px 10px; 72 | margin-bottom: 15px; 73 | border-top: 1px solid #eee; 74 | border-bottom: 1px solid #eee; 75 | background: #f8f8f8; 76 | color: #666; 77 | } 78 | 79 | #changelist #toolbar form input { 80 | border-radius: 4px; 81 | font-size: 14px; 82 | padding: 5px; 83 | color: #333; 84 | } 85 | 86 | #changelist #toolbar form #searchbar { 87 | height: 19px; 88 | border: 1px solid #ccc; 89 | padding: 2px 5px; 90 | margin: 0; 91 | vertical-align: top; 92 | font-size: 13px; 93 | } 94 | 95 | #changelist #toolbar form #searchbar:focus { 96 | border-color: #999; 97 | } 98 | 99 | #changelist #toolbar form input[type="submit"] { 100 | border: 1px solid #ccc; 101 | padding: 2px 10px; 102 | margin: 0; 103 | vertical-align: middle; 104 | background: #fff; 105 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 106 | cursor: pointer; 107 | color: #333; 108 | } 109 | 110 | #changelist #toolbar form input[type="submit"]:focus, 111 | #changelist #toolbar form input[type="submit"]:hover { 112 | border-color: #999; 113 | } 114 | 115 | #changelist #changelist-search img { 116 | vertical-align: middle; 117 | margin-right: 4px; 118 | } 119 | 120 | /* FILTER COLUMN */ 121 | 122 | #changelist-filter { 123 | position: absolute; 124 | top: 0; 125 | right: 0; 126 | z-index: 1000; 127 | width: 240px; 128 | background: #f8f8f8; 129 | border-left: none; 130 | margin: 0; 131 | } 132 | 133 | #changelist-filter h2 { 134 | font-size: 14px; 135 | text-transform: uppercase; 136 | letter-spacing: 0.5px; 137 | padding: 5px 15px; 138 | margin-bottom: 12px; 139 | border-bottom: none; 140 | } 141 | 142 | #changelist-filter h3 { 143 | font-weight: 400; 144 | font-size: 14px; 145 | padding: 0 15px; 146 | margin-bottom: 10px; 147 | } 148 | 149 | #changelist-filter ul { 150 | margin: 5px 0; 151 | padding: 0 15px 15px; 152 | border-bottom: 1px solid #eaeaea; 153 | } 154 | 155 | #changelist-filter ul:last-child { 156 | border-bottom: none; 157 | padding-bottom: none; 158 | } 159 | 160 | #changelist-filter li { 161 | list-style-type: none; 162 | margin-left: 0; 163 | padding-left: 0; 164 | } 165 | 166 | #changelist-filter a { 167 | display: block; 168 | color: #999; 169 | text-overflow: ellipsis; 170 | overflow-x: hidden; 171 | } 172 | 173 | #changelist-filter li.selected { 174 | border-left: 5px solid #eaeaea; 175 | padding-left: 10px; 176 | margin-left: -15px; 177 | } 178 | 179 | #changelist-filter li.selected a { 180 | color: #5b80b2; 181 | } 182 | 183 | #changelist-filter a:focus, #changelist-filter a:hover, 184 | #changelist-filter li.selected a:focus, 185 | #changelist-filter li.selected a:hover { 186 | color: #036; 187 | } 188 | 189 | /* DATE DRILLDOWN */ 190 | 191 | .change-list ul.toplinks { 192 | display: block; 193 | float: left; 194 | padding: 0; 195 | margin: 0; 196 | width: 100%; 197 | } 198 | 199 | .change-list ul.toplinks li { 200 | padding: 3px 6px; 201 | font-weight: bold; 202 | list-style-type: none; 203 | display: inline-block; 204 | } 205 | 206 | .change-list ul.toplinks .date-back a { 207 | color: #999; 208 | } 209 | 210 | .change-list ul.toplinks .date-back a:focus, 211 | .change-list ul.toplinks .date-back a:hover { 212 | color: #036; 213 | } 214 | 215 | /* PAGINATOR */ 216 | 217 | .paginator { 218 | font-size: 13px; 219 | padding-top: 10px; 220 | padding-bottom: 10px; 221 | line-height: 22px; 222 | margin: 0; 223 | border-top: 1px solid #ddd; 224 | } 225 | 226 | .paginator a:link, .paginator a:visited { 227 | padding: 2px 6px; 228 | background: #79aec8; 229 | text-decoration: none; 230 | color: #fff; 231 | } 232 | 233 | .paginator a.showall { 234 | padding: 0; 235 | border: none; 236 | background: none; 237 | color: #5b80b2; 238 | } 239 | 240 | .paginator a.showall:focus, .paginator a.showall:hover { 241 | background: none; 242 | color: #036; 243 | } 244 | 245 | .paginator .end { 246 | margin-right: 6px; 247 | } 248 | 249 | .paginator .this-page { 250 | padding: 2px 6px; 251 | font-weight: bold; 252 | font-size: 13px; 253 | vertical-align: top; 254 | } 255 | 256 | .paginator a:focus, .paginator a:hover { 257 | color: white; 258 | background: #036; 259 | } 260 | 261 | /* ACTIONS */ 262 | 263 | .filtered .actions { 264 | margin-right: 280px; 265 | border-right: none; 266 | } 267 | 268 | #changelist table input { 269 | margin: 0; 270 | vertical-align: baseline; 271 | } 272 | 273 | #changelist table tbody tr.selected { 274 | background-color: #FFFFCC; 275 | } 276 | 277 | #changelist .actions { 278 | padding: 10px; 279 | background: #fff; 280 | border-top: none; 281 | border-bottom: none; 282 | line-height: 24px; 283 | color: #999; 284 | } 285 | 286 | #changelist .actions.selected { 287 | background: #fffccf; 288 | border-top: 1px solid #fffee8; 289 | border-bottom: 1px solid #edecd6; 290 | } 291 | 292 | #changelist .actions span.all, 293 | #changelist .actions span.action-counter, 294 | #changelist .actions span.clear, 295 | #changelist .actions span.question { 296 | font-size: 13px; 297 | margin: 0 0.5em; 298 | display: none; 299 | } 300 | 301 | #changelist .actions:last-child { 302 | border-bottom: none; 303 | } 304 | 305 | #changelist .actions select { 306 | vertical-align: top; 307 | height: 24px; 308 | background: none; 309 | color: #000; 310 | border: 1px solid #ccc; 311 | border-radius: 4px; 312 | font-size: 14px; 313 | padding: 0 0 0 4px; 314 | margin: 0; 315 | margin-left: 10px; 316 | } 317 | 318 | #changelist .actions select:focus { 319 | border-color: #999; 320 | } 321 | 322 | #changelist .actions label { 323 | display: inline-block; 324 | vertical-align: middle; 325 | font-size: 13px; 326 | } 327 | 328 | #changelist .actions .button { 329 | font-size: 13px; 330 | border: 1px solid #ccc; 331 | border-radius: 4px; 332 | background: #fff; 333 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset; 334 | cursor: pointer; 335 | height: 24px; 336 | line-height: 1; 337 | padding: 4px 8px; 338 | margin: 0; 339 | color: #333; 340 | } 341 | 342 | #changelist .actions .button:focus, #changelist .actions .button:hover { 343 | border-color: #999; 344 | } 345 | -------------------------------------------------------------------------------- /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 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | -o-text-overflow: ellipsis; 27 | } 28 | -------------------------------------------------------------------------------- /static/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | body.login { 4 | background: #f8f8f8; 5 | } 6 | 7 | .login #header { 8 | height: auto; 9 | padding: 5px 16px; 10 | } 11 | 12 | .login #header h1 { 13 | font-size: 18px; 14 | } 15 | 16 | .login #header h1 a { 17 | color: #fff; 18 | } 19 | 20 | .login #content { 21 | padding: 20px 20px 0; 22 | } 23 | 24 | .login #container { 25 | background: #fff; 26 | border: 1px solid #eaeaea; 27 | border-radius: 4px; 28 | overflow: hidden; 29 | width: 28em; 30 | min-width: 300px; 31 | margin: 100px auto; 32 | } 33 | 34 | .login #content-main { 35 | width: 100%; 36 | } 37 | 38 | .login .form-row { 39 | padding: 4px 0; 40 | float: left; 41 | width: 100%; 42 | border-bottom: none; 43 | } 44 | 45 | .login .form-row label { 46 | padding-right: 0.5em; 47 | line-height: 2em; 48 | font-size: 1em; 49 | clear: both; 50 | color: #333; 51 | } 52 | 53 | .login .form-row #id_username, .login .form-row #id_password { 54 | clear: both; 55 | padding: 8px; 56 | width: 100%; 57 | -webkit-box-sizing: border-box; 58 | -moz-box-sizing: border-box; 59 | box-sizing: border-box; 60 | } 61 | 62 | .login span.help { 63 | font-size: 10px; 64 | display: block; 65 | } 66 | 67 | .login .submit-row { 68 | clear: both; 69 | padding: 1em 0 0 9.4em; 70 | margin: 0; 71 | border: none; 72 | background: none; 73 | text-align: left; 74 | } 75 | 76 | .login .password-reset-link { 77 | text-align: center; 78 | } 79 | -------------------------------------------------------------------------------- /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 | .module ul, .module ol { 34 | margin-left: 0; 35 | margin-right: 1.5em; 36 | } 37 | 38 | .addlink, .changelink { 39 | padding-left: 0; 40 | padding-right: 16px; 41 | background-position: 100% 1px; 42 | } 43 | 44 | .deletelink { 45 | padding-left: 0; 46 | padding-right: 16px; 47 | background-position: 100% 1px; 48 | } 49 | 50 | .object-tools { 51 | float: left; 52 | } 53 | 54 | thead th:first-child, 55 | tfoot td:first-child { 56 | border-left: none; 57 | } 58 | 59 | /* LAYOUT */ 60 | 61 | #user-tools { 62 | right: auto; 63 | left: 0; 64 | text-align: left; 65 | } 66 | 67 | div.breadcrumbs { 68 | text-align: right; 69 | } 70 | 71 | #content-main { 72 | float: right; 73 | } 74 | 75 | #content-related { 76 | float: left; 77 | margin-left: -300px; 78 | margin-right: auto; 79 | } 80 | 81 | .colMS { 82 | margin-left: 300px; 83 | margin-right: 0; 84 | } 85 | 86 | /* SORTABLE TABLES */ 87 | 88 | table thead th.sorted .sortoptions { 89 | float: left; 90 | } 91 | 92 | thead th.sorted .text { 93 | padding-right: 0; 94 | padding-left: 42px; 95 | } 96 | 97 | /* dashboard styles */ 98 | 99 | .dashboard .module table td a { 100 | padding-left: .6em; 101 | padding-right: 16px; 102 | } 103 | 104 | /* changelists styles */ 105 | 106 | .change-list .filtered table { 107 | border-left: none; 108 | border-right: 0px none; 109 | } 110 | 111 | #changelist-filter { 112 | right: auto; 113 | left: 0; 114 | border-left: none; 115 | border-right: none; 116 | } 117 | 118 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { 119 | margin-right: 0; 120 | margin-left: 280px; 121 | } 122 | 123 | #changelist-filter li.selected { 124 | border-left: none; 125 | padding-left: 10px; 126 | margin-left: 0; 127 | border-right: 5px solid #eaeaea; 128 | padding-right: 10px; 129 | margin-right: -15px; 130 | } 131 | 132 | .filtered .actions { 133 | margin-left: 280px; 134 | margin-right: 0; 135 | } 136 | 137 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 138 | border-right: none; 139 | border-left: none; 140 | } 141 | 142 | /* FORMS */ 143 | 144 | .aligned label { 145 | padding: 0 0 3px 1em; 146 | float: right; 147 | } 148 | 149 | .submit-row { 150 | text-align: left 151 | } 152 | 153 | .submit-row p.deletelink-box { 154 | float: right; 155 | } 156 | 157 | .submit-row input.default { 158 | margin-left: 0; 159 | } 160 | 161 | .vDateField, .vTimeField { 162 | margin-left: 2px; 163 | } 164 | 165 | .aligned .form-row input { 166 | margin-left: 5px; 167 | } 168 | 169 | form .aligned p.help, form .aligned div.help { 170 | clear: right; 171 | } 172 | 173 | form ul.inline li { 174 | float: right; 175 | padding-right: 0; 176 | padding-left: 7px; 177 | } 178 | 179 | input[type=submit].default, .submit-row input.default { 180 | float: left; 181 | } 182 | 183 | fieldset .field-box { 184 | float: right; 185 | margin-left: 20px; 186 | margin-right: 0; 187 | } 188 | 189 | .errorlist li { 190 | background-position: 100% 12px; 191 | padding: 0; 192 | } 193 | 194 | .errornote { 195 | background-position: 100% 12px; 196 | padding: 10px 12px; 197 | } 198 | 199 | /* WIDGETS */ 200 | 201 | .calendarnav-previous { 202 | top: 0; 203 | left: auto; 204 | right: 10px; 205 | } 206 | 207 | .calendarnav-next { 208 | top: 0; 209 | right: auto; 210 | left: 10px; 211 | } 212 | 213 | .calendar caption, .calendarbox h2 { 214 | text-align: center; 215 | } 216 | 217 | .selector { 218 | float: right; 219 | } 220 | 221 | .selector .selector-filter { 222 | text-align: right; 223 | } 224 | 225 | .inline-deletelink { 226 | float: left; 227 | } 228 | 229 | form .form-row p.datetime { 230 | overflow: hidden; 231 | } 232 | 233 | .related-widget-wrapper { 234 | float: right; 235 | } 236 | 237 | /* MISC */ 238 | 239 | .inline-related h2, .inline-group h2 { 240 | text-align: right 241 | } 242 | 243 | .inline-related h3 span.delete { 244 | padding-right: 20px; 245 | padding-left: inherit; 246 | left: 10px; 247 | right: inherit; 248 | float:left; 249 | } 250 | 251 | .inline-related h3 span.delete label { 252 | margin-left: inherit; 253 | margin-right: 2px; 254 | } 255 | 256 | /* IE7 specific bug fixes */ 257 | 258 | div.colM { 259 | position: relative; 260 | } 261 | 262 | .submit-row input { 263 | float: left; 264 | } 265 | -------------------------------------------------------------------------------- /static/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | Weights used in this project: Light (300), Regular (400), Bold (700) 3 | -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/static/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/static/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxinglong007/WAPI/65f0010f3e0ce22c510b54f236bb17938dccee5b/static/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - http://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/js/SelectBox.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | 'use strict'; 3 | var SelectBox = { 4 | cache: {}, 5 | init: function(id) { 6 | var box = document.getElementById(id); 7 | var node; 8 | SelectBox.cache[id] = []; 9 | var cache = SelectBox.cache[id]; 10 | var boxOptions = box.options; 11 | var boxOptionsLength = boxOptions.length; 12 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 13 | node = boxOptions[i]; 14 | cache.push({value: node.value, text: node.text, displayed: 1}); 15 | } 16 | }, 17 | redisplay: function(id) { 18 | // Repopulate HTML select box from cache 19 | var box = document.getElementById(id); 20 | var node; 21 | $(box).empty(); // clear all options 22 | var new_options = box.outerHTML.slice(0, -9); // grab just the opening tag 23 | var cache = SelectBox.cache[id]; 24 | for (var i = 0, j = cache.length; i < j; i++) { 25 | node = cache[i]; 26 | if (node.displayed) { 27 | var new_option = new Option(node.text, node.value, false, false); 28 | // Shows a tooltip when hovering over the option 29 | new_option.setAttribute("title", node.text); 30 | new_options += new_option.outerHTML; 31 | } 32 | } 33 | new_options += ''; 34 | box.outerHTML = new_options; 35 | }, 36 | filter: function(id, text) { 37 | // Redisplay the HTML select box, displaying only the choices containing ALL 38 | // the words in text. (It's an AND search.) 39 | var tokens = text.toLowerCase().split(/\s+/); 40 | var node, token; 41 | var cache = SelectBox.cache[id]; 42 | for (var i = 0, j = cache.length; i < j; i++) { 43 | node = cache[i]; 44 | node.displayed = 1; 45 | var node_text = node.text.toLowerCase(); 46 | var numTokens = tokens.length; 47 | for (var k = 0; k < numTokens; k++) { 48 | token = tokens[k]; 49 | if (node_text.indexOf(token) === -1) { 50 | node.displayed = 0; 51 | break; // Once the first token isn't found we're done 52 | } 53 | } 54 | } 55 | SelectBox.redisplay(id); 56 | }, 57 | delete_from_cache: function(id, value) { 58 | var node, delete_index = null; 59 | var cache = SelectBox.cache[id]; 60 | for (var i = 0, j = cache.length; i < j; i++) { 61 | node = cache[i]; 62 | if (node.value === value) { 63 | delete_index = i; 64 | break; 65 | } 66 | } 67 | cache.splice(delete_index, 1); 68 | }, 69 | add_to_cache: function(id, option) { 70 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); 71 | }, 72 | cache_contains: function(id, value) { 73 | // Check if an item is contained in the cache 74 | var node; 75 | var cache = SelectBox.cache[id]; 76 | for (var i = 0, j = cache.length; i < j; i++) { 77 | node = cache[i]; 78 | if (node.value === value) { 79 | return true; 80 | } 81 | } 82 | return false; 83 | }, 84 | move: function(from, to) { 85 | var from_box = document.getElementById(from); 86 | var option; 87 | var boxOptions = from_box.options; 88 | var boxOptionsLength = boxOptions.length; 89 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 90 | option = boxOptions[i]; 91 | var option_value = option.value; 92 | if (option.selected && SelectBox.cache_contains(from, option_value)) { 93 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 94 | SelectBox.delete_from_cache(from, option_value); 95 | } 96 | } 97 | SelectBox.redisplay(from); 98 | SelectBox.redisplay(to); 99 | }, 100 | move_all: function(from, to) { 101 | var from_box = document.getElementById(from); 102 | var option; 103 | var boxOptions = from_box.options; 104 | var boxOptionsLength = boxOptions.length; 105 | for (var i = 0, j = boxOptionsLength; i < j; i++) { 106 | option = boxOptions[i]; 107 | var option_value = option.value; 108 | if (SelectBox.cache_contains(from, option_value)) { 109 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 110 | SelectBox.delete_from_cache(from, option_value); 111 | } 112 | } 113 | SelectBox.redisplay(from); 114 | SelectBox.redisplay(to); 115 | }, 116 | sort: function(id) { 117 | SelectBox.cache[id].sort(function(a, b) { 118 | a = a.text.toLowerCase(); 119 | b = b.text.toLowerCase(); 120 | try { 121 | if (a > b) { 122 | return 1; 123 | } 124 | if (a < b) { 125 | return -1; 126 | } 127 | } 128 | catch (e) { 129 | // silently fail on IE 'unknown' exception 130 | } 131 | return 0; 132 | } ); 133 | }, 134 | select_all: function(id) { 135 | var box = document.getElementById(id); 136 | var boxOptions = box.options; 137 | var boxOptionsLength = boxOptions.length; 138 | for (var i = 0; i < boxOptionsLength; i++) { 139 | boxOptions[i].selected = 'selected'; 140 | } 141 | } 142 | }; 143 | window.SelectBox = SelectBox; 144 | })(django.jQuery); 145 | -------------------------------------------------------------------------------- /static/admin/js/actions.js: -------------------------------------------------------------------------------- 1 | /*global gettext, interpolate, ngettext*/ 2 | (function($) { 3 | 'use strict'; 4 | var lastChecked; 5 | 6 | $.fn.actions = function(opts) { 7 | var options = $.extend({}, $.fn.actions.defaults, opts); 8 | var actionCheckboxes = $(this); 9 | var list_editable_changed = false; 10 | var showQuestion = function() { 11 | $(options.acrossClears).hide(); 12 | $(options.acrossQuestions).show(); 13 | $(options.allContainer).hide(); 14 | }, 15 | showClear = function() { 16 | $(options.acrossClears).show(); 17 | $(options.acrossQuestions).hide(); 18 | $(options.actionContainer).toggleClass(options.selectedClass); 19 | $(options.allContainer).show(); 20 | $(options.counterContainer).hide(); 21 | }, 22 | reset = function() { 23 | $(options.acrossClears).hide(); 24 | $(options.acrossQuestions).hide(); 25 | $(options.allContainer).hide(); 26 | $(options.counterContainer).show(); 27 | }, 28 | clearAcross = function() { 29 | reset(); 30 | $(options.acrossInput).val(0); 31 | $(options.actionContainer).removeClass(options.selectedClass); 32 | }, 33 | checker = function(checked) { 34 | if (checked) { 35 | showQuestion(); 36 | } else { 37 | reset(); 38 | } 39 | $(actionCheckboxes).prop("checked", checked) 40 | .parent().parent().toggleClass(options.selectedClass, checked); 41 | }, 42 | updateCounter = function() { 43 | var sel = $(actionCheckboxes).filter(":checked").length; 44 | // data-actions-icnt is defined in the generated HTML 45 | // and contains the total amount of objects in the queryset 46 | var actions_icnt = $('.action-counter').data('actionsIcnt'); 47 | $(options.counterContainer).html(interpolate( 48 | ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), { 49 | sel: sel, 50 | cnt: actions_icnt 51 | }, true)); 52 | $(options.allToggle).prop("checked", function() { 53 | var value; 54 | if (sel === actionCheckboxes.length) { 55 | value = true; 56 | showQuestion(); 57 | } else { 58 | value = false; 59 | clearAcross(); 60 | } 61 | return value; 62 | }); 63 | }; 64 | // Show counter by default 65 | $(options.counterContainer).show(); 66 | // Check state of checkboxes and reinit state if needed 67 | $(this).filter(":checked").each(function(i) { 68 | $(this).parent().parent().toggleClass(options.selectedClass); 69 | updateCounter(); 70 | if ($(options.acrossInput).val() === 1) { 71 | showClear(); 72 | } 73 | }); 74 | $(options.allToggle).show().click(function() { 75 | checker($(this).prop("checked")); 76 | updateCounter(); 77 | }); 78 | $("a", options.acrossQuestions).click(function(event) { 79 | event.preventDefault(); 80 | $(options.acrossInput).val(1); 81 | showClear(); 82 | }); 83 | $("a", options.acrossClears).click(function(event) { 84 | event.preventDefault(); 85 | $(options.allToggle).prop("checked", false); 86 | clearAcross(); 87 | checker(0); 88 | updateCounter(); 89 | }); 90 | lastChecked = null; 91 | $(actionCheckboxes).click(function(event) { 92 | if (!event) { event = window.event; } 93 | var target = event.target ? event.target : event.srcElement; 94 | if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) { 95 | var inrange = false; 96 | $(lastChecked).prop("checked", target.checked) 97 | .parent().parent().toggleClass(options.selectedClass, target.checked); 98 | $(actionCheckboxes).each(function() { 99 | if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) { 100 | inrange = (inrange) ? false : true; 101 | } 102 | if (inrange) { 103 | $(this).prop("checked", target.checked) 104 | .parent().parent().toggleClass(options.selectedClass, target.checked); 105 | } 106 | }); 107 | } 108 | $(target).parent().parent().toggleClass(options.selectedClass, target.checked); 109 | lastChecked = target; 110 | updateCounter(); 111 | }); 112 | $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() { 113 | list_editable_changed = true; 114 | }); 115 | $('form#changelist-form button[name="index"]').click(function(event) { 116 | if (list_editable_changed) { 117 | return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost.")); 118 | } 119 | }); 120 | $('form#changelist-form input[name="_save"]').click(function(event) { 121 | var action_changed = false; 122 | $('select option:selected', options.actionContainer).each(function() { 123 | if ($(this).val()) { 124 | action_changed = true; 125 | } 126 | }); 127 | if (action_changed) { 128 | if (list_editable_changed) { 129 | return 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.")); 130 | } else { 131 | return 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.")); 132 | } 133 | } 134 | }); 135 | }; 136 | /* Setup plugin defaults */ 137 | $.fn.actions.defaults = { 138 | actionContainer: "div.actions", 139 | counterContainer: "span.action-counter", 140 | allContainer: "div.actions span.all", 141 | acrossInput: "div.actions input.select-across", 142 | acrossQuestions: "div.actions span.question", 143 | acrossClears: "div.actions span.clear", 144 | allToggle: "#action-toggle", 145 | selectedClass: "selected" 146 | }; 147 | $(document).ready(function() { 148 | var $actionsEls = $('tr input.action-select'); 149 | if ($actionsEls.length > 0) { 150 | $actionsEls.actions(); 151 | } 152 | }); 153 | })(django.jQuery); 154 | -------------------------------------------------------------------------------- /static/admin/js/actions.min.js: -------------------------------------------------------------------------------- 1 | (function(a){var f;a.fn.actions=function(e){var b=a.extend({},a.fn.actions.defaults,e),g=a(this),k=!1,l=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()},m=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},n=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},p=function(){n(); 2 | a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)},q=function(c){c?l():n();a(g).prop("checked",c).parent().parent().toggleClass(b.selectedClass,c)},h=function(){var c=a(g).filter(":checked").length,d=a(".action-counter").data("actionsIcnt");a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:d},!0));a(b.allToggle).prop("checked",function(){var a;c===g.length?(a=!0,l()):(a=!1,p());return a})};a(b.counterContainer).show(); 3 | a(this).filter(":checked").each(function(c){a(this).parent().parent().toggleClass(b.selectedClass);h();1===a(b.acrossInput).val()&&m()});a(b.allToggle).show().click(function(){q(a(this).prop("checked"));h()});a("a",b.acrossQuestions).click(function(c){c.preventDefault();a(b.acrossInput).val(1);m()});a("a",b.acrossClears).click(function(c){c.preventDefault();a(b.allToggle).prop("checked",!1);p();q(0);h()});f=null;a(g).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(f&& 4 | a.data(f)!==a.data(d)&&!0===c.shiftKey){var e=!1;a(f).prop("checked",d.checked).parent().parent().toggleClass(b.selectedClass,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(){k=!0});a('form#changelist-form button[name="index"]').click(function(a){if(k)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 k?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"};a(document).ready(function(){var e=a("tr input.action-select");0' + gettext("Show") + 11 | ')'); 12 | } 13 | }); 14 | // Add toggle to anchor tag 15 | $("fieldset.collapse a.collapse-toggle").click(function(ev) { 16 | if ($(this).closest("fieldset").hasClass("collapsed")) { 17 | // Show 18 | $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]); 19 | } else { 20 | // Hide 21 | $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]); 22 | } 23 | return false; 24 | }); 25 | }); 26 | })(django.jQuery); 27 | -------------------------------------------------------------------------------- /static/admin/js/collapse.min.js: -------------------------------------------------------------------------------- 1 | (function(a){a(document).ready(function(){a("fieldset.collapse").each(function(b,c){0===a(c).find("div.errors").length&&a(c).addClass("collapsed").find("h2").first().append(' ('+gettext("Show")+")")});a("fieldset.collapse a.collapse-toggle").click(function(b){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!1})})})(django.jQuery); 3 | -------------------------------------------------------------------------------- /static/admin/js/inlines.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.formset=function(b){var a=c.extend({},c.fn.formset.defaults,b),d=c(this);b=d.parent();var k=function(a,g,l){var b=new RegExp("("+g+"-(\\d+|__prefix__))");g=g+"-"+l;c(a).prop("for")&&c(a).prop("for",c(a).prop("for").replace(b,g));a.id&&(a.id=a.id.replace(b,g));a.name&&(a.name=a.name.replace(b,g))},e=c("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(e.val(),10),g=c("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),h=""===g.val()||0'+a.addText+""),m=b.find("tr:last a")):(d.filter(":last").after('"),m=d.filter(":last").next().find("a")));m.click(function(b){b.preventDefault();b=c("#"+a.prefix+"-empty"); 3 | var f=b.clone(!0);f.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);f.is("tr")?f.children(":last").append('
    '+a.deleteText+"
    "):f.is("ul")||f.is("ol")?f.append('
  • '+a.deleteText+"
  • "):f.children(":first").append(''+a.deleteText+"");f.find("*").each(function(){k(this,a.prefix,e.val())});f.insertBefore(c(b)); 4 | c(e).val(parseInt(e.val(),10)+1);l+=1;""!==g.val()&&0>=g.val()-e.val()&&m.parent().hide();f.find("a."+a.deleteCssClass).click(function(b){b.preventDefault();f.remove();--l;a.removed&&a.removed(f);c(document).trigger("formset:removed",[f,a.prefix]);b=c("."+a.formCssClass);c("#id_"+a.prefix+"-TOTAL_FORMS").val(b.length);(""===g.val()||0 0) { 26 | values.push(field.val()); 27 | } 28 | }); 29 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 30 | }; 31 | 32 | prepopulatedField.data('_changed', false); 33 | prepopulatedField.change(function() { 34 | prepopulatedField.data('_changed', true); 35 | }); 36 | 37 | if (!prepopulatedField.val()) { 38 | $(dependencies.join(',')).keyup(populate).change(populate).focus(populate); 39 | } 40 | }); 41 | }; 42 | })(django.jQuery); 43 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate.min.js: -------------------------------------------------------------------------------- 1 | (function(c){c.fn.prepopulate=function(e,f,g){return this.each(function(){var a=c(this),b=function(){if(!a.data("_changed")){var b=[];c.each(e,function(a,d){d=c(d);0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/djcelery/style.css: -------------------------------------------------------------------------------- 1 | .form-row.field-traceback p { 2 | font-family: monospace; 3 | white-space: pre; 4 | } 5 | -------------------------------------------------------------------------------- /templates/hostconfig.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | hosts 文件修改 4 |
    5 |
    6 |
    7 | /etc/hosts 文件修改 8 | 注意:须由熟悉配置人员修改 9 |      {% if info%} Success!! {{ now }} {% endif %} 10 |
    /etc/hosts
    11 | 12 |

    13 | 14 | 15 |
    16 |
    17 | 18 |
    19 | 20 | --------------------------------------------------------------------------------