meerschaum 2.4.0.dev1__py3-none-any.whl → 2.4.0rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. meerschaum/_internal/arguments/_parse_arguments.py +2 -5
  2. meerschaum/_internal/docs/index.py +3 -2
  3. meerschaum/_internal/entry.py +13 -7
  4. meerschaum/_internal/shell/Shell.py +38 -44
  5. meerschaum/_internal/term/TermPageHandler.py +2 -3
  6. meerschaum/_internal/term/__init__.py +13 -11
  7. meerschaum/actions/api.py +10 -7
  8. meerschaum/actions/bootstrap.py +2 -1
  9. meerschaum/actions/delete.py +4 -1
  10. meerschaum/actions/register.py +1 -3
  11. meerschaum/actions/stack.py +24 -19
  12. meerschaum/actions/start.py +25 -26
  13. meerschaum/actions/sync.py +53 -52
  14. meerschaum/api/__init__.py +48 -14
  15. meerschaum/api/_events.py +15 -10
  16. meerschaum/api/_oauth2.py +2 -2
  17. meerschaum/api/_websockets.py +5 -4
  18. meerschaum/api/dash/__init__.py +1 -11
  19. meerschaum/api/dash/callbacks/dashboard.py +47 -55
  20. meerschaum/api/dash/callbacks/jobs.py +15 -16
  21. meerschaum/api/dash/callbacks/login.py +16 -10
  22. meerschaum/api/dash/callbacks/pipes.py +3 -4
  23. meerschaum/api/dash/callbacks/plugins.py +1 -1
  24. meerschaum/api/dash/callbacks/register.py +15 -11
  25. meerschaum/api/dash/components.py +54 -59
  26. meerschaum/api/dash/jobs.py +5 -9
  27. meerschaum/api/dash/pages/pipes.py +4 -1
  28. meerschaum/api/dash/pipes.py +13 -17
  29. meerschaum/api/dash/plugins.py +6 -4
  30. meerschaum/api/dash/sessions.py +176 -0
  31. meerschaum/api/dash/users.py +2 -53
  32. meerschaum/api/dash/webterm.py +12 -17
  33. meerschaum/api/resources/static/js/terminado.js +1 -1
  34. meerschaum/api/routes/_actions.py +4 -20
  35. meerschaum/api/routes/_jobs.py +8 -7
  36. meerschaum/api/routes/_webterm.py +5 -6
  37. meerschaum/config/_default.py +6 -1
  38. meerschaum/config/_version.py +1 -1
  39. meerschaum/config/stack/__init__.py +9 -7
  40. meerschaum/config/static/__init__.py +4 -0
  41. meerschaum/connectors/__init__.py +15 -9
  42. meerschaum/connectors/api/{APIConnector.py → _APIConnector.py} +3 -1
  43. meerschaum/connectors/api/__init__.py +2 -1
  44. meerschaum/connectors/parse.py +18 -16
  45. meerschaum/connectors/sql/__init__.py +3 -1
  46. meerschaum/connectors/sql/_pipes.py +39 -39
  47. meerschaum/connectors/valkey/{ValkeyConnector.py → _ValkeyConnector.py} +5 -5
  48. meerschaum/connectors/valkey/__init__.py +3 -1
  49. meerschaum/connectors/valkey/_pipes.py +13 -8
  50. meerschaum/core/Pipe/_data.py +155 -100
  51. meerschaum/jobs/_Job.py +1 -6
  52. meerschaum/jobs/__init__.py +7 -2
  53. meerschaum/utils/dataframe.py +4 -1
  54. meerschaum/utils/formatting/_shell.py +5 -6
  55. meerschaum/utils/packages/__init__.py +14 -9
  56. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/METADATA +1 -1
  57. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/RECORD +65 -65
  58. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/WHEEL +1 -1
  59. meerschaum/api/dash/actions.py +0 -255
  60. /meerschaum/connectors/{Connector.py → _Connector.py} +0 -0
  61. /meerschaum/connectors/sql/{SQLConnector.py → _SQLConnector.py} +0 -0
  62. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/LICENSE +0 -0
  63. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/NOTICE +0 -0
  64. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/entry_points.txt +0 -0
  65. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/top_level.txt +0 -0
  66. {meerschaum-2.4.0.dev1.dist-info → meerschaum-2.4.0rc2.dist-info}/zip-safe +0 -0
