meerschaum 2.3.5.dev0__py3-none-any.whl → 2.4.0__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 (99) hide show
  1. meerschaum/_internal/arguments/__init__.py +2 -1
  2. meerschaum/_internal/arguments/_parse_arguments.py +88 -12
  3. meerschaum/_internal/docs/index.py +3 -2
  4. meerschaum/_internal/entry.py +42 -20
  5. meerschaum/_internal/shell/Shell.py +38 -44
  6. meerschaum/_internal/term/TermPageHandler.py +2 -3
  7. meerschaum/_internal/term/__init__.py +13 -11
  8. meerschaum/actions/api.py +26 -23
  9. meerschaum/actions/bootstrap.py +38 -11
  10. meerschaum/actions/copy.py +3 -3
  11. meerschaum/actions/delete.py +4 -1
  12. meerschaum/actions/register.py +1 -3
  13. meerschaum/actions/stack.py +24 -19
  14. meerschaum/actions/start.py +41 -41
  15. meerschaum/actions/sync.py +53 -52
  16. meerschaum/api/__init__.py +48 -14
  17. meerschaum/api/_events.py +26 -17
  18. meerschaum/api/_oauth2.py +2 -2
  19. meerschaum/api/_websockets.py +5 -4
  20. meerschaum/api/dash/__init__.py +7 -16
  21. meerschaum/api/dash/callbacks/__init__.py +1 -0
  22. meerschaum/api/dash/callbacks/dashboard.py +52 -58
  23. meerschaum/api/dash/callbacks/jobs.py +15 -16
  24. meerschaum/api/dash/callbacks/login.py +16 -10
  25. meerschaum/api/dash/callbacks/pipes.py +41 -0
  26. meerschaum/api/dash/callbacks/plugins.py +1 -1
  27. meerschaum/api/dash/callbacks/register.py +15 -11
  28. meerschaum/api/dash/components.py +54 -59
  29. meerschaum/api/dash/jobs.py +5 -9
  30. meerschaum/api/dash/pages/__init__.py +1 -0
  31. meerschaum/api/dash/pages/pipes.py +19 -0
  32. meerschaum/api/dash/pipes.py +86 -58
  33. meerschaum/api/dash/plugins.py +6 -4
  34. meerschaum/api/dash/sessions.py +176 -0
  35. meerschaum/api/dash/users.py +3 -41
  36. meerschaum/api/dash/webterm.py +12 -17
  37. meerschaum/api/resources/static/js/terminado.js +1 -1
  38. meerschaum/api/routes/_actions.py +4 -118
  39. meerschaum/api/routes/_jobs.py +45 -24
  40. meerschaum/api/routes/_login.py +4 -4
  41. meerschaum/api/routes/_pipes.py +3 -3
  42. meerschaum/api/routes/_webterm.py +5 -6
  43. meerschaum/config/_default.py +15 -3
  44. meerschaum/config/_version.py +1 -1
  45. meerschaum/config/stack/__init__.py +64 -21
  46. meerschaum/config/static/__init__.py +6 -0
  47. meerschaum/connectors/{Connector.py → _Connector.py} +19 -13
  48. meerschaum/connectors/__init__.py +24 -14
  49. meerschaum/connectors/api/{APIConnector.py → _APIConnector.py} +3 -1
  50. meerschaum/connectors/api/__init__.py +2 -1
  51. meerschaum/connectors/api/_actions.py +22 -36
  52. meerschaum/connectors/api/_jobs.py +1 -0
  53. meerschaum/connectors/parse.py +18 -16
  54. meerschaum/connectors/poll.py +30 -24
  55. meerschaum/connectors/sql/__init__.py +3 -1
  56. meerschaum/connectors/sql/_pipes.py +172 -197
  57. meerschaum/connectors/sql/_plugins.py +45 -43
  58. meerschaum/connectors/sql/_users.py +46 -38
  59. meerschaum/connectors/valkey/_ValkeyConnector.py +535 -0
  60. meerschaum/connectors/valkey/__init__.py +10 -0
  61. meerschaum/connectors/valkey/_fetch.py +75 -0
  62. meerschaum/connectors/valkey/_pipes.py +844 -0
  63. meerschaum/connectors/valkey/_plugins.py +265 -0
  64. meerschaum/connectors/valkey/_users.py +305 -0
  65. meerschaum/core/Pipe/__init__.py +3 -0
  66. meerschaum/core/Pipe/_attributes.py +1 -2
  67. meerschaum/core/Pipe/_clear.py +16 -13
  68. meerschaum/core/Pipe/_copy.py +106 -0
  69. meerschaum/core/Pipe/_data.py +165 -101
  70. meerschaum/core/Pipe/_drop.py +4 -4
  71. meerschaum/core/Pipe/_dtypes.py +14 -14
  72. meerschaum/core/Pipe/_edit.py +15 -14
  73. meerschaum/core/Pipe/_sync.py +134 -53
  74. meerschaum/core/Pipe/_verify.py +11 -11
  75. meerschaum/core/User/_User.py +14 -12
  76. meerschaum/jobs/_Job.py +27 -14
  77. meerschaum/jobs/__init__.py +7 -2
  78. meerschaum/jobs/systemd.py +20 -8
  79. meerschaum/plugins/_Plugin.py +17 -13
  80. meerschaum/utils/_get_pipes.py +14 -20
  81. meerschaum/utils/dataframe.py +291 -101
  82. meerschaum/utils/dtypes/__init__.py +31 -6
  83. meerschaum/utils/dtypes/sql.py +4 -4
  84. meerschaum/utils/formatting/_shell.py +5 -6
  85. meerschaum/utils/misc.py +3 -3
  86. meerschaum/utils/packages/__init__.py +14 -9
  87. meerschaum/utils/packages/_packages.py +2 -0
  88. meerschaum/utils/prompt.py +1 -1
  89. meerschaum/utils/schedule.py +1 -0
  90. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/METADATA +7 -1
  91. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/RECORD +98 -89
  92. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/WHEEL +1 -1
  93. meerschaum/api/dash/actions.py +0 -255
  94. /meerschaum/connectors/sql/{SQLConnector.py → _SQLConnector.py} +0 -0
  95. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/LICENSE +0 -0
  96. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/NOTICE +0 -0
  97. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/entry_points.txt +0 -0
  98. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/top_level.txt +0 -0
  99. {meerschaum-2.3.5.dev0.dist-info → meerschaum-2.4.0.dist-info}/zip-safe +0 -0
