mirror of
https://github.com/RobbieHan/sandboxMP.git
synced 2026-02-03 10:53:15 +08:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b58be33aac | ||
|
|
f1dde180fb | ||
|
|
6765fa8b66 | ||
|
|
ad74ed1802 | ||
|
|
a36f8d74f6 | ||
|
|
cea6fa7cba | ||
|
|
eb10ffe9be | ||
|
|
9c204933e8 | ||
|
|
371b1ebbe3 | ||
|
|
9d0bd95b69 | ||
|
|
4fbdc88743 | ||
|
|
860ae14d4c | ||
|
|
00f7112b67 | ||
|
|
ba936d7f9e | ||
|
|
c399b77703 | ||
|
|
894fe29e15 | ||
|
|
602edea8f8 | ||
|
|
9d149a6882 | ||
|
|
0b47673759 | ||
|
|
e2edef0af2 |
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.js linguist-language=python
|
||||
*.css linguist-language=python
|
||||
*.html linguist-language=python
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea
|
||||
3
.idea/dictionaries/RobbieHan.xml
generated
3
.idea/dictionaries/RobbieHan.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="RobbieHan" />
|
||||
</component>
|
||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (sandboxMP)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/sandboxMP.iml" filepath="$PROJECT_DIR$/.idea/sandboxMP.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
32
.idea/sandboxMP.iml
generated
32
.idea/sandboxMP.iml
generated
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="django" name="Django">
|
||||
<configuration>
|
||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||
<option name="settingsModule" value="sandboxMP/settings.py" />
|
||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||
<option name="environment" value="<map/>" />
|
||||
<option name="doNotUseTestRunner" value="false" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/../sandboxMP\templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
803
.idea/workspace.xml
generated
803
.idea/workspace.xml
generated
@@ -1,803 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="80da5b45-7eca-459a-bbe3-5443bc141768" name="Default" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/apps/system/urls.py" afterPath="$PROJECT_DIR$/apps/system/urls.py" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/system/views_role.py" afterPath="$PROJECT_DIR$/apps/system/views_role.py" />
|
||||
<change beforePath="$PROJECT_DIR$/db.sqlite3" afterPath="$PROJECT_DIR$/db.sqlite3" />
|
||||
<change beforePath="$PROJECT_DIR$/templates/system/role.html" afterPath="$PROJECT_DIR$/templates/system/role.html" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="DjangoConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)">
|
||||
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||
<file leaf-file-name="urls.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/urls.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="601">
|
||||
<caret line="38" column="0" lean-forward="true" selection-start-line="38" selection-start-column="0" selection-end-line="38" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#28#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="role_role2menu.html" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role_role2menu.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2097">
|
||||
<caret line="177" column="13" lean-forward="true" selection-start-line="177" selection-start-column="13" selection-end-line="177" selection-end-column="13" />
|
||||
<folding>
|
||||
<element signature="e#1424#1456#0#HTML" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="custom.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/apps/custom.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="221">
|
||||
<caret line="13" column="28" lean-forward="false" selection-start-line="13" selection-start-column="28" selection-end-line="13" selection-end-column="28" />
|
||||
<folding>
|
||||
<element signature="e#73#84#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="models.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/models.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="404">
|
||||
<caret line="32" column="84" lean-forward="false" selection-start-line="32" selection-start-column="84" selection-end-line="32" selection-end-column="84" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="views_role.py" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views_role.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="414">
|
||||
<caret line="92" column="32" lean-forward="true" selection-start-line="92" selection-start-column="32" selection-end-line="92" selection-end-column="32" />
|
||||
<folding>
|
||||
<element signature="e#78#89#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="role.html" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="217">
|
||||
<caret line="229" column="25" lean-forward="false" selection-start-line="229" selection-start-column="13" selection-end-line="229" selection-end-column="25" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Python Script" />
|
||||
<option value="HTML File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>reverse</find>
|
||||
<find>OA</find>
|
||||
</findStrings>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/templates/base-left.html" />
|
||||
<option value="$PROJECT_DIR$/templates/head-footer.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/models.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/mixin.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/system.html" />
|
||||
<option value="$PROJECT_DIR$/sandboxMP/urls.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/system_index.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/tests.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/structure/structure_create.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/structure/strueture_users.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/structure/strueture_user.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/structure/structure.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/structure/structure_user.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/users/user_create.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/users/user_detail.html" />
|
||||
<option value="$PROJECT_DIR$/templates/base-static.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/users/passwd_change.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/users/user.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views_user.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/forms.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views.menu.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/menu_form.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/apps.py" />
|
||||
<option value="$PROJECT_DIR$/sandboxMP/settings.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views_structure.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/menu_update.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/menu_list.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/role_create.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views_menu.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/role_update.html" />
|
||||
<option value="$PROJECT_DIR$/apps/custom.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/role_role2user.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views_role.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/role_role2menu.html" />
|
||||
<option value="$PROJECT_DIR$/apps/system/urls.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/role.html" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsGulpfileManager">
|
||||
<detection-done>true</detection-done>
|
||||
<sorting>DEFINITION_ORDER</sorting>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="-1448" />
|
||||
<option name="y" value="-8" />
|
||||
<option name="width" value="1456" />
|
||||
<option name="height" value="876" />
|
||||
</component>
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state>
|
||||
<expanded-state>
|
||||
<State>
|
||||
<id />
|
||||
</State>
|
||||
</expanded-state>
|
||||
<selected-state>
|
||||
<State>
|
||||
<id>AngularJS</id>
|
||||
</State>
|
||||
</selected-state>
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectView">
|
||||
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||
<flattenPackages />
|
||||
<showMembers />
|
||||
<showModules />
|
||||
<showLibraryContents />
|
||||
<hideEmptyPackages />
|
||||
<abbreviatePackageNames />
|
||||
<autoscrollToSource />
|
||||
<autoscrollFromSource />
|
||||
<sortByType />
|
||||
<manualOrder />
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scratches" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="sandboxMP" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="sandboxMP" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="sandboxMP" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="sandboxMP" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="apps" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="sandboxMP" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="sandboxMP" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="sandboxMP" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="sandboxMP" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="templates" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="system" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scope" />
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="DefaultHtmlFileTemplate" value="HTML File" />
|
||||
</component>
|
||||
<component name="PyConsoleOptionsProvider">
|
||||
<option name="myPythonConsoleState">
|
||||
<console-settings is-module-sdk="true">
|
||||
<option name="myUseModuleSdk" value="true" />
|
||||
</console-settings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates\system" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates\system\users" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates\system\structure" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\apps\system" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates\system" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\apps" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="sandboxMP" type="Python.DjangoServer" factoryName="Django server">
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
<env name="DJANGO_SETTINGS_MODULE" value="sandboxMP.settings" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="" />
|
||||
<option name="IS_MODULE_SDK" value="false" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<module name="sandboxMP" />
|
||||
<option name="launchJavascriptDebuger" value="false" />
|
||||
<option name="port" value="8000" />
|
||||
<option name="host" value="" />
|
||||
<option name="additionalOptions" value="" />
|
||||
<option name="browserUrl" value="" />
|
||||
<option name="runTestServer" value="false" />
|
||||
<option name="runNoReload" value="false" />
|
||||
<option name="useCustomRunCommand" value="false" />
|
||||
<option name="customRunCommand" value="" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="ShelveChangesManager" show_recycled="false">
|
||||
<option name="remove_strategy" value="false" />
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="80da5b45-7eca-459a-bbe3-5443bc141768" name="Default" comment="" />
|
||||
<created>1539589405377</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1539589405377</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TodoView">
|
||||
<todo-panel id="selected-file">
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
<todo-panel id="all">
|
||||
<are-packages-shown value="true" />
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="-1448" y="-8" width="1456" height="876" extended-state="6" />
|
||||
<layout>
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32882273" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24156693" sideWeight="0.5042644" order="7" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.270636" sideWeight="0.49573562" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32882273" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32882273" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Mongo Explorer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.21380244" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.20558739" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="SciView" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.18656716" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.21650879" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3297062" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24156693" sideWeight="0.5042644" order="7" side_tool="true" content_ui="tabs" />
|
||||
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.12948857" sideWeight="0.49573562" order="2" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3297062" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3297062" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="manage.py@sandboxMP" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.28073993" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Mongo Explorer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.3297062" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.20095949" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||
<window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="SciView" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.18656716" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.21650879" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<option name="time" value="24" />
|
||||
</breakpoint-manager>
|
||||
<watches-manager />
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/templates/base-left.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="483">
|
||||
<caret line="36" column="13" lean-forward="true" selection-start-line="36" selection-start-column="13" selection-end-line="36" selection-end-column="13" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="153">
|
||||
<caret line="9" column="58" lean-forward="true" selection-start-line="9" selection-start-column="58" selection-end-line="9" selection-end-column="58" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/system_index.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="12" column="0" lean-forward="true" selection-start-line="12" selection-start-column="0" selection-end-line="12" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/urls/conf.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="68">
|
||||
<caret line="11" column="15" lean-forward="true" selection-start-line="11" selection-start-column="15" selection-end-line="11" selection-end-column="15" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/tests.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="51">
|
||||
<caret line="3" column="0" lean-forward="false" selection-start-line="3" selection-start-column="0" selection-end-line="3" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="0">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/braces/views/_ajax.py" />
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/structure/structure_create.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="524">
|
||||
<caret line="89" column="11" lean-forward="true" selection-start-line="89" selection-start-column="11" selection-end-line="89" selection-end-column="11" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/structure/structure_user.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-15">
|
||||
<caret line="29" column="95" lean-forward="true" selection-start-line="29" selection-start-column="95" selection-end-line="29" selection-end-column="95" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/structure/structure.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="836">
|
||||
<caret line="238" column="22" lean-forward="false" selection-start-line="238" selection-start-column="22" selection-end-line="238" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/static/plugins/datatables/dataTables.const-1.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="68">
|
||||
<caret line="4" column="8" lean-forward="false" selection-start-line="4" selection-start-column="8" selection-end-line="4" selection-end-column="8" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/urls/resolvers.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="260">
|
||||
<caret line="220" column="33" lean-forward="true" selection-start-line="220" selection-start-column="33" selection-end-line="220" selection-end-column="33" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/users/user_create.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1396">
|
||||
<caret line="129" column="26" lean-forward="false" selection-start-line="129" selection-start-column="26" selection-end-line="129" selection-end-column="26" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/head-footer.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1598">
|
||||
<caret line="94" column="22" lean-forward="true" selection-start-line="94" selection-start-column="22" selection-end-line="94" selection-end-column="22" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/base-static.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="238">
|
||||
<caret line="14" column="73" lean-forward="true" selection-start-line="14" selection-start-column="73" selection-end-line="14" selection-end-column="73" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/users/user_detail.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="967">
|
||||
<caret line="191" column="14" lean-forward="false" selection-start-line="191" selection-start-column="14" selection-end-line="191" selection-end-column="14" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/users/passwd_change.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="459">
|
||||
<caret line="90" column="0" lean-forward="true" selection-start-line="90" selection-start-column="0" selection-end-line="90" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/contrib/auth/decorators.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-459">
|
||||
<caret line="9" column="57" lean-forward="false" selection-start-line="9" selection-start-column="57" selection-end-line="9" selection-end-column="57" />
|
||||
<folding>
|
||||
<element signature="e#0#27#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/sandboxMP/urls.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="493">
|
||||
<caret line="29" column="63" lean-forward="true" selection-start-line="29" selection-start-column="63" selection-end-line="30" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#633#665#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/db/models/base.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="238">
|
||||
<caret line="100" column="8" lean-forward="false" selection-start-line="100" selection-start-column="8" selection-end-line="100" selection-end-column="8" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/utils/encoding.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-1649">
|
||||
<caret line="121" column="4" lean-forward="false" selection-start-line="121" selection-start-column="4" selection-end-line="121" selection-end-column="4" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/contrib/flatpages/models.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="595">
|
||||
<caret line="39" column="22" lean-forward="false" selection-start-line="39" selection-start-column="22" selection-end-line="39" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/db/models/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-204">
|
||||
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#53#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/forms/models.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="230">
|
||||
<caret line="472" column="4" lean-forward="false" selection-start-line="472" selection-start-column="4" selection-end-line="472" selection-end-column="4" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/users/user.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="500">
|
||||
<caret line="67" column="35" lean-forward="true" selection-start-line="67" selection-start-column="35" selection-end-line="67" selection-end-column="35" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/users/login.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="170">
|
||||
<caret line="10" column="57" lean-forward="true" selection-start-line="10" selection-start-column="57" selection-end-line="10" selection-end-column="57" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/views/generic/__init__.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="187">
|
||||
<caret line="11" column="11" lean-forward="false" selection-start-line="11" selection-start-column="11" selection-end-line="11" selection-end-column="11" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/forms.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="432">
|
||||
<caret line="127" column="0" lean-forward="false" selection-start-line="127" selection-start-column="0" selection-end-line="127" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#73#82#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/mixin.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="119">
|
||||
<caret line="7" column="6" lean-forward="false" selection-start-line="7" selection-start-column="6" selection-end-line="7" selection-end-column="6" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views_user.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-815">
|
||||
<caret line="62" column="53" lean-forward="false" selection-start-line="62" selection-start-column="53" selection-end-line="62" selection-end-column="53" />
|
||||
<folding>
|
||||
<element signature="e#78#87#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/apps.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="85">
|
||||
<caret line="5" column="0" lean-forward="true" selection-start-line="5" selection-start-column="0" selection-end-line="5" selection-end-column="0" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/sandboxMP/settings.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="221">
|
||||
<caret line="56" column="38" lean-forward="true" selection-start-line="56" selection-start-column="38" selection-end-line="56" selection-end-column="38" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/menu_form.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1122">
|
||||
<caret line="66" column="49" lean-forward="false" selection-start-line="66" selection-start-column="49" selection-end-line="66" selection-end-column="49" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/views/generic/base.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="197">
|
||||
<caret line="130" column="33" lean-forward="true" selection-start-line="130" selection-start-column="4" selection-end-line="130" selection-end-column="33" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/shortcuts.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="342">
|
||||
<caret line="56" column="50" lean-forward="true" selection-start-line="56" selection-start-column="21" selection-end-line="56" selection-end-column="50" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/http/response.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-1063">
|
||||
<caret line="475" column="6" lean-forward="false" selection-start-line="475" selection-start-column="6" selection-end-line="475" selection-end-column="6" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views_structure.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="238">
|
||||
<caret line="14" column="5" lean-forward="false" selection-start-line="14" selection-start-column="5" selection-end-line="14" selection-end-column="5" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/menu_list.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="606">
|
||||
<caret line="160" column="11" lean-forward="true" selection-start-line="160" selection-start-column="11" selection-end-line="160" selection-end-column="11" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role_update.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="657">
|
||||
<caret line="80" column="14" lean-forward="false" selection-start-line="80" selection-start-column="14" selection-end-line="80" selection-end-column="14" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role_form.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="504">
|
||||
<caret line="70" column="11" lean-forward="true" selection-start-line="70" selection-start-column="11" selection-end-line="70" selection-end-column="11" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/views/generic/detail.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="272">
|
||||
<caret line="20" column="0" lean-forward="false" selection-start-line="20" selection-start-column="0" selection-end-line="25" selection-end-column="11" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/views/generic/edit.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="289">
|
||||
<caret line="69" column="39" lean-forward="true" selection-start-line="69" selection-start-column="39" selection-end-line="69" selection-end-column="39" />
|
||||
<folding>
|
||||
<element signature="e#559#654#0" expanded="false" />
|
||||
<element signature="e#690#758#0" expanded="false" />
|
||||
<element signature="e#798#864#0" expanded="false" />
|
||||
<element signature="e#915#1106#0" expanded="false" />
|
||||
<element signature="e#1147#1527#0" expanded="false" />
|
||||
<element signature="e#1568#1819#0" expanded="false" />
|
||||
<element signature="e#1861#1978#0" expanded="false" />
|
||||
<element signature="e#2022#2149#0" expanded="false" />
|
||||
<element signature="e#2201#2373#0" expanded="false" />
|
||||
<element signature="e#2554#3721#0" expanded="false" />
|
||||
<element signature="e#3762#3978#0" expanded="false" />
|
||||
<element signature="e#4019#4503#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views_menu.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="391">
|
||||
<caret line="23" column="0" lean-forward="true" selection-start-line="23" selection-start-column="0" selection-end-line="23" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#41#0" expanded="false" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/menu_update.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="223">
|
||||
<caret line="75" column="26" lean-forward="false" selection-start-line="75" selection-start-column="26" selection-end-line="75" selection-end-column="26" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role_role2user.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="563">
|
||||
<caret line="98" column="20" lean-forward="false" selection-start-line="98" selection-start-column="20" selection-end-line="98" selection-end-column="20" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/urls.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="601">
|
||||
<caret line="38" column="0" lean-forward="true" selection-start-line="38" selection-start-column="0" selection-end-line="38" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#28#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/custom.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="221">
|
||||
<caret line="13" column="28" lean-forward="false" selection-start-line="13" selection-start-column="28" selection-end-line="13" selection-end-column="28" />
|
||||
<folding>
|
||||
<element signature="e#73#84#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role_role2menu.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="2097">
|
||||
<caret line="177" column="13" lean-forward="true" selection-start-line="177" selection-start-column="13" selection-end-line="177" selection-end-column="13" />
|
||||
<folding>
|
||||
<element signature="e#1424#1456#0#HTML" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/models.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="404">
|
||||
<caret line="32" column="84" lean-forward="false" selection-start-line="32" selection-start-column="84" selection-end-line="32" selection-end-column="84" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views_role.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="414">
|
||||
<caret line="92" column="32" lean-forward="true" selection-start-line="92" selection-start-column="32" selection-end-line="92" selection-end-column="32" />
|
||||
<folding>
|
||||
<element signature="e#78#89#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/role.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="217">
|
||||
<caret line="229" column="25" lean-forward="false" selection-start-line="229" selection-start-column="13" selection-end-line="229" selection-end-column="25" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="masterDetails">
|
||||
<states>
|
||||
<state key="ScopeChooserConfigurable.UI">
|
||||
<settings>
|
||||
<splitter-proportions>
|
||||
<option name="proportions">
|
||||
<list>
|
||||
<option value="0.2" />
|
||||
</list>
|
||||
</option>
|
||||
</splitter-proportions>
|
||||
</settings>
|
||||
</state>
|
||||
</states>
|
||||
</component>
|
||||
</project>
|
||||
Binary file not shown.
1
apps/cmdb/__init__.py
Normal file
1
apps/cmdb/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
default_app_config = 'cmdb.apps.CmdbConfig'
|
||||
3
apps/cmdb/admin.py
Normal file
3
apps/cmdb/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
8
apps/cmdb/apps.py
Normal file
8
apps/cmdb/apps.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CmdbConfig(AppConfig):
|
||||
name = 'cmdb'
|
||||
|
||||
def ready(self):
|
||||
from .signals import auto_delete_file
|
||||
99
apps/cmdb/forms.py
Normal file
99
apps/cmdb/forms.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# @Time : 2018/12/19 16:13
|
||||
# @Author : RobbieHan
|
||||
# @File : forms.py
|
||||
|
||||
from django import forms
|
||||
|
||||
from .models import Code, DeviceInfo, ConnectionInfo
|
||||
|
||||
|
||||
class CodeCreateForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Code
|
||||
fields = '__all__'
|
||||
|
||||
error_messages = {
|
||||
'key': {'required': 'key不能为空'},
|
||||
'value': {'required': 'value不能为空'}
|
||||
}
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(CodeCreateForm, self).clean()
|
||||
key = cleaned_data.get('key')
|
||||
value = cleaned_data.get('value')
|
||||
|
||||
if Code.objects.filter(key=key).count():
|
||||
raise forms.ValidationError('key:{}已存在'.format(key))
|
||||
|
||||
if Code.objects.filter(value=value).count():
|
||||
raise forms.ValidationError('value: {}已存在'.format(value))
|
||||
|
||||
|
||||
class CodeUpdateForm(CodeCreateForm):
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = self.cleaned_data
|
||||
key = cleaned_data.get('key')
|
||||
value = cleaned_data.get('value')
|
||||
|
||||
if self.instance:
|
||||
matching_code = Code.objects.exclude(pk=self.instance.pk)
|
||||
if matching_code.filter(key=key).exists():
|
||||
msg = 'key:{} 已经存在'.format(key)
|
||||
raise forms.ValidationError(msg)
|
||||
if matching_code.filter(value=value).exists():
|
||||
msg = 'value:{} 已经存在'.format(value)
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
|
||||
class DeviceCreateForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = DeviceInfo
|
||||
exclude = ['dev_connection']
|
||||
error_messages = {
|
||||
'hostname': {'required': '请填写设备地址'},
|
||||
'buyDate': {'required': '请填写购买日期'},
|
||||
'warrantyDate': {'required': '请填写到保日期'}
|
||||
}
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(DeviceCreateForm, self).clean()
|
||||
hostname = cleaned_data.get('hostname')
|
||||
|
||||
if DeviceInfo.objects.filter(hostname=hostname).count():
|
||||
raise forms.ValidationError('设备地址:{}已存在'.format(hostname))
|
||||
|
||||
|
||||
class DeviceUpdateForm(DeviceCreateForm):
|
||||
def clean(self):
|
||||
cleaned_data = self.cleaned_data
|
||||
hostname = cleaned_data.get('hostname')
|
||||
|
||||
if self.instance:
|
||||
matching_device = DeviceInfo.objects.exclude(pk=self.instance.pk)
|
||||
if matching_device.filter(hostname=hostname).exists():
|
||||
raise forms.ValidationError('设备地址:{}已存在'.format(hostname))
|
||||
|
||||
|
||||
class ConnectionInfoForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ConnectionInfo
|
||||
fields = '__all__'
|
||||
|
||||
error_messages = {
|
||||
'port': {'required': '端口不能为空'},
|
||||
}
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = self.cleaned_data
|
||||
username = cleaned_data.get('username')
|
||||
password = cleaned_data.get('password')
|
||||
private_key = cleaned_data.get('private_key')
|
||||
auth_type = cleaned_data.get('auth_type')
|
||||
if len(username) == 0:
|
||||
raise forms.ValidationError('用户名不能为空!')
|
||||
if auth_type == 'password' and len(password) == 0:
|
||||
raise forms.ValidationError('认证类型为[密码]时,必须设置密码信息!')
|
||||
if auth_type == 'private_key' and len(private_key) == 0:
|
||||
raise forms.ValidationError('认证类型为[密钥]时,必须设置密钥信息!')
|
||||
0
apps/cmdb/migrations/__init__.py
Normal file
0
apps/cmdb/migrations/__init__.py
Normal file
122
apps/cmdb/models.py
Normal file
122
apps/cmdb/models.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class AbstractMode(models.Model):
|
||||
parent = models.ForeignKey(
|
||||
'self', blank=True, null=True, on_delete=models.SET_NULL, related_name='child'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class Code(AbstractMode):
|
||||
key = models.CharField(max_length=80, verbose_name='键')
|
||||
value = models.CharField(max_length=80, verbose_name='值')
|
||||
desc = models.CharField(max_length=100, blank=True, default='', verbose_name='备注')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '字典'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class TimeAbstract(models.Model):
|
||||
add_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
|
||||
modify_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class ConnectionAbstract(models.Model):
|
||||
auth_method_choices = (
|
||||
('private_key', '密钥认证'),
|
||||
('password', '密码认证')
|
||||
)
|
||||
hostname = models.CharField(max_length=50, verbose_name='设备地址(IP或域名)')
|
||||
port = models.IntegerField(default=22, verbose_name='SSH端口')
|
||||
username = models.CharField(max_length=15, blank=True, default='', verbose_name='SSH用户名')
|
||||
password = models.CharField(max_length=80, blank=True, default='', verbose_name='SSH密码')
|
||||
private_key = models.CharField(max_length=100, blank=True, default='', verbose_name='密钥路径')
|
||||
auth_type = models.CharField(max_length=30, choices=auth_method_choices, default='')
|
||||
status = models.CharField(max_length=10, blank=True, default='')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class DeviceAbstract(models.Model):
|
||||
sys_hostname = models.CharField(max_length=150, blank=True, default='', verbose_name='主机名')
|
||||
mac_address = models.CharField(max_length=150, blank=True, default='', verbose_name='MAC地址')
|
||||
sn_number = models.CharField(max_length=150, blank=True, default='', verbose_name='SN号码')
|
||||
os_type = models.CharField(max_length=150, blank=True, default='', verbose_name='系统类型')
|
||||
device_type = models.CharField(max_length=150, blank=True, default='', verbose_name='设备类型')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class DeviceScanInfo(ConnectionAbstract, DeviceAbstract, TimeAbstract):
|
||||
error_message = models.CharField(max_length=80, blank=True, default='', verbose_name='错误信息')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '扫描信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class ConnectionInfo(ConnectionAbstract, TimeAbstract):
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'SSH连接信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class Cabinet(models.Model):
|
||||
number = models.CharField(max_length=50, verbose_name='机柜编号')
|
||||
position = models.CharField(max_length=80, verbose_name='机柜位置')
|
||||
desc = models.TextField(blank=True, default='', verbose_name='备注信息')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '机柜信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
class DeviceInfo(AbstractMode, DeviceAbstract, TimeAbstract):
|
||||
hostname = models.CharField(max_length=50, verbose_name='设备地址(IP或域名)')
|
||||
network_type = models.IntegerField(blank=True, null=True, verbose_name='网络类型')
|
||||
service_type = models.IntegerField(blank=True, null=True, verbose_name='服务类型')
|
||||
operation_type = models.IntegerField(blank=True, null=True, verbose_name='业务类型')
|
||||
leader = models.IntegerField(blank=True, null=True, verbose_name='责任人')
|
||||
dev_cabinet = models.IntegerField(blank=True, null=True, verbose_name='机柜信息')
|
||||
dev_connection = models.IntegerField(blank=True, null=True, verbose_name='连接信息')
|
||||
buyDate = models.DateField(default=datetime.now, verbose_name="购买日期")
|
||||
warrantyDate = models.DateField(default=datetime.now, verbose_name="到保日期")
|
||||
desc = models.TextField(blank=True, default='', verbose_name='备注信息')
|
||||
changed_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
history = HistoricalRecords(excluded_fields=['add_time', 'modify_time', 'parent'])
|
||||
|
||||
class Meta:
|
||||
verbose_name = '设备信息'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
self.changed_by = value
|
||||
|
||||
|
||||
class DeviceFile(TimeAbstract):
|
||||
device = models.ForeignKey('DeviceInfo', blank=True, null=True, on_delete=models.SET_NULL, verbose_name='设备')
|
||||
file_content = models.FileField(upload_to="asset_file/%Y/%m", null=True, blank=True, verbose_name="资产文件")
|
||||
upload_user = models.CharField(max_length=20, verbose_name="上传人")
|
||||
|
||||
39
apps/cmdb/signals.py
Normal file
39
apps/cmdb/signals.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import os
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
|
||||
from .models import DeviceFile, DeviceInfo
|
||||
from utils.db_utils import MongodbDriver
|
||||
|
||||
|
||||
@receiver(post_delete, sender=DeviceFile)
|
||||
def auto_delete_file(sender, instance, **kwargs):
|
||||
if instance.file_content:
|
||||
if os.path.isfile(instance.file_content.path):
|
||||
os.remove(instance.file_content.path)
|
||||
|
||||
|
||||
@receiver(post_save, sender=DeviceInfo)
|
||||
def auto_compare_diff(sender, instance, **kwargs):
|
||||
record = instance.history.latest()
|
||||
prev_record = record.prev_record
|
||||
ope_type = {'~': 'update', '+': 'create', '-': 'delete'}
|
||||
compare_result = {
|
||||
'id': record.id,
|
||||
'changed_by': record.changed_by.name,
|
||||
'history_type': ope_type[record.history_type],
|
||||
'history_date': record.history_date
|
||||
}
|
||||
changes = {}
|
||||
if prev_record is not None:
|
||||
delta = record.diff_against(prev_record)
|
||||
for change in delta.changes:
|
||||
changes[change.field] = [change.old, change.new]
|
||||
compare_result['changes'] = changes
|
||||
if compare_result['changes'] or compare_result['history_type'] == 'create':
|
||||
try:
|
||||
mongo = MongodbDriver(collection='change_compare')
|
||||
mongo.insert(compare_result)
|
||||
except Exception as e:
|
||||
pass
|
||||
56
apps/cmdb/tasks.py
Normal file
56
apps/cmdb/tasks.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import time
|
||||
import logging
|
||||
|
||||
from celery import shared_task
|
||||
from celery_once import QueueOnce
|
||||
|
||||
from utils.sandbox_utils import SandboxScan, LoginExecution
|
||||
from .models import DeviceScanInfo
|
||||
|
||||
info_logger = logging.getLogger('sandbox_info')
|
||||
|
||||
|
||||
@shared_task(base=QueueOnce)
|
||||
def scan_execution():
|
||||
scan = SandboxScan()
|
||||
execution = LoginExecution()
|
||||
scan_type = execution.get_scan_type()
|
||||
auth_type = execution.get_auth_type()
|
||||
start_time = time.time()
|
||||
if scan_type == 'basic_scan':
|
||||
hosts = scan.basic_scan()
|
||||
for host in hosts:
|
||||
DeviceScanInfo.objects.update_or_create(
|
||||
hostname=host,
|
||||
)
|
||||
else:
|
||||
hosts = scan.os_scan()
|
||||
login_hosts = [host for host in hosts if host['os'] in ['Linux', 'embedded']]
|
||||
nologin_hosts = [host for host in hosts if host not in login_hosts]
|
||||
for host in nologin_hosts:
|
||||
DeviceScanInfo.objects.update_or_create(
|
||||
hostname=host['host'],
|
||||
defaults={
|
||||
'os_type': host['os']
|
||||
}
|
||||
)
|
||||
for host in login_hosts:
|
||||
kwargs = {
|
||||
'hostname': host['host'],
|
||||
'username': execution.get_ssh_username(),
|
||||
'port': execution.get_ssh_port(),
|
||||
'password': execution.get_ssh_password(),
|
||||
'private_key': execution.get_ssh_private_key()
|
||||
}
|
||||
defaults = execution.login_execution(auth_type=auth_type, **kwargs)
|
||||
DeviceScanInfo.objects.update_or_create(
|
||||
hostname=host['host'],
|
||||
defaults=defaults
|
||||
)
|
||||
end_time = time.time()
|
||||
msg = 'Scan task has been completed, execution time: %(time)s, %(num)s hosts are up.' % {
|
||||
'time': end_time - start_time,
|
||||
'num': len(hosts)
|
||||
}
|
||||
info_logger.info(msg)
|
||||
return msg
|
||||
22
apps/cmdb/tests.py
Normal file
22
apps/cmdb/tests.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
from django.views.generic.base import View
|
||||
from django.shortcuts import HttpResponse
|
||||
import logging
|
||||
from .models import Code
|
||||
|
||||
info_logger = logging.getLogger('sandbox_info')
|
||||
error_logger = logging.getLogger('sandbox_error')
|
||||
|
||||
|
||||
class TestLoggingView(View):
|
||||
|
||||
def get(self, request):
|
||||
print('a')
|
||||
info_logger.info('The system print a letter "a" ')
|
||||
try:
|
||||
Code.objects.get(id=100)
|
||||
except Exception as e:
|
||||
error_logger.error(e)
|
||||
return HttpResponse("OK!")
|
||||
36
apps/cmdb/urls.py
Normal file
36
apps/cmdb/urls.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import CmdbView
|
||||
from . import views_code, views_scan, views_eam
|
||||
|
||||
app_name = 'cmdb'
|
||||
|
||||
urlpatterns = [
|
||||
path('', CmdbView.as_view(), name='index'),
|
||||
path('portal/code/', views_code.CodeView.as_view(), name='portal-code'),
|
||||
path('portal/code/create/', views_code.CodeCreateView.as_view(), name='portal-code-create'),
|
||||
path('portal/code/list/', views_code.CodeListView.as_view(), name='portal-code-list'),
|
||||
path('portal/code/update/', views_code.CodeUpdateView.as_view(), name='portal-code-update'),
|
||||
path('portal/code/delete/', views_code.CodeDeleteView.as_view(), name='portal-code-delete'),
|
||||
|
||||
path('portal/scan_config/', views_scan.ScanConfigView.as_view(), name='portal-scan_config'),
|
||||
path('portal/device_scan/', views_scan.DeviceScanView.as_view(), name='portal-device_scan'),
|
||||
path('portal/device_scan/list/', views_scan.DeviceScanListView.as_view(), name='portal-device_scan-list'),
|
||||
path('portal/device_scan/detail/', views_scan.DeviceScanDetailView.as_view(), name='portal-device_scan-detail'),
|
||||
path('portal/device_scan/delete/', views_scan.DeviceScanDeleteView.as_view(), name='portal-device_scan-delete'),
|
||||
path('portal/device_scan/exec/', views_scan.DeviceScanExecView.as_view(), name='portal-device_scan-exec'),
|
||||
path('portal/device_scan/inbound/', views_scan.DeviceScanInboundView.as_view(), name='portal-device_scan-inbound'),
|
||||
|
||||
path('eam/cabinet/', views_eam.CabinetView.as_view(), name='eam-cabinet'),
|
||||
path('eam/cabinet/create/', views_eam.CabinetCreateView.as_view(), name='eam-cabinet-create'),
|
||||
path('eam/cabinet/update/', views_eam.CabinetUpdateView.as_view(), name='eam-cabinet-update'),
|
||||
path('eam/cabinet/list/', views_eam.CabinetListView.as_view(), name='eam-cabinet-list'),
|
||||
path('eam/cabinet/delete/', views_eam.CabinetDeleteView.as_view(), name='eam-cabinet-delete'),
|
||||
|
||||
path('eam/device/', views_eam.DeviceView.as_view(), name='eam-device'),
|
||||
path('eam/device/create/', views_eam.DeviceCreateView.as_view(), name='eam-device-create'),
|
||||
path('eam/device/update/', views_eam.DeviceUpdateView.as_view(), name='eam-device-update'),
|
||||
path('eam/device/list/', views_eam.DeviceListView.as_view(), name='eam-device-list'),
|
||||
path('eam/device/delete/', views_eam.DeviceDeleteView.as_view(), name='eam-device-delete'),
|
||||
path('eam/device/device2connection/', views_eam.Device2ConnectionView.as_view(), name='eam-device-device2connection'),
|
||||
]
|
||||
9
apps/cmdb/views.py
Normal file
9
apps/cmdb/views.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from system.mixin import LoginRequiredMixin
|
||||
from custom import BreadcrumbMixin
|
||||
|
||||
|
||||
class CmdbView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
|
||||
template_name = 'cmdb/cmdb_index.html'
|
||||
53
apps/cmdb/views_code.py
Normal file
53
apps/cmdb/views_code.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# @Time : 2018/12/19 13:31
|
||||
# @Author : RobbieHan
|
||||
# @File : views_code.py.py
|
||||
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from system.mixin import LoginRequiredMixin
|
||||
from custom import (BreadcrumbMixin, SandboxCreateView,
|
||||
SandboxListView, SandboxUpdateView, SandboxDeleteView)
|
||||
from .models import Code
|
||||
from .forms import CodeCreateForm, CodeUpdateForm
|
||||
|
||||
|
||||
class CodeView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'cmdb/code.html'
|
||||
|
||||
def get_context_data(self):
|
||||
self.kwargs['code_parent'] = Code.objects.filter(parent=None)
|
||||
return super().get_context_data(**self.kwargs)
|
||||
|
||||
|
||||
class CodeCreateView(SandboxCreateView):
|
||||
model = Code
|
||||
form_class = CodeCreateForm
|
||||
template_name_suffix = '_create'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['code_parent'] = Code.objects.filter(parent=None)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class CodeListView(SandboxListView):
|
||||
model = Code
|
||||
fields = ['id', 'key', 'value', 'parent__value']
|
||||
|
||||
def get(self, request):
|
||||
if 'parent' in request.GET and request.GET['parent']:
|
||||
self.filters = dict(parent__key=request.GET['parent'])
|
||||
return super().get(request)
|
||||
|
||||
|
||||
class CodeUpdateView(SandboxUpdateView):
|
||||
model = Code
|
||||
form_class = CodeUpdateForm
|
||||
template_name_suffix = '_update'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['code_parent'] = Code.objects.filter(parent=None)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class CodeDeleteView(SandboxDeleteView):
|
||||
model = Code
|
||||
160
apps/cmdb/views_eam.py
Normal file
160
apps/cmdb/views_eam.py
Normal file
@@ -0,0 +1,160 @@
|
||||
import re
|
||||
|
||||
from django.views.generic import TemplateView, View
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from system.mixin import LoginRequiredMixin
|
||||
from custom import (BreadcrumbMixin, SandboxDeleteView,
|
||||
SandboxListView, SandboxUpdateView, SandboxCreateView)
|
||||
from .models import Cabinet, DeviceInfo, Code, ConnectionInfo
|
||||
from .forms import DeviceCreateForm, DeviceUpdateForm, ConnectionInfoForm
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class CabinetView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'cmdb/cabinet.html'
|
||||
|
||||
|
||||
class CabinetCreateView(SandboxCreateView):
|
||||
model = Cabinet
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CabinetUpdateView(SandboxUpdateView):
|
||||
model = Cabinet
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class CabinetListView(SandboxListView):
|
||||
model = Cabinet
|
||||
fields = ['id', 'number', 'position', 'desc']
|
||||
|
||||
def get_filters(self):
|
||||
data = self.request.GET
|
||||
filters = {}
|
||||
if 'number' in data and data['number']:
|
||||
filters['number__icontains'] = data['number']
|
||||
if 'position' in data and data['position']:
|
||||
filters['position__icontains'] = data['position']
|
||||
return filters
|
||||
|
||||
|
||||
class CabinetDeleteView(SandboxDeleteView):
|
||||
model = Cabinet
|
||||
|
||||
|
||||
def get_device_public():
|
||||
all_code = Code.objects.all()
|
||||
all_cabinet = Cabinet.objects.all()
|
||||
all_user = User.objects.all()
|
||||
all_device = DeviceInfo.objects.all()
|
||||
ret = {
|
||||
'all_code': all_code,
|
||||
'all_cabinet': all_cabinet,
|
||||
'all_user': all_user,
|
||||
'all_device': all_device,
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
class DeviceView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'cmdb/deviceinfo.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
device_public = get_device_public()
|
||||
kwargs.update(device_public)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class DeviceListView(SandboxListView):
|
||||
model = DeviceInfo
|
||||
fields = ['id', 'sys_hostname', 'sn_number', 'os_type', 'device_type', 'hostname', 'mac_address', 'leader']
|
||||
|
||||
def get_filters(self):
|
||||
data = self.request.GET
|
||||
filters = {}
|
||||
if 'sys_hostname' in data and data['sys_hostname']:
|
||||
filters['sys_hostname__icontains'] = data['sys_hostname']
|
||||
if 'hostname' in data and data['hostname']:
|
||||
filters['hostname__icontains'] = data['hostname']
|
||||
if 'network_type' in data and data['network_type']:
|
||||
filters['network_type'] = data['network_type']
|
||||
if 'service_type' in data and data['service_type']:
|
||||
filters['service_type'] = data['service_type']
|
||||
if 'operation_type' in data and data['operation_type']:
|
||||
filters['operation_type'] = data['operation_type']
|
||||
return filters
|
||||
|
||||
def get_datatables_paginator(self, request):
|
||||
context_data = super().get_datatables_paginator(request)
|
||||
data = context_data['data']
|
||||
for device in data:
|
||||
user_id = device['leader']
|
||||
device['leader'] = get_object_or_404(
|
||||
User, pk=int(user_id)).name if user_id else ''
|
||||
return context_data
|
||||
|
||||
|
||||
class DeviceCreateView(SandboxCreateView):
|
||||
model = DeviceInfo
|
||||
form_class = DeviceCreateForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
public_data = get_device_public()
|
||||
kwargs.update(public_data)
|
||||
print(public_data)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class DeviceUpdateView(SandboxUpdateView):
|
||||
model = DeviceInfo
|
||||
form_class = DeviceUpdateForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
public_data = get_device_public()
|
||||
kwargs.update(public_data)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class DeviceDeleteView(SandboxDeleteView):
|
||||
model = DeviceInfo
|
||||
|
||||
|
||||
class Device2ConnectionView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
ret = dict()
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
device = get_object_or_404(DeviceInfo, pk=int(request.GET['id']))
|
||||
ret['device'] = device
|
||||
dev_connection = device.dev_connection
|
||||
if dev_connection:
|
||||
connection_info = get_object_or_404(
|
||||
ConnectionInfo, pk=int(dev_connection)
|
||||
)
|
||||
ret['connection_info'] = connection_info
|
||||
return render(request, 'cmdb/deviceinfo2connection.html', ret)
|
||||
|
||||
def post(self, request):
|
||||
res = dict(result=False)
|
||||
con_info = ConnectionInfo()
|
||||
if 'id' in request.POST and request.POST['id']:
|
||||
con_info = get_object_or_404(ConnectionInfo, pk=request.POST['id'])
|
||||
form = ConnectionInfoForm(request.POST, instance=con_info)
|
||||
if form.is_valid():
|
||||
instance = form.save()
|
||||
con_id = getattr(instance, 'id')
|
||||
device = get_object_or_404(DeviceInfo, hostname=request.POST['hostname'])
|
||||
device.dev_connection = con_id
|
||||
device.save()
|
||||
res['result'] = True
|
||||
else:
|
||||
pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
|
||||
form_errors = str(form.errors)
|
||||
errors = re.findall(pattern, form_errors)
|
||||
res['error'] = errors[0]
|
||||
return JsonResponse(res)
|
||||
118
apps/cmdb/views_scan.py
Normal file
118
apps/cmdb/views_scan.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# @Time : 2018/12/29 19:25
|
||||
# @Author : RobbieHan
|
||||
# @File : views_scan.py
|
||||
|
||||
import ast
|
||||
import logging
|
||||
from ruamel import yaml
|
||||
|
||||
from django.views.generic import View, TemplateView
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
|
||||
from celery_once import AlreadyQueued
|
||||
|
||||
from system.mixin import LoginRequiredMixin
|
||||
from custom import BreadcrumbMixin, SandboxListView, SandboxDeleteView
|
||||
from utils.sandbox_utils import ConfigFileMixin
|
||||
from system.models import Menu
|
||||
from .models import (DeviceScanInfo, ConnectionInfo, DeviceInfo,
|
||||
ConnectionAbstract, DeviceAbstract)
|
||||
from .tasks import scan_execution
|
||||
|
||||
error_logger = logging.getLogger('sandbox_error')
|
||||
|
||||
|
||||
class ScanConfigView(LoginRequiredMixin, BreadcrumbMixin, ConfigFileMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
menu = Menu.get_menu_by_request_url(request.path_info)
|
||||
template_name = 'cmdb/scan_config.html'
|
||||
context = self.get_conf_content()
|
||||
context.update(menu)
|
||||
return render(request, template_name, context)
|
||||
|
||||
def post(self, request):
|
||||
ret = dict(result=False)
|
||||
config = dict()
|
||||
hosts = request.POST
|
||||
try:
|
||||
config['net_address'] = ast.literal_eval(hosts['net_address'])
|
||||
config['ssh_username'] = hosts['ssh_username']
|
||||
config['ssh_port'] = hosts['ssh_port']
|
||||
config['ssh_password'] = hosts['ssh_password']
|
||||
config['ssh_private_key'] = hosts['ssh_private_key']
|
||||
config['commands'] = ast.literal_eval(hosts['commands'])
|
||||
config['auth_type'] = hosts['auth_type']
|
||||
config['scan_type'] = hosts['scan_type']
|
||||
config['email'] = hosts['email']
|
||||
config['send_email'] = hosts['send_email']
|
||||
data = dict(hosts=config)
|
||||
config_file = self.get_config_file()
|
||||
with open(config_file, 'w', encoding='utf-8') as f:
|
||||
yaml.dump(data, f, Dumper=yaml.RoundTripDumper, indent=4)
|
||||
ret['result'] = True
|
||||
except Exception as e:
|
||||
error_logger.error(e)
|
||||
|
||||
return JsonResponse(ret)
|
||||
|
||||
|
||||
class DeviceScanView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'cmdb/device_scan.html'
|
||||
|
||||
|
||||
class DeviceScanListView(SandboxListView):
|
||||
model = DeviceScanInfo
|
||||
fields = ['id', 'sys_hostname', 'hostname', 'mac_address', 'auth_type', 'status', 'os_type', 'device_type']
|
||||
|
||||
|
||||
class DeviceScanDetailView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
ret = Menu.get_menu_by_request_url(request.path_info)
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
device = get_object_or_404(DeviceScanInfo, pk=int(request.GET['id']))
|
||||
ret['device'] = device
|
||||
return render(request, 'cmdb/device_scan_detail.html', ret)
|
||||
|
||||
|
||||
class DeviceScanDeleteView(SandboxDeleteView):
|
||||
model = DeviceScanInfo
|
||||
|
||||
|
||||
class DeviceScanExecView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, request):
|
||||
ret = dict(status='fail')
|
||||
try:
|
||||
scan_execution.delay()
|
||||
ret['status'] = 'success'
|
||||
except AlreadyQueued:
|
||||
ret['status'] = 'already_queued'
|
||||
return JsonResponse(ret)
|
||||
|
||||
|
||||
class DeviceScanInboundView(LoginRequiredMixin, View):
|
||||
def post(self, request):
|
||||
ret = dict(result=False)
|
||||
login_succeed = list(DeviceScanInfo.objects.filter(status='succeed').values())
|
||||
connection_fields = [field.name for field in ConnectionAbstract._meta.fields if field.name is not 'id']
|
||||
device_fields = [field.name for field in DeviceAbstract._meta.fields if field.name is not 'id']
|
||||
device_fields.append('hostname')
|
||||
for host in login_succeed:
|
||||
connection_defaults = {key: host[key] for key in host.keys() & connection_fields}
|
||||
device_defaults = {key: host[key] for key in host.keys() & device_fields}
|
||||
connection_info, _ = ConnectionInfo.objects.update_or_create(
|
||||
hostname=host['hostname'],
|
||||
defaults=connection_defaults
|
||||
)
|
||||
connection_id = int(getattr(connection_info, 'id'))
|
||||
device_defaults['dev_connection'] = connection_id
|
||||
device_defaults['changed_by_id'] = request.user.id
|
||||
DeviceInfo.objects.update_or_create(
|
||||
hostname=host['hostname'],
|
||||
defaults=device_defaults
|
||||
)
|
||||
ret['result'] = True
|
||||
return JsonResponse(ret)
|
||||
109
apps/custom.py
109
apps/custom.py
@@ -3,12 +3,25 @@
|
||||
# @File : custom.py
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from django.views.generic import CreateView, UpdateView
|
||||
from django.views.generic import CreateView, UpdateView, View
|
||||
from django.shortcuts import HttpResponse
|
||||
from django.http import Http404
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.db.models.query import QuerySet
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
from system.mixin import LoginRequiredMixin
|
||||
from system.models import Menu
|
||||
|
||||
|
||||
class BreadcrumbMixin:
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
menu = Menu.get_menu_by_request_url(url=self.request.path_info)
|
||||
if menu is not None:
|
||||
kwargs.update(menu)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class SandboxGetObjectMixin:
|
||||
@@ -32,6 +45,69 @@ class SandboxGetObjectMixin:
|
||||
return obj
|
||||
|
||||
|
||||
class SandboxMultipleObjectMixin:
|
||||
|
||||
filters = {}
|
||||
fields = []
|
||||
queryset = None
|
||||
model = None
|
||||
|
||||
def get_queryset(self):
|
||||
if self.queryset is not None:
|
||||
queryset = self.queryset
|
||||
if isinstance(queryset, QuerySet):
|
||||
queryset = queryset.all()
|
||||
elif self.model is not None:
|
||||
queryset = self.model._default_manager.all()
|
||||
else:
|
||||
raise ImproperlyConfigured(
|
||||
"%(cls)s is missing a QuerySet. Define "
|
||||
"%(cls)s.model, %(cls)s.queryset."
|
||||
% {'cls': self.__class__.__name__}
|
||||
)
|
||||
return queryset
|
||||
|
||||
def get_datatables_paginator(self, request):
|
||||
datatables = request.GET
|
||||
draw = int(datatables.get('draw'))
|
||||
start = int(datatables.get('start'))
|
||||
length = int(datatables.get('length'))
|
||||
order_column = datatables.get('order[0][column]')
|
||||
order_dir = datatables.get('order[0][dir]')
|
||||
order_field = datatables.get('columns[{}][data]'.format(order_column))
|
||||
queryset = self.get_queryset()
|
||||
if order_dir == 'asc':
|
||||
queryset = queryset.order_by(order_field)
|
||||
else:
|
||||
queryset = queryset.order_by('-{0}'.format(order_field))
|
||||
record_total_count = queryset.count()
|
||||
filters = self.get_filters()
|
||||
fields = self.get_fields()
|
||||
if filters:
|
||||
queryset = queryset.filter(**filters)
|
||||
if fields:
|
||||
queryset = queryset.values(*fields)
|
||||
|
||||
record_filter_count = queryset.count()
|
||||
|
||||
object_list = queryset[start:(start + length)]
|
||||
|
||||
data = list(object_list)
|
||||
|
||||
return {
|
||||
'draw': draw,
|
||||
'recordsTotal': record_total_count,
|
||||
'recordsFiltered': record_filter_count,
|
||||
'data': data,
|
||||
}
|
||||
|
||||
def get_filters(self):
|
||||
return self.filters
|
||||
|
||||
def get_fields(self):
|
||||
return self.fields
|
||||
|
||||
|
||||
class SandboxEditViewMixin:
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -40,6 +116,11 @@ class SandboxEditViewMixin:
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
res['result'] = True
|
||||
else:
|
||||
pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'
|
||||
form_errors = str(form.errors)
|
||||
errors = re.findall(pattern, form_errors)
|
||||
res['error'] = errors[0]
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
|
||||
|
||||
@@ -55,3 +136,27 @@ class SandboxUpdateView(LoginRequiredMixin, SandboxEditViewMixin, SandboxGetObje
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class SandboxListView(LoginRequiredMixin, SandboxMultipleObjectMixin, View):
|
||||
"""
|
||||
JsonResponse some json of objects, set by `self.model` or `self.queryset`.
|
||||
"""
|
||||
def get(self, request):
|
||||
context = self.get_datatables_paginator(request)
|
||||
return JsonResponse(context)
|
||||
|
||||
|
||||
class SandboxDeleteView(LoginRequiredMixin, SandboxMultipleObjectMixin, View):
|
||||
|
||||
def post(self, request):
|
||||
context = dict(result=False)
|
||||
queryset = self.get_queryset()
|
||||
if 'id' in request.POST and request.POST['id']:
|
||||
id_list = map(int, request.POST['id'].split(','))
|
||||
queryset.filter(id__in=id_list).delete()
|
||||
context['result'] = True
|
||||
else:
|
||||
raise AttributeError("Sandbox delete view %s must be called with id. "
|
||||
% self.__class__.__name__)
|
||||
return JsonResponse(context)
|
||||
@@ -0,0 +1 @@
|
||||
default_app_config = 'system.apps.SystemConfig'
|
||||
|
||||
BIN
apps/system/__pycache__/middleware.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/middleware.cpython-36.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -2,4 +2,10 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class SystemConfig(AppConfig):
|
||||
name = 'apps.system'
|
||||
name = 'system'
|
||||
|
||||
def ready(self):
|
||||
from .signals import create_menu
|
||||
from .signals import user_logged_in_handler
|
||||
from .signals import user_logged_out_handler
|
||||
from .signals import user_login_failed_handler
|
||||
|
||||
100
apps/system/middleware.py
Normal file
100
apps/system/middleware.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import re
|
||||
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
|
||||
|
||||
class MenuCollection(MiddlewareMixin):
|
||||
|
||||
def get_user(self, request):
|
||||
return request.user
|
||||
|
||||
def get_menu_from_role(self, request, user=None):
|
||||
if user is None:
|
||||
user = self.get_user(request)
|
||||
try:
|
||||
menus = user.roles.values(
|
||||
'permissions__id',
|
||||
'permissions__name',
|
||||
'permissions__url',
|
||||
'permissions__icon',
|
||||
'permissions__code',
|
||||
'permissions__parent'
|
||||
).distinct()
|
||||
return [menu for menu in menus if menu['permissions__id'] is not None]
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
def get_permission_url(self, request):
|
||||
role_menus = self.get_menu_from_role(request)
|
||||
if role_menus is not None:
|
||||
permission_url_list = [menu['permissions__url'] for menu in role_menus]
|
||||
return permission_url_list
|
||||
|
||||
def get_permission_menu(self, request):
|
||||
permission_menu_list = []
|
||||
role_menus = self.get_menu_from_role(request)
|
||||
if role_menus is not None:
|
||||
for item in role_menus:
|
||||
menu = {
|
||||
'id': item['permissions__id'],
|
||||
'name': item['permissions__name'],
|
||||
'url': item['permissions__url'],
|
||||
'icon': item['permissions__icon'],
|
||||
'code': item['permissions__code'],
|
||||
'parent': item['permissions__parent'],
|
||||
'status': False,
|
||||
'sub_menu': [],
|
||||
}
|
||||
permission_menu_list.append(menu)
|
||||
return permission_menu_list
|
||||
|
||||
def get_top_reveal_menu(self, request):
|
||||
top_menu = []
|
||||
permission_menu_dict = {}
|
||||
request_url = request.path_info
|
||||
permission_menu_list = self.get_permission_menu(request)
|
||||
if permission_menu_list is not None:
|
||||
for menu in permission_menu_list:
|
||||
|
||||
url = menu['url']
|
||||
if url and re.match(url, request_url):
|
||||
menu['status'] = True
|
||||
if menu['parent'] is None:
|
||||
top_menu.insert(0, menu)
|
||||
permission_menu_dict[menu['id']] = menu
|
||||
|
||||
menu_data = []
|
||||
for i in permission_menu_dict:
|
||||
if permission_menu_dict[i]['parent']:
|
||||
pid = permission_menu_dict[i]['parent']
|
||||
parent_menu = permission_menu_dict[pid]
|
||||
parent_menu['sub_menu'].append(permission_menu_dict[i])
|
||||
else:
|
||||
menu_data.append(permission_menu_dict[i])
|
||||
if [menu['sub_menu'] for menu in menu_data if menu['url'] in request_url]:
|
||||
reveal_menu = [menu['sub_menu'] for menu in menu_data if menu['url'] in request_url][0]
|
||||
else:
|
||||
reveal_menu = None
|
||||
return top_menu, reveal_menu
|
||||
|
||||
def process_request(self, request):
|
||||
if self.get_top_reveal_menu(request):
|
||||
request.top_menu, request.reveal_menu = self.get_top_reveal_menu(request)
|
||||
request.permission_url_list = self.get_permission_url(request)
|
||||
|
||||
|
||||
class RbacMiddleware(MiddlewareMixin):
|
||||
|
||||
def process_request(self, request):
|
||||
if hasattr(request, 'permission_url_list'):
|
||||
request_url = request.path_info
|
||||
permission_url = request.permission_url_list
|
||||
for url in settings.SAFE_URL:
|
||||
if re.match(url, request_url):
|
||||
return None
|
||||
if request_url in permission_url:
|
||||
return None
|
||||
else:
|
||||
return render(request, 'page404.html')
|
||||
22
apps/system/migrations/0002_auto_20181115_2124.py
Normal file
22
apps/system/migrations/0002_auto_20181115_2124.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 2.1.2 on 2018-11-15 21:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('system', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='menu',
|
||||
options={'ordering': ['number'], 'verbose_name': '菜单', 'verbose_name_plural': '菜单'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='menu',
|
||||
name='number',
|
||||
field=models.FloatField(blank=True, null=True, verbose_name='编号'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@@ -11,6 +11,7 @@ class Menu(models.Model):
|
||||
icon = models.CharField(max_length=50, null=True, blank=True, verbose_name="图标")
|
||||
code = models.CharField(max_length=50, null=True, blank=True, verbose_name="编码")
|
||||
url = models.CharField(max_length=128, unique=True, null=True, blank=True)
|
||||
number = models.FloatField(null=True, blank=True, verbose_name="编号")
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -18,10 +19,14 @@ class Menu(models.Model):
|
||||
class Meta:
|
||||
verbose_name = '菜单'
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ['number']
|
||||
|
||||
@classmethod
|
||||
def get_menu_by_request_url(cls, url):
|
||||
return dict(menu=Menu.objects.get(url=url))
|
||||
try:
|
||||
return dict(menu=Menu.objects.get(url=url))
|
||||
except:
|
||||
None
|
||||
|
||||
|
||||
class Role(models.Model):
|
||||
|
||||
50
apps/system/signals.py
Normal file
50
apps/system/signals.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import logging
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_save
|
||||
from django.contrib.auth.signals import user_logged_in, user_logged_out, user_login_failed
|
||||
|
||||
from .models import Role, Menu
|
||||
|
||||
error_logger = logging.getLogger('sandbox_error')
|
||||
info_logger = logging.getLogger('sandbox_info')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Menu)
|
||||
def create_menu(sender, instance, **kwargs):
|
||||
queryset = Role.objects.filter(id=1)
|
||||
try:
|
||||
admin_role = queryset.get()
|
||||
admin_role.permissions.add(instance)
|
||||
except queryset.model.DoesNotExist as e:
|
||||
error_logger.error(e)
|
||||
|
||||
|
||||
@receiver(user_logged_in)
|
||||
def user_logged_in_handler(sender, request, user, **kwargs):
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
msg = 'login user: {user}, remote ip: {ip}, action: login, status: successed'.format(
|
||||
user=user.username,
|
||||
ip=ip,
|
||||
)
|
||||
info_logger.info(msg)
|
||||
|
||||
|
||||
@receiver(user_logged_out)
|
||||
def user_logged_out_handler(sender, request, user, **kwargs):
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
msg = 'login user: {user}, remote ip: {ip}, action: logout, status: successed'.format(
|
||||
user=user.username,
|
||||
ip=ip,
|
||||
)
|
||||
info_logger.info(msg)
|
||||
|
||||
|
||||
@receiver(user_login_failed)
|
||||
def user_login_failed_handler(sender, credentials, request, **kwargs):
|
||||
msg = 'logout failed for: {credentials}'.format(
|
||||
credentials=credentials,
|
||||
)
|
||||
|
||||
info_logger.info(msg)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
from django.shortcuts import render
|
||||
from django.views.generic.base import View
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
from custom import BreadcrumbMixin
|
||||
|
||||
|
||||
class SystemView(LoginRequiredMixin, View):
|
||||
class SystemView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
|
||||
def get(self, request):
|
||||
return render(request, 'system/system_index.html')
|
||||
template_name = 'system/system_index.html'
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
from django.views.generic import ListView
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
from apps.custom import SandboxCreateView, SandboxUpdateView
|
||||
from apps.custom import SandboxCreateView, SandboxUpdateView, BreadcrumbMixin
|
||||
from .models import Menu
|
||||
|
||||
|
||||
class MenuCreateView(SandboxCreateView):
|
||||
model = Menu
|
||||
fields = '__all__'
|
||||
extra_context = dict(menu_all=Menu.objects.all())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['menu_all'] = Menu.objects.all()
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
|
||||
class MenuListView(LoginRequiredMixin, ListView):
|
||||
class MenuListView(LoginRequiredMixin, BreadcrumbMixin, ListView):
|
||||
model = Menu
|
||||
context_object_name = 'menu_all'
|
||||
|
||||
@@ -20,4 +23,7 @@ class MenuUpdateView(SandboxUpdateView):
|
||||
model = Menu
|
||||
fields = '__all__'
|
||||
template_name_suffix = '_update'
|
||||
extra_context = dict(menu_all=Menu.objects.all())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs['menu_all'] = Menu.objects.all()
|
||||
return super().get_context_data(**kwargs)
|
||||
|
||||
@@ -12,12 +12,12 @@ from django.shortcuts import render
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
from .models import Role, Menu
|
||||
from custom import SandboxCreateView, SandboxUpdateView
|
||||
from custom import SandboxCreateView, SandboxUpdateView, BreadcrumbMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class RoleView(LoginRequiredMixin, TemplateView):
|
||||
class RoleView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'system/role.html'
|
||||
|
||||
|
||||
|
||||
@@ -14,11 +14,12 @@ from django.contrib.auth import get_user_model
|
||||
from .mixin import LoginRequiredMixin
|
||||
from .models import Structure
|
||||
from .forms import StructureForm
|
||||
from apps.custom import BreadcrumbMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class StructureView(LoginRequiredMixin, TemplateView):
|
||||
class StructureView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
|
||||
template_name = 'system/structure/structure.html'
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from django.db.models import Q
|
||||
from .forms import LoginForm, UserCreateForm, UserUpdateForm, PasswordChangeForm
|
||||
from .mixin import LoginRequiredMixin
|
||||
from .models import Structure, Role
|
||||
from apps.custom import BreadcrumbMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
@@ -39,6 +40,7 @@ class LoginView(View):
|
||||
redirect_to = request.GET.get('next', '/')
|
||||
login_form = LoginForm(request.POST)
|
||||
ret = dict(login_form=login_form)
|
||||
print(request.META.get('REMOTE_ADDR'))
|
||||
if login_form.is_valid():
|
||||
user_name = request.POST['username']
|
||||
pass_word = request.POST['password']
|
||||
@@ -63,7 +65,7 @@ class LogoutView(View):
|
||||
return HttpResponseRedirect(reverse('login'))
|
||||
|
||||
|
||||
class UserView(LoginRequiredMixin, TemplateView):
|
||||
class UserView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'system/users/user.html'
|
||||
|
||||
|
||||
|
||||
3
apps/utils/__init__.py
Normal file
3
apps/utils/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# @Time : 2018/12/29 16:26
|
||||
# @Author : RobbieHan
|
||||
# @File : __init__.py.py
|
||||
18
apps/utils/db_utils.py
Normal file
18
apps/utils/db_utils.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import pymongo
|
||||
|
||||
|
||||
class MongodbDriver(object):
|
||||
|
||||
def __init__(self, db='device', collection='change_compare'):
|
||||
self.client = pymongo.MongoClient('127.0.0.1', 27017)
|
||||
self.db = self.client[db]
|
||||
self.col = self.db[collection]
|
||||
|
||||
def insert(self, content):
|
||||
return self.col.insert(content)
|
||||
|
||||
def find(self, sort_by, **filters,):
|
||||
data = self.col.find(filters)
|
||||
if sort_by:
|
||||
data.sort(sort_by, pymongo.DESCENDING)
|
||||
return data
|
||||
209
apps/utils/sandbox_utils.py
Normal file
209
apps/utils/sandbox_utils.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# @Time : 2018/12/29 19:22
|
||||
# @Author : RobbieHan
|
||||
# @File : sandbox_utils.py
|
||||
|
||||
import os
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
import yaml
|
||||
import logging
|
||||
import nmap
|
||||
import paramiko
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sandboxMP.settings')
|
||||
error_logger = logging.getLogger('sandbox_error')
|
||||
|
||||
|
||||
class ConfigFileMixin:
|
||||
config_file = None
|
||||
|
||||
def get_config_file(self):
|
||||
"""
|
||||
Return 'config_file' that will be used to look up the scan hosts IP,
|
||||
network, range of IP, or other config settings.
|
||||
This method is called by the default implementation of get_hosts(),
|
||||
"""
|
||||
|
||||
if self.config_file is None:
|
||||
config_file = os.path.join(os.path.join(settings.BASE_DIR, 'config'), 'scanhosts.yml')
|
||||
if os.path.exists(config_file):
|
||||
return config_file
|
||||
else:
|
||||
msg = ' %(cls)s is missing a config file. Define %(cls)s.config_file, ' \
|
||||
'or override %(cls)s.get_config_file().' % {'cls': self.__class__.__name__}
|
||||
error_logger.error(msg)
|
||||
raise ValueError(msg)
|
||||
|
||||
return self.config_file
|
||||
|
||||
def get_conf_content(self, *key):
|
||||
"""
|
||||
Get the configuration content from config file .
|
||||
Example ssh_password, commands, email which is in the config file.
|
||||
"""
|
||||
_config = self.get_config_file()
|
||||
with open(_config) as f:
|
||||
content = yaml.load(f)
|
||||
if key is not None:
|
||||
try:
|
||||
num = 0
|
||||
while num < len(key):
|
||||
content = content[key[num]]
|
||||
num += 1
|
||||
except Exception as e:
|
||||
msg = '%(exc)s is not in %(config)s.' % {
|
||||
'exc': e,
|
||||
'config': _config
|
||||
}
|
||||
error_logger.error(msg)
|
||||
raise ValueError(msg)
|
||||
return content
|
||||
|
||||
def get_commands(self):
|
||||
"""
|
||||
Get the commands from config file.
|
||||
"""
|
||||
key = ['hosts', 'commands']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_net_address(self):
|
||||
"""
|
||||
Return the hosts that will be used to scan.
|
||||
Subclasses can override this to return any hosts.
|
||||
"""
|
||||
key = ['hosts', 'net_address']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
|
||||
class SandboxScan(ConfigFileMixin):
|
||||
|
||||
def basic_scan(self):
|
||||
"""
|
||||
Use ICMP discovery online hosts and return online hosts.
|
||||
"""
|
||||
hosts = self.get_net_address()
|
||||
nm = nmap.PortScanner()
|
||||
nm.scan(hosts=hosts, arguments='-n -sP -PE')
|
||||
online_hosts = nm.all_hosts()
|
||||
return online_hosts
|
||||
|
||||
def os_scan(self):
|
||||
"""
|
||||
Get the system type by nmap scan and return hosts list with os type.
|
||||
"""
|
||||
hosts = self.get_net_address()
|
||||
nm = nmap.PortScanner()
|
||||
nm.scan(hosts=hosts, arguments='-n sS -O')
|
||||
online_hosts = []
|
||||
for host in nm.all_hosts():
|
||||
try:
|
||||
os_type = nm[host]['osmatch'][0]['osclass'][0]['osfamily']
|
||||
except Exception:
|
||||
os_type = 'unknown'
|
||||
host_dict = {'host': host, 'os': os_type}
|
||||
online_hosts.append(host_dict)
|
||||
return online_hosts
|
||||
|
||||
def get_net_address(self):
|
||||
"""
|
||||
Return the hosts that will be used to scan.
|
||||
Subclasses can override this to return any hosts.`
|
||||
"""
|
||||
hosts_list = super().get_net_address()
|
||||
hosts = ' '.join(str(i) for i in hosts_list)
|
||||
return hosts
|
||||
|
||||
|
||||
class LoginExecution(ConfigFileMixin):
|
||||
|
||||
def login_execution(self, auth_type='password', **kwargs):
|
||||
"""
|
||||
Support two authentication modes: password or private_key, and auth_type default is password.
|
||||
"""
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
if auth_type == 'password':
|
||||
ssh.connect(
|
||||
kwargs['hostname'],
|
||||
kwargs['port'],
|
||||
kwargs['username'],
|
||||
kwargs['password'],
|
||||
timeout=3,
|
||||
)
|
||||
kwargs['auth_type'] = 'password'
|
||||
elif auth_type == 'private_key':
|
||||
kwargs['auth_type'] = 'private_key'
|
||||
private_key = paramiko.RSAKey.from_private_key_file(kwargs['private_key'])
|
||||
ssh.connect(
|
||||
kwargs['hostname'],
|
||||
kwargs['port'],
|
||||
kwargs['username'],
|
||||
private_key,
|
||||
timeout=3,
|
||||
)
|
||||
kwargs['status'] = 'succeed'
|
||||
kwargs['error_message'] = ''
|
||||
commands = self.get_commands()
|
||||
for key, value in commands.items():
|
||||
stdin, stdout, stderr = ssh.exec_command(value, timeout=5)
|
||||
result = str(stdout.read()).strip('b').strip("'").strip('\\n')
|
||||
kwargs[key] = result
|
||||
except Exception as e:
|
||||
msg = '%(exc)s hostname %(hostname)s' % {
|
||||
'exc': e,
|
||||
'hostname': kwargs['hostname']
|
||||
}
|
||||
error_logger.error(msg)
|
||||
kwargs['status'] = 'failed'
|
||||
kwargs['error_message'] = str(e)
|
||||
return kwargs
|
||||
|
||||
def password_login_execution(self, **kwargs):
|
||||
"""
|
||||
Login to the remote system with a password.
|
||||
Kwargs is a dict containing hostname, port, username and password.
|
||||
Example: kwargs = {'hostname': '172.16.3.101', 'port': 22, 'username': 'root', 'password': 'paw123'}
|
||||
"""
|
||||
return self.login_execution(**kwargs)
|
||||
|
||||
def private_key_login_execution(self, **kwargs):
|
||||
"""
|
||||
Login to the remote system with a private_key.
|
||||
Kwargs is a dict containing hostname, port, username and private key.
|
||||
Example:kwargs = {'hostname': '172.16.3.101', 'port': 22, 'username': 'root', 'private_key': '/root/.ssh/id_rsa'}
|
||||
"""
|
||||
return self.login_execution(auth_type='private_key', **kwargs)
|
||||
|
||||
def get_auth_type(self):
|
||||
key = ['hosts', 'auth_type']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_ssh_username(self):
|
||||
key = ['hosts', 'ssh_username']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_ssh_port(self):
|
||||
key = ['hosts', 'ssh_port']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_ssh_password(self):
|
||||
key = ['hosts', 'ssh_password']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_ssh_private_key(self):
|
||||
key = ['hosts', 'ssh_private_key']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_email(self):
|
||||
key = ['hosts', 'email']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_send_email(self):
|
||||
key = ['hosts', 'send_email']
|
||||
return self.get_conf_content(*key)
|
||||
|
||||
def get_scan_type(self):
|
||||
key = ['hosts', 'scan_type']
|
||||
return self.get_conf_content(*key)
|
||||
18
config/scanhosts.yml
Normal file
18
config/scanhosts.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
hosts:
|
||||
net_address:
|
||||
- '172.16.3.0/24'
|
||||
- '172.16.2.100-105'
|
||||
ssh_username: 'root'
|
||||
ssh_port: '22'
|
||||
ssh_password: '1234@abcd.com'
|
||||
ssh_private_key: '/root/.ssh/id_rsa'
|
||||
commands:
|
||||
sys_hostname: 'hostname'
|
||||
mac_address: 'cat /sys/class/net/[^tsbvl]*/address'
|
||||
sn_number: 'dmidecode -s system-serial-number'
|
||||
os_type: 'cat /etc/redhat-release'
|
||||
device_type: 'echo `dmidecode -s system-manufacturer && dmidecode -s system-product-name`'
|
||||
email: 'robbie_han@outlook.com'
|
||||
send_email: 'false'
|
||||
scan_type: 'basic_scan'
|
||||
auth_type: 'private_key'
|
||||
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
1
requirements/dev.txt
Normal file
1
requirements/dev.txt
Normal file
@@ -0,0 +1 @@
|
||||
-r pro.txt
|
||||
14
requirements/pro.txt
Normal file
14
requirements/pro.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
django==2.1.5
|
||||
pillow==5.3.0
|
||||
mysqlclient==1.3.13
|
||||
ipython==7.1.1
|
||||
pyyaml==4.2b1
|
||||
ruamel.yaml==0.15.80
|
||||
python-nmap==0.6.1
|
||||
redis==3.0.1
|
||||
pymongo==3.7.1
|
||||
paramiko==2.4.2
|
||||
django-simple-history==2.6.0
|
||||
celery==4.2.1
|
||||
celery-once==2.0.0
|
||||
flower==0.9.2
|
||||
@@ -0,0 +1,5 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from .celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app')
|
||||
Binary file not shown.
38
sandboxMP/celery.py
Normal file
38
sandboxMP/celery.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import os
|
||||
from celery import Celery
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sandboxMP.settings')
|
||||
|
||||
app = Celery('sandbox')
|
||||
|
||||
app.config_from_object('django.conf:settings')
|
||||
|
||||
app.autodiscover_tasks()
|
||||
|
||||
BROKER_URL = 'redis://localhost:6379/0'
|
||||
|
||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
|
||||
|
||||
CELERY_TIMEZONE = 'Asia/Shanghai'
|
||||
|
||||
CELERY_ENABLE_UTC = False
|
||||
|
||||
CELERYD_FORCE_EXECV = True
|
||||
|
||||
CELERYD_CONCURRENCY = 5
|
||||
|
||||
CELERY_ACKS_LATE = True
|
||||
|
||||
CELERYD_MAX_TASKS_PER_CHILD = 100
|
||||
|
||||
CELERYD_TASK_TIME_LIMIT = 60 * 5
|
||||
|
||||
|
||||
app.conf.ONCE = {
|
||||
'backend': 'celery_once.backends.Redis',
|
||||
'settings': {
|
||||
'url': 'redis://localhost:6379/2',
|
||||
'default_timeout': 60 * 5
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .celery import *
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
@@ -27,7 +29,7 @@ SECRET_KEY = 'o6ijylqj@xxpvxzybcv2khtu5zk@y56nt4ptsb4dbgmdz8t%q='
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
@@ -39,7 +41,9 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'simple_history',
|
||||
'system',
|
||||
'cmdb',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -50,6 +54,9 @@ MIDDLEWARE = [
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'apps.system.middleware.MenuCollection',
|
||||
'apps.system.middleware.RbacMiddleware',
|
||||
'simple_history.middleware.HistoryRequestMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'sandboxMP.urls'
|
||||
@@ -79,14 +86,24 @@ WSGI_APPLICATION = 'sandboxMP.wsgi.application'
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
# }
|
||||
# }
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'sandboxMP',
|
||||
'HOST': '127.0.0.1',
|
||||
'USER': 'ddadmin',
|
||||
'PASSWORD': '1234@abcd.com',
|
||||
'PORT': '3306'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
|
||||
|
||||
@@ -132,3 +149,72 @@ MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
LOGIN_URL = '/login/'
|
||||
|
||||
# safe url
|
||||
SAFE_URL = [r'^/$',
|
||||
'/login/',
|
||||
'/logout',
|
||||
'/index/',
|
||||
'/media/',
|
||||
'/admin/',
|
||||
'/ckeditor/',
|
||||
'/test/',
|
||||
]
|
||||
|
||||
# session timeout
|
||||
|
||||
SESSION_COOKIE_AGE = 60 * 20
|
||||
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
|
||||
SESSION_SAVE_EVERY_REQUEST = True
|
||||
|
||||
|
||||
# logging config
|
||||
|
||||
BASE_LOG_DIR = os.path.join(BASE_DIR, 'slogs')
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': '[%(asctime)s][task_id:%(name)s][%(levelname)s]'
|
||||
'[%(filename)s:%(lineno)d][%(message)s]'
|
||||
},
|
||||
'simple': {
|
||||
'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
|
||||
},
|
||||
|
||||
},
|
||||
'handlers': {
|
||||
'default': {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(BASE_LOG_DIR, "sandbox_info.log"),
|
||||
'maxBytes': 1024 * 1024 * 50,
|
||||
'backupCount': 3,
|
||||
'formatter': 'simple',
|
||||
'encoding': 'utf-8',
|
||||
},
|
||||
'error': {
|
||||
'level': 'ERROR',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(BASE_LOG_DIR, "sandbox_err.log"),
|
||||
'backupCount': 5,
|
||||
'formatter': 'standard',
|
||||
'encoding': 'utf-8',
|
||||
}
|
||||
|
||||
},
|
||||
'loggers': {
|
||||
'sandbox_info': {
|
||||
'handlers': ['default'],
|
||||
'level': 'INFO',
|
||||
'propagate': True,
|
||||
},
|
||||
'sandbox_error': {
|
||||
'handlers': ['error'],
|
||||
'level': 'ERROR',
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ from django.urls import re_path
|
||||
from django.views.static import serve
|
||||
|
||||
from system.views_user import IndexView, LoginView, LogoutView
|
||||
|
||||
from cmdb.tests import TestLoggingView
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
@@ -28,6 +28,9 @@ urlpatterns = [
|
||||
path('login/', LoginView.as_view(), name='login'),
|
||||
path('logout/', LogoutView.as_view(), name='logout'),
|
||||
path('system/', include('system.urls', namespace='system')),
|
||||
path('cmdb/', include('cmdb.urls', namespace='cmdb')),
|
||||
|
||||
path('test/', TestLoggingView.as_view()),
|
||||
|
||||
]
|
||||
|
||||
@@ -35,4 +38,4 @@ if settings.DEBUG:
|
||||
urlpatterns += [
|
||||
re_path(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),
|
||||
|
||||
]
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@ var DATATABLES_CONSTANT = {
|
||||
|
||||
// datatables常量
|
||||
DATA_TABLES : {
|
||||
DEFAULT_OPTION : { // DataTables初始化选项
|
||||
SERVER_SIDE_OPTION : { // DataTables初始化选项
|
||||
oLanguage : {
|
||||
sProcessing : "处理中...",
|
||||
sLengthMenu : "每页 _MENU_ 项",//"显示 _MENU_ 项结果,",
|
||||
|
||||
@@ -21,20 +21,32 @@
|
||||
<!-- /.search form -->
|
||||
|
||||
<!-- Sidebar Menu -->
|
||||
<ul class="sidebar-menu">
|
||||
<ul class="sidebar-menu">
|
||||
<li class="header"></li>
|
||||
<!-- Optionally, you can add icons to the links -->
|
||||
<li class="treeview">
|
||||
<a href="#"><i class="fa fa-calendar"></i> <span>一级菜单</span>
|
||||
<span class="pull-right-container">
|
||||
<i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
<li><a href="#"><i class="fa fa-caret-right"></i>二级菜单</a></li>
|
||||
<li><a href="#"><i class="fa fa-caret-right"></i>二级菜单</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% for menu in request.reveal_menu %}
|
||||
{% if not menu.url %}
|
||||
<li class="treeview" id="{{ menu.code }}">
|
||||
<a href="">
|
||||
<i class="{{ menu.icon }}"></i><span>{{ menu.name }}</span>
|
||||
<span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="treeview-menu">
|
||||
{% for sub in menu.sub_menu %}
|
||||
<li id="{{ sub.code }}">
|
||||
<a href="{{ sub.url }}"><i class="fa fa-caret-right"></i>{{ sub.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li id="{{ menu.code }}">
|
||||
<a href="{{ menu.url }}"><i class="{{ menu.icon }}"></i><span>{{ menu.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<!-- /.sidebar-menu -->
|
||||
</section>
|
||||
@@ -44,7 +56,14 @@
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
|
||||
<section class="content-header margin-bottom">
|
||||
<ol class="breadcrumb">
|
||||
{% if menu.parent %}
|
||||
<li class="active"><a href="{{ menu.parent.url | default:'' }}">{{ menu.parent.name }}</a></li>
|
||||
{% endif %}
|
||||
<li class="active"><a href="{{ menu.url }}">{{ menu.name }}</a></li>
|
||||
</ol>
|
||||
</section>
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
276
templates/cmdb/cabinet.html
Normal file
276
templates/cmdb/cabinet.html
Normal file
@@ -0,0 +1,276 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div id="devlist">
|
||||
<div class="box box-primary" id="liebiao">
|
||||
<div class="box-header">
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnRefresh" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-repeat"></i>刷新
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnCreate" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-plus"></i>新增
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnDelete" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-trash"></i>删除
|
||||
</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<form class="form-inline" id="queryForm">
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>机柜编号:</label>
|
||||
<input type="text" name="number" class="form-control inputText" id="number">
|
||||
</div>
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>机柜位置:</label>
|
||||
<input type="text" name="position" class="form-control inputText" id="position">
|
||||
</div>
|
||||
<button type="button" id="btnSearch" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-search"></i>查询
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table id="dtbList" class="display" cellspacing="0" width="100%">
|
||||
<thead>
|
||||
<tr valign="middle">
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>ID</th>
|
||||
<th>机柜编号</th>
|
||||
<th>机柜位置</th>
|
||||
<th>备注信息</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br> <br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 菜单选中高亮
|
||||
$(function () {
|
||||
$('#CMDB-EAM').addClass('active');
|
||||
$('#CMDB-EAM-CABINET').addClass('active');
|
||||
|
||||
});
|
||||
|
||||
// datatables 初始化配置
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
|
||||
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'cmdb:eam-cabinet-list' %}",
|
||||
"data": function (d) {
|
||||
d.number = $("#number").val();
|
||||
d.position = $("#position").val();
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
{
|
||||
data: "id",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
data: "number",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "position",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "desc",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
width: "10%",
|
||||
bSortable: "false",
|
||||
render: function (data, type, row, meta) {
|
||||
var ret = "";
|
||||
var ret = "<button title='详情-修改' onclick='doUpdate("
|
||||
+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 刷新数据
|
||||
$("#btnRefresh").click(function () {
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
//新建数据
|
||||
$("#btnCreate").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '新增',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: "{% url 'cmdb:eam-cabinet-create' %}",
|
||||
end: function () {
|
||||
//关闭时做的事情
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//修改数据
|
||||
function doUpdate(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'cmdb:eam-cabinet-update' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//checkbox全选
|
||||
$("#checkAll").on("click", function () {
|
||||
if ($(this).prop("checked") === true) {
|
||||
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
|
||||
$('#example tbody tr').addClass('selected');
|
||||
} else {
|
||||
$("input[name='checkList']").prop("checked", false);
|
||||
$('#example tbody tr').removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
//批量删除
|
||||
$("#btnDelete").click(function () {
|
||||
if ($("input[name='checkList']:checked").length == 0) {
|
||||
layer.msg("请选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
var arrId = new Array();
|
||||
$("input[name='checkList']:checked").each(function () {
|
||||
//alert($(this).val());
|
||||
arrId.push($(this).val());
|
||||
});
|
||||
|
||||
sId = arrId.join(',');
|
||||
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:eam-cabinet-delete' %}",
|
||||
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert("操作成功", {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert("操作失败", {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//删除单个数据
|
||||
function doDelete(id) {
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:eam-cabinet-delete' %}",
|
||||
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('删除成功', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('删除失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//select2
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
$("#btnSearch").click(function(){
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
99
templates/cmdb/cabinet_form.html
Normal file
99
templates/cmdb/cabinet_form.html
Normal file
@@ -0,0 +1,99 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
<!-- iCheck for checkboxes and radio inputs -->
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
<input type="hidden" name='id' value="{{ cabinet.id }}" />
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h4>机柜信息</h4>
|
||||
</legend>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">机柜编号</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="number" type="text" value="{{ cabinet.number }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">机柜位置</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="position" type="text" value="{{ cabinet.position }}"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">描述信息</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" id="desc" name="desc" type="text" value="{{ cabinet.desc }}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function getUrl() {
|
||||
if ($("input[name='id']").val()) {
|
||||
var url = "{% url 'cmdb:eam-cabinet-update' %}";
|
||||
} else {
|
||||
var url = "{% url 'cmdb:eam-cabinet-create' %}";
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: getUrl(),
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert(msg.error, {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
20
templates/cmdb/cmdb_index.html
Normal file
20
templates/cmdb/cmdb_index.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
这里是配置管理首页(临时内容)
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
274
templates/cmdb/code.html
Normal file
274
templates/cmdb/code.html
Normal file
@@ -0,0 +1,274 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div id="devlist">
|
||||
<div class="box box-primary" id="liebiao">
|
||||
<div class="box-header">
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnRefresh" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-repeat"></i>刷新
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnCreate" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-plus"></i>新增
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnDelete" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-trash"></i>删除
|
||||
</button>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<form class="form-inline" id="queryForm">
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>字典分类:</label>
|
||||
<select class="form-control inputText select2" name="parent" id="parent">
|
||||
<option style='text-align:center' value="">---所有---</option>
|
||||
{% for code in code_parent %}
|
||||
<option value={{ code.key}}>{{ code.value }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table id="dtbList" class="display" cellspacing="0" width="100%">
|
||||
<thead>
|
||||
<tr valign="middle">
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>ID</th>
|
||||
<th>KEY</th>
|
||||
<th>VALUE</th>
|
||||
<th>所属</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br> <br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 菜单选中高亮
|
||||
$(function () {
|
||||
$('#CMDB-PORTAL').addClass('active');
|
||||
$('#CDMB-PORTAL-CODE').addClass('active');
|
||||
});
|
||||
|
||||
// datatables 初始化配置
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
|
||||
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'cmdb:portal-code-list' %}",
|
||||
"data": function (d) {
|
||||
d.parent = $("#parent").val();
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
{
|
||||
data: "id",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
data: "key",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "value",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "parent__value",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
width: "10%",
|
||||
bSortable: "false",
|
||||
render: function (data, type, row, meta) {
|
||||
var ret = "";
|
||||
var ret = "<button title='详情' onclick='doUpdate("
|
||||
+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//select2
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
//过滤刷新接口获取新的数据
|
||||
$("#parent").change(function () {
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
|
||||
|
||||
// 刷新数据
|
||||
$("#btnRefresh").click(function () {
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
//新建字典
|
||||
$("#btnCreate").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '新增',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: "{% url 'cmdb:portal-code-create' %}",
|
||||
end: function () {
|
||||
//关闭时做的事情
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//修改字典
|
||||
function doUpdate(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'cmdb:portal-code-update' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//checkbox全选
|
||||
$("#checkAll").on("click", function () {
|
||||
if ($(this).prop("checked") === true) {
|
||||
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
|
||||
$('#example tbody tr').addClass('selected');
|
||||
} else {
|
||||
$("input[name='checkList']").prop("checked", false);
|
||||
$('#example tbody tr').removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
//批量删除
|
||||
$("#btnDelete").click(function () {
|
||||
if ($("input[name='checkList']:checked").length == 0) {
|
||||
layer.msg("请选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
var arrId = new Array();
|
||||
$("input[name='checkList']:checked").each(function () {
|
||||
//alert($(this).val());
|
||||
arrId.push($(this).val());
|
||||
});
|
||||
|
||||
sId = arrId.join(',');
|
||||
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:portal-code-delete' %}",
|
||||
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert("操作成功", {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert("操作失败", {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//删除单个数据
|
||||
function doDelete(id) {
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:portal-code-delete' %}",
|
||||
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('删除成功', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('删除失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
97
templates/cmdb/code_create.html
Normal file
97
templates/cmdb/code_create.html
Normal file
@@ -0,0 +1,97 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
<!-- iCheck for checkboxes and radio inputs -->
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h4>新建字典</h4>
|
||||
</legend>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">KEY</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="key" type="text"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">VALUE</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="value" type="text" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">父菜单</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" name="parent">
|
||||
<option value=""></option>
|
||||
{% for parent in code_parent %}
|
||||
<option value={{ parent.id }}> {{ parent.value }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">描述信息</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" id="desc" name="desc" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'cmdb:portal-code-create' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert(msg.error, {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
99
templates/cmdb/code_update.html
Normal file
99
templates/cmdb/code_update.html
Normal file
@@ -0,0 +1,99 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
<!-- iCheck for checkboxes and radio inputs -->
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
<input type="hidden" name='id' type='text' value="{{ code.id }}"/>
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h4>修改字典</h4>
|
||||
</legend>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">KEY</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="key" type="text" value="{{ code.key }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">VALUE</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="value" type="text" value="{{ code.value }}"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">父菜单</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" name="parent">
|
||||
<option value={{ code.parent.id }}> {{ code.parent.value }} </option>
|
||||
<option value=""></option>
|
||||
{% for parent in code_parent %}
|
||||
<option value={{ parent.id }}> {{ parent.value }} </option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">描述信息</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" id="desc" name="desc" type="text" value="{{ code.desc }}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'cmdb:portal-code-update' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert(msg.error, {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
329
templates/cmdb/device_scan.html
Normal file
329
templates/cmdb/device_scan.html
Normal file
@@ -0,0 +1,329 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div id="devlist">
|
||||
<div class="box box-primary" id="liebiao">
|
||||
<div class="box-header">
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnRefresh" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-repeat"></i> 刷新
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnScan" class="btn btn-default" onclick="doScan()">
|
||||
<i class="glyphicon glyphicon-search"></i> 执行扫描
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnInbound" class="btn btn-default" onclick="doInbound()">
|
||||
<i class="glyphicon glyphicon-floppy-disk"></i> 执行入库
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnDelete" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-trash"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table id="dtbList" class="display" cellspacing="0" width="100%">
|
||||
<thead>
|
||||
<tr valign="middle">
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>ID</th>
|
||||
<th>主机名</th>
|
||||
<th>IP地址</th>
|
||||
<th>MAC地址</th>
|
||||
<th>认证类型</th>
|
||||
<th>登陆状态</th>
|
||||
<th>系统类型</th>
|
||||
<th>设备类型</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<small>点击【执行入库】可将扫描结果中,登陆状态为:成功(succeed)的设备数据导入正式设备管理数据库。</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 菜单选中高亮
|
||||
$(function () {
|
||||
$('#CMDB-PORTAL').addClass('active');
|
||||
$('#CDMB-PORTAL-DEVICE_SCAN').addClass('active');
|
||||
|
||||
});
|
||||
|
||||
// datatables 初始化配置
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
|
||||
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'cmdb:portal-device_scan-list' %}",
|
||||
|
||||
},
|
||||
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
{
|
||||
data: "id",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
data: "sys_hostname",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "hostname",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "mac_address",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "auth_type",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "status",
|
||||
render: function (data, type, row, meta) {
|
||||
if (data == "succeed") {
|
||||
var ret = "<button class='btn btn-info btn-xs'>成功</button>";
|
||||
return ret;
|
||||
}
|
||||
if (data == "failed") {
|
||||
var ret = "<button class='btn btn-danger btn-xs'>失败</button>";
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
var ret = "<button class='btn btn-default btn-xs'>未知</button>";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "os_type",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "device_type",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
width: "10%",
|
||||
bSortable: "false",
|
||||
render: function (data, type, row, meta) {
|
||||
var ret = "";
|
||||
var ret = "<button title='详情' onclick='doDetail("
|
||||
+ data + ")'><i class='glyphicon glyphicon-list-alt'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 刷新数据
|
||||
$("#btnRefresh").click(function () {
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
|
||||
|
||||
function doDetail(id){
|
||||
window.location.href="/cmdb/portal/device_scan/detail/?id="+id;
|
||||
}
|
||||
|
||||
//checkbox全选
|
||||
$("#checkAll").on("click", function () {
|
||||
if ($(this).prop("checked") === true) {
|
||||
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
|
||||
$('#example tbody tr').addClass('selected');
|
||||
} else {
|
||||
$("input[name='checkList']").prop("checked", false);
|
||||
$('#example tbody tr').removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
//批量删除
|
||||
$("#btnDelete").click(function () {
|
||||
if ($("input[name='checkList']:checked").length == 0) {
|
||||
layer.msg("请选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
var arrId = new Array();
|
||||
$("input[name='checkList']:checked").each(function () {
|
||||
//alert($(this).val());
|
||||
arrId.push($(this).val());
|
||||
});
|
||||
|
||||
sId = arrId.join(',');
|
||||
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:portal-device_scan-delete' %}",
|
||||
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert("操作成功", {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert("操作失败", {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//删除单个数据
|
||||
function doDelete(id) {
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:portal-device_scan-delete' %}",
|
||||
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('删除成功', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('删除失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//资产扫描
|
||||
function doScan() {
|
||||
layer.alert('确定开始扫描吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{% url 'cmdb:portal-device_scan-exec' %}",
|
||||
cache: false,
|
||||
beforeSend:function(){
|
||||
this.layerIndex = layer.load(2, {
|
||||
shade: [0.1,'#fff']
|
||||
});
|
||||
},
|
||||
success: function (msg) {
|
||||
layer.closeAll('loading');
|
||||
if (msg.status == 'success') {
|
||||
layer.alert('扫描任务已下发', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
else if (msg.status == 'already_queued') {
|
||||
layer.alert('当前已有扫描任务正在执行', {icon: 4});
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
else {
|
||||
//alert(msg.message);
|
||||
layer.alert('扫描失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function doInbound() {
|
||||
layer.alert('确定将扫描结果导入设备管理库吗?', {
|
||||
title: '提示'
|
||||
, icon: 3
|
||||
, time: 0
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:portal-device_scan-inbound' %}",
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('设备已入库', {icon: 1});
|
||||
}
|
||||
else {
|
||||
//alert(msg.message);
|
||||
layer.alert('设备入库失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
113
templates/cmdb/device_scan_detail.html
Normal file
113
templates/cmdb/device_scan_detail.html
Normal file
@@ -0,0 +1,113 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">设备详情</h3>
|
||||
|
||||
<div class="box-tools">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i
|
||||
class="fa fa-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<div class="btn-group pull-right margin">
|
||||
<button type="button" class="btn btn-primary btn-xs margin-r-5" title="返回" id="btnReturn">
|
||||
<i class="fa fa-undo"> 返回</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive mailbox-messages">
|
||||
<table class="table" id="tbWorkList" style="white-space: nowrap;">
|
||||
<tbody>
|
||||
<tr class="info">
|
||||
<td width="10%"><strong>主机名</strong></td>
|
||||
<td class="text-left">{{ device.sys_hostname }}</td>
|
||||
<td width="10%"><strong>SN编号</strong></td>
|
||||
<td class="text-left">{{ device.sn_number }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>SSH用户名</strong></td>
|
||||
<td>{{ device.username }}</td>
|
||||
<td><strong>SSH端口</strong></td>
|
||||
<td>{{ device.port }}</td>
|
||||
</tr>
|
||||
<tr class="info">
|
||||
<td><strong>认证类型</strong></td>
|
||||
<td>{{ device.auth_type }}</td>
|
||||
<td><strong>登陆状态</strong></td>
|
||||
<td>{{ device.status }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>IP地址</strong></td>
|
||||
<td>{{ device.hostname }}</td>
|
||||
<td><strong>MAC地址</strong></td>
|
||||
<td>{{ device.mac_address }}</td>
|
||||
</tr>
|
||||
<tr class="info">
|
||||
<td><strong>系统类型</strong></td>
|
||||
<td>{{ device.os_type }}</td>
|
||||
<td><strong>设备类型</strong></td>
|
||||
<td>{{ device.device_type }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>入库时间</strong></td>
|
||||
<td>{{ device.add_time }}</td>
|
||||
<td><strong>变更时间</strong></td>
|
||||
<td>{{ device.modify_time }}</td>
|
||||
</tr>
|
||||
<tr class="info">
|
||||
<td><strong>错误信息</strong></td>
|
||||
<td colspan="3">{{ device.error_message }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<br>
|
||||
<div class="box-footer margin-b-10">
|
||||
<small>该设备信息为自动扫描入库设备,不提供修改功能,可通过管理页面【执行入库】按钮将登陆状态为:成功(succeed)的设备迁移到正式设备管理库</small>
|
||||
</div>
|
||||
<!-- /.box-footer -->
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
<!-- TO DO List -->
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script src="{% static 'plugins/masonry/masonry.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#CMDB-PORTAL').addClass('active');
|
||||
$('#CDMB-PORTAL-DEVICE_SCAN').addClass('active');
|
||||
|
||||
});
|
||||
//返回
|
||||
$("#btnReturn").click(function () {
|
||||
history.back();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
343
templates/cmdb/deviceinfo.html
Normal file
343
templates/cmdb/deviceinfo.html
Normal file
@@ -0,0 +1,343 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div id="devlist">
|
||||
<div class="box box-primary" id="liebiao">
|
||||
<div class="box-header">
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnRefresh" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-repeat"></i>刷新
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnCreate" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-plus"></i>新增
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div class="btn-group pull-left"> </div>
|
||||
<div class="btn-group pull-left">
|
||||
<button type="button" id="btnDelete" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-trash"></i>删除
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-header">
|
||||
<form class="form-inline" id="queryForm">
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>主机名:</label>
|
||||
<input type="text" name="sys_hostname" class="form-control inputText" id="sys_hostname">
|
||||
</div>
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>设备地址:</label>
|
||||
<input type="text" name="hostname" class="form-control inputText" id="hostname">
|
||||
</div>
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>网络类型:</label>
|
||||
<select class="form-control inputText select2" name="network_type" id="network_type">
|
||||
<option></option>
|
||||
{% for code in all_code %}
|
||||
{% ifequal code.parent.key 'NETWORK_TYPE' %}
|
||||
<option value="{{ code.id }}">{{ code.value }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>服务类型:</label>
|
||||
<select class="form-control inputText select2" name="service_type" , id="service_type">
|
||||
<option></option>
|
||||
{% for code in all_code %}
|
||||
{% if code.parent.key == 'SERVICE_TYPE' %}
|
||||
<option value="{{ code.id }}">{{ code.value }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group searchArea margin-r-5 margin-top-5">
|
||||
<label>业务类型:</label>
|
||||
<select class="form-control inputText select2" name="operation_type" , id="operation_type">
|
||||
<option></option>
|
||||
{% for code in all_code %}
|
||||
{% if code.parent.key == 'OPERATION_TYPE' %}
|
||||
<option value="{{ code.id }}">{{ code.value }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" id="btnSearch" class="btn btn-default">
|
||||
<i class="glyphicon glyphicon-search"></i>查询
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table id="dtbList" class="display" cellspacing="0" width="100%">
|
||||
<thead>
|
||||
<tr valign="middle">
|
||||
<th><input type="checkbox" id="checkAll"></th>
|
||||
<th>ID</th>
|
||||
<th>主机名</th>
|
||||
<th>SN编号</th>
|
||||
<th>系统类型</th>
|
||||
<th>设备类型</th>
|
||||
<th>设备地址</th>
|
||||
<th>MAC地址</th>
|
||||
<th>责任人</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<br> <br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
// 菜单选中高亮
|
||||
$(function () {
|
||||
$('#CMDB-EAM').addClass('active');
|
||||
$('#CMDB-EAM-DEVICE').addClass('active');
|
||||
|
||||
});
|
||||
|
||||
// datatables 初始化配置
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
|
||||
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'cmdb:eam-device-list' %}",
|
||||
"data": function (d) {
|
||||
d.sys_hostname = $("#sys_hostname").val();
|
||||
d.hostname = $("#hostname").val();
|
||||
d.network_type = $("#network_type").val();
|
||||
d.service_type = $("#service_type").val();
|
||||
d.operation_type = $("#operation_type").val();
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
|
||||
{
|
||||
data: "id",
|
||||
},
|
||||
{
|
||||
data: "sys_hostname",
|
||||
},
|
||||
{
|
||||
data: "sn_number",
|
||||
},
|
||||
{
|
||||
data: "os_type",
|
||||
},
|
||||
{
|
||||
data: "device_type",
|
||||
},
|
||||
{
|
||||
data: "hostname",
|
||||
},
|
||||
{
|
||||
data: "mac_address",
|
||||
},
|
||||
{
|
||||
data: "leader",
|
||||
},
|
||||
{
|
||||
data: "id",
|
||||
bSortable: "false",
|
||||
render: function (data, type, row, meta) {
|
||||
var ret = "<button title='详情' onclick='doDetail("
|
||||
+ data + ")'><i class='glyphicon glyphicon-list-alt'></i></button>";
|
||||
ret = ret + "<button title='修改' onclick='doUpdate("
|
||||
+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
|
||||
ret = ret + "<button title='认证管理' onclick='doDevice2Connection("
|
||||
+ data + ")'><i class='glyphicon glyphicon-user'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// 刷新数据
|
||||
$("#btnRefresh").click(function () {
|
||||
window.location.reload();
|
||||
});
|
||||
//新建数据
|
||||
$("#btnCreate").click(function () {
|
||||
var div=layer.open({
|
||||
type: 2,
|
||||
title: '新增',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: "{% url 'cmdb:eam-device-create' %}",
|
||||
end: function () {
|
||||
//关闭时做的事情
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
layer.full(div )
|
||||
});
|
||||
|
||||
//修改数据
|
||||
function doUpdate(id) {
|
||||
var div=layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'cmdb:eam-device-update' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
layer.full(div )
|
||||
}
|
||||
|
||||
//checkbox全选
|
||||
$("#checkAll").on("click", function () {
|
||||
if ($(this).prop("checked") === true) {
|
||||
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
|
||||
$('#example tbody tr').addClass('selected');
|
||||
} else {
|
||||
$("input[name='checkList']").prop("checked", false);
|
||||
$('#example tbody tr').removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
//批量删除
|
||||
$("#btnDelete").click(function () {
|
||||
if ($("input[name='checkList']:checked").length == 0) {
|
||||
layer.msg("请选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
|
||||
var arrId = new Array();
|
||||
$("input[name='checkList']:checked").each(function () {
|
||||
//alert($(this).val());
|
||||
arrId.push($(this).val());
|
||||
});
|
||||
|
||||
sId = arrId.join(',');
|
||||
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:eam-device-delete' %}",
|
||||
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert("操作成功", {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert("操作失败", {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//删除单个数据
|
||||
function doDelete(id) {
|
||||
layer.alert('确定删除吗?', {
|
||||
title: '提示'
|
||||
, icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸
|
||||
, time: 0 //不自动关闭
|
||||
, btn: ['YES', 'NO']
|
||||
, yes: function (index) {
|
||||
layer.close(index);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "{% url 'cmdb:eam-device-delete' %}",
|
||||
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('删除成功', {icon: 1});
|
||||
oDataTable.ajax.reload();
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('删除失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//select2
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
$("#btnSearch").click(function(){
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
|
||||
|
||||
function doDevice2Connection(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '认证管理',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'cmdb:eam-device-device2connection' %}" + '?id=' + id, 'no'],
|
||||
end: function () {
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
108
templates/cmdb/deviceinfo2connection.html
Normal file
108
templates/cmdb/deviceinfo2connection.html
Normal file
@@ -0,0 +1,108 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
<!-- iCheck for checkboxes and radio inputs -->
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
<input type="hidden" name='id' value="{{ connection_info.id }}" />
|
||||
<input type="hidden" name='hostname' value="{{ device.hostname }}" />
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
<h4>关联设备:{{ device.sys_hostname }}({{ device.hostname }})</h4>
|
||||
</legend>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">用户名</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="username" type="text" value="{{ connection_info.username }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">认证类型</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="auth_type">
|
||||
<option value="password" {% ifequal connection_info.auth_type 'password' %}selected="selected"{% endifequal %}>密码</option>
|
||||
<option value="private_key" {% ifequal connection_info.auth_type 'private_key' %}selected="selected"{% endifequal %}>密钥</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">密码</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="password" type="password" value="{{ connection_info.password }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">密钥</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="private_key" type="text" value="{{ connection_info.private_key }}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">端口</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="port" type="text" value="{{ connection_info.port }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">状态</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="status" type="text" value="{{ connection_info.status }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'cmdb:eam-device-device2connection' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert(msg.error, {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
221
templates/cmdb/deviceinfo_form.html
Normal file
221
templates/cmdb/deviceinfo_form.html
Normal file
@@ -0,0 +1,221 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{%static 'plugins/select2/select2.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap-datetimepicker.min.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
<input type="hidden" name='id' value="{{ deviceinfo.id }}" />
|
||||
<input type="hidden" name='changed_by' value="{{ request.user.id }}" />
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<fieldset>
|
||||
<legend>
|
||||
</legend>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">主机名</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="sys_hostname" type="text" value="{{ deviceinfo.sys_hostname }}" />
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">SN编号</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="sn_number" type="text" value="{{ deviceinfo.sn_number }}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">系统类型</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="os_type" type="text" value="{{ deviceinfo.os_type }}" />
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">设备类型</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="device_type" type="text" value="{{ deviceinfo.device_type }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">设备地址</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="hostname" type="text" value="{{ deviceinfo.hostname }}" />
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">MAC地址</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="mac_address" type="text" value="{{ deviceinfo.mac_address }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">网络类型</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="network_type">
|
||||
<option {% ifequal deviceinfo.network_type '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for code in all_code %}
|
||||
{% ifequal code.parent.key 'NETWORK_TYPE' %}
|
||||
<option value="{{ code.id }}" {% ifequal deviceinfo.network_type code.id %}selected="selected"{% endifequal %}>
|
||||
{{ code.value }}</option>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">服务类型</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="service_type">
|
||||
<option {% ifequal deviceinfo.service_type '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for code in all_code %}
|
||||
{% if code.parent.key == 'SERVICE_TYPE' %}
|
||||
<option value="{{ code.id }}" {% ifequal deviceinfo.service_type code.id %}selected="selected"{% endifequal %}>
|
||||
{{ code.value }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">业务类型</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="operation_type">
|
||||
<option {% ifequal deviceinfo.operation_type '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for code in all_code %}
|
||||
{% if code.parent.key == 'OPERATION_TYPE' %}
|
||||
<option value="{{ code.id }}" {% ifequal deviceinfo.operation_type code.id %}selected="selected"{% endifequal %}>
|
||||
{{ code.value }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">机柜信息</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="dev_cabinet">
|
||||
<option {% ifequal deviceinfo.dev_cabinet '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for cabinet in all_cabinet %}
|
||||
<option value="{{ cabinet.id }}" {% ifequal deviceinfo.dev_cabinet cabinet.id %}selected="selected"{% endifequal %}>
|
||||
{{ cabinet.number }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">购买日期</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" class="form-control pull-right form_datetime" name="buyDate"
|
||||
value="{{ deviceinfo.buyDate | date:'Y-m-d' }}" readonly/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">质保日期</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" class="form-control pull-right form_datetime" name="warrantyDate"
|
||||
value="{{ deviceinfo.warrantyDate | date:'Y-m-d' }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">所属</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="parent">
|
||||
<option {% ifequal deviceinfo.parent_id '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for device in all_device %}
|
||||
<option value="{{ device.id }}" {% ifequal deviceinfo.parent_id device.id %}selected="selected"{% endifequal %}>
|
||||
{{ device.sys_hostname }}({{ device.hostname }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">责任人</label>
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" style="width:100%;" name="leader">
|
||||
<option {% ifequal deviceinfo.leader '' %}selected="selected"{% endifequal %}></option>
|
||||
{% for u in all_user %}
|
||||
<option value="{{ u.id }}" {% ifequal deviceinfo.leader u.id %}selected="selected"{% endifequal %}>
|
||||
{{ u.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">备注信息</label>
|
||||
<div class="col-sm-8">
|
||||
<textarea class="form-control" name="desc" rows="5" >{{ deviceinfo.desc }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
<div class="row span7 text-center ">
|
||||
<button type="button" id="btnCancel" class="btn btn-default margin-right " >重置</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right " >保存</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
|
||||
<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function getUrl() {
|
||||
if ($("input[name='id']").val()) {
|
||||
var url = "{% url 'cmdb:eam-device-update' %}";
|
||||
} else {
|
||||
var url = "{% url 'cmdb:eam-device-create' %}";
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: getUrl(),
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert(msg.error, {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
})
|
||||
|
||||
|
||||
/*input 时间输入选择*/
|
||||
$(".form_datetime").datetimepicker({
|
||||
language: 'zh',
|
||||
minView: 'month', //选择范围知道日期,不选择时分
|
||||
//weekStart: 1,
|
||||
//todayBtn: 1,
|
||||
autoclose: 1,
|
||||
todayHighlight: 1,
|
||||
//startView: 2,
|
||||
forceParse: 0,
|
||||
showMeridian: 1,
|
||||
format: 'yyyy-mm-dd'
|
||||
}).on('changeDate', function (ev) {
|
||||
$(this).datetimepicker('hide');
|
||||
});
|
||||
|
||||
// select2
|
||||
$(function () {
|
||||
//Initialize Select2 Elements
|
||||
$(".select2").select2();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
176
templates/cmdb/scan_config.html
Normal file
176
templates/cmdb/scan_config.html
Normal file
@@ -0,0 +1,176 @@
|
||||
{% extends "base-left.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<!-- Horizontal Form -->
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">扫面参数配置</h3>
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
<!-- form start -->
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">扫描网段</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" id="net_address" name="net_address" value="{{ hosts.net_address }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">登陆用户</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" id="ssh_username" name="ssh_username" value="{{ hosts.ssh_username }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">SSH端口</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" id="ssh_port" name="ssh_port" value="{{ hosts.ssh_port }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">登陆密码</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" type="password" id="ssh_password" name="ssh_password" value="{{ hosts.ssh_password }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">密钥路径</label>
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" id="ssh_private_key" name="ssh_private_key" value="{{ hosts.ssh_private_key }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">运行命令</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="form-control" rows="5" id="commands" name="commands" readonly>{{ hosts.commands }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">认证方式</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control" name="auth_type">
|
||||
<option value="password" {% ifequal hosts.auth_type 'password' %}selected="selected"{% endifequal %}>密码认证</option>
|
||||
<option value="private_key" {% ifequal hosts.auth_type 'private_key' %}selected="selected"{% endifequal %}>私钥认证</option>
|
||||
</select>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">扫描方式</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control" name="scan_type">
|
||||
<option value="basic_scan" {% ifequal hosts.scan_type 'basic_scan' %}selected="selected"{% endifequal %}>基础扫描</option>
|
||||
<option value="enhanced_scan" {% ifequal hosts.scan_type 'enhanced_scan' %}selected="selected"{% endifequal %}>加强扫描</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">收件邮箱</label>
|
||||
|
||||
<div class="col-sm-10">
|
||||
<input class="form-control" id="email" name="email" value="{{ hosts.email }}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">发送邮件</label>
|
||||
<div class="col-sm-10">
|
||||
<label class="control-label">
|
||||
<input type="radio" class="minimal" name="send_email" value="true" {% ifequal hosts.send_email 'true' %}checked{% endifequal %}>是
|
||||
</label>
|
||||
<label class="control-label">
|
||||
<input type="radio" class="minimal" name="send_email" value="false" {% ifequal hosts.send_email 'false' %}checked{% endifequal %}>否
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<span class="pull-right">
|
||||
<button type="button" id="btnCancel" class="btn btn-default">取消</button>
|
||||
<button type="button" id="btnSave" class="btn btn-info">保存</button>
|
||||
</span>
|
||||
</div>
|
||||
<!-- /.box-footer -->
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">参数配置说明</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<a class="product-title"><strong>扫描网段</strong><span class="label label-danger pull-right">必填参数</span></a>
|
||||
<p><small>网络扫描地址列表,列表中可以包含一个或多个网段,也可以是一个或多个地址区间,例如['192.168.100.0/24', '192.168.100.10-20']</small></p>
|
||||
<a class="product-title"><strong>登陆用户</strong><span class="label label-danger pull-right">必填参数</span></a>
|
||||
<p><small>系统登陆测试使用的用户名,默认root。</small></p>
|
||||
<a class="product-title"><strong>登陆密码</strong><span class="label label-danger pull-right">可选参数</span></a>
|
||||
<p><small>系统登陆测试使用的密码,如过认证方式为密码认证,必须填写密码信息。</small></p>
|
||||
<a class="product-title"><strong>密钥路径</strong><span class="label label-primary pull-right">可选参数</span></a>
|
||||
<p><small>系统登陆测试使用的密钥存放路径,如过认证方式为私钥认证,必须填写密钥路径。</small></p>
|
||||
<a class="product-title"><strong>运行命令</strong><span class="label label-default pull-right">预定义参数</span></a>
|
||||
<p><small>登陆系统后运行的基本命令,用来获取系统基本信息,当扫描方式为加强扫描时,才会执行运行命令,运行命令为预定义,禁止修改。</small></p>
|
||||
<a class="product-title"><strong>认证方式</strong><span class="label label-primary pull-right">可选参数</span></a>
|
||||
<p><small>系统登陆认证方式,包括密码认证和私钥认证两种方式,当扫描方式为加强扫描时,需要设定认证方式。</small></p>
|
||||
<a class="product-title"><strong>扫描方式</strong><span class="label label-primary pull-right">可选参数</span></a>
|
||||
<p><small>系统扫描方式,包括基本扫描和加强扫描,当设置为加强扫描时会登陆系统执行运行命令获取系统信息。</small></p>
|
||||
<a class="product-title"><strong>收件邮箱</strong><span class="label label-primary pull-right">可选参数</span></a>
|
||||
<p><small>用于接收扫描结果邮件,可以通过发送邮件选项设置是否发送通知邮件。</small></p>
|
||||
</div><!-- /.box-body -->
|
||||
</div><!-- /.box -->
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- /.content -->
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
// 菜单选中高亮
|
||||
$(function () {
|
||||
$('#CMDB-PORTAL').addClass('active');
|
||||
$('#CMDB-PORTAL-SCAN_CONFIG').addClass('active');
|
||||
|
||||
});
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var hosts = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'cmdb:portal-scan_config' %}",
|
||||
cache: false,
|
||||
data: hosts,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1});
|
||||
} else {
|
||||
layer.alert('数据保存失败', {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -20,9 +20,13 @@
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div class="collapse navbar-collapse pull-left" id="navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active" ><a href="#" id="index">头部导航</a></li>
|
||||
</ul>
|
||||
{% for menu in request.top_menu %}
|
||||
<ul class="nav navbar-nav">
|
||||
<li {% ifequal menu.status True %}class="active" {% endifequal %}>
|
||||
<a href="{{ menu.url }}" id="{{ menu.code }}">{{ menu.name | default_if_none:"" }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if request.user.is_authenticated %}
|
||||
<div class="navbar-custom-menu">
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="name" type="text"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">代码</label>
|
||||
<label class="col-sm-2 control-label">编号</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="code" type="text"/>
|
||||
<input class="form-control" name="number" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
@@ -43,7 +43,12 @@
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" name="url" type="text" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">代码</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" name="code" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="name" type="text" value="{{ menu.name }}"/>
|
||||
</div>
|
||||
<label class="col-sm-2 control-label">代码</label>
|
||||
<label class="col-sm-2 control-label">编号</label>
|
||||
<div class="col-sm-3">
|
||||
<input class="form-control" name="code" type="text" value="{{ menu.code }}"/>
|
||||
<input class="form-control" name="number" type="text" value="{{ menu.number }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
@@ -32,6 +32,7 @@
|
||||
<div class="col-sm-3">
|
||||
<select class="form-control select2" name="parent">
|
||||
<option value="{{ menu.parent.id }}">{{ menu.parent.name }}</option>
|
||||
<option value=""> </option>
|
||||
{% for parent_menu in menu_all %}
|
||||
<option value={{ parent_menu.id }}> {{ parent_menu.name }} </option>
|
||||
{% endfor %}
|
||||
@@ -44,6 +45,12 @@
|
||||
<input class="form-control" name="url" type="text" value="{{ menu.url | default:'' }}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<label class="col-sm-2 control-label">代码</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" name="code" type="text" value="{{ menu.code | default:'' }}"/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="box-footer ">
|
||||
|
||||
@@ -60,7 +60,13 @@
|
||||
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'plugins/datatables/dataTables.const.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#SYSTEM-RBAC').addClass('active');
|
||||
$('#SYSTEM-RBAC-ROLE').addClass('active');
|
||||
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
|
||||
@@ -57,6 +57,13 @@
|
||||
<script src="{% static 'plugins/datatables/dataTables.const.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#SYSTEM-BASIC').addClass('active');
|
||||
$('#SYSTEM-BASIC-STRUCTURE').addClass('active');
|
||||
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
|
||||
@@ -4,14 +4,87 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="pad margin no-print">
|
||||
<div class="callout callout-info" style="margin-bottom: 0!important;">
|
||||
<h4><i class="fa fa-info-circle"></i>系统管理:</h4>
|
||||
系统管理模块包含:系统权限管理和系统设置,系统权限管理可实现基于角色组的权限管理,可根据角色组权限动态生成URL导航菜单。
|
||||
</div>
|
||||
</div>
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
系统管理首页:system_index,content是页面定义的主要区域,
|
||||
头部和底部内容以及导航栏都是通过模板继承的,之后的所有
|
||||
功能前端页面都是在content内进行编辑。
|
||||
</section>
|
||||
<section class="invoice">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h2 class="page-header">
|
||||
<i class="fa fa-github"></i> RBAC权限管理历史版本
|
||||
</h2>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-12 table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>编号</th>
|
||||
<th>TAG</th>
|
||||
<th>发布日期</th>
|
||||
<th>TAG地址</th>
|
||||
<th>Commit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>v1.19</td>
|
||||
<td>2018-11-16</td>
|
||||
<td>https://github.com/RobbieHan/sandboxMP/tree/v1.19</td>
|
||||
<td>system config</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>v1.18</td>
|
||||
<td>2018-11-16</td>
|
||||
<td>https://github.com/RobbieHan/sandboxMP/tree/v1.18</td>
|
||||
<td>rbac config</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>v1.17</td>
|
||||
<td>2018-11-14</td>
|
||||
<td>https://github.com/RobbieHan/sandboxMP/tree/v1.17</td>
|
||||
<td>role2menu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>v1.16</td>
|
||||
<td>2018-11-14</td>
|
||||
<td>https://github.com/RobbieHan/sandboxMP/tree/v1.17</td>
|
||||
<td>role2user</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<div class="row">
|
||||
<!-- accepted payments column -->
|
||||
<div class="col-xs-12">
|
||||
<p class="lead">其他信息:</p>
|
||||
|
||||
<p class="text-muted well well-sm no-shadow" style="margin-top: 10px;">
|
||||
<strong>权限管理开发文档获取地址(知识星球):</strong> https://t.zsxq.com/a6IqBMr (微信中打开链接)<br>
|
||||
<strong>知识星球快捷入口:</strong>微信公众号搜索[知识星球],关注后发送52824366,获取星球连接。<br>
|
||||
<strong>知乎专栏SandBox:</strong>https://zhuanlan.zhihu.com/sandbox <br>
|
||||
<strong>轻量级办公管理系统项目开源地址:</strong>https://github.com/RobbieHan/gistandard <br>
|
||||
</p>
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -88,6 +88,14 @@
|
||||
<script src="{% static 'plugins/datatables/dataTables.const.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#SYSTEM-BASIC').addClass('active');
|
||||
$('#SYSTEM-BASIC-USER').addClass('active');
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var oDataTable = null;
|
||||
$(function () {
|
||||
|
||||
Reference in New Issue
Block a user