@@ -7,27 +7,24 @@ Custom components are defined here.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from meerschaum.utils.venv import Venv
10
+
11
11
  from meerschaum.utils.packages import attempt_import, import_dcc, import_html
12
12
  from meerschaum.utils.typing import SuccessTuple, List
13
13
  from meerschaum.config.static import STATIC_CONFIG
14
14
  from meerschaum.utils.misc import remove_ansi
15
15
  from meerschaum._internal.shell.Shell import get_shell_intro
16
16
  from meerschaum.api import endpoints, CHECK_UPDATE
17
- from meerschaum.connectors import instance_types
17
+ from meerschaum.connectors import instance_types, _load_builtin_custom_connectors
18
18
  from meerschaum.utils.misc import get_connector_labels
19
19
  from meerschaum.config import __doc__ as doc
20
20
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
21
21
  html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
22
22
  dex = attempt_import('dash_extensions', lazy=False, check_update=CHECK_UPDATE)
23
23
  dash_ace = attempt_import('dash_ace', lazy=False, check_update=CHECK_UPDATE)
24
-
25
- component_ids = {
26
-
27
- }
24
+ _load_builtin_custom_connectors()
28
25
 
29
26
  go_button = dbc.Button('Execute', id='go-button', color='primary', style={'width': '100%'})
