profile and other stuff

This commit is contained in:
2019-08-14 16:38:03 +02:00
parent 859a5d880a
commit 9ab0d43f43
16 changed files with 297 additions and 624 deletions

2
.idea/backend.iml generated
View File

@@ -17,7 +17,7 @@
</component>
<component name="NewModuleRootManager">
<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="module" module-name="ocmp" />
<orderEntry type="module" module-name="OpenCastPythonClient" />

2
.idea/misc.xml generated
View File

@@ -3,7 +3,7 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</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">
<option name="shown" value="true" />
</component>

4
.idea/vcs.xml generated
View File

@@ -2,9 +2,7 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../OpenCastPythonClient" vcs="Git" />
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/../../media-abstraction-layer" vcs="Git" />
<mapping directory="$USER_HOME$/Projects/newsMap" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../frontend" vcs="Git" />
</component>
</project>

662
.idea/workspace.xml generated
View File

@@ -2,18 +2,31 @@
<project version="4">
<component name="ChangeListManager">
<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 afterPath="$USER_HOME$/Projects/newsMap/news_map/news_sources/de_newspaper.db" afterDir="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$/../.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../activate_this.py" beforeDir="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="$USER_HOME$/Projects/newsMap/.idea/workspace.xml" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/.idea/workspace.xml" afterDir="false" />
<change beforePath="$USER_HOME$/Projects/newsMap/Pipfile" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/Pipfile" afterDir="false" />
<change beforePath="$USER_HOME$/Projects/newsMap/Pipfile.lock" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/Pipfile.lock" 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="$USER_HOME$/Projects/newsMap/news_map/newsMap.py" beforeDir="false" afterPath="$USER_HOME$/Projects/newsMap/news_map/newsMap.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$/.idea/backend.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/backend.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/api/__init__.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>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<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))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;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))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
</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">
<option name="RECENT_TEMPLATES">
<list>
@@ -127,117 +44,23 @@
</list>
</option>
</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">
<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" />
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="ProjectId" id="1PPJuamSCMuifjd70Sp8tYSAlOw" />
<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">
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<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_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 name="RunDashboard">
<option name="ruleStates">
@@ -251,7 +74,29 @@
</list>
</option>
</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">
<module name="ocmp" />
<option name="INTERPRETER_OPTIONS" value="" />
@@ -264,6 +109,7 @@
<option name="IS_MODULE_SDK" value="false" />
<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$/../../media-abstraction-layer/backend/api.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
@@ -285,6 +131,7 @@
<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="$USER_HOME$/Projects/newsMap/news_map/news_item_store/dictNewsItemStore.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
@@ -306,6 +153,7 @@
<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="$USER_HOME$/Projects/newsMap/news_map/gatherer/dummyNewsGatherer.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
@@ -327,6 +175,7 @@
<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$/recorder_adapters/extron_smp.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
@@ -336,27 +185,6 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</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">
<module name="backend" />
<option name="target" value="$PROJECT_DIR$/__init__.py" />
@@ -373,19 +201,20 @@
<method v="2" />
</configuration>
<list>
<item itemvalue="Flask server.backend" />
<item itemvalue="Python.api" />
<item itemvalue="Python.ingest" />
<item itemvalue="Python.dummyNewsGatherer" />
<item itemvalue="Python.dictNewsItemStore" />
<item itemvalue="Python.extron_smp" />
<item itemvalue="Python.__main__" />
</list>
<recent_temporary>
<list>
<item itemvalue="Python.__main__" />
<item itemvalue="Python.extron_smp" />
<item itemvalue="Python.dictNewsItemStore" />
<item itemvalue="Python.dummyNewsGatherer" />
<item itemvalue="Python.api" />
<item itemvalue="Python.ingest" />
</list>
</recent_temporary>
</component>
@@ -402,355 +231,38 @@
<workItem from="1556266473180" duration="14572000" />
<workItem from="1557483399929" duration="284000" />
<workItem from="1557483805341" duration="173000" />
<workItem from="1565770023268" duration="8793000" />
<workItem from="1565778873035" duration="9376000" />
</task>
<servers />
</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">
<option name="version" value="1" />
</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">
<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$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>
<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>
<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>
</project>

View File

@@ -42,7 +42,6 @@ def verify_token(token):
app.logger.info(decoded)
return True
basic_auth = HTTPBasicAuth()
multi_auth = MultiAuth(basic_auth, jwt_auth)

