profile and other stuff
This commit is contained in:
2
.idea/backend.iml
generated
2
.idea/backend.iml
generated
@@ -17,7 +17,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="jdk" jdkName="Python 3.7 (backend-pKjQcArQ)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Pipenv (backend)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="module" module-name="ocmp" />
|
<orderEntry type="module" module-name="ocmp" />
|
||||||
<orderEntry type="module" module-name="OpenCastPythonClient" />
|
<orderEntry type="module" module-name="OpenCastPythonClient" />
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -3,7 +3,7 @@
|
|||||||
<component name="JavaScriptSettings">
|
<component name="JavaScriptSettings">
|
||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Pipenv (newsMap)" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Pipenv (backend)" project-jdk-type="Python SDK" />
|
||||||
<component name="PyCharmProfessionalAdvertiser">
|
<component name="PyCharmProfessionalAdvertiser">
|
||||||
<option name="shown" value="true" />
|
<option name="shown" value="true" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
4
.idea/vcs.xml
generated
4
.idea/vcs.xml
generated
@@ -2,9 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/../../OpenCastPythonClient" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/../../media-abstraction-layer" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/../frontend" vcs="Git" />
|
||||||
<mapping directory="$USER_HOME$/Projects/newsMap" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
662
.idea/workspace.xml
generated
662
.idea/workspace.xml
generated
@@ -2,18 +2,31 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="dbc2bdbd-c8f7-46d2-961a-6a2b77f8f4c5" name="Default Changelist" comment="">
|
<list default="true" id="dbc2bdbd-c8f7-46d2-961a-6a2b77f8f4c5" name="Default Changelist" comment="">
|
||||||
<change afterPath="$USER_HOME$/Projects/newsMap/.idea/other.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/../.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../.idea/workspace.xml" afterDir="false" />
|
||||||
<change afterPath="$USER_HOME$/Projects/newsMap/news_map/news_sources/de_newspaper.db" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/../activate_this.py" beforeDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/ingest.py" beforeDir="false" afterPath="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/ingest.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/service.py" beforeDir="false" afterPath="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/service.py" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$" beforeDir="false" afterPath="$PROJECT_DIR$" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$" beforeDir="false" afterPath="$PROJECT_DIR$" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/.idea/newsMap.iml" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/.idea/newsMap.iml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/backend.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/backend.iml" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/.idea/workspace.xml" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/Pipfile" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/Pipfile" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/Pipfile.lock" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/Pipfile.lock" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/news_map/gatherer/newsGatherer.py" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/news_map/gatherer/newsGatherer.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/__init__.py" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/news_map/newsMap.py" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/news_map/newsMap.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/api/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/__init__.py" afterDir="false" />
|
||||||
<change beforePath="$USER_HOME$/Projects/newsMap/news_map/news_sources/wiki_newspaper_scraper.py" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/news_map/news_sources/wiki_newspaper_scraper.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/api/auth_api.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/auth_api.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/api/control_api.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/control_api.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/api/user_api.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/user_api.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/auth/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/auth/__init__.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/auth/basic_auth.py" beforeDir="false" afterPath="$PROJECT_DIR$/auth/basic_auth.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/auth/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/auth/config.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/auth/templates/login.html" beforeDir="false" afterPath="$PROJECT_DIR$/auth/templates/login.html" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/config.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/models/recorder_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/models/recorder_model.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/models/user_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/models/user_model.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/api/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/api/index.ts" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/api/userRepository.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/api/userRepository.ts" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/components/Profile.vue" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/components/Profile.vue" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/main.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/main.ts" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/../frontend/src/plugins/i18n.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/plugins/i18n.ts" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
@@ -24,102 +37,6 @@
|
|||||||
<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)">
|
<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)" />
|
<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>
|
||||||
<component name="FileEditorManager">
|
|
||||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/api.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1275">
|
|
||||||
<caret line="97" column="47" selection-start-line="97" selection-start-column="47" selection-end-line="97" selection-end-column="47" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="true">
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/extron_smp.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="385">
|
|
||||||
<caret line="383" column="20" selection-start-line="383" selection-start-column="20" selection-end-line="383" selection-end-column="20" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#14#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/extron_smp_testing.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state>
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#14#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="426">
|
|
||||||
<caret line="75" column="17" lean-forward="true" selection-start-line="75" selection-start-column="17" selection-end-line="75" selection-end-column="17" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#16#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/models.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="300">
|
|
||||||
<caret line="27" column="28" selection-start-line="27" selection-start-column="28" selection-end-line="27" selection-end-column="28" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#9#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/divaapiclient.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="252">
|
|
||||||
<caret line="322" selection-start-line="322" selection-end-line="322" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#23#37#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_item_store/newsItemStore.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/diva_testing.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="7320">
|
|
||||||
<caret line="492" column="26" selection-start-line="492" selection-start-column="26" selection-end-line="492" selection-end-column="26" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_item_store/dictNewsItemStore.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
<file pinned="false" current-in-tab="false">
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_analyzer/basicWordcountNewsAnalyzer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
</file>
|
|
||||||
</leaf>
|
|
||||||
</component>
|
|
||||||
<component name="FileTemplateManagerImpl">
|
<component name="FileTemplateManagerImpl">
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
@@ -127,117 +44,23 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="FindInProjectRecents">
|
|
||||||
<findStrings>
|
|
||||||
<find>metadata</find>
|
|
||||||
<find>UploadFiles(</find>
|
|
||||||
<find>api</find>
|
|
||||||
<find>get_api</find>
|
|
||||||
<find>alternate_user</find>
|
|
||||||
<find>DIVA_INGEST_SESSIONS</find>
|
|
||||||
<find>chunked_upload</find>
|
|
||||||
<find>diva_create_asset</find>
|
|
||||||
<find>getin</find>
|
|
||||||
<find>ingesti</find>
|
|
||||||
<find>api_v1</find>
|
|
||||||
<find>newsItems</find>
|
|
||||||
<find>expect</find>
|
|
||||||
<find>app</find>
|
|
||||||
<find>logger</find>
|
|
||||||
<find>dumps</find>
|
|
||||||
<find>create_user</find>
|
|
||||||
<find>move_media_from_user_to_user</find>
|
|
||||||
<find>DIVA_INGEST_USER_BASE_NAME</find>
|
|
||||||
<find>index</find>
|
|
||||||
<find>get_ingest_user_name_pw</find>
|
|
||||||
<find>other_roles</find>
|
|
||||||
<find>other_ro</find>
|
|
||||||
<find>_build</find>
|
|
||||||
<find>genre</find>
|
|
||||||
<find>roles</find>
|
|
||||||
<find>author</find>
|
|
||||||
<find>nested</find>
|
|
||||||
<find>_build_asset_dict</find>
|
|
||||||
<find>esc</find>
|
|
||||||
</findStrings>
|
|
||||||
<replaceStrings>
|
|
||||||
<replace />
|
|
||||||
</replaceStrings>
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
|
||||||
<component name="IdeDocumentHistory">
|
|
||||||
<option name="CHANGED_PATHS">
|
|
||||||
<list>
|
|
||||||
<option value="$PROJECT_DIR$/api/room_api.py" />
|
|
||||||
<option value="$PROJECT_DIR$/api/recorder_api.py" />
|
|
||||||
<option value="$PROJECT_DIR$/models/recorder_model.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../oc_media_portal/frontend/src/components/Uploader.vue" />
|
|
||||||
<option value="$PROJECT_DIR$/models/room_model.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../oc_media_portal/backend/__init__.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../oc_media_portal/backend/spectrogram.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../oc_media_portal/backend/main.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/ingest.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/service.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/tools/upload.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/tools/media_files.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/models.py" />
|
|
||||||
<option value="$USER_HOME$/Projects/newsMap/news_map/newsMap.py" />
|
|
||||||
<option value="$USER_HOME$/Projects/newsMap/news_map/gatherer/newsGatherer.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/__init__.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/api.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/diva_testing.py" />
|
|
||||||
<option value="$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/divaapiclient.py" />
|
|
||||||
<option value="$PROJECT_DIR$/recorder_adapters/__init__.py" />
|
|
||||||
<option value="$PROJECT_DIR$/recorder_adapters/extron_smp.py" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectFrameBounds" fullScreen="true">
|
|
||||||
<option name="x" value="1680" />
|
|
||||||
<option name="y" value="-49" />
|
|
||||||
<option name="width" value="1920" />
|
|
||||||
<option name="height" value="1200" />
|
|
||||||
</component>
|
</component>
|
||||||
|
<component name="ProjectId" id="1PPJuamSCMuifjd70Sp8tYSAlOw" />
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
<component name="ProjectView">
|
|
||||||
<navigator proportions="" version="1">
|
|
||||||
<foldersAlwaysOnTop value="true" />
|
|
||||||
</navigator>
|
|
||||||
<panes>
|
|
||||||
<pane id="ProjectPane">
|
|
||||||
<subPane>
|
|
||||||
<expand>
|
|
||||||
<path>
|
|
||||||
<item name="backend" type="b2602c69:ProjectViewProjectNode" />
|
|
||||||
<item name="lrc" type="462c0819:PsiDirectoryNode" />
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<item name="backend" type="b2602c69:ProjectViewProjectNode" />
|
|
||||||
<item name="lrc" type="462c0819:PsiDirectoryNode" />
|
|
||||||
<item name="backend" type="462c0819:PsiDirectoryNode" />
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<item name="backend" type="b2602c69:ProjectViewProjectNode" />
|
|
||||||
<item name="lrc" type="462c0819:PsiDirectoryNode" />
|
|
||||||
<item name="backend" type="462c0819:PsiDirectoryNode" />
|
|
||||||
<item name="recorder_adapters" type="462c0819:PsiDirectoryNode" />
|
|
||||||
</path>
|
|
||||||
</expand>
|
|
||||||
<select />
|
|
||||||
</subPane>
|
|
||||||
</pane>
|
|
||||||
<pane id="Scope" />
|
|
||||||
</panes>
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">
|
<component name="PropertiesComponent">
|
||||||
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
<property name="last_opened_file_path" value="$PROJECT_DIR$/models" />
|
||||||
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
|
||||||
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
|
||||||
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
|
<property name="settings.editor.selected.configurable" value="project.propVCSSupport.Mappings" />
|
||||||
|
</component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
|
<recent name="C:\Users\tkurz\kit_projects\lrc\backend\models" />
|
||||||
|
</key>
|
||||||
</component>
|
</component>
|
||||||
<component name="RunDashboard">
|
<component name="RunDashboard">
|
||||||
<option name="ruleStates">
|
<option name="ruleStates">
|
||||||
@@ -251,7 +74,29 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="RunManager" selected="Python.extron_smp">
|
<component name="RunManager" selected="Python.__main__">
|
||||||
|
<configuration name="__main__" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||||
|
<module name="backend" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/__main__.py" />
|
||||||
|
<option name="PARAMETERS" value="" />
|
||||||
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
|
<option name="MODULE_MODE" value="false" />
|
||||||
|
<option name="REDIRECT_INPUT" value="false" />
|
||||||
|
<option name="INPUT_FILE" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
<configuration name="api" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
<configuration name="api" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||||
<module name="ocmp" />
|
<module name="ocmp" />
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
@@ -264,6 +109,7 @@
|
|||||||
<option name="IS_MODULE_SDK" value="false" />
|
<option name="IS_MODULE_SDK" value="false" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/../../media-abstraction-layer/backend/api.py" />
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/../../media-abstraction-layer/backend/api.py" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
@@ -285,6 +131,7 @@
|
|||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
<option name="SCRIPT_NAME" value="$USER_HOME$/Projects/newsMap/news_map/news_item_store/dictNewsItemStore.py" />
|
<option name="SCRIPT_NAME" value="$USER_HOME$/Projects/newsMap/news_map/news_item_store/dictNewsItemStore.py" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
@@ -306,6 +153,7 @@
|
|||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
<option name="SCRIPT_NAME" value="$USER_HOME$/Projects/newsMap/news_map/gatherer/dummyNewsGatherer.py" />
|
<option name="SCRIPT_NAME" value="$USER_HOME$/Projects/newsMap/news_map/gatherer/dummyNewsGatherer.py" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
@@ -327,6 +175,7 @@
|
|||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/recorder_adapters/extron_smp.py" />
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/recorder_adapters/extron_smp.py" />
|
||||||
<option name="PARAMETERS" value="" />
|
<option name="PARAMETERS" value="" />
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
@@ -336,27 +185,6 @@
|
|||||||
<option name="INPUT_FILE" value="" />
|
<option name="INPUT_FILE" value="" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="ingest" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
|
||||||
<module name="OpenCastPythonClient" />
|
|
||||||
<option name="INTERPRETER_OPTIONS" value="" />
|
|
||||||
<option name="PARENT_ENVS" value="true" />
|
|
||||||
<envs>
|
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
|
||||||
</envs>
|
|
||||||
<option name="SDK_HOME" value="" />
|
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api" />
|
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
|
||||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
||||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
||||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/ingest.py" />
|
|
||||||
<option name="PARAMETERS" value="" />
|
|
||||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
|
||||||
<option name="EMULATE_TERMINAL" value="false" />
|
|
||||||
<option name="MODULE_MODE" value="false" />
|
|
||||||
<option name="REDIRECT_INPUT" value="false" />
|
|
||||||
<option name="INPUT_FILE" value="" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<configuration name="backend" type="Python.FlaskServer">
|
<configuration name="backend" type="Python.FlaskServer">
|
||||||
<module name="backend" />
|
<module name="backend" />
|
||||||
<option name="target" value="$PROJECT_DIR$/__init__.py" />
|
<option name="target" value="$PROJECT_DIR$/__init__.py" />
|
||||||
@@ -373,19 +201,20 @@
|
|||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Flask server.backend" />
|
||||||
<item itemvalue="Python.api" />
|
<item itemvalue="Python.api" />
|
||||||
<item itemvalue="Python.ingest" />
|
|
||||||
<item itemvalue="Python.dummyNewsGatherer" />
|
<item itemvalue="Python.dummyNewsGatherer" />
|
||||||
<item itemvalue="Python.dictNewsItemStore" />
|
<item itemvalue="Python.dictNewsItemStore" />
|
||||||
<item itemvalue="Python.extron_smp" />
|
<item itemvalue="Python.extron_smp" />
|
||||||
|
<item itemvalue="Python.__main__" />
|
||||||
</list>
|
</list>
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Python.__main__" />
|
||||||
<item itemvalue="Python.extron_smp" />
|
<item itemvalue="Python.extron_smp" />
|
||||||
<item itemvalue="Python.dictNewsItemStore" />
|
<item itemvalue="Python.dictNewsItemStore" />
|
||||||
<item itemvalue="Python.dummyNewsGatherer" />
|
<item itemvalue="Python.dummyNewsGatherer" />
|
||||||
<item itemvalue="Python.api" />
|
<item itemvalue="Python.api" />
|
||||||
<item itemvalue="Python.ingest" />
|
|
||||||
</list>
|
</list>
|
||||||
</recent_temporary>
|
</recent_temporary>
|
||||||
</component>
|
</component>
|
||||||
@@ -402,355 +231,38 @@
|
|||||||
<workItem from="1556266473180" duration="14572000" />
|
<workItem from="1556266473180" duration="14572000" />
|
||||||
<workItem from="1557483399929" duration="284000" />
|
<workItem from="1557483399929" duration="284000" />
|
||||||
<workItem from="1557483805341" duration="173000" />
|
<workItem from="1557483805341" duration="173000" />
|
||||||
|
<workItem from="1565770023268" duration="8793000" />
|
||||||
|
<workItem from="1565778873035" duration="9376000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TimeTrackingManager">
|
|
||||||
<option name="totallyTimeSpent" value="40587000" />
|
|
||||||
</component>
|
|
||||||
<component name="ToolWindowManager">
|
|
||||||
<frame x="1680" y="-49" width="1920" height="1200" extended-state="0" />
|
|
||||||
<editor active="true" />
|
|
||||||
<layout>
|
|
||||||
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.22064245" />
|
|
||||||
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
|
|
||||||
<window_info id="Favorites" order="2" side_tool="true" />
|
|
||||||
<window_info anchor="bottom" id="Message" order="0" />
|
|
||||||
<window_info anchor="bottom" id="Find" order="1" />
|
|
||||||
<window_info active="true" anchor="bottom" id="Run" order="2" visible="true" weight="0.32920355" />
|
|
||||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
|
||||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
|
||||||
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
|
|
||||||
<window_info anchor="bottom" id="TODO" order="6" />
|
|
||||||
<window_info anchor="bottom" id="Docker" order="7" show_stripe_button="false" />
|
|
||||||
<window_info anchor="bottom" id="Version Control" order="8" />
|
|
||||||
<window_info anchor="bottom" id="Database Changes" order="9" />
|
|
||||||
<window_info anchor="bottom" id="Terminal" order="10" weight="0.28584072" />
|
|
||||||
<window_info anchor="bottom" id="Python Console" order="11" />
|
|
||||||
<window_info anchor="bottom" id="Event Log" order="12" side_tool="true" weight="0.32959184" />
|
|
||||||
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
|
|
||||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
|
||||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
|
||||||
<window_info anchor="right" id="SciView" order="3" />
|
|
||||||
<window_info anchor="right" id="Database" order="4" />
|
|
||||||
</layout>
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
<option name="version" value="1" />
|
<option name="version" value="1" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="Vcs.Log.Tabs.Properties">
|
||||||
|
<option name="TAB_STATES">
|
||||||
|
<map>
|
||||||
|
<entry key="MAIN">
|
||||||
|
<value>
|
||||||
|
<State>
|
||||||
|
<option name="COLUMN_ORDER" />
|
||||||
|
</State>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsManagerConfiguration">
|
||||||
|
<ignored-roots>
|
||||||
|
<path value="$USER_HOME$/Projects/newsMap" />
|
||||||
|
<path value="$PROJECT_DIR$/../../OpenCastPythonClient" />
|
||||||
|
<path value="$PROJECT_DIR$/../../media-abstraction-layer" />
|
||||||
|
</ignored-roots>
|
||||||
|
</component>
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
|
<SUITE FILE_PATH="coverage/backend$extron_smp.coverage" NAME="extron_smp Coverage Results" MODIFIED="1565782117031" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/recorder_adapters" />
|
||||||
<SUITE FILE_PATH="coverage/backend$main.coverage" NAME="main Coverage Results" MODIFIED="1557306314589" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/../../oc_media_portal/backend" />
|
<SUITE FILE_PATH="coverage/backend$main.coverage" NAME="main Coverage Results" MODIFIED="1557306314589" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/../../oc_media_portal/backend" />
|
||||||
<SUITE FILE_PATH="coverage/backend$backend.coverage" NAME="backend Coverage Results" MODIFIED="1556810339611" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
|
<SUITE FILE_PATH="coverage/backend$backend.coverage" NAME="backend Coverage Results" MODIFIED="1556810339611" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="" />
|
||||||
</component>
|
<SUITE FILE_PATH="coverage/backend$__main__.coverage" NAME="__main__ Coverage Results" MODIFIED="1565793060617" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<component name="editorHistoryManager">
|
|
||||||
<entry file="file://$USER_HOME$/.virtualenvs/backend-ogkP9-fi/lib/python3.7/site-packages/ffmpeg/_ffmpeg.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="45">
|
|
||||||
<caret line="15" column="4" selection-start-line="15" selection-start-column="4" selection-end-line="15" selection-end-column="9" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file:///usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/wave.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="465">
|
|
||||||
<caret line="31" column="21" selection-start-line="31" selection-start-column="21" selection-end-line="31" selection-end-column="21" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/.virtualenvs/backend-ogkP9-fi/lib/python3.7/site-packages/matplotlib/pyplot.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="540">
|
|
||||||
<caret line="686" column="4" selection-start-line="686" selection-start-column="4" selection-end-line="686" selection-end-column="4" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/.virtualenvs/backend-ogkP9-fi/lib/python3.7/site-packages/matplotlib/figure.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="318">
|
|
||||||
<caret line="1820" column="8" selection-start-line="1820" selection-start-column="8" selection-end-line="1820" selection-end-column="11" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/frontend/src/router.js" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/frontend/public/index.html" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/frontend/src/views/Home.vue" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/backend/main.py" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/backend/__init__.py" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/backend/spectrogram.py" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../oc_media_portal/frontend/src/components/Uploader.vue" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/ingest.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="903">
|
|
||||||
<caret line="167" column="14" selection-start-line="167" selection-start-column="14" selection-end-line="167" selection-end-column="14" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/info.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state>
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#15#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/api/service.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="3255">
|
|
||||||
<caret line="228" column="50" selection-start-line="228" selection-start-column="50" selection-end-line="228" selection-end-column="50" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/.virtualenvs/backend-ogkP9-fi/lib/python3.7/site-packages/flask/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="300">
|
|
||||||
<caret line="44" selection-start-line="44" selection-end-line="44" selection-end-column="7" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file:///usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="210">
|
|
||||||
<caret line="298" column="4" selection-start-line="298" selection-start-column="4" selection-end-line="298" selection-end-column="9" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/uploads/test.txt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/.local/share/virtualenvs/OpenCastPythonClient-4-tsbEhp/lib/python3.7/site-packages/werkzeug/wrappers.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="7740">
|
|
||||||
<caret line="543" column="17" selection-start-line="543" selection-start-column="17" selection-end-line="543" selection-end-column="17" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/tools/upload.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="420">
|
|
||||||
<caret line="30" column="13" selection-start-line="30" selection-start-column="13" selection-end-line="30" selection-end-column="13" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#9#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/tools/media_files.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="45">
|
|
||||||
<caret line="14" column="87" selection-start-line="14" selection-start-column="87" selection-end-line="14" selection-end-column="87" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#9#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/manage.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="373">
|
|
||||||
<caret line="32" column="71" lean-forward="true" selection-start-line="32" selection-start-column="71" selection-end-line="32" selection-end-column="71" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/serve_frontend.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="135">
|
|
||||||
<caret line="15" selection-start-line="15" selection-end-line="15" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/api/group_api.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="186">
|
|
||||||
<caret line="29" column="40" selection-start-line="29" selection-start-column="40" selection-end-line="29" selection-end-column="40" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#267#310#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/api/recorder_api.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1815">
|
|
||||||
<caret line="127" selection-start-line="127" selection-end-line="127" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#267#310#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/main.py" />
|
|
||||||
<entry file="file://$PROJECT_DIR$/api/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="525">
|
|
||||||
<caret line="36" selection-start-line="36" selection-end-line="36" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#25#59#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../OpenCastPythonClient/ocpy/main.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="105">
|
|
||||||
<caret line="7" column="64" selection-start-line="7" selection-start-column="55" selection-end-line="7" selection-end-column="64" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/test.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/faz_website.txt">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="225">
|
|
||||||
<caret line="15" column="21" lean-forward="true" selection-start-line="15" selection-start-column="21" selection-end-line="15" selection-end-column="21" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/newsMap.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="435">
|
|
||||||
<caret line="29" column="29" selection-start-line="29" selection-start-column="29" selection-end-line="29" selection-end-column="29" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/basicNewsGatherer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state>
|
|
||||||
<folding>
|
|
||||||
<element signature="e#77#121#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/dummyNewsGatherer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="216">
|
|
||||||
<caret line="40" column="37" selection-start-line="40" selection-start-column="37" selection-end-line="40" selection-end-column="37" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/newsGatherer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="540">
|
|
||||||
<caret line="42" column="8" selection-start-line="42" selection-start-column="8" selection-end-line="42" selection-end-column="8" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/gatherer/rssNewsGatherer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="268">
|
|
||||||
<caret line="44" column="38" selection-start-line="44" selection-start-column="38" selection-end-line="44" selection-end-column="38" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_item_store/mongoNewsItemStore.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="210">
|
|
||||||
<caret line="41" column="8" selection-start-line="41" selection-start-column="8" selection-end-line="41" selection-end-column="8" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file:///usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/telnetlib.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="-105">
|
|
||||||
<caret selection-end-line="32" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="240">
|
|
||||||
<caret line="24" column="2" selection-start-line="24" selection-start-column="2" selection-end-line="24" selection-end-column="2" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#9#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/api.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="1275">
|
|
||||||
<caret line="97" column="47" selection-start-line="97" selection-start-column="47" selection-end-line="97" selection-end-column="47" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/models.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="300">
|
|
||||||
<caret line="27" column="28" selection-start-line="27" selection-start-column="28" selection-end-line="27" selection-end-column="28" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#9#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_item_store/newsItemStore.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/diva_testing.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="7320">
|
|
||||||
<caret line="492" column="26" selection-start-line="492" selection-start-column="26" selection-end-line="492" selection-end-column="26" />
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_item_store/dictNewsItemStore.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$USER_HOME$/Projects/newsMap/news_map/news_analyzer/basicWordcountNewsAnalyzer.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor" />
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/../../media-abstraction-layer/backend/media_backends/divaapiclient.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="252">
|
|
||||||
<caret line="322" selection-start-line="322" selection-end-line="322" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#23#37#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/extron_smp_testing.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state>
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#14#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/__init__.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="426">
|
|
||||||
<caret line="75" column="17" lean-forward="true" selection-start-line="75" selection-start-column="17" selection-end-line="75" selection-end-column="17" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#16#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
<entry file="file://$PROJECT_DIR$/recorder_adapters/extron_smp.py">
|
|
||||||
<provider selected="true" editor-type-id="text-editor">
|
|
||||||
<state relative-caret-position="385">
|
|
||||||
<caret line="383" column="20" selection-start-line="383" selection-start-column="20" selection-end-line="383" selection-end-column="20" />
|
|
||||||
<folding>
|
|
||||||
<element signature="e#0#14#0" expanded="true" />
|
|
||||||
</folding>
|
|
||||||
</state>
|
|
||||||
</provider>
|
|
||||||
</entry>
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -42,7 +42,6 @@ def verify_token(token):
|
|||||||
app.logger.info(decoded)
|
app.logger.info(decoded)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
basic_auth = HTTPBasicAuth()
|
basic_auth = HTTPBasicAuth()
|
||||||
multi_auth = MultiAuth(basic_auth, jwt_auth)
|
multi_auth = MultiAuth(basic_auth, jwt_auth)
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ api_v1.add_namespace(api_cron_job)
|
|||||||
api_v1.add_namespace(api_control)
|
api_v1.add_namespace(api_control)
|
||||||
|
|
||||||
auth_api_bp = Blueprint('auth_api', __name__, url_prefix='/api/auth')
|
auth_api_bp = Blueprint('auth_api', __name__, url_prefix='/api/auth')
|
||||||
|
auth_api_v1 = Api(auth_api_bp, prefix="/v1", version='0.1', title='Auth API',
|
||||||
|
description='Auth API', doc='/v1/doc/', authorizations=api_authorizations, security='bearerAuth')
|
||||||
|
|
||||||
|
auth_api_providers_ns = Namespace('providers')
|
||||||
|
auth_api_register_ns = Namespace('register')
|
||||||
|
auth_api_v1.add_namespace(auth_api_providers_ns)
|
||||||
|
auth_api_v1.add_namespace(auth_api_register_ns)
|
||||||
# user_api_bp = Blueprint('user_api', __name__, url_prefix='/api/user')
|
# user_api_bp = Blueprint('user_api', __name__, url_prefix='/api/user')
|
||||||
# group_api_bp = Blueprint('group_api', __name__, url_prefix='/api/group')
|
# group_api_bp = Blueprint('group_api', __name__, url_prefix='/api/group')
|
||||||
|
|
||||||
|
|||||||
@@ -7,23 +7,27 @@ Login through API does not start a new session, but instead returns JWT.
|
|||||||
"""
|
"""
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import jwt
|
import jwt
|
||||||
from flask import request, jsonify, current_app, url_for, Response, session, redirect, make_response
|
from flask import request, jsonify, current_app, url_for, Response, session, redirect, make_response
|
||||||
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_refresh_token_required, get_jwt_identity
|
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_refresh_token_required, get_jwt_identity, \
|
||||||
|
get_raw_jwt, jwt_required
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
from flask_login import logout_user, login_user
|
from flask_login import logout_user, login_user
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
|
from flask_restplus import Resource, fields
|
||||||
from werkzeug.routing import BuildError
|
from werkzeug.routing import BuildError
|
||||||
|
|
||||||
from backend import db, app
|
from backend import db, app, jwt_extended
|
||||||
from backend.api import auth_api_bp
|
from backend.api import auth_api_bp, auth_api_providers_ns, auth_api_register_ns
|
||||||
from backend.auth import AUTH_PROVIDERS, oidc_auth
|
from backend.auth import AUTH_PROVIDERS, oidc_auth
|
||||||
from backend.models.user_model import User, Group
|
from backend.models.user_model import User, Group, BlacklistToken
|
||||||
|
|
||||||
|
|
||||||
@auth_api_bp.route('/providers', methods=('GET',))
|
@auth_api_bp.route('/providers', methods=('GET',))
|
||||||
@@ -39,6 +43,12 @@ def get_auth_providers():
|
|||||||
return jsonify(providers)
|
return jsonify(providers)
|
||||||
|
|
||||||
|
|
||||||
|
@auth_api_providers_ns.route('/')
|
||||||
|
class AuthProviders(Resource):
|
||||||
|
def get(self):
|
||||||
|
return get_auth_providers()
|
||||||
|
|
||||||
|
|
||||||
@auth_api_bp.route('/register', methods=('POST',))
|
@auth_api_bp.route('/register', methods=('POST',))
|
||||||
def register():
|
def register():
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
@@ -48,6 +58,21 @@ def register():
|
|||||||
return jsonify(user.to_dict()), 201
|
return jsonify(user.to_dict()), 201
|
||||||
|
|
||||||
|
|
||||||
|
@auth_api_register_ns.route('/')
|
||||||
|
@auth_api_register_ns.expect(auth_api_register_ns.model('RegisterModel', {
|
||||||
|
'nickname': fields.String(required=False, description='The user\'s nickname'),
|
||||||
|
'first_name': fields.String(required=False, description='The user\'s first name'),
|
||||||
|
'last_name': fields.String(required=False, description='The user\'s last name'),
|
||||||
|
'lang': fields.String(required=False, description='The user\'s preferred language'),
|
||||||
|
'timezone': fields.String(required=False, description='The user\'s preferred timezone'),
|
||||||
|
'email': fields.String(required=True, description='The user\'s e-mail address'),
|
||||||
|
'password': fields.String(required=False, description='The group\'s name')
|
||||||
|
}))
|
||||||
|
class AuthProviders(Resource):
|
||||||
|
def get(self):
|
||||||
|
return register()
|
||||||
|
|
||||||
|
|
||||||
@auth_api_bp.route('/login', methods=('GET', 'POST',))
|
@auth_api_bp.route('/login', methods=('GET', 'POST',))
|
||||||
def login():
|
def login():
|
||||||
print("login")
|
print("login")
|
||||||
@@ -62,11 +87,30 @@ def login():
|
|||||||
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
|
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
|
||||||
|
|
||||||
token = {
|
token = {
|
||||||
'access_token': create_access_token(identity=user.email, fresh=True),
|
'access_token': create_access_token(identity=user, fresh=True),
|
||||||
'refresh_token': create_refresh_token(identity=user.email)
|
'refresh_token': create_refresh_token(identity=user)
|
||||||
}
|
}
|
||||||
return jsonify(token), 200
|
return jsonify(token), 200
|
||||||
|
|
||||||
|
# Endpoint for revoking the current users access token
|
||||||
|
@auth_api_bp.route('/logout', methods=['GET', 'DELETE'])
|
||||||
|
@jwt_required
|
||||||
|
def logout():
|
||||||
|
jti = get_raw_jwt()['jti']
|
||||||
|
db.session.add(BlacklistToken(token=jti))
|
||||||
|
db.session.commit()
|
||||||
|
return jsonify({"msg": "Successfully logged out"}), 200
|
||||||
|
|
||||||
|
|
||||||
|
# Endpoint for revoking the current users refresh token
|
||||||
|
@auth_api_bp.route('/logout2', methods=['GET', 'DELETE'])
|
||||||
|
@jwt_refresh_token_required
|
||||||
|
def logout2():
|
||||||
|
jti = get_raw_jwt()['jti']
|
||||||
|
db.session.add(BlacklistToken(token=jti))
|
||||||
|
db.session.commit()
|
||||||
|
return jsonify({"msg": "Successfully logged out"}), 200
|
||||||
|
|
||||||
|
|
||||||
def check_and_create_groups(groups: Iterable[str]):
|
def check_and_create_groups(groups: Iterable[str]):
|
||||||
user_groups = []
|
user_groups = []
|
||||||
@@ -92,6 +136,7 @@ def create_or_retrieve_user_from_userinfo(userinfo):
|
|||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
app.logger.info("user found -> update user")
|
app.logger.info("user found -> update user")
|
||||||
|
pprint(user.to_dict())
|
||||||
user.first_name = userinfo.get("given_name", "")
|
user.first_name = userinfo.get("given_name", "")
|
||||||
user.last_name = userinfo.get("family_name", "")
|
user.last_name = userinfo.get("family_name", "")
|
||||||
for g in user_groups:
|
for g in user_groups:
|
||||||
@@ -121,8 +166,8 @@ def oidc(redirect_url=None):
|
|||||||
token = jwt.encode(flask.session['id_token'], current_app.config['SECRET_KEY'])
|
token = jwt.encode(flask.session['id_token'], current_app.config['SECRET_KEY'])
|
||||||
else:
|
else:
|
||||||
token = json.dumps({
|
token = json.dumps({
|
||||||
'access_token': create_access_token(identity=user.email, fresh=True),
|
'access_token': create_access_token(identity=user, fresh=True),
|
||||||
'refresh_token': create_refresh_token(identity=user.email)
|
'refresh_token': create_refresh_token(identity=user)
|
||||||
})
|
})
|
||||||
if redirect_url is None:
|
if redirect_url is None:
|
||||||
redirect_url = request.headers.get("Referer")
|
redirect_url = request.headers.get("Referer")
|
||||||
@@ -142,8 +187,10 @@ def refresh():
|
|||||||
"""Refresh token endpoint. This will generate a new access token from
|
"""Refresh token endpoint. This will generate a new access token from
|
||||||
the refresh token, but will mark that access token as non-fresh,
|
the refresh token, but will mark that access token as non-fresh,
|
||||||
as we do not actually verify a password in this endpoint."""
|
as we do not actually verify a password in this endpoint."""
|
||||||
current_user = get_jwt_identity()
|
jwt_identity = get_jwt_identity()
|
||||||
app.logger.info("Refreshing token for " + current_user)
|
user = User.get_by_identifier(jwt_identity)
|
||||||
new_token = create_access_token(identity=current_user, fresh=False)
|
app.logger.info("Refreshing token for " + str(user))
|
||||||
|
new_token = create_access_token(identity=user, fresh=False)
|
||||||
ret = {'access_token': new_token}
|
ret = {'access_token': new_token}
|
||||||
return jsonify(ret), 200
|
return jsonify(ret), 200
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Login through API does not start a new session, but instead returns JWT.
|
|||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from flask_jwt_extended import jwt_required
|
from flask_jwt_extended import jwt_required, get_current_user, get_jwt_claims
|
||||||
from flask_restplus import fields, Resource
|
from flask_restplus import fields, Resource
|
||||||
|
|
||||||
from backend import db
|
from backend import db
|
||||||
@@ -35,6 +35,8 @@ class ControlCommand(Resource):
|
|||||||
@api_control.expect(control_command_parser)
|
@api_control.expect(control_command_parser)
|
||||||
@api_control.marshal_with(control_command_response_model, skip_none=False, code=201)
|
@api_control.marshal_with(control_command_response_model, skip_none=False, code=201)
|
||||||
def post(self):
|
def post(self):
|
||||||
current_user = {'identity': get_jwt_identity(), 'type': type(get_jwt_identity())}
|
print(get_current_user())
|
||||||
|
print(get_jwt_identity())
|
||||||
|
current_user = {'user': get_current_user(), 'claims': get_jwt_claims()}
|
||||||
args = self.control_command_parser.parse_args()
|
args = self.control_command_parser.parse_args()
|
||||||
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}
|
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}
|
||||||
|
|||||||
@@ -5,46 +5,72 @@ For example: listing of available auth providers or registration of users.
|
|||||||
|
|
||||||
Login through API does not start a new session, but instead returns JWT.
|
Login through API does not start a new session, but instead returns JWT.
|
||||||
"""
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import jwt
|
import jwt
|
||||||
from flask import request, jsonify, current_app, url_for
|
from flask import request, jsonify, current_app, url_for
|
||||||
from flask_jwt_extended import get_jwt_identity, jwt_optional, jwt_required
|
from flask_jwt_extended import get_jwt_identity, jwt_optional, jwt_required
|
||||||
from flask_restplus import Resource, fields
|
from flask_restplus import Resource, fields, inputs
|
||||||
|
|
||||||
from backend import db, app, jwt_auth
|
from backend import db, app, jwt_auth
|
||||||
from backend.api import api_bp, api_user
|
from backend.api import api_bp, api_user
|
||||||
from backend.auth import oidc_auth
|
from backend.auth import oidc_auth
|
||||||
from backend.models.user_model import User, Group
|
from backend.models.user_model import User, Group
|
||||||
|
|
||||||
|
|
||||||
user_model = api_user.model('User', {
|
user_model = api_user.model('User', {
|
||||||
'id': fields.String(required=True, description='The user\'s identifier'),
|
'id': fields.String(required=True, description='The user\'s identifier'),
|
||||||
'first_name': fields.String(required=True, description='The user\'s first name'),
|
'first_name': fields.String(required=True, description='The user\'s first name'),
|
||||||
'last_name': fields.String(required=True, description='The user\'s last name'),
|
'last_name': fields.String(required=True, description='The user\'s last name'),
|
||||||
'email': fields.String(required=True, description='The user\'s email address'),
|
'email': fields.String(required=True, description='The user\'s email address'),
|
||||||
'nickname': fields.String(required=False, description='The user\'s nick name'),
|
'nickname': fields.String(required=False, description='The user\'s nick name'),
|
||||||
'groups': fields.List(fields.Nested(api_user.model('user_group', {'id':fields.Integer(), 'name': fields.String()})),
|
'groups': fields.List(
|
||||||
|
fields.Nested(api_user.model('user_group', {'id': fields.Integer(), 'name': fields.String()})),
|
||||||
required=False, description='Group memberships.'),
|
required=False, description='Group memberships.'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
user_update_parser = api_user.parser()
|
||||||
|
user_update_parser.add_argument('email', type=inputs.email, required=False, nullable=False, store_missing=False)
|
||||||
|
user_update_parser.add_argument('nickname', type=str, required=False, store_missing=False)
|
||||||
|
user_update_parser.add_argument('first_name', type=str, required=False, store_missing=False)
|
||||||
|
user_update_parser.add_argument('last_name', type=str, required=False, store_missing=False)
|
||||||
|
|
||||||
@api_user.route('/profile', methods=['GET'])
|
@api_user.route('/profile')
|
||||||
class Profile(Resource):
|
class Profile(Resource):
|
||||||
@jwt_auth.login_required
|
@jwt_required
|
||||||
@api_user.marshal_list_with(user_model)
|
@api_user.marshal_with(user_model)
|
||||||
def get(self):
|
def get(self):
|
||||||
"""Get infos about logged in user."""
|
"""Get infos about logged in user."""
|
||||||
current_user_id = get_jwt_identity()
|
current_user_id = get_jwt_identity()
|
||||||
app.logger.info(current_user_id)
|
app.logger.info(current_user_id)
|
||||||
return User.get_by_identifier(current_user_id)
|
return User.get_by_identifier(current_user_id)
|
||||||
|
|
||||||
|
@jwt_required
|
||||||
|
def put(self):
|
||||||
|
current_user_id = get_jwt_identity()
|
||||||
|
print(api_user.payload)
|
||||||
|
app.logger.info(current_user_id)
|
||||||
|
args = user_update_parser.parse_args()
|
||||||
|
args['last_time_modified'] = datetime.utcnow()
|
||||||
|
pprint(args)
|
||||||
|
|
||||||
|
num_rows_matched = User.query.filter_by(id=current_user_id).update(args)
|
||||||
|
print(num_rows_matched)
|
||||||
|
|
||||||
|
if num_rows_matched < 1:
|
||||||
|
api_user.abort(404)
|
||||||
|
db.session.commit()
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
|
||||||
@api_user.route('')
|
@api_user.route('')
|
||||||
class UserList(Resource):
|
class UserList(Resource):
|
||||||
"""
|
"""
|
||||||
This is a test class.
|
This is a test class.
|
||||||
"""
|
"""
|
||||||
#@jwt_auth.login_required
|
|
||||||
|
# @jwt_auth.login_required
|
||||||
@jwt_required
|
@jwt_required
|
||||||
@api_user.doc('users')
|
@api_user.doc('users')
|
||||||
@api_user.marshal_list_with(user_model)
|
@api_user.marshal_list_with(user_model)
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ If frontend pages are build by frontend code (JS, etc.) authentication should co
|
|||||||
|
|
||||||
This code uses login_user and logout user (to start and end sessions) ... API code returns JWTs.
|
This code uses login_user and logout user (to start and end sessions) ... API code returns JWTs.
|
||||||
"""
|
"""
|
||||||
from flask import Blueprint, jsonify
|
from flask import Blueprint, jsonify, url_for
|
||||||
from flask_login import logout_user, LoginManager
|
from flask_login import logout_user, LoginManager
|
||||||
from werkzeug.routing import BuildError
|
from werkzeug.routing import BuildError
|
||||||
|
|
||||||
|
from backend import jwt_extended
|
||||||
|
from backend.models import BlacklistToken, User
|
||||||
|
|
||||||
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
|
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
|
||||||
|
|
||||||
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
|
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
|
||||||
@@ -49,3 +52,27 @@ def login_select():
|
|||||||
@auth_bp.route('/logout', methods=('GET', ))
|
@auth_bp.route('/logout', methods=('GET', ))
|
||||||
def logout():
|
def logout():
|
||||||
logout_user()
|
logout_user()
|
||||||
|
|
||||||
|
|
||||||
|
@jwt_extended.user_claims_loader
|
||||||
|
def add_claims_to_access_token(user):
|
||||||
|
if isinstance(user, str):
|
||||||
|
return {}
|
||||||
|
return {'role': user.role, 'groups': [g.to_dict() for g in user.groups]}
|
||||||
|
|
||||||
|
|
||||||
|
@jwt_extended.user_identity_loader
|
||||||
|
def user_identity_loader(user):
|
||||||
|
return user.email
|
||||||
|
|
||||||
|
|
||||||
|
@jwt_extended.user_loader_callback_loader
|
||||||
|
def user_loader_callback(identity):
|
||||||
|
user = User.get_by_identifier(identity)
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@jwt_extended.token_in_blacklist_loader
|
||||||
|
def check_if_token_in_blacklist(decrypted_token):
|
||||||
|
jti = decrypted_token['jti']
|
||||||
|
return BlacklistToken.get_by_token(jti) is not None
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
# Route for handling the login page logic
|
# Route for handling the login page logic
|
||||||
from flask import request, redirect, render_template, url_for
|
from flask import request, redirect, render_template
|
||||||
from flask_login import login_user
|
from flask_login import login_user
|
||||||
|
|
||||||
from backend.auth import auth_bp
|
from backend.auth import auth_bp
|
||||||
|
from backend.models.user_model import User
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route('/base_login', methods=['GET', 'POST'])
|
@auth_bp.route('/base_login', methods=['GET', 'POST'])
|
||||||
def base_login():
|
def base_login():
|
||||||
error = None
|
error = None
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
|
user = User.authenticate(email=request.form['email'], password=request.form['password'])
|
||||||
|
if user is None:
|
||||||
error = 'Invalid Credentials. Please try again.'
|
error = 'Invalid Credentials. Please try again.'
|
||||||
else:
|
else:
|
||||||
login_user()
|
login_user(user)
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
return render_template('login.html', error=error)
|
return render_template('login.html', error=error)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ AUTH_PROVIDERS: Dict[str, Dict[str, str]] = {
|
|||||||
"KIT OIDC":
|
"KIT OIDC":
|
||||||
{
|
{
|
||||||
"type": "oidc",
|
"type": "oidc",
|
||||||
"url": "auth.oidc"
|
"url": "auth_api.oidc"
|
||||||
},
|
},
|
||||||
"Base Login":
|
"Base Login":
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<h1>Please login</h1>
|
<h1>Please login</h1>
|
||||||
<br>
|
<br>
|
||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
<input type="text" placeholder="Username" name="username" value="{{
|
<input type="text" placeholder="E-Mail" name="email" value="{{
|
||||||
request.form.username }}">
|
request.form.username }}">
|
||||||
<input type="password" placeholder="Password" name="password" value="{{
|
<input type="password" placeholder="Password" name="password" value="{{
|
||||||
request.form.password }}">
|
request.form.password }}">
|
||||||
|
|||||||
38
config.py
38
config.py
@@ -2,17 +2,18 @@
|
|||||||
# ...
|
# ...
|
||||||
# available languages
|
# available languages
|
||||||
import os
|
import os
|
||||||
|
|
||||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
class Config():
|
class Config():
|
||||||
#SERVER_NAME = "ubkaps154.ubka.uni-karlsruhe.de:5443"
|
# SERVER_NAME = "ubkaps154.ubka.uni-karlsruhe.de:5443"
|
||||||
#SERVER_NAME = "localhost.dev"
|
# SERVER_NAME = "localhost.dev"
|
||||||
SERVER_NAME = "localhost:5443"
|
SERVER_NAME = "localhost:5443"
|
||||||
#SERVER_NAME = "localhost"
|
# SERVER_NAME = "localhost"
|
||||||
#SERVER_NAME = "localhost.localdomain"
|
# SERVER_NAME = "localhost.localdomain"
|
||||||
#PORT = 5443
|
# PORT = 5443
|
||||||
#PREFERRED_URL_SCHEME = 'https'
|
# PREFERRED_URL_SCHEME = 'https'
|
||||||
|
|
||||||
TEMPLATE_AUTO_RELOAD = True
|
TEMPLATE_AUTO_RELOAD = True
|
||||||
|
|
||||||
@@ -62,24 +63,39 @@ class Config():
|
|||||||
'es': 'Español'
|
'es': 'Español'
|
||||||
}
|
}
|
||||||
|
|
||||||
#ASSETS_DEBUG = True
|
# ASSETS_DEBUG = True
|
||||||
|
|
||||||
#JWT_SECRET = "abcxyz"
|
# JWT_SECRET = "abcxyz"
|
||||||
#JWT_ALGORITHM = "HS256"
|
# JWT_ALGORITHM = "HS256"
|
||||||
#JWT_EXP_DELTA_SECONDS = 5 * 60
|
# JWT_EXP_DELTA_SECONDS = 5 * 60
|
||||||
|
|
||||||
JWT_SECRET_KEY = "abcxyz"
|
JWT_SECRET_KEY = "abcxyz"
|
||||||
|
JWT_BLACKLIST_ENABLED = True
|
||||||
|
JWT_BLACKLIST_TOKEN_CHECKS = ['access', 'refresh']
|
||||||
|
|
||||||
AUTH_RETURN_EXTERNAL_JWT = False
|
AUTH_RETURN_EXTERNAL_JWT = False
|
||||||
|
|
||||||
INDEX_TEMPLATE = "index.html"
|
INDEX_TEMPLATE = "index.html"
|
||||||
|
|
||||||
|
# # INITIAL VALUES # #
|
||||||
|
|
||||||
PERMISSIONS = ["RECODER_NEW", "RECORDER_EDIT", "RECODER_SHOW", "RECORDER_DELETE",
|
PERMISSIONS = ["RECODER_NEW", "RECORDER_EDIT", "RECODER_SHOW", "RECORDER_DELETE",
|
||||||
"RECORDER_COMMAND_EXECUTE", "RECORDER_COMMAND_EDIT_ACL",
|
"RECORDER_COMMAND_EXECUTE", "RECORDER_COMMAND_EDIT_ACL",
|
||||||
"VIRTUAL_COMMAND_CREATE", "VIRTUAL_COMMAND_EDIT", "VIRTUAL_COMMAND_SHOW", "VIRTUAL_COMMAND_DELETE",
|
"VIRTUAL_COMMAND_CREATE", "VIRTUAL_COMMAND_EDIT", "VIRTUAL_COMMAND_SHOW", "VIRTUAL_COMMAND_DELETE",
|
||||||
"CRON_JOB_CREATE", "CRON_JOB_EDIT", "CRON_JOB_SHOW", "CRON_JOB_DELETE"]
|
"CRON_JOB_CREATE", "CRON_JOB_EDIT", "CRON_JOB_SHOW", "CRON_JOB_DELETE"]
|
||||||
|
|
||||||
GROUPS = ["Admins", "ZML", "read_only"]
|
GROUPS = [ #{"name": "Admins",
|
||||||
|
#"permissions": PERMISSIONS},
|
||||||
|
{"name": "ZML"},
|
||||||
|
{"name": "read_only"}]
|
||||||
|
|
||||||
|
USERS = [{"nickname": "admin",
|
||||||
|
"first_name": "tobias",
|
||||||
|
"last_name": "kurze",
|
||||||
|
"email": "kurze@kit.edu",
|
||||||
|
"role": "admin",
|
||||||
|
"password": "admin"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(Config):
|
class ProductionConfig(Config):
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class RecorderModel(db.Model):
|
|||||||
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
|
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
|
||||||
recorders = db.relationship('Recorder', back_populates='recorder_model')
|
recorders = db.relationship('Recorder', back_populates='recorder_model')
|
||||||
checksum = db.Column(db.String(63), unique=True, nullable=False)
|
checksum = db.Column(db.String(63), unique=True, nullable=False)
|
||||||
requires_user = db.Column(db.Boolean)
|
_requires_user = db.Column(db.Integer, default=False, name='requires_user')
|
||||||
requires_password = db.Column(db.Boolean)
|
_requires_password = db.Column(db.Integer, default=True, name='requires_password')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all():
|
def get_all():
|
||||||
@@ -47,6 +47,22 @@ class RecorderModel(db.Model):
|
|||||||
def get_by_checksum(md5_sum):
|
def get_by_checksum(md5_sum):
|
||||||
return RecorderModel.query.filter(RecorderModel.checksum == md5_sum).first()
|
return RecorderModel.query.filter(RecorderModel.checksum == md5_sum).first()
|
||||||
|
|
||||||
|
@hybrid_property
|
||||||
|
def requires_user(self):
|
||||||
|
return self._requires_user > 0
|
||||||
|
|
||||||
|
@requires_user.setter
|
||||||
|
def requires_user(self, val: bool):
|
||||||
|
self._requires_user = 1 if val else 0
|
||||||
|
|
||||||
|
@hybrid_property
|
||||||
|
def requires_password(self):
|
||||||
|
return self._requires_password > 0
|
||||||
|
|
||||||
|
@requires_password.setter
|
||||||
|
def requires_password(self, val: bool):
|
||||||
|
self._requires_password = 1 if val else 0
|
||||||
|
|
||||||
|
|
||||||
class Recorder(db.Model):
|
class Recorder(db.Model):
|
||||||
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
|
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
|
||||||
@@ -64,8 +80,8 @@ class Recorder(db.Model):
|
|||||||
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
|
network_name = db.Column(db.String(127), unique=True, nullable=True, default=None)
|
||||||
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
|
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
|
||||||
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
|
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
|
||||||
username = db.column(db.String(127))
|
username = db.Column(db.String, nullable=True, default=None)
|
||||||
password = db.column(db.String(127))
|
password = db.Column(db.String, nullable=True, default=None)
|
||||||
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
|
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
|
||||||
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
|
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
|
||||||
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table, back_populates='recorders')
|
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table, back_populates='recorders')
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ class User(UserMixin, db.Model):
|
|||||||
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
||||||
external_user = db.Column(db.Boolean, default=False)
|
external_user = db.Column(db.Boolean, default=False)
|
||||||
last_seen = db.Column(db.DateTime, default=datetime.utcnow())
|
last_seen = db.Column(db.DateTime, default=datetime.utcnow())
|
||||||
|
last_time_modified = db.Column(db.DateTime, default=datetime.utcnow())
|
||||||
jwt_exp_delta_seconds = db.Column(db.Integer, nullable=True)
|
jwt_exp_delta_seconds = db.Column(db.Integer, nullable=True)
|
||||||
acquainted = db.relationship('User',
|
acquainted = db.relationship('User',
|
||||||
secondary=acquaintances,
|
secondary=acquaintances,
|
||||||
@@ -264,6 +265,8 @@ class User(UserMixin, db.Model):
|
|||||||
:param password:
|
:param password:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
if self.password is None:
|
||||||
|
return False
|
||||||
return sha256_crypt.verify(password, self.password)
|
return sha256_crypt.verify(password, self.password)
|
||||||
|
|
||||||
def get_id(self):
|
def get_id(self):
|
||||||
@@ -375,7 +378,7 @@ class User(UserMixin, db.Model):
|
|||||||
sort_keys=True, indent=4)
|
sort_keys=True, indent=4)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User %r>' % self.nickname
|
return '<User %r>' % self.email
|
||||||
|
|
||||||
|
|
||||||
class BlacklistToken(db.Model):
|
class BlacklistToken(db.Model):
|
||||||
@@ -395,6 +398,10 @@ class BlacklistToken(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<id: token: {}'.format(self.token)
|
return '<id: token: {}'.format(self.token)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_by_token(jwt_id):
|
||||||
|
return BlacklistToken.query.filter(BlacklistToken.token == jwt_id).first()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_blacklist(auth_token):
|
def check_blacklist(auth_token):
|
||||||
"""
|
"""
|
||||||
@@ -457,6 +464,20 @@ class Permission(db.Model):
|
|||||||
back_populates='permissions')
|
back_populates='permissions')
|
||||||
|
|
||||||
|
|
||||||
|
@event.listens_for(User.__table__, 'after_create')
|
||||||
|
def insert_initial_users(*args, **kwargs):
|
||||||
|
for u in app.config.get("USERS", []):
|
||||||
|
db.session.add(User(**u))
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@event.listens_for(Group.__table__, 'after_create')
|
||||||
|
def insert_initial_groups(*args, **kwargs):
|
||||||
|
for g in app.config.get("GROUPS", []):
|
||||||
|
db.session.add(Group(**g))
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
@event.listens_for(Permission.__table__, 'after_create')
|
@event.listens_for(Permission.__table__, 'after_create')
|
||||||
def insert_initial_permissions(*args, **kwargs):
|
def insert_initial_permissions(*args, **kwargs):
|
||||||
for p in app.config.get("PERMISSIONS", []):
|
for p in app.config.get("PERMISSIONS", []):
|
||||||
|
|||||||
Reference in New Issue
Block a user