mirror of
https://github.com/RobbieHan/sandboxMP.git
synced 2026-02-03 10:53:15 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cea6fa7cba | ||
|
|
eb10ffe9be | ||
|
|
9c204933e8 | ||
|
|
371b1ebbe3 | ||
|
|
9d0bd95b69 | ||
|
|
4fbdc88743 | ||
|
|
860ae14d4c | ||
|
|
00f7112b67 | ||
|
|
ba936d7f9e | ||
|
|
c399b77703 | ||
|
|
894fe29e15 | ||
|
|
602edea8f8 | ||
|
|
9d149a6882 | ||
|
|
0b47673759 | ||
|
|
e2edef0af2 | ||
|
|
1f94ffa857 | ||
|
|
134ea4426f | ||
|
|
04d01aa273 | ||
|
|
4570252f6d |
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>
|
||||
777
.idea/workspace.xml
generated
777
.idea/workspace.xml
generated
@@ -1,777 +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/custom.py" afterPath="$PROJECT_DIR$/apps/custom.py" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/system/urls.py" afterPath="$PROJECT_DIR$/apps/system/urls.py" />
|
||||
<change beforePath="$PROJECT_DIR$/apps/system/views_menu.py" afterPath="$PROJECT_DIR$/apps/system/views_menu.py" />
|
||||
<change beforePath="$PROJECT_DIR$/db.sqlite3" afterPath="$PROJECT_DIR$/db.sqlite3" />
|
||||
<change beforePath="$PROJECT_DIR$/templates/system/menu_list.html" afterPath="$PROJECT_DIR$/templates/system/menu_list.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="510">
|
||||
<caret line="30" column="0" lean-forward="true" selection-start-line="30" selection-start-column="0" selection-end-line="30" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#28#0" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="menu_update.html" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/templates/system/menu_update.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="623">
|
||||
<caret line="100" column="0" lean-forward="true" selection-start-line="100" selection-start-column="0" selection-end-line="100" selection-end-column="0" />
|
||||
<folding />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="menu_list.html" pinned="false" current-in-tab="false">
|
||||
<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>
|
||||
</file>
|
||||
<file leaf-file-name="views_menu.py" pinned="false" current-in-tab="true">
|
||||
<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="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="555">
|
||||
<caret line="55" column="53" lean-forward="true" selection-start-line="55" selection-start-column="53" selection-end-line="55" selection-end-column="53" />
|
||||
<folding>
|
||||
<element signature="e#73#84#0" expanded="true" />
|
||||
</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$/apps/system/urls.py" />
|
||||
<option value="$PROJECT_DIR$/templates/system/menu_update.html" />
|
||||
<option value="$PROJECT_DIR$/templates/system/menu_list.html" />
|
||||
<option value="$PROJECT_DIR$/apps/custom.py" />
|
||||
<option value="$PROJECT_DIR$/apps/system/views_menu.py" />
|
||||
</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="7">
|
||||
<option name="x" value="-1379" />
|
||||
<option name="y" value="113" />
|
||||
<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="Scope" />
|
||||
<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="apps" type="462c0819:PsiDirectoryNode" />
|
||||
<item name="system" type="462c0819:PsiDirectoryNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
<pane id="Scratches" />
|
||||
</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="D:/PycharmProject/sandboxOA" />
|
||||
<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="MoveFile.RECENT_KEYS">
|
||||
<recent name="D:\ProjectFile\sandboxMP\templates\system" />
|
||||
<recent name="D:\ProjectFile\sandboxMP\apps" />
|
||||
</key>
|
||||
<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>
|
||||
</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="-8" y="-8" width="1936" height="1056" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<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.3297062" 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="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="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.23068553" sideWeight="0.49573562" order="2" 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="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.1609808" 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="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="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.26792964" sideWeight="0.5" order="3" side_tool="false" 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="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="Run" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.23274696" sideWeight="0.49573562" order="2" 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.2012894" 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="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="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" />
|
||||
</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$/apps/system/views_user.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="221">
|
||||
<caret line="20" column="6" lean-forward="false" selection-start-line="20" selection-start-column="6" selection-end-line="20" selection-end-column="6" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/apps/system/views.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="34">
|
||||
<caret line="2" column="0" lean-forward="true" selection-start-line="2" selection-start-column="0" selection-end-line="2" 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="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://$PROJECT_DIR$/static/bootstrap/js/npm.js">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="12" column="28" lean-forward="true" selection-start-line="12" selection-start-column="28" selection-end-line="12" selection-end-column="28" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/index.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="238">
|
||||
<caret line="14" column="14" lean-forward="true" selection-start-line="14" selection-start-column="14" selection-end-line="14" selection-end-column="14" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/templates/base-layer.html">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="476">
|
||||
<caret line="28" column="22" lean-forward="true" selection-start-line="28" selection-start-column="22" selection-end-line="28" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<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" />
|
||||
<folding>
|
||||
<element signature="e#0#70#0" expanded="false" />
|
||||
</folding>
|
||||
</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://$PROJECT_DIR$/apps/system/models.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="528">
|
||||
<caret line="72" column="24" lean-forward="true" selection-start-line="72" selection-start-column="24" selection-end-line="72" selection-end-column="24" />
|
||||
<folding>
|
||||
<element signature="e#0#28#0" expanded="false" />
|
||||
</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/views/generic/detail.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="78">
|
||||
<caret line="114" column="33" lean-forward="true" selection-start-line="114" selection-start-column="4" selection-end-line="114" 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://$USER_HOME$/Envs/sandboxMP/Lib/site-packages/django/views/generic/edit.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="971">
|
||||
<caret line="181" column="6" lean-forward="false" selection-start-line="181" selection-start-column="6" selection-end-line="181" selection-end-column="6" />
|
||||
<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_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$/apps/system/urls.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="510">
|
||||
<caret line="30" column="0" lean-forward="true" selection-start-line="30" selection-start-column="0" selection-end-line="30" selection-end-column="0" />
|
||||
<folding>
|
||||
<element signature="e#0#28#0" expanded="true" />
|
||||
</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="623">
|
||||
<caret line="100" column="0" lean-forward="true" selection-start-line="100" selection-start-column="0" selection-end-line="100" selection-end-column="0" />
|
||||
<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$/apps/custom.py">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="555">
|
||||
<caret line="55" column="53" lean-forward="true" selection-start-line="55" selection-start-column="53" selection-end-line="55" selection-end-column="53" />
|
||||
<folding>
|
||||
<element signature="e#73#84#0" expanded="true" />
|
||||
</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="true" />
|
||||
</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
|
||||
46
apps/cmdb/forms.py
Normal file
46
apps/cmdb/forms.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# @Time : 2018/12/19 16:13
|
||||
# @Author : RobbieHan
|
||||
# @File : forms.py
|
||||
|
||||
from django import forms
|
||||
|
||||
from .models import Code
|
||||
|
||||
|
||||
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)
|
||||
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.BooleanField(default=True, 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=50, blank=True, default='', verbose_name='主机名')
|
||||
mac_address = models.CharField(max_length=50, blank=True, default='', verbose_name='MAC地址')
|
||||
sn_number = models.CharField(max_length=50, blank=True, default='', verbose_name='SN号码')
|
||||
os_type = models.CharField(max_length=50, blank=True, default='', verbose_name='系统类型')
|
||||
device_type = models.CharField(max_length=50, 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'])
|
||||
|
||||
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="上传人")
|
||||
|
||||
13
apps/cmdb/signals.py
Normal file
13
apps/cmdb/signals.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_delete
|
||||
|
||||
from .models import DeviceFile
|
||||
|
||||
|
||||
@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)
|
||||
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!")
|
||||
23
apps/cmdb/urls.py
Normal file
23
apps/cmdb/urls.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import CmdbView
|
||||
from . import views_code, views_scan
|
||||
|
||||
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'),
|
||||
|
||||
]
|
||||
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
|
||||
92
apps/cmdb/views_scan.py
Normal file
92
apps/cmdb/views_scan.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# @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
|
||||
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)
|
||||
114
apps/custom.py
114
apps/custom.py
@@ -3,15 +3,29 @@
|
||||
# @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:
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
|
||||
if queryset is None:
|
||||
@@ -31,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(**self.filters)
|
||||
if fields:
|
||||
queryset = queryset.values(*self.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):
|
||||
@@ -39,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')
|
||||
|
||||
|
||||
@@ -50,7 +132,31 @@ class SandboxCreateView(LoginRequiredMixin, SandboxEditViewMixin, CreateView):
|
||||
|
||||
|
||||
class SandboxUpdateView(LoginRequiredMixin, SandboxEditViewMixin, SandboxGetObjectMixin, UpdateView):
|
||||
|
||||
"""View for updating an object, with a response rendered by a template."""
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
return super().post(request, *args, **kwargs)
|
||||
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.
BIN
apps/system/__pycache__/views_role.cpython-36.pyc
Normal file
BIN
apps/system/__pycache__/views_role.cpython-36.pyc
Normal file
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,7 +1,7 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import SystemView
|
||||
from . import views_structure, views_user, views_menu
|
||||
from . import views_structure, views_user, views_menu, views_role
|
||||
|
||||
app_name = 'system'
|
||||
|
||||
@@ -27,4 +27,12 @@ urlpatterns = [
|
||||
path('rbac/menu/create/', views_menu.MenuCreateView.as_view(), name='rbac-menu-create'),
|
||||
path('rbac/menu/update/', views_menu.MenuUpdateView.as_view(), name='rbac-menu-update'),
|
||||
|
||||
path('rbac/role/', views_role.RoleView.as_view(), name='rbac-role'),
|
||||
path('rbac/role/create/', views_role.RoleCreateView.as_view(), name='rbac-role-create'),
|
||||
path('rbac/role/list/', views_role.RoleListView.as_view(), name='rbac-role-list'),
|
||||
path('rbac/role/update/', views_role.RoleUpdateView.as_view(), name='rbac-role-update'),
|
||||
path('rbac/role/delete/', views_role.RoleDeleteView.as_view(), name='rbac-role-delete'),
|
||||
path('rbac/role/role2user/', views_role.Role2UserView.as_view(), name="rbac-role-role2user"),
|
||||
path('rbac/role/role2menu/', views_role.Role2MenuView.as_view(), name="rbac-role-role2menu"),
|
||||
path('rbac/role/role2menu_list/', views_role.Role2MenuListView.as_view(), name="rbac-role-role2menu_list"),
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
118
apps/system/views_role.py
Normal file
118
apps/system/views_role.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# @Time : 2018/11/13 23:25
|
||||
# @Author : RobbieHan
|
||||
# @File : views_role.py
|
||||
|
||||
import json
|
||||
|
||||
from django.views.generic.base import View
|
||||
from django.shortcuts import HttpResponse, get_object_or_404
|
||||
from django.views.generic import TemplateView
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.shortcuts import render
|
||||
|
||||
from .mixin import LoginRequiredMixin
|
||||
from .models import Role, Menu
|
||||
from custom import SandboxCreateView, SandboxUpdateView, BreadcrumbMixin
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class RoleView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
|
||||
template_name = 'system/role.html'
|
||||
|
||||
|
||||
class RoleCreateView(SandboxCreateView):
|
||||
model = Role
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class RoleListView(LoginRequiredMixin, View):
|
||||
|
||||
def get(self, reqeust):
|
||||
fields = ['id', 'name', 'desc']
|
||||
ret = dict(data=list(Role.objects.values(*fields)))
|
||||
return HttpResponse(json.dumps(ret), content_type='application/json')
|
||||
|
||||
|
||||
class RoleUpdateView(SandboxUpdateView):
|
||||
model = Role
|
||||
fields = '__all__'
|
||||
template_name_suffix = '_update'
|
||||
|
||||
|
||||
class RoleDeleteView(LoginRequiredMixin, View):
|
||||
|
||||
def post(self, request):
|
||||
ret = dict(result=False)
|
||||
if 'id' in request.POST and request.POST['id']:
|
||||
id_list = map(int, request.POST['id'].split(','))
|
||||
Role.objects.filter(id__in=id_list).delete()
|
||||
ret['result'] = True
|
||||
return HttpResponse(json.dumps(ret), content_type='application/json')
|
||||
|
||||
|
||||
class Role2UserView(LoginRequiredMixin, View):
|
||||
"""
|
||||
角色关联用户
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
role = get_object_or_404(Role, pk=int(request.GET.get('id')))
|
||||
added_users = role.userprofile_set.all()
|
||||
all_users = User.objects.all()
|
||||
un_add_users = set(all_users).difference(added_users)
|
||||
ret = dict(role=role, added_users=added_users, un_add_users=list(un_add_users))
|
||||
return render(request, 'system/role_role2user.html', ret)
|
||||
|
||||
def post(self, request):
|
||||
res = dict(result=False)
|
||||
id_list = None
|
||||
role = get_object_or_404(Role, pk=int(request.POST.get('id')))
|
||||
if 'to' in request.POST and request.POST['to']:
|
||||
id_list = map(int, request.POST.getlist('to', []))
|
||||
role.userprofile_set.clear()
|
||||
if id_list:
|
||||
for user in User.objects.filter(id__in=id_list):
|
||||
role.userprofile_set.add(user)
|
||||
res['result'] = True
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
|
||||
|
||||
class Role2MenuView(LoginRequiredMixin, View):
|
||||
"""
|
||||
角色绑定菜单
|
||||
"""
|
||||
def get(self, request):
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
role = get_object_or_404(Role, pk=request.GET['id'])
|
||||
ret = dict(role=role)
|
||||
return render(request, 'system/role_role2menu.html', ret)
|
||||
|
||||
def post(self, request):
|
||||
res = dict(result=False)
|
||||
role = get_object_or_404(Role, pk=request.POST['id'])
|
||||
tree = json.loads(self.request.POST['tree'])
|
||||
role.permissions.clear()
|
||||
for menu in tree:
|
||||
if menu['checked'] is True:
|
||||
menu_checked = get_object_or_404(Menu, pk=menu['id'])
|
||||
role.permissions.add(menu_checked)
|
||||
res['result'] = True
|
||||
return HttpResponse(json.dumps(res), content_type='application/json')
|
||||
|
||||
|
||||
class Role2MenuListView(LoginRequiredMixin, View):
|
||||
"""
|
||||
获取zTree菜单列表
|
||||
"""
|
||||
def get(self, request):
|
||||
fields = ['id', 'name', 'parent']
|
||||
if 'id' in request.GET and request.GET['id']:
|
||||
role = Role.objects.get(id=request.GET.get('id'))
|
||||
role_menus = role.permissions.values(*fields)
|
||||
ret = dict(data=list(role_menus))
|
||||
else:
|
||||
menus = Menu.objects.all()
|
||||
ret = dict(data=list(menus.values(*fields)))
|
||||
return HttpResponse(json.dumps(ret), content_type='application/json')
|
||||
@@ -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
|
||||
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.2
|
||||
pillow==5.3.0
|
||||
mysqlclient==1.3.13
|
||||
ipython==7.1.1
|
||||
pyyaml==3.13
|
||||
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 %}
|
||||
|
||||
|
||||
|
||||
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" />
|
||||
</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 %}
|
||||
302
templates/cmdb/device_scan.html
Normal file
302
templates/cmdb/device_scan.html
Normal file
@@ -0,0 +1,302 @@
|
||||
{% 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</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 %}
|
||||
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 ">
|
||||
|
||||
261
templates/system/role.html
Normal file
261
templates/system/role.html
Normal file
@@ -0,0 +1,261 @@
|
||||
{% 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' %}">
|
||||
{% 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-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>
|
||||
</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.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 () {
|
||||
oDataTable = initTable();
|
||||
|
||||
function initTable() {
|
||||
var oTable = $('#dtbList').DataTable($.extend(true, {},
|
||||
DATATABLES_CONSTANT.DATA_TABLES.DEFAULT_OPTION,
|
||||
{
|
||||
ajax: {
|
||||
"url": "{% url 'system:rbac-role-list' %}",
|
||||
},
|
||||
columns: [
|
||||
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
|
||||
{
|
||||
data: "id",
|
||||
width: "5%",
|
||||
},
|
||||
{
|
||||
data: "name",
|
||||
//width : "20%",
|
||||
},
|
||||
{
|
||||
data: "desc",
|
||||
//width : "20%",
|
||||
},
|
||||
|
||||
{
|
||||
data: "id",
|
||||
width: "16%",
|
||||
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='doUpdateUser("
|
||||
+ data + ")'><i class='glyphicon glyphicon-user'></i></button>";
|
||||
ret = ret + "<button title='关联菜单' onclick='doUpdateMenu("
|
||||
+ data + ")'><i class='glyphicon glyphicon-tree-conifer'></i></button>";
|
||||
ret = ret + "<button title='删除' onclick='doDelete("
|
||||
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
|
||||
return ret;
|
||||
}
|
||||
}],
|
||||
}));
|
||||
return oTable;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$("#btnCreate").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '新增',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '300px'],
|
||||
content: "{% url 'system:rbac-role-create' %}",
|
||||
end: function () {
|
||||
//关闭时做的事情
|
||||
oDataTable.ajax.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#btnRefresh").click(function () {
|
||||
oDataTable.ajax.reload();
|
||||
});
|
||||
|
||||
function doUpdate(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '编辑',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '400px'],
|
||||
content: ["{% url 'system:rbac-role-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 'system:rbac-role-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 'system:rbac-role-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 doUpdateUser(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '绑定用户',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['800px', '600px'],
|
||||
content: ["{% url 'system:rbac-role-role2user' %}" + '?id=' + id, 'no'],
|
||||
});
|
||||
}
|
||||
|
||||
//关联菜单
|
||||
function doUpdateMenu(id) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '权限分配',
|
||||
shadeClose: false,
|
||||
maxmin: true,
|
||||
area: ['600px', '480px'],
|
||||
content: ["{% url 'system:rbac-role-role2menu' %}" + '?id=' + id, 'no'],
|
||||
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
80
templates/system/role_form.html
Normal file
80
templates/system/role_form.html
Normal file
@@ -0,0 +1,80 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% 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">名称</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control" name="name" 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="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/combo-select/jquery.combo.select.js' %}"></script>
|
||||
<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'system:rbac-role-create' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert('数据保存失败', {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
/*select 支持输入检索*/
|
||||
$(function () {
|
||||
$('select').comboSelect();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
179
templates/system/role_role2menu.html
Normal file
179
templates/system/role_role2menu.html
Normal file
@@ -0,0 +1,179 @@
|
||||
{% extends "base-layer.html" %} {% load static %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/zTree/css/metroStyle/metroStyle.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'plugins/zTree/css/zTreeStyle/zTreeStyle.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'plugins/zTree/css/demo.css' %}" type="text/css">
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
|
||||
<style type="text/css">
|
||||
.ztree li span.button.switch.level0 {
|
||||
visibility: hidden;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.ztree li ul.level0 {
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<div class="box box-danger">
|
||||
<div class="box-body">
|
||||
<form class="form-horizontal" id="addTreeForm" action="" method="post">
|
||||
{% csrf_token %}
|
||||
<!-- 注释1:页面实例是由Role2MenuView视图返回的,同时传递了上下文role,这里使用role.id时用来提交POST请求时向后台传递的id-->
|
||||
<input type="hidden" name='id' value="{{ role.id }}"/>
|
||||
<input type="hidden" name="tree" id="tree" value=""/>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<div class="row span7 text-center ">
|
||||
<label class="control-label"><h5>所有菜单</h5></label>
|
||||
|
||||
</div>
|
||||
<div style="zTreeDemoBackground:left">
|
||||
<ul id="left_tree" class="ztree"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<br><br><br><br><br><br>
|
||||
<div class="text-center">
|
||||
<button type="button" id="btnSave" class="btn btn-info margin-right ">生成</button>
|
||||
</div>
|
||||
<div class="text-center text-gray margin-top-5">{{ role.name }}权限</div>
|
||||
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<div class="row span7 text-center">
|
||||
<label class="control-label"><h5>已选菜单</h5></label>
|
||||
</div>
|
||||
<ul id="right_tree" class="ztree"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script type="text/javascript" src="{% static 'plugins/zTree/js/jquery.ztree.core.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'plugins/zTree/js/jquery.ztree.excheck.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
var zTree;
|
||||
var demoIframe;
|
||||
|
||||
var left_tree_setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true,
|
||||
selectedMulti: true
|
||||
},
|
||||
check: {
|
||||
enable: true,
|
||||
//chkboxType : { "Y" : "", "N" : "" }
|
||||
},
|
||||
data: {
|
||||
key: {
|
||||
name: "name",
|
||||
//title:"title",
|
||||
},
|
||||
simpleData: {
|
||||
enable: true,
|
||||
idKey: "id",
|
||||
pIdKey: "parent",
|
||||
rootPId: ""
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
var right_tree_setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true,
|
||||
selectedMulti: true
|
||||
},
|
||||
check: {
|
||||
enable: false,
|
||||
//chkboxType : { "Y" : "", "N" : "" }
|
||||
},
|
||||
data: {
|
||||
key: {
|
||||
name: "name",
|
||||
//title:"title",
|
||||
},
|
||||
simpleData: {
|
||||
enable: true,
|
||||
idKey: "id",
|
||||
pIdKey: "parent",
|
||||
rootPId: ""
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{% url 'system:rbac-role-role2menu_list' %}",
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
layer.close();
|
||||
var t = $("#left_tree");
|
||||
t = $.fn.zTree.init(t, left_tree_setting, msg.data);
|
||||
var treeObj = $.fn.zTree.getZTreeObj("left_tree");
|
||||
treeObj.expandAll(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "{% url 'system:rbac-role-role2menu_list' %}",
|
||||
data: {"id":{{role.id}}},
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
layer.close();
|
||||
var t = $("#right_tree");
|
||||
t = $.fn.zTree.init(t, right_tree_setting, msg.data);
|
||||
var treeObj = $.fn.zTree.getZTreeObj("right_tree");
|
||||
treeObj.expandAll(true);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var treeObj = $.fn.zTree.getZTreeObj("left_tree");
|
||||
var nodes = treeObj.getCheckedNodes(true);
|
||||
$("#tree").val(JSON.stringify(nodes));
|
||||
var data = $("#addTreeForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addTreeForm").attr('method'),
|
||||
url: "{% url 'system:rbac-role-role2menu' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
beforeSend: function () {
|
||||
this.layerIndex = layer.load(1, {
|
||||
shade: [0.1, '#fff']
|
||||
});
|
||||
},
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('操作成功', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll();
|
||||
});
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('操作失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
105
templates/system/role_role2user.html
Normal file
105
templates/system/role_role2user.html
Normal file
@@ -0,0 +1,105 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="selectUsersForm" action="" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name='id' value="{{ role.id }}"/>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<label class="control-label">可选用户:</label>
|
||||
<select name="from" id="multiselect" class="form-control" size="18" multiple="multiple">
|
||||
{% for item in un_add_users %}
|
||||
<option value="{{ item.id }}">{{ item.name }}({{ item.username }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<br><br><br><br><br><br>
|
||||
<button type="button" id="multiselect_rightAll" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-forward"></i></button>
|
||||
<button type="button" id="multiselect_rightSelected" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-chevron-right"></i></button>
|
||||
<button type="button" id="multiselect_leftSelected" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-chevron-left"></i></button>
|
||||
<button type="button" id="multiselect_leftAll" class="btn btn-block"><i
|
||||
class="glyphicon glyphicon-backward"></i></button>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<label class="control-label">{{ role.name }}-已绑定用户:</label>
|
||||
<select name="to" id="multiselect_to" class="form-control" size="18" multiple="multiple">
|
||||
{% for item in added_users %}
|
||||
<option value="{{ item.id }}">{{ item.name }}({{ item.username }})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 margin-top-5">
|
||||
<p class="text-maroon">*注意:一个用户可以添加到多个角色中,继承多个角色的权限</p>
|
||||
</div>
|
||||
</div>
|
||||
</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/select/multiselect.min.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
//初始化多选列表
|
||||
$('#multiselect').multiselect({
|
||||
search: {
|
||||
left: '<input type="text" class="form-control" placeholder="Search..." />',
|
||||
right: '<input type="text" class="form-control" placeholder="Search..." />',
|
||||
},
|
||||
fireSearch: function (value) {
|
||||
return value.length > 3;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
$('#multiselect_to option').prop('selected', true);
|
||||
var data = $("#selectUsersForm").serialize();
|
||||
console.log(data);
|
||||
$.ajax({
|
||||
type: $("#selectUsersForm").attr('method'),
|
||||
url: "{% url 'system:rbac-role-role2user' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('操作成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll();
|
||||
});
|
||||
} else {
|
||||
//alert(msg.message);
|
||||
layer.alert('操作失败', {icon: 2});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
81
templates/system/role_update.html
Normal file
81
templates/system/role_update.html
Normal file
@@ -0,0 +1,81 @@
|
||||
{% extends 'base-layer.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block main %}
|
||||
<div class="box box-danger">
|
||||
<form class="form-horizontal" id="addForm" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name='id' value="{{ role.id }}"/>
|
||||
<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-8">
|
||||
<input class="form-control" name="name" type="text" value="{{ role.name }}"/>
|
||||
</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="desc" type="text" value="{{ role.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/combo-select/jquery.combo.select.js' %}"></script>
|
||||
<script src="{% static 'bootstrap/js/bootstrap-datetimepicker.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
$("#btnSave").click(function () {
|
||||
var data = $("#addForm").serialize();
|
||||
$.ajax({
|
||||
type: $("#addForm").attr('method'),
|
||||
url: "{% url 'system:rbac-role-update' %}",
|
||||
data: data,
|
||||
cache: false,
|
||||
success: function (msg) {
|
||||
if (msg.result) {
|
||||
layer.alert('数据保存成功!', {icon: 1}, function (index) {
|
||||
parent.layer.closeAll(); //关闭所有弹窗
|
||||
});
|
||||
} else {
|
||||
layer.alert('数据保存失败', {icon: 5});
|
||||
//$('errorMessage').html(msg.message)
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*点取消刷新新页面*/
|
||||
$("#btnCancel").click(function () {
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
/*select 支持输入检索*/
|
||||
$(function () {
|
||||
$('select').comboSelect();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -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