30
- test_button = dbc.Button('Test', id='test-button', color='danger', style={'display' : 'none'})
27
+ test_button = dbc.Button('Test', id='test-button', color='danger', style={'display': 'none'})
31
28
  get_items_menu = dbc.DropdownMenu(
32
29
  label='More', id='get-items-menu', children=[
33
30
  dbc.DropdownMenuItem("Plugins", id='get-plugins-button'),
@@ -42,21 +39,21 @@ get_items_menu = dbc.DropdownMenu(
42
39
  )
43
40
  show_pipes_button = dbc.Button(
44
41
  'Pipes',
45
- id = 'get-pipes-button',
46
- color = 'info',
47
- style = {'width': '100%'},
42
+ id='get-pipes-button',
43
+ color='info',
44
+ style={'width': '100%'},
48
45
  )
49
46
  show_jobs_button = dbc.Button(
50
47
  'Jobs',
51
- id = 'get-jobs-button',
52
- color = 'success',
53
- style = {'width': '100%'},
48
+ id='get-jobs-button',
49
+ color='success',
50
+ style={'width': '100%'},
54
51
  )
55
52
  cancel_button = dbc.Button(
56
53
  'Terminal',
57
- id = 'cancel-button',
58
- color = 'dark',
59
- style = {'width': '100%', 'background-color': 'black', 'display': 'none'},
54
+ id='cancel-button',
55
+ color='dark',
56
+ style={'width': '100%', 'background-color': 'black', 'display': 'none'},
60
57
  )
61
58
  bottom_buttons_content = dbc.Card(
62
59
  dbc.CardBody(
@@ -70,28 +67,26 @@ bottom_buttons_content = dbc.Card(
70
67
  )
71
68
  )
72
69
  console_div = html.Div(
73
- id = 'console-div',
74
- children = [html.Pre(get_shell_intro(), id='console-pre')],
70
+ id='console-div',
71
+ children=[html.Pre(get_shell_intro(), id='console-pre')],
75
72
  )
76
73
 
77
- location = dcc.Location(id='location', refresh=False)
74
+ location = dcc.Location(id='mrsm-location', refresh=False)
78
75
 
79
76
  search_parameters_editor = dash_ace.DashAceEditor(
80
- id = 'search-parameters-editor',
81
- theme = 'monokai',
82
- mode = 'json',
83
- tabSize = 2,
84
- placeholder = (
77
+ id='search-parameters-editor',
78
+ theme='monokai',
79
+ mode='json',
80
+ tabSize=2,
81
+ placeholder=(
85
82
  'Additional search parameters. ' +
86
83
  'Simple dictionary format or JSON accepted.'
87
84
  ),
88
- style = {'height' : 100},
85
+ style={'height': 100},
89
86
  )
90
87
 
91
88
  sidebar = dbc.Offcanvas(
92
- children=[
93
-
94
- ],
89
+ children=[],
95
90
  title='Pages',
96
91
  )
97
92
 
@@ -99,13 +94,13 @@ download_dataframe = dcc.Download(id='download-dataframe-csv')
99
94
  download_logs = dcc.Download(id='download-logs')
100
95
 
101
96
  instance_select = dbc.Select(
102
- id = 'instance-select',
103
- size = 'sm',
104
- options = [
97
+ id='instance-select',
98
+ size='sm',
99
+ options=[
105
100
  {'label': i, 'value': i}
106
101
  for i in get_connector_labels(*instance_types)
107
102
  ],
108
- class_name = 'dbc_dark custom-select custom-select-sm',
103
+ class_name='dbc_dark custom-select custom-select-sm',
109
104
  )
110
105
 
111
106
 
@@ -116,17 +111,17 @@ navbar = dbc.Navbar(
116
111
  dbc.Row(
117
112
  [
118
113
  dbc.Col(
119
- html.Img(
120
- src = endpoints['dash'] + "/assets/logo_48x48.png",
121
- title = doc,
122
- ),
114
+ html.Img(
115
+ src=endpoints['dash'] + "/assets/logo_48x48.png",
116
+ title=doc,
117
+ ),
123
118
  ),
124
119
  ],
125
- align = 'center',
126
- className = 'g-0 navbar-logo-row',
120
+ align='center',
121
+ className='g-0 navbar-logo-row',
127
122
  ),
128
- href = '/docs',
129
- style = {"textDecoration": "none"},
123
+ href='/docs',
124
+ style={"textDecoration": "none"},
130
125
  ),
131
126
  dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
132
127
  dbc.Collapse(
@@ -136,30 +131,30 @@ navbar = dbc.Navbar(
136
131
  dbc.Col(
137
132
  dbc.Button(
138
133
  "Sign out",
139
- color = 'link',
140
- style = {'margin-left': '30px'},
141
- id = 'sign-out-button',
134
+ color='link',
135
+ style={'margin-left': '30px'},
136
+ id='sign-out-button',
142
137
  ),
143
138
  ),
144
139
  ],
145
- className = "g-0 ms-auto flex-nowrap mt-3 mt-md-0",
140
+ className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
146
141
  ),
147
- id = 'navbar-collapse',
148
- is_open = False,
149
- navbar = True,
142
+ id='navbar-collapse',
143
+ is_open=False,
144
+ navbar=True,
150
145
  ),
151
146
  ],
152
- style = {'max-width': '96%'},
147
+ style={'max-width': '96%'},
153
148
  ),
154
- color = 'dark', dark=True,
155
- style = {'width': '100% !important'},
149
+ color='dark', dark=True,
150
+ style={'width': '100% !important'},
156
151
  )
157
152
 
158
153
  refresh_jobs_interval = dcc.Interval(
159
- id = 'refresh-jobs-interval',
160
- interval = 1 * 1000,
161
- n_intervals = 0,
162
- disabled = False,
154
+ id='refresh-jobs-interval',
155
+ interval=(1 * 1000),
156
+ n_intervals=0,
157
+ disabled=False,
163
158
  )
164
159
 
165
160
  def alert_from_success_tuple(success: SuccessTuple) -> dbc.Alert:
@@ -169,11 +164,11 @@ def alert_from_success_tuple(success: SuccessTuple) -> dbc.Alert:
169
164
  return dbc.Alert('', is_open=False) if not isinstance(success, tuple) else (
170
165
  dbc.Alert(
171
166
  remove_ansi(success[1]),
172
- id = 'success-alert',
173
- dismissable = True,
174
- fade = True,
175
- is_open = not (success[1] in STATIC_CONFIG['system']['success']['ignore']),
176
- color = 'success' if success[0] else 'danger',
167
+ id='success-alert',
168
+ dismissable=True,
169
+ fade=True,
170
+ is_open=(success[1] not in STATIC_CONFIG['system']['success']['ignore']),
171
+ color='success' if success[0] else 'danger',
177
172
  )
178
173
  )
179
174
 
@@ -7,24 +7,20 @@ Functions for interacting with jobs via the web interface.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
- from dash.dependencies import Input, Output, State
11
- from meerschaum.utils.typing import List, Optional, Dict, Any, Tuple, Union, WebState
10
+ from meerschaum.utils.typing import List, Dict, WebState
12
11
  from meerschaum.utils.packages import attempt_import, import_html, import_dcc
13
- from meerschaum.api.dash.components import alert_from_success_tuple, build_cards_grid
14
- from meerschaum.api.dash.users import is_session_authenticated
12
+ from meerschaum.api.dash.sessions import is_session_authenticated
15
13
  from meerschaum.api import CHECK_UPDATE
16
- dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
17
- html, dcc = import_html(), import_dcc()
18
14
  from meerschaum.jobs import (
19
15
  get_jobs,
20
- get_running_jobs,
21
- get_paused_jobs,
22
- get_stopped_jobs,
23
16
  get_executor_keys_from_context,
24
17
  Job,
25
18
  )
26
19
  from meerschaum.config import get_config
27
20
  from meerschaum.utils.misc import sorted_dict
21
+ from dash.dependencies import Input, Output, State
22
+ dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
23
+ html, dcc = import_html(), import_dcc()
28
24
 
29
25
  STATUS_EMOJI: Dict[str, str] = {
30
26
  'running': get_config('formatting', 'emoji', 'running'),
@@ -5,12 +5,15 @@
5
5
  Display pipes via a shareable URL.
6
6
  """
7
7
 
8
- from meerschaum.api import get_api_connector, CHECK_UPDATE
8
+ from meerschaum.api import CHECK_UPDATE
9
9
  from meerschaum.utils.packages import import_html, import_dcc
10
+ from meerschaum.api.dash.components import download_dataframe
11
+
10
12
  html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
11
13
  import dash_bootstrap_components as dbc
12
14
 
13
15
  layout = dbc.Container([
14
16
  dcc.Location('pipes-location'),
17
+ download_dataframe,
15
18
  html.Div(id='pipe-output-div'),
16
19
  ])
@@ -12,18 +12,16 @@ import shlex
12
12
  from textwrap import dedent
13
13
  from dash.dependencies import Input, Output, State
14
14
  from meerschaum.utils.typing import List, Optional, Dict, Any, Tuple, Union
15
- from meerschaum.utils.misc import string_to_dict, json_serialize_datetime
15
+ from meerschaum.utils.misc import string_to_dict
16
16
  from meerschaum.utils.packages import attempt_import, import_dcc, import_html, import_pandas
17
17
  from meerschaum.utils.sql import get_pd_type
18
18
  from meerschaum.utils.yaml import yaml
19
19
  from meerschaum.connectors.sql._fetch import get_pipe_query
20
- from meerschaum.api import endpoints, CHECK_UPDATE
21
- from meerschaum.api.dash import (
22
- dash_app, debug, _get_pipes
23
- )
20
+ from meerschaum.api import CHECK_UPDATE
21
+ from meerschaum.api.dash import debug, _get_pipes
24
22
  from meerschaum.api.dash.connectors import get_web_connector
25
23
  from meerschaum.api.dash.components import alert_from_success_tuple, build_cards_grid
26
- from meerschaum.api.dash.users import is_session_authenticated
24
+ from meerschaum.api.dash.sessions import is_session_authenticated
27
25
  from meerschaum.config import get_config
28
26
  import meerschaum as mrsm
29
27
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
@@ -235,12 +233,10 @@ def build_pipe_card(
235
233
  ),
236
234
  dbc.Col(
237
235
  dbc.Button(
238
- [
239
- html.I(
240
- className="bi bi-share",
241
- ),
242
- ],
243
- # href=pipe_url,
236
+ "🔗",
237
+ href=pipe_url,
238
+ external_link=True,
239
+ target="_blank",
244
240
  style={'float': 'right'},
245
241
  outline=True,
246
242
  color='link',
@@ -553,11 +549,11 @@ def accordion_items_from_pipe(
553
549
  backtrack_df = pipe.get_backtrack_data(debug=debug, limit=1)
554
550
  try:
555
551
  json_text = backtrack_df.fillna(pd.NA).to_json(
556
- orient = 'records',
557
- date_format = 'iso',
558
- force_ascii = False,
559
- indent = 4,
560
- date_unit = 'ns',
552
+ orient='records',
553
+ date_format='iso',
554
+ force_ascii=False,
555
+ indent=4,
556
+ date_unit='ns',
561
557
  ) if backtrack_df is not None else '[]'
562
558
  except Exception as e:
563
559
  warn(e)
@@ -13,7 +13,8 @@ from meerschaum.api import get_api_connector, endpoints, CHECK_UPDATE
13
13
  html, dcc = import_html(check_update=CHECK_UPDATE), import_dcc(check_update=CHECK_UPDATE)
14
14
  import dash_bootstrap_components as dbc
15
15
  from meerschaum.core import Plugin
16
- from meerschaum.api.dash import dash_app, debug, active_sessions
16
+ from meerschaum.api.dash import dash_app, debug
17
+ from meerschaum.api.dash.sessions import get_username_from_session
17
18
 
18
19
 
19
20
  def get_plugins_cards(
@@ -88,9 +89,10 @@ def is_plugin_owner(plugin_name: str, session_data: Dict['str', Any]) -> bool:
88
89
  Check whether the currently logged in user is the owner of a plugin.
89
90
  """
90
91
  plugin = Plugin(plugin_name)
91
- _username = active_sessions.get(
92
- session_data.get('session-id', None), {}
93
- ).get('username', None)
92
+ session_id = session_data.get('session-id', None)
93
+ if session_id is None:
94
+ return False
95
+ _username = get_username_from_session(session_id)
94
96
  _plugin_username = get_api_connector().get_plugin_username(plugin, debug=debug)
95
97
  return (
96
98
  _username is not None
@@ -0,0 +1,176 @@
1
+ #! /usr/bin/env python3
2
+ # vim:fenc=utf-8
3
+
4
+ """
5
+ Define caching functions for session management.
6
+ """
7
+
8
+ import json
9
+
10
+ from meerschaum.utils.typing import Union, Dict, Any, Optional
11
+ from meerschaum.api import debug, no_auth
12
+ from meerschaum.api import get_cache_connector, get_api_connector
13
+ from meerschaum.core import User
14
+ from meerschaum.config import get_config
15
+ from meerschaum.utils.warnings import dprint
16
+
17
+ SESSION_KEY_TEMPLATE: str = 'mrsm_session_id:{session_id}'
18
+ EXPIRES_SECONDS: int = get_config('system', 'api', 'cache', 'session_expires_minutes') * 60
19
+ _active_sessions: Dict[str, Dict[str, Any]] = {}
20
+
21
+
22
+ def get_session_key(session_id: str) -> str:
23
+ """
24
+ Return the session key for the cache connector.
25
+ """
26
+ return SESSION_KEY_TEMPLATE.format(session_id=session_id)
27
+
28
+
29
+ def set_session(session_id: str, session_data: Dict[str, Any]):
30
+ """
31
+ Set a `session_id` to a dictionary.
32
+ """
33
+ conn = get_cache_connector()
34
+ if conn is None:
35
+ _active_sessions[session_id] = session_data
36
+ if debug:
37
+ dprint(f"Setting in-memory data for {session_id}:\n{session_data}")
38
+ return
39
+
40
+ session_key = get_session_key(session_id)
41
+ session_data_str = json.dumps(session_data, separators=(',', ':'))
42
+ if debug:
43
+ dprint(f"Setting production data for {session_id=}:\n{session_data_str}")
44
+
45
+ conn.set(session_key, session_data_str, ex=EXPIRES_SECONDS)
46
+
47
+
48
+ def update_session(session_id: Optional[str], session_data: Dict[str, Any]):
49
+ """
50
+ Update the session's data dictionary.
51
+ """
52
+ existing_session_data = get_session_data(session_id) or {}
53
+ existing_session_data.update(session_data)
54
+ set_session(str(session_id), existing_session_data)
55
+
56
+
57
+ def get_session_data(session_id: Optional[str]) -> Union[Dict[str, Any], None]:
58
+ """
59
+ Return the session data dictionary.
60
+ """
61
+ if debug:
62
+ dprint(f"Getting session data for {session_id=}")
63
+ conn = get_cache_connector()
64
+ if conn is None:
65
+ return _active_sessions.get(str(session_id), None)
66
+
67
+ session_key = get_session_key(str(session_id))
68
+ session_data_str = conn.get(session_key)
69
+ if not session_data_str:
70
+ return None
71
+
72
+ return json.loads(session_data_str)
73
+
74
+
75
+ def get_username_from_session(session_id: Optional[str]) -> Union[str, None]:
76
+ """
77
+ If a `session_id` has been set, return the username.
78
+ Otherwise return `None`.
79
+ """
80
+ if debug:
81
+ dprint(f"Getting username for {session_id=}")
82
+ session_data = get_session_data(session_id)
83
+ if session_data is None:
84
+ return None
85
+
86
+ return session_data.get('username', None)
87
+
88
+
89
+ def is_session_active(session_id: Union[str, None]) -> bool:
90
+ """
91
+ Return whether a given `session_id` has been set.
92
+ """
93
+ return get_username_from_session(str(session_id)) is not None
94
+
95
+
96
+ def delete_session(session_id: str):
97
+ """
98
+ Delete a session if it's been set.
99
+ """
100
+ if debug:
101
+ dprint(f"Deleting {session_id=}")
102
+ conn = get_cache_connector()
103
+ if conn is None:
104
+ _ = _active_sessions.pop(session_id, None)
105
+ return
106
+
107
+ session_key = get_session_key(session_id)
108
+ conn.client.delete(session_key)
109
+
110
+
111
+ def is_session_authenticated(session_id: Optional[str]) -> bool:
112
+ """
113
+ Check is a session ID is active.
114
+ If running in secure mode, check whether a session ID corresponds to an admin.
115
+
116
+ Parameters
117
+ ----------
118
+ session_id: str
119
+ The session UUID.
120
+
121
+ Returns
122
+ -------
123
+ A bool whether the session is authenticated to perform actions.
124
+ """
125
+ if debug:
126
+ dprint(f"Checking authentication for {session_id=}")
127
+
128
+ if no_auth:
129
+ return True
130
+
131
+ if session_id is None:
132
+ return False
133
+
134
+ session_data = get_session_data(session_id)
135
+ if session_data is None:
136
+ return False
137
+ username = session_data.get('username', None)
138
+ if username is None:
139
+ return False
140
+
141
+ cached_auth = session_data.get('authenticated', None)
142
+ if cached_auth is not None:
143
+ return cached_auth
144
+
145
+ permissions = get_config('system', 'api', 'permissions')
146
+ allow_non_admin = permissions.get('actions', {}).get('non_admin', False)
147
+
148
+ is_auth = True if allow_non_admin else session_is_admin(session_id)
149
+ update_session(session_id, {'authenticated': is_auth})
150
+ return is_auth
151
+
152
+
153
+ def session_is_admin(session_id: str) -> bool:
154
+ """
155
+ Check whether a session ID corresponds to an admin user.
156
+ """
157
+ if debug:
158
+ dprint(f"Check admin for {session_id=}")
159
+ session_data = get_session_data(session_id)
160
+ if session_data is None:
161
+ return False
162
+
163
+ username = session_data.get('username', None)
164
+ if username is None:
165
+ return False
166
+
167
+ cached_admin = session_data.get('admin', None)
168
+ if cached_admin is not None:
169
+ return cached_admin
170
+
171
+ conn = get_api_connector()
172
+ user = User(username, instance=conn)
173
+ user_type = conn.get_user_type(user, debug=debug)
174
+ is_admin = user_type == 'admin'
175
+ update_session(session_id, {'admin': is_admin})
176
+ return is_admin
@@ -8,13 +8,10 @@ Functions for interacting with users.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
- from meerschaum.api import debug, CHECK_UPDATE, get_api_connector, no_auth
12
- from meerschaum.api.dash import active_sessions, authenticated_sessions, unauthenticated_sessions
11
+ from meerschaum.api import debug, CHECK_UPDATE
13
12
  from meerschaum.api.dash.connectors import get_web_connector
14
- from meerschaum.utils.typing import WebState, SuccessTuple, List, Tuple, Optional
13
+ from meerschaum.utils.typing import WebState, SuccessTuple, List, Tuple
15
14
  from meerschaum.utils.packages import attempt_import, import_html, import_dcc
16
- from meerschaum.config import get_config
17
- from meerschaum.core import User
18
15
  dcc, html = import_dcc(check_update=CHECK_UPDATE), import_html(check_update=CHECK_UPDATE)
19
16
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
20
17
 
@@ -35,51 +32,3 @@ def get_users_cards(state: WebState) -> Tuple[List[dbc.Card], List[SuccessTuple]
35
32
  )
36
33
 
37
34
  return cards, alerts
38
-
39
-
40
- def is_session_authenticated(session_id: str) -> bool:
41
- """
42
- Check is a session ID is active.
43
- If running in secure mode, check whether a session ID corresponds to an admin.
44
-
45
- Parameters
46
- ----------
47
- session_id: str
48
- The session UUID.
49
-
50
- Returns
51
- -------
52
- A bool whether the session is authenticated to perform actions.
53
- """
54
- if no_auth:
55
- return True
56
- if session_id not in active_sessions:
57
- return False
58
- if session_id in unauthenticated_sessions:
59
- return False
60
- if session_id in authenticated_sessions:
61
- return True
62
-
63
- permissions = get_config('system', 'api', 'permissions')
64
- allow_non_admin = permissions.get('actions', {}).get('non_admin', False)
65
-
66
- is_auth = True if allow_non_admin else session_is_admin(session_id)
67
- username = active_sessions.get(session_id, {}).get('username', None)
68
-
69
- if is_auth:
70
- authenticated_sessions[session_id] = username
71
- else:
72
- unauthenticated_sessions[session_id] = username
73
-
74
- return is_auth
75
-
76
-
77
- def session_is_admin(session_id: str) -> bool:
78
- """
79
- Check whether a session ID corresponds to an admin user.
80
- """
81
- conn = get_api_connector()
82
- username = active_sessions.get(session_id, {}).get('username', None)
83
- user = User(username, instance=conn)
84
- user_type = conn.get_user_type(user, debug=debug)
85
- return user_type == 'admin'
@@ -7,16 +7,12 @@ Functions for interacting with the Webterm via the dashboard.
7
7
  """
8
8
 
9
9
  import time
10
- from urllib.parse import urlparse
11
- from meerschaum.config import get_config
12
- from meerschaum.api import debug, CHECK_UPDATE, get_api_connector, no_auth
13
- from meerschaum.api.dash import active_sessions
14
- from meerschaum.api.dash.users import is_session_authenticated
10
+ from meerschaum.api import CHECK_UPDATE, get_api_connector
11
+ from meerschaum.api.dash.sessions import is_session_authenticated, get_username_from_session
15
12
  from meerschaum.api.dash.components import alert_from_success_tuple, console_div
16
- from meerschaum.utils.typing import WebState, SuccessTuple, List, Tuple, Optional, Any
17
- from meerschaum.utils.packages import attempt_import, import_html, import_dcc, run_python_package
13
+ from meerschaum.utils.typing import WebState, Tuple, Any
14
+ from meerschaum.utils.packages import attempt_import, import_html, import_dcc
18
15
  from meerschaum._internal.term.tools import is_webterm_running
19
- from meerschaum.config.static import STATIC_CONFIG
20
16
  from meerschaum.utils.threading import Thread, RLock
21
17
  dcc, html = import_dcc(check_update=CHECK_UPDATE), import_html(check_update=CHECK_UPDATE)
22
18
  dbc = attempt_import('dash_bootstrap_components', lazy=False, check_update=CHECK_UPDATE)
@@ -30,7 +26,7 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
30
26
  Start the webterm and return its iframe.
31
27
  """
32
28
  session_id = state['session-store.data'].get('session-id', None)
33
- username = active_sessions.get(session_id, {}).get('username', None)
29
+ username = get_username_from_session(session_id)
34
30
  if not is_session_authenticated(session_id):
35
31
  msg = f"User '{username}' is not authorized to access the webterm."
36
32
  return (
@@ -57,24 +53,23 @@ def get_webterm(state: WebState) -> Tuple[Any, Any]:
57
53
  return console_div, [alert_from_success_tuple((False, "Could not start the webterm server."))]
58
54
 
59
55
 
60
-
61
56
  webterm_procs = {}
62
57
  def start_webterm() -> None:
63
58
  """
64
59
  Start the webterm thread.
65
60
  """
66
- from meerschaum._internal.entry import entry
67
61
  from meerschaum.utils.packages import run_python_package
68
62
 
69
63
  def run():
64
+ conn = get_api_connector()
70
65
  _ = run_python_package(
71
66
  'meerschaum',
72
- ['start', 'webterm'],
73
- capture_output = True,
74
- as_proc = True,
75
- store_proc_dict = webterm_procs,
76
- store_proc_key = 'process',
77
- venv = None,
67
+ ['start', 'webterm', '-i', str(conn)],
68
+ capture_output=True,
69
+ as_proc=True,
70
+ store_proc_dict=webterm_procs,
71
+ store_proc_key='process',
72
+ venv=None,
78
73
  )
79
74
 
80
75
  with _locks['webterm_thread']:
@@ -15,7 +15,7 @@ function make_terminal(element, size, ws_url) {
15
15
  term.attachCustomKeyEventHandler(copyPasteKeyEventHandler);
16
16
  term.open(element);
17
17
 
18
- sessionStore = sessionStorage.getItem("session-store");
18
+ sessionStore = localStorage.getItem("session-store");
19
19
  ws.onopen = function (event) {
20
20
  ws.send(sessionStore);
21
21
  ws.send(