@@ -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)
@@ -48,13 +46,14 @@ def pipe_from_ctx(ctx, trigger_property: str = 'n_clicks') -> Union[mrsm.Pipe, N
48
46
  return None
49
47
  return mrsm.Pipe(**meta)
50
48
 
49
+
51
50
  def keys_from_state(
52
- state: Dict[str, Any],
53
- with_params: bool = False
54
- ) -> Union[
55
- Tuple[List[str], List[str], List[str]],
56
- Tuple[List[str], List[str], List[str], str],
57
- ]:
51
+ state: Dict[str, Any],
52
+ with_params: bool = False
53
+ ) -> Union[
54
+ Tuple[List[str], List[str], List[str]],
55
+ Tuple[List[str], List[str], List[str], str],
56
+ ]:
58
57
  """
59
58
  Read the current state and return the selected keys lists.
60
59
  """
@@ -85,10 +84,11 @@ def keys_from_state(
85
84
  keys.append(params)
86
85
  return tuple(keys)
87
86
 
87
+
88
88
  def pipes_from_state(
89
- state: Dict[str, Any],
90
- **kw
91
- ):
89
+ state: Dict[str, Any],
90
+ **kw
91
+ ):
92
92
  _ck, _mk, _lk, _params = keys_from_state(state, with_params=True)
93
93
  try:
94
94
  _pipes = _get_pipes(
@@ -103,10 +103,10 @@ def pipes_from_state(
103
103
 
104
104
 
105
105
  def build_pipe_card(
106
- pipe: mrsm.Pipe,
107
- authenticated: bool = False,
108
- _build_children_num: int = 10,
109
- ) -> 'dbc.Card':
106
+ pipe: mrsm.Pipe,
107
+ authenticated: bool = False,
108
+ _build_children_num: int = 10,
109
+ ) -> 'dbc.Card':
110
110
  """
111
111
  Return a card for the given pipe.
112
112
 
@@ -128,11 +128,11 @@ def build_pipe_card(
128
128
  dbc.Col(
129
129
  (
130
130
  dbc.DropdownMenu(
131
- label = "Manage",
132
- children = [
131
+ label="Manage",
132
+ children=[
133
133
  dbc.DropdownMenuItem(
134
134
  'Open in Python',
135
- id = {
135
+ id={
136
136
  'type': 'manage-pipe-button',
137
137
  'index': meta_str,
138
138
  'action': 'python',
@@ -140,7 +140,7 @@ def build_pipe_card(
140
140
  ),
141
141
  dbc.DropdownMenuItem(
142
142
  'Delete',
143
- id = {
143
+ id={
144
144
  'type': 'manage-pipe-button',
145
145
  'index': meta_str,
146
146
  'action': 'delete',
@@ -148,7 +148,7 @@ def build_pipe_card(
148
148
  ),
149
149
  dbc.DropdownMenuItem(
150
150
  'Drop',
151
- id = {
151
+ id={
152
152
  'type': 'manage-pipe-button',
153
153
  'index': meta_str,
154
154
  'action': 'drop',
@@ -156,7 +156,7 @@ def build_pipe_card(
156
156
  ),
157
157
  dbc.DropdownMenuItem(
158
158
  'Clear',
159
- id = {
159
+ id={
160
160
  'type': 'manage-pipe-button',
161
161
  'index': meta_str,
162
162
  'action': 'clear',
@@ -164,7 +164,7 @@ def build_pipe_card(
164
164
  ),
165
165
  dbc.DropdownMenuItem(
166
166
  'Verify',
167
- id = {
167
+ id={
168
168
  'type': 'manage-pipe-button',
169
169
  'index': meta_str,
170
170
  'action': 'verify',
@@ -172,56 +172,84 @@ def build_pipe_card(
172
172
  ),
173
173
  dbc.DropdownMenuItem(
174
174
  'Sync',
175
- id = {
175
+ id={
176
176
  'type': 'manage-pipe-button',
177
177
  'index': meta_str,
178
178
  'action': 'sync',
179
179
  },
180
180
  ),
181
181
  ],
182
- direction = "up",
183
- menu_variant = "dark",
184
- size = 'sm',
185
- color = 'secondary',
182
+ direction="up",
183
+ menu_variant="dark",
184
+ size='sm',
185
+ color='secondary',
186
186
  )
187
187
  ) if authenticated else [],
188
- width = 2,
188
+ width=2,
189
189
  ),
190
190
  dbc.Col(width=6),
191
191
  dbc.Col(
192
192
  dbc.Button(
193
193
  'Download CSV',
194
- size = 'sm',
195
- color = 'link',
196
- style = {'float': 'right'},
197
- id = {'type': 'pipe-download-csv-button', 'index': meta_str},
194
+ size='sm',
195
+ color='link',
196
+ style={'float': 'right'},
197
+ id={'type': 'pipe-download-csv-button', 'index': meta_str},
198
198
  ),
199
- width = 4,
199
+ width=4,
200
200
  ),
201
201
  ],
202
- justify = 'start',
202
+ justify='start',
203
203
  )
204
204
  card_body_children = [
205
- html.H5(
206
- html.B(str(pipe)),
207
- className = 'card-title',
208
- style = {'font-family': ['monospace']}
209
- ),
210
205
  html.Div(
211
206
  dbc.Accordion(
212
207
  accordion_items_from_pipe(
213
208
  pipe,
214
- authenticated = authenticated,
215
- _build_children_num = _build_children_num,
209
+ authenticated=authenticated,
210
+ _build_children_num=_build_children_num,
216
211
  ),
217
- flush = True,
218
- start_collapsed = True,
219
- id = {'type': 'pipe-accordion', 'index': meta_str},
212
+ flush=True,
213
+ start_collapsed=True,
214
+ id={'type': 'pipe-accordion', 'index': meta_str},
220
215
  )
221
216
  )
222
217
 
223
218
  ]
219
+
220
+ pipe_url = (
221
+ f"/dash/pipes/{pipe.connector_keys}/{pipe.metric_key}/{pipe.location_key}"
222
+ )
223
+
224
+ card_header_children = dbc.Row(
225
+ [
226
+ dbc.Col(
227
+ html.H5(
228
+ html.B(str(pipe)),
229
+ className='card-title',
230
+ style={'font-family': ['monospace']}
231
+ ),
232
+ width=11,
233
+ ),
234
+ dbc.Col(
235
+ dbc.Button(
236
+ "🔗",
237
+ href=pipe_url,
238
+ external_link=True,
239
+ target="_blank",
240
+ style={'float': 'right'},
241
+ outline=True,
242
+ color='link',
243
+ id={'type': 'share-pipe-button', 'index': meta_str},
244
+ ),
245
+ width=1,
246
+ ),
247
+ ],
248
+ justify='start',
249
+ )
250
+
224
251
  return dbc.Card([
252
+ dbc.CardHeader(children=card_header_children),
225
253
  dbc.CardBody(children=card_body_children),
226
254
  dbc.CardFooter(children=footer_children),
227
255
  ])
@@ -270,11 +298,11 @@ def get_pipes_cards(*keys, session_data: Optional[Dict[str, Any]] = None):
270
298
 
271
299
 
272
300
  def accordion_items_from_pipe(
273
- pipe: mrsm.Pipe,
274
- active_items: Optional[List[str]] = None,
275
- authenticated: bool = False,
276
- _build_children_num: int = 10,
277
- ) -> 'List[dbc.AccordionItem]':
301
+ pipe: mrsm.Pipe,
302
+ active_items: Optional[List[str]] = None,
303
+ authenticated: bool = False,
304
+ _build_children_num: int = 10,
305
+ ) -> 'List[dbc.AccordionItem]':
278
306
  """
279
307
  Build the accordion items for a given pipe.
280
308
  """
@@ -521,11 +549,11 @@ def accordion_items_from_pipe(
521
549
  backtrack_df = pipe.get_backtrack_data(debug=debug, limit=1)
522
550
  try:
523
551
  json_text = backtrack_df.fillna(pd.NA).to_json(
524
- orient = 'records',
525
- date_format = 'iso',
526
- force_ascii = False,
527
- indent = 4,
528
- date_unit = 'ns',
552
+ orient='records',
553
+ date_format='iso',
554
+ force_ascii=False,
555
+ indent=4,
556
+ date_unit='ns',
529
557
  ) if backtrack_df is not None else '[]'
530
558
  except Exception as e:
531
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,16 +8,14 @@ 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
 
18
+
21
19
  def get_users_cards(state: WebState) -> Tuple[List[dbc.Card], List[SuccessTuple]]:
22
20
  """
23
21
  Return the cards and alerts for users.
@@ -34,39 +32,3 @@ def get_users_cards(state: WebState) -> Tuple[List[dbc.Card], List[SuccessTuple]
34
32
  )
35
33
 
36
34
  return cards, alerts
37
-
38
-
39
- def is_session_authenticated(session_id: str) -> bool:
40
- """
41
- Check is a session ID is active.
42
- If running in secure mode, check whether a session ID corresponds to an admin.
43
-
44
- Parameters
45
- ----------
46
- session_id: str
47
- The session UUID.
48
-
49
- Returns
50
- -------
51
- A bool whether the session is authenticated to perform actions.
52
- """
53
- if no_auth:
54
- return True
55
- if session_id in unauthenticated_sessions:
56
- return False
57
- if session_id in authenticated_sessions:
58
- return True
59
- permissions = get_config('system', 'api', 'permissions')
60
- allow_non_admin = permissions.get('actions', {}).get('non_admin', False)
61
- if allow_non_admin:
62
- return True
63
- conn = get_api_connector()
64
- username = active_sessions.get(session_id, {}).get('username', None)
65
- user = User(username, instance=conn)
66
- user_type = conn.get_user_type(user, debug=debug)
67
- is_auth = user_type == 'admin'
68
- if is_auth:
69
- authenticated_sessions[session_id] = username
70
- else:
71
- unauthenticated_sessions[session_id] = username
72
- return is_auth
@@ -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(