meerschaum 2.9.0rc2__py3-none-any.whl → 2.9.1__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.
- meerschaum/api/dash/callbacks/__init__.py +5 -2
- meerschaum/api/dash/callbacks/custom.py +17 -25
- meerschaum/api/dash/callbacks/dashboard.py +5 -21
- meerschaum/api/dash/callbacks/settings/__init__.py +8 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +76 -0
- meerschaum/api/dash/components.py +110 -7
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/settings/__init__.py +8 -0
- meerschaum/api/dash/pages/settings/password_reset.py +63 -0
- meerschaum/api/resources/static/css/dash.css +7 -0
- meerschaum/api/routes/_pipes.py +76 -36
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/__init__.py +1 -0
- meerschaum/connectors/api/_pipes.py +79 -30
- meerschaum/connectors/sql/_pipes.py +38 -5
- meerschaum/connectors/valkey/_ValkeyConnector.py +2 -0
- meerschaum/connectors/valkey/_pipes.py +51 -39
- meerschaum/core/Pipe/__init__.py +1 -0
- meerschaum/core/Pipe/_sync.py +64 -4
- meerschaum/plugins/__init__.py +26 -4
- meerschaum/utils/dataframe.py +58 -3
- meerschaum/utils/dtypes/__init__.py +45 -17
- meerschaum/utils/dtypes/sql.py +182 -3
- meerschaum/utils/misc.py +1 -1
- meerschaum/utils/packages/_packages.py +6 -3
- meerschaum/utils/sql.py +122 -6
- meerschaum/utils/venv/__init__.py +4 -1
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/METADATA +14 -9
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/RECORD +35 -36
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/WHEEL +1 -1
- meerschaum/_internal/gui/__init__.py +0 -43
- meerschaum/_internal/gui/app/__init__.py +0 -50
- meerschaum/_internal/gui/app/_windows.py +0 -74
- meerschaum/_internal/gui/app/actions.py +0 -30
- meerschaum/_internal/gui/app/pipes.py +0 -47
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/LICENSE +0 -0
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/NOTICE +0 -0
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/top_level.txt +0 -0
- {meerschaum-2.9.0rc2.dist-info → meerschaum-2.9.1.dist-info}/zip-safe +0 -0
@@ -6,13 +6,16 @@
|
|
6
6
|
Define callbacks for pages.
|
7
7
|
"""
|
8
8
|
|
9
|
+
from meerschaum.api import debug as _debug
|
9
10
|
import meerschaum.api.dash.callbacks.dashboard
|
10
11
|
import meerschaum.api.dash.callbacks.login
|
11
12
|
import meerschaum.api.dash.callbacks.plugins
|
12
13
|
import meerschaum.api.dash.callbacks.jobs
|
13
14
|
import meerschaum.api.dash.callbacks.register
|
14
15
|
import meerschaum.api.dash.callbacks.pipes
|
16
|
+
import meerschaum.api.dash.callbacks.settings
|
15
17
|
from meerschaum.api.dash.callbacks.custom import init_dash_plugins, add_plugin_pages
|
16
18
|
|
17
|
-
init_dash_plugins()
|
18
|
-
add_plugin_pages()
|
19
|
+
init_dash_plugins(debug=_debug)
|
20
|
+
add_plugin_pages(debug=_debug)
|
21
|
+
|
@@ -11,12 +11,12 @@ from typing import Any, Dict
|
|
11
11
|
|
12
12
|
from meerschaum.api.dash import dash_app
|
13
13
|
from meerschaum.plugins import _dash_plugins, _plugin_endpoints_to_pages
|
14
|
-
from meerschaum.utils.warnings import warn
|
14
|
+
from meerschaum.utils.warnings import warn, dprint
|
15
15
|
from meerschaum.api.dash.callbacks.dashboard import _paths, _required_login, _pages
|
16
16
|
from meerschaum.api.dash.components import pages_navbar
|
17
17
|
|
18
18
|
|
19
|
-
def init_dash_plugins():
|
19
|
+
def init_dash_plugins(debug: bool = False):
|
20
20
|
"""
|
21
21
|
Fire the initial callbacks for Dash plugins.
|
22
22
|
"""
|
@@ -32,29 +32,21 @@ def init_dash_plugins():
|
|
32
32
|
)
|
33
33
|
|
34
34
|
|
35
|
-
def add_plugin_pages():
|
35
|
+
def add_plugin_pages(debug: bool = False):
|
36
36
|
"""
|
37
37
|
Allow users to add pages via the `@web_page` decorator.
|
38
38
|
"""
|
39
|
-
for
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
page_layout
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
)
|
54
|
-
]
|
55
|
-
)
|
56
|
-
)
|
57
|
-
_pages[page_key] = _endpoint
|
58
|
-
_paths[_endpoint] = page_layout
|
59
|
-
if _page_dict['login_required']:
|
60
|
-
_required_login.add(_endpoint)
|
39
|
+
for plugin_name, pages_dicts in _plugin_endpoints_to_pages.items():
|
40
|
+
if debug:
|
41
|
+
dprint(f"Adding pages from plugin '{plugin_name}'...")
|
42
|
+
for _endpoint, _page_dict in pages_dicts.items():
|
43
|
+
page_layout = _page_dict['function']()
|
44
|
+
if not _page_dict['skip_navbar']:
|
45
|
+
if isinstance(page_layout, list):
|
46
|
+
page_layout = [pages_navbar] + page_layout
|
47
|
+
else:
|
48
|
+
page_layout = [pages_navbar, page_layout]
|
49
|
+
_pages[_page_dict['page_key']] = _endpoint
|
50
|
+
_paths[_endpoint] = page_layout
|
51
|
+
if _page_dict['login_required']:
|
52
|
+
_required_login.add(_endpoint)
|
@@ -33,7 +33,10 @@ from meerschaum.api.dash.users import get_users_cards
|
|
33
33
|
from meerschaum.api.dash.graphs import get_graphs_cards
|
34
34
|
from meerschaum.api.dash.webterm import get_webterm
|
35
35
|
from meerschaum.api.dash.components import (
|
36
|
-
alert_from_success_tuple,
|
36
|
+
alert_from_success_tuple,
|
37
|
+
console_div,
|
38
|
+
build_cards_grid,
|
39
|
+
build_pages_offcanvas_children,
|
37
40
|
)
|
38
41
|
from meerschaum.api.dash import pages
|
39
42
|
from meerschaum.utils.typing import Dict
|
@@ -1093,26 +1096,7 @@ def toggle_pages_offcanvas(n_clicks: Optional[int], is_open: bool):
|
|
1093
1096
|
"""
|
1094
1097
|
Toggle the pages sidebar.
|
1095
1098
|
"""
|
1096
|
-
pages_children =
|
1097
|
-
dbc.ListGroup(
|
1098
|
-
[
|
1099
|
-
dbc.ListGroupItem(
|
1100
|
-
dbc.Button(
|
1101
|
-
html.P(
|
1102
|
-
' '.join([word.capitalize() for word in page_key.split(' ')]),
|
1103
|
-
style={'text-decoration': 'none', 'fontSize': '18px'},
|
1104
|
-
),
|
1105
|
-
style={'width': '100%', 'text-align': 'left'},
|
1106
|
-
href=page_href,
|
1107
|
-
color='dark',
|
1108
|
-
)
|
1109
|
-
)
|
1110
|
-
for page_key, page_href in _pages.items()
|
1111
|
-
],
|
1112
|
-
flush=True,
|
1113
|
-
),
|
1114
|
-
outline=True,
|
1115
|
-
)
|
1099
|
+
pages_children = build_pages_offcanvas_children()
|
1116
1100
|
if n_clicks:
|
1117
1101
|
return not is_open, pages_children
|
1118
1102
|
return is_open, pages_children
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define the callbacks for the password reset page.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import dash
|
9
|
+
from dash.exceptions import PreventUpdate
|
10
|
+
from dash.dependencies import Input, Output, State
|
11
|
+
import dash_bootstrap_components as dbc
|
12
|
+
|
13
|
+
from meerschaum.core.User import User
|
14
|
+
from meerschaum.config.static import STATIC_CONFIG
|
15
|
+
from meerschaum.api import get_api_connector, debug
|
16
|
+
from meerschaum.api.dash import dash_app
|
17
|
+
from meerschaum.api.dash.components import alert_from_success_tuple
|
18
|
+
from meerschaum.api.dash.sessions import get_username_from_session
|
19
|
+
|
20
|
+
|
21
|
+
@dash_app.callback(
|
22
|
+
Output('password-reset-alert-div', 'children'),
|
23
|
+
Input('password-reset-button', 'n_clicks'),
|
24
|
+
State('password-reset-input', 'value',),
|
25
|
+
State('session-store', 'data'),
|
26
|
+
)
|
27
|
+
def password_reset_button_click(n_clicks, new_password_value, session_store_data):
|
28
|
+
"""
|
29
|
+
Attempt the password reset with the form data.
|
30
|
+
"""
|
31
|
+
if not n_clicks:
|
32
|
+
raise PreventUpdate
|
33
|
+
|
34
|
+
session_id = session_store_data.get('session-id', None)
|
35
|
+
username = get_username_from_session(session_id)
|
36
|
+
if not username:
|
37
|
+
return alert_from_success_tuple(
|
38
|
+
(False, "Invalid session. Are you logged in correctly?")
|
39
|
+
)
|
40
|
+
|
41
|
+
instance_connector = get_api_connector()
|
42
|
+
user = User(username, new_password_value)
|
43
|
+
success, msg = instance_connector.edit_user(user, debug=debug)
|
44
|
+
return alert_from_success_tuple((success, msg))
|
45
|
+
|
46
|
+
|
47
|
+
@dash_app.callback(
|
48
|
+
Output('password-reset-input', 'valid'),
|
49
|
+
Output('password-reset-input', 'invalid'),
|
50
|
+
Input('password-reset-input', 'value'),
|
51
|
+
)
|
52
|
+
def validate_new_password(new_password_value):
|
53
|
+
if not new_password_value:
|
54
|
+
raise PreventUpdate
|
55
|
+
|
56
|
+
valid = (len(new_password_value) >= STATIC_CONFIG['users']['min_password_length'])
|
57
|
+
return valid, not valid
|
58
|
+
|
59
|
+
|
60
|
+
@dash_app.callback(
|
61
|
+
Output("password-reset-confirm-input", "valid"),
|
62
|
+
Output("password-reset-confirm-input", "invalid"),
|
63
|
+
Output("password-reset-button", 'disabled'),
|
64
|
+
Input("password-reset-confirm-input", "value"),
|
65
|
+
State("password-reset-input", "value"),
|
66
|
+
)
|
67
|
+
def validate_new_passwords_match(confirm_password_value, new_password_value):
|
68
|
+
if not confirm_password_value:
|
69
|
+
raise PreventUpdate
|
70
|
+
|
71
|
+
new_password_is_valid, _ = validate_new_password(new_password_value)
|
72
|
+
if not new_password_is_valid:
|
73
|
+
raise PreventUpdate
|
74
|
+
|
75
|
+
valid = confirm_password_value == new_password_value
|
76
|
+
return valid, not valid, not valid
|
@@ -110,6 +110,13 @@ instance_select = dbc.Select(
|
|
110
110
|
class_name='dbc_dark custom-select custom-select-sm',
|
111
111
|
)
|
112
112
|
|
113
|
+
sign_out_button = dbc.Button(
|
114
|
+
"Sign out",
|
115
|
+
color='link',
|
116
|
+
style={'margin-left': '30px'},
|
117
|
+
id='sign-out-button',
|
118
|
+
)
|
119
|
+
|
113
120
|
logo_row = dbc.Row(
|
114
121
|
[
|
115
122
|
dbc.Col(
|
@@ -128,7 +135,30 @@ logo_row = dbc.Row(
|
|
128
135
|
pages_navbar = html.Div(
|
129
136
|
[
|
130
137
|
pages_offcanvas,
|
131
|
-
dbc.Navbar(
|
138
|
+
dbc.Navbar(
|
139
|
+
dbc.Container(
|
140
|
+
[
|
141
|
+
logo_row,
|
142
|
+
dbc.NavbarToggler(id="navbar-toggler", n_clicks=0),
|
143
|
+
dbc.Collapse(
|
144
|
+
dbc.Row(
|
145
|
+
[
|
146
|
+
dbc.Col(
|
147
|
+
sign_out_button,
|
148
|
+
className="ms-auto",
|
149
|
+
),
|
150
|
+
],
|
151
|
+
className="g-0 ms-auto flex-nowrap mt-3 mt-md-0",
|
152
|
+
),
|
153
|
+
id='navbar-collapse',
|
154
|
+
is_open=False,
|
155
|
+
navbar=True,
|
156
|
+
),
|
157
|
+
]
|
158
|
+
),
|
159
|
+
dark=True,
|
160
|
+
color='dark'
|
161
|
+
),
|
132
162
|
],
|
133
163
|
id='pages-navbar-div',
|
134
164
|
)
|
@@ -143,12 +173,7 @@ navbar = dbc.Navbar(
|
|
143
173
|
[
|
144
174
|
dbc.Col(instance_select),
|
145
175
|
dbc.Col(
|
146
|
-
|
147
|
-
"Sign out",
|
148
|
-
color='link',
|
149
|
-
style={'margin-left': '30px'},
|
150
|
-
id='sign-out-button',
|
151
|
-
),
|
176
|
+
sign_out_button,
|
152
177
|
className="ms-auto",
|
153
178
|
),
|
154
179
|
],
|
@@ -207,3 +232,81 @@ def build_cards_grid(cards: List[dbc.Card], num_columns: int = 3) -> html.Div:
|
|
207
232
|
rows.append(r)
|
208
233
|
rows.append(html.Br())
|
209
234
|
return html.Div(rows)
|
235
|
+
|
236
|
+
|
237
|
+
def build_pages_offcanvas_children():
|
238
|
+
"""
|
239
|
+
Return the contents of the pages offcanvas.
|
240
|
+
"""
|
241
|
+
from meerschaum.api.dash.callbacks.dashboard import _pages
|
242
|
+
from meerschaum.api.dash.callbacks.custom import _plugin_endpoints_to_pages
|
243
|
+
pages_listgroup_items = []
|
244
|
+
custom_pages = []
|
245
|
+
for pages_dicts in _plugin_endpoints_to_pages.values():
|
246
|
+
for page_dict in pages_dicts.values():
|
247
|
+
custom_pages.append(page_dict['page_key'])
|
248
|
+
|
249
|
+
for page_key, page_href in _pages.items():
|
250
|
+
if page_key in custom_pages:
|
251
|
+
continue
|
252
|
+
pages_listgroup_items.append(
|
253
|
+
dbc.ListGroupItem(
|
254
|
+
dbc.Button(
|
255
|
+
' '.join([word.capitalize() for word in page_key.split(' ')]),
|
256
|
+
style={
|
257
|
+
'width': '100%',
|
258
|
+
'text-align': 'left',
|
259
|
+
'text-decoration': 'none',
|
260
|
+
'padding-left': '0',
|
261
|
+
},
|
262
|
+
href=page_href,
|
263
|
+
color='dark',
|
264
|
+
)
|
265
|
+
)
|
266
|
+
)
|
267
|
+
|
268
|
+
plugins_accordion_items = []
|
269
|
+
for page_group, pages_dicts in _plugin_endpoints_to_pages.items():
|
270
|
+
plugin_listgroup_items = [
|
271
|
+
dbc.ListGroupItem(
|
272
|
+
dbc.Button(
|
273
|
+
' '.join([word.capitalize() for word in page_dict['page_key'].split(' ')]),
|
274
|
+
style={
|
275
|
+
'width': '100%',
|
276
|
+
'text-align': 'left',
|
277
|
+
'text-decoration': 'none',
|
278
|
+
'padding-left': '0',
|
279
|
+
},
|
280
|
+
href=page_href,
|
281
|
+
color='dark',
|
282
|
+
)
|
283
|
+
)
|
284
|
+
for page_href, page_dict in pages_dicts.items()
|
285
|
+
]
|
286
|
+
plugin_listgroup = dbc.ListGroup(plugin_listgroup_items, flush=True)
|
287
|
+
plugin_accordion_item = dbc.AccordionItem(
|
288
|
+
plugin_listgroup,
|
289
|
+
title=(
|
290
|
+
page_group.capitalize()
|
291
|
+
if page_group and not page_group[0].isupper()
|
292
|
+
else page_group
|
293
|
+
),
|
294
|
+
class_name='pages-offcanvas-accordion',
|
295
|
+
)
|
296
|
+
plugins_accordion_items.append(plugin_accordion_item)
|
297
|
+
plugins_accordion = dbc.Accordion(
|
298
|
+
plugins_accordion_items,
|
299
|
+
start_collapsed=True,
|
300
|
+
flush=True,
|
301
|
+
always_open=True,
|
302
|
+
)
|
303
|
+
pages_listgroup_items.append(plugins_accordion)
|
304
|
+
|
305
|
+
pages_children = dbc.Card(
|
306
|
+
dbc.ListGroup(
|
307
|
+
pages_listgroup_items,
|
308
|
+
flush=True,
|
309
|
+
),
|
310
|
+
outline=True,
|
311
|
+
)
|
312
|
+
return pages_children
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#! /usr/bin/env python3
|
2
|
+
# vim:fenc=utf-8
|
3
|
+
|
4
|
+
"""
|
5
|
+
Define the password reset page layout.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import dash_bootstrap_components as dbc
|
9
|
+
import dash.html as html
|
10
|
+
import dash.dcc as dcc
|
11
|
+
from meerschaum.plugins import web_page
|
12
|
+
|
13
|
+
|
14
|
+
@web_page('password-reset', login_required=True, page_group='Settings')
|
15
|
+
def page_layout():
|
16
|
+
"""
|
17
|
+
Return the layout for this page.
|
18
|
+
"""
|
19
|
+
return dbc.Container([
|
20
|
+
html.Br(),
|
21
|
+
html.H3('Password Reset'),
|
22
|
+
html.Br(),
|
23
|
+
html.Div(id="password-reset-alert-div"),
|
24
|
+
dbc.Form([
|
25
|
+
dbc.Row(
|
26
|
+
[
|
27
|
+
dbc.Label("New Password", html_for="password-reset-input", width=2),
|
28
|
+
dbc.Col(
|
29
|
+
dbc.Input(
|
30
|
+
type="password",
|
31
|
+
id="password-reset-input",
|
32
|
+
placeholder="Enter new password",
|
33
|
+
),
|
34
|
+
width=10,
|
35
|
+
),
|
36
|
+
],
|
37
|
+
className="mb-3",
|
38
|
+
),
|
39
|
+
dbc.Row(
|
40
|
+
[
|
41
|
+
dbc.Label("Confirm Password", html_for="password-reset-confirm-input", width=2),
|
42
|
+
dbc.Col(
|
43
|
+
dbc.Input(
|
44
|
+
type="password",
|
45
|
+
id="password-reset-confirm-input",
|
46
|
+
placeholder="Confirm new password",
|
47
|
+
),
|
48
|
+
width=10,
|
49
|
+
),
|
50
|
+
],
|
51
|
+
className="mb-3",
|
52
|
+
),
|
53
|
+
dbc.Row(
|
54
|
+
[
|
55
|
+
dbc.Col(
|
56
|
+
dbc.Button("Submit", id="password-reset-button", disabled=True),
|
57
|
+
),
|
58
|
+
],
|
59
|
+
justify="end",
|
60
|
+
className="mb-3",
|
61
|
+
),
|
62
|
+
]),
|
63
|
+
])
|
@@ -73,3 +73,10 @@ a {
|
|
73
73
|
.input-text {
|
74
74
|
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif !important;
|
75
75
|
}
|
76
|
+
.pages-offcanvas-accordion button {
|
77
|
+
background-color: var(--bs-dark) !important;
|
78
|
+
color: white !important;
|
79
|
+
}
|
80
|
+
.pages-offcanvas-accordion div {
|
81
|
+
padding: 0 !important;
|
82
|
+
}
|
meerschaum/api/routes/_pipes.py
CHANGED
@@ -383,8 +383,10 @@ def get_pipe_data(
|
|
383
383
|
params: Optional[str] = None,
|
384
384
|
limit: int = MAX_RESPONSE_ROW_LIMIT,
|
385
385
|
order: str = 'asc',
|
386
|
-
|
387
|
-
|
386
|
+
date_format: str = 'iso',
|
387
|
+
date_unit: str = 'us',
|
388
|
+
double_precision: int = 15,
|
389
|
+
geometry_format: str = 'wkb_hex',
|
388
390
|
curr_user = (
|
389
391
|
fastapi.Depends(manager) if not no_auth else None
|
390
392
|
),
|
@@ -401,8 +403,20 @@ def get_pipe_data(
|
|
401
403
|
The connector key to the instance on which the pipe is registered.
|
402
404
|
Defaults to the configured value for `meerschaum:api_instance`.
|
403
405
|
|
404
|
-
|
405
|
-
|
406
|
+
date_format: str, default 'iso'
|
407
|
+
Serialzation format for datetime values.
|
408
|
+
Accepted values are `'iso`' (ISO8601) and `'epoch'` (epoch milliseconds).
|
409
|
+
|
410
|
+
date_unit: str, default 'us'
|
411
|
+
Timestamp precision for serialization. Accepted values are `'s'` (seconds),
|
412
|
+
`'ms'` (milliseconds), `'us'` (microseconds), and `'ns'`.
|
413
|
+
|
414
|
+
double_precision: int, default 15
|
415
|
+
The number of decimal places to use when encoding floating point values (maximum `15`).
|
416
|
+
|
417
|
+
geometry_format: str, default 'wkb_hex'
|
418
|
+
The serialization format for geometry data.
|
419
|
+
Accepted values are `geojson`, `wkb_hex`, and `wkt`.
|
406
420
|
"""
|
407
421
|
if limit > MAX_RESPONSE_ROW_LIMIT:
|
408
422
|
raise fastapi.HTTPException(
|
@@ -469,25 +483,6 @@ def get_pipe_data(
|
|
469
483
|
detail=f"Cannot retrieve data from protected table '{pipe.target}'.",
|
470
484
|
)
|
471
485
|
|
472
|
-
if as_chunks:
|
473
|
-
chunks_cursor_token = generate_chunks_cursor_token(
|
474
|
-
pipe,
|
475
|
-
select_columns=_select_columns,
|
476
|
-
omit_columns=_omit_columns,
|
477
|
-
begin=begin,
|
478
|
-
end=end,
|
479
|
-
params=_params,
|
480
|
-
limit=limit,
|
481
|
-
order=order,
|
482
|
-
debug=debug,
|
483
|
-
)
|
484
|
-
return fastapi.Response(
|
485
|
-
json.dumps({
|
486
|
-
'chunks_cursor': chunks_cursor,
|
487
|
-
}),
|
488
|
-
media_type='application/json',
|
489
|
-
)
|
490
|
-
|
491
486
|
df = pipe.get_data(
|
492
487
|
select_columns=_select_columns,
|
493
488
|
omit_columns=_omit_columns,
|
@@ -504,7 +499,13 @@ def get_pipe_data(
|
|
504
499
|
detail="Could not fetch data with the given parameters.",
|
505
500
|
)
|
506
501
|
|
507
|
-
json_content = to_json(
|
502
|
+
json_content = to_json(
|
503
|
+
df,
|
504
|
+
date_format=date_format,
|
505
|
+
date_unit=date_unit,
|
506
|
+
geometry_format=geometry_format,
|
507
|
+
double_precision=double_precision,
|
508
|
+
)
|
508
509
|
return fastapi.Response(
|
509
510
|
json_content,
|
510
511
|
media_type='application/json',
|
@@ -554,37 +555,70 @@ def get_pipe_chunk_bounds(
|
|
554
555
|
)
|
555
556
|
|
556
557
|
|
557
|
-
@app.
|
558
|
-
pipes_endpoint + '/{connector_keys}/{metric_key}/{location_key}/
|
558
|
+
@app.delete(
|
559
|
+
pipes_endpoint + '/{connector_keys}/{metric_key}/{location_key}/drop',
|
559
560
|
tags=['Pipes: Data'],
|
560
561
|
)
|
561
|
-
def
|
562
|
+
def drop_pipe(
|
562
563
|
connector_keys: str,
|
563
564
|
metric_key: str,
|
564
565
|
location_key: str,
|
565
|
-
|
566
|
-
|
566
|
+
instance_keys: Optional[str] = None,
|
567
|
+
curr_user = (
|
568
|
+
fastapi.Depends(manager) if not no_auth else None
|
569
|
+
),
|
570
|
+
):
|
567
571
|
"""
|
568
|
-
|
572
|
+
Drop a pipe's target table.
|
569
573
|
"""
|
574
|
+
allow_actions = mrsm.get_config('system', 'api', 'permissions', 'actions', 'non_admin')
|
575
|
+
if not allow_actions:
|
576
|
+
return False, (
|
577
|
+
"The administrator for this server has not allowed actions.\n\n"
|
578
|
+
"Please contact the system administrator, or if you are running this server, "
|
579
|
+
"open the configuration file with `edit config system` and search for 'permissions'."
|
580
|
+
" Under the keys `api:permissions:actions`, " +
|
581
|
+
"you can toggle non-admin actions."
|
582
|
+
)
|
583
|
+
pipe_object = get_pipe(connector_keys, metric_key, location_key, instance_keys)
|
584
|
+
results = get_api_connector(instance_keys=instance_keys).drop_pipe(pipe_object, debug=debug)
|
585
|
+
pipes(instance_keys, refresh=True)
|
586
|
+
return results
|
570
587
|
|
571
588
|
|
572
589
|
@app.delete(
|
573
|
-
pipes_endpoint + '/{connector_keys}/{metric_key}/{location_key}/
|
590
|
+
pipes_endpoint + '/{connector_keys}/{metric_key}/{location_key}/clear',
|
574
591
|
tags=['Pipes: Data'],
|
575
592
|
)
|
576
|
-
def
|
593
|
+
def clear_pipe(
|
577
594
|
connector_keys: str,
|
578
595
|
metric_key: str,
|
579
596
|
location_key: str,
|
580
597
|
instance_keys: Optional[str] = None,
|
598
|
+
begin: Union[str, int, None] = None,
|
599
|
+
end: Union[str, int, None] = None,
|
600
|
+
params: Optional[str] = None,
|
581
601
|
curr_user = (
|
582
602
|
fastapi.Depends(manager) if not no_auth else None
|
583
603
|
),
|
584
604
|
):
|
585
605
|
"""
|
586
|
-
|
606
|
+
Delete rows from a pipe's target table.
|
587
607
|
"""
|
608
|
+
_params = {}
|
609
|
+
if params == 'null':
|
610
|
+
params = None
|
611
|
+
if params is not None:
|
612
|
+
try:
|
613
|
+
_params = json.loads(params)
|
614
|
+
except Exception:
|
615
|
+
_params = None
|
616
|
+
if not isinstance(_params, dict):
|
617
|
+
raise fastapi.HTTPException(
|
618
|
+
status_code=409,
|
619
|
+
detail="Params must be a valid JSON-encoded dictionary.",
|
620
|
+
)
|
621
|
+
|
588
622
|
allow_actions = mrsm.get_config('system', 'api', 'permissions', 'actions', 'non_admin')
|
589
623
|
if not allow_actions:
|
590
624
|
return False, (
|
@@ -594,13 +628,19 @@ def drop_pipe(
|
|
594
628
|
" Under the keys `api:permissions:actions`, " +
|
595
629
|
"you can toggle non-admin actions."
|
596
630
|
)
|
597
|
-
|
598
|
-
|
631
|
+
pipe = get_pipe(connector_keys, metric_key, location_key, instance_keys)
|
632
|
+
begin, end = pipe.parse_date_bounds(begin, end)
|
633
|
+
results = get_api_connector(instance_keys=instance_keys).clear_pipe(
|
634
|
+
pipe,
|
635
|
+
begin=begin,
|
636
|
+
end=end,
|
637
|
+
params=_params,
|
638
|
+
debug=debug,
|
639
|
+
)
|
599
640
|
pipes(instance_keys, refresh=True)
|
600
641
|
return results
|
601
642
|
|
602
643
|
|
603
|
-
|
604
644
|
@app.get(
|
605
645
|
pipes_endpoint + '/{connector_keys}/{metric_key}/{location_key}/csv',
|
606
646
|
tags=['Pipes: Data'],
|
meerschaum/config/_version.py
CHANGED