View File

@@ -45,6 +45,13 @@ api_v1.add_namespace(api_cron_job)
api_v1.add_namespace(api_control)
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')
# group_api_bp = Blueprint('group_api', __name__, url_prefix='/api/group')

View File

@@ -7,23 +7,27 @@ Login through API does not start a new session, but instead returns JWT.
"""
import base64
import json
from pprint import pprint
import flask
from datetime import datetime, timedelta
import jwt
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 random import randint
from flask_login import logout_user, login_user
from typing import Iterable
from flask_restplus import Resource, fields
from werkzeug.routing import BuildError
from backend import db, app
from backend.api import auth_api_bp
from backend import db, app, jwt_extended
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.models.user_model import User, Group
from backend.models.user_model import User, Group, BlacklistToken
@auth_api_bp.route('/providers', methods=('GET',))
@@ -39,6 +43,12 @@ def get_auth_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',))
def register():
data = request.get_json()
@@ -48,6 +58,21 @@ def register():
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',))
def login():
print("login")
@@ -62,11 +87,30 @@ def login():
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
token = {
'access_token': create_access_token(identity=user.email, fresh=True),
'refresh_token': create_refresh_token(identity=user.email)
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
}
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]):
user_groups = []
@@ -92,6 +136,7 @@ def create_or_retrieve_user_from_userinfo(userinfo):
if user is not None:
app.logger.info("user found -> update user")
pprint(user.to_dict())
user.first_name = userinfo.get("given_name", "")
user.last_name = userinfo.get("family_name", "")
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'])
else:
token = json.dumps({
'access_token': create_access_token(identity=user.email, fresh=True),
'refresh_token': create_refresh_token(identity=user.email)
'access_token': create_access_token(identity=user, fresh=True),
'refresh_token': create_refresh_token(identity=user)
})
if redirect_url is None:
redirect_url = request.headers.get("Referer")
@@ -142,8 +187,10 @@ def refresh():
"""Refresh token endpoint. This will generate a new access token from
the refresh token, but will mark that access token as non-fresh,
as we do not actually verify a password in this endpoint."""
current_user = get_jwt_identity()
app.logger.info("Refreshing token for " + current_user)
new_token = create_access_token(identity=current_user, fresh=False)
jwt_identity = get_jwt_identity()
user = User.get_by_identifier(jwt_identity)
app.logger.info("Refreshing token for " + str(user))
new_token = create_access_token(identity=user, fresh=False)
ret = {'access_token': new_token}
return jsonify(ret), 200

View File

@@ -8,7 +8,7 @@ Login through API does not start a new session, but instead returns JWT.
import json
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 backend import db
@@ -35,6 +35,8 @@ class ControlCommand(Resource):
@api_control.expect(control_command_parser)
@api_control.marshal_with(control_command_response_model, skip_none=False, code=201)
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()
return {'time': datetime.utcnow(), 'output': args, 'state': current_user}

View File

@@ -5,45 +5,71 @@ For example: listing of available auth providers or registration of users.
Login through API does not start a new session, but instead returns JWT.
"""
from datetime import datetime
from pprint import pprint
import flask
import jwt
from flask import request, jsonify, current_app, url_for
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.api import api_bp, api_user
from backend.auth import oidc_auth
from backend.models.user_model import User, Group
user_model = api_user.model('User', {
'id': fields.String(required=True, description='The user\'s identifier'),
'first_name': fields.String(required=True, description='The user\'s first name'),
'last_name': fields.String(required=True, description='The user\'s last name'),
'email': fields.String(required=True, description='The user\'s email address'),
'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.'),
})
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):
@jwt_auth.login_required
@api_user.marshal_list_with(user_model)
@jwt_required
@api_user.marshal_with(user_model)
def get(self):
"""Get infos about logged in user."""
current_user_id = get_jwt_identity()
app.logger.info(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('')
class UserList(Resource):
"""
This is a test class.
"""
# @jwt_auth.login_required
@jwt_required
@api_user.doc('users')

View File

@@ -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.
"""
from flask import Blueprint, jsonify
from flask import Blueprint, jsonify, url_for
from flask_login import logout_user, LoginManager
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')
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
@@ -49,3 +52,27 @@ def login_select():
@auth_bp.route('/logout', methods=('GET', ))
def logout():
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

View File

@@ -1,18 +1,20 @@
# 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 backend.auth import auth_bp
from backend.models.user_model import User
@auth_bp.route('/base_login', methods=['GET', 'POST'])
def base_login():
error = None
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.'
else:
login_user()
login_user(user)
return redirect("/")
return render_template('login.html', error=error)

View File

@@ -4,7 +4,7 @@ AUTH_PROVIDERS: Dict[str, Dict[str, str]] = {
"KIT OIDC":
{
"type": "oidc",
"url": "auth.oidc"
"url": "auth_api.oidc"
},
"Base Login":
{

View File

@@ -9,7 +9,7 @@
<h1>Please login</h1>
<br>
<form action="" method="post">
<input type="text" placeholder="Username" name="username" value="{{
<input type="text" placeholder="E-Mail" name="email" value="{{
request.form.username }}">
<input type="password" placeholder="Password" name="password" value="{{
request.form.password }}">

View File

@@ -2,6 +2,7 @@
# ...
# available languages
import os
basedir = os.path.abspath(os.path.dirname(__file__))
@@ -69,17 +70,32 @@ class Config():
# JWT_EXP_DELTA_SECONDS = 5 * 60
JWT_SECRET_KEY = "abcxyz"
JWT_BLACKLIST_ENABLED = True
JWT_BLACKLIST_TOKEN_CHECKS = ['access', 'refresh']
AUTH_RETURN_EXTERNAL_JWT = False
INDEX_TEMPLATE = "index.html"
# # INITIAL VALUES # #
PERMISSIONS = ["RECODER_NEW", "RECORDER_EDIT", "RECODER_SHOW", "RECORDER_DELETE",
"RECORDER_COMMAND_EXECUTE", "RECORDER_COMMAND_EDIT_ACL",
"VIRTUAL_COMMAND_CREATE", "VIRTUAL_COMMAND_EDIT", "VIRTUAL_COMMAND_SHOW", "VIRTUAL_COMMAND_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):

View File

@@ -28,8 +28,8 @@ class RecorderModel(db.Model):
recorder_commands = db.relationship('RecorderCommand', back_populates='recorder_model')
recorders = db.relationship('Recorder', back_populates='recorder_model')
checksum = db.Column(db.String(63), unique=True, nullable=False)
requires_user = db.Column(db.Boolean)
requires_password = db.Column(db.Boolean)
_requires_user = db.Column(db.Integer, default=False, name='requires_user')
_requires_password = db.Column(db.Integer, default=True, name='requires_password')
@staticmethod
def get_all():
@@ -47,6 +47,22 @@ class RecorderModel(db.Model):
def get_by_checksum(md5_sum):
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):
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)
telnet_port = db.Column(db.Integer, unique=False, nullable=False, default=23)
ssh_port = db.Column(db.Integer, unique=False, nullable=False, default=22)
username = db.column(db.String(127))
password = db.column(db.String(127))
username = db.Column(db.String, nullable=True, default=None)
password = db.Column(db.String, nullable=True, default=None)
recorder_model_id = db.Column(db.Integer, db.ForeignKey('recorder_model.id'))
recorder_model = db.relationship('RecorderModel', back_populates='recorders')
virtual_commands = db.relationship('VirtualCommand', secondary=virtual_command_recorder_table, back_populates='recorders')

View File

@@ -83,6 +83,7 @@ class User(UserMixin, db.Model):
registered_on = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
external_user = db.Column(db.Boolean, default=False)
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)
acquainted = db.relationship('User',
secondary=acquaintances,
@@ -264,6 +265,8 @@ class User(UserMixin, db.Model):
:param password:
:return:
"""
if self.password is None:
return False
return sha256_crypt.verify(password, self.password)
def get_id(self):
@@ -375,7 +378,7 @@ class User(UserMixin, db.Model):
sort_keys=True, indent=4)
def __repr__(self):
return '<User %r>' % self.nickname
return '<User %r>' % self.email
class BlacklistToken(db.Model):
@@ -395,6 +398,10 @@ class BlacklistToken(db.Model):
def __repr__(self):
return '<id: token: {}'.format(self.token)
@staticmethod
def get_by_token(jwt_id):
return BlacklistToken.query.filter(BlacklistToken.token == jwt_id).first()
@staticmethod
def check_blacklist(auth_token):
"""
@@ -457,6 +464,20 @@ class Permission(db.Model):
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')
def insert_initial_permissions(*args, **kwargs):
for p in app.config.get("PERMISSIONS", []):