gaard-api 0.2.13__tar.gz → 0.2.14__tar.gz
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.
- {gaard_api-0.2.13/src/gaard_api.egg-info → gaard_api-0.2.14}/PKG-INFO +1 -1
- {gaard_api-0.2.13 → gaard_api-0.2.14}/pyproject.toml +1 -1
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/database_initial.sql +14 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/database_updates.sql +13 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/models.py +25 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/dashboards.py +343 -76
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/main.py +1 -1
- {gaard_api-0.2.13 → gaard_api-0.2.14/src/gaard_api.egg-info}/PKG-INFO +1 -1
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_admin_api.py +240 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_database_migrations.py +15 -5
- {gaard_api-0.2.13 → gaard_api-0.2.14}/MANIFEST.in +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/README.md +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/setup.cfg +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/database.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/database_legacy_updates.sql +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/defaults.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/migration_runner.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/prompt_runtime.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/security.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin/services.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/getgaard.svg +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/identity.js +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/main.js +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/styles.css +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/vendor/gridstack/gridstack-all.js +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/assets/vendor/gridstack/gridstack.min.css +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/index.html +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/admin-web/package.json +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/admin.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/analysis.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/prompts.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/query.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api/v1/schema.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/api_registry.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/auth_dependencies.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/auth_hooks.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/cli.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/cli_commands.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/conversations.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/core/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/core/error_handlers.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/core/schema_cache.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/core/settings.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/example_data/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/example_data/medical_poc/__init__.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/example_data/medical_poc/schema.sql +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/example_data/medical_poc/seed.sql +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/example_database.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/extension_services.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/extensions.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/license.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/package_updates.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/py.typed +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/query_hooks.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/server_cli.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/siem.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api/tls_http.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api.egg-info/SOURCES.txt +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api.egg-info/dependency_links.txt +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api.egg-info/entry_points.txt +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api.egg-info/requires.txt +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/src/gaard_api.egg-info/top_level.txt +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_analysis_api.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_api_cli.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_api_registry.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_conversation_api.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_error_handlers.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_license_api.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_license_service.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_prompt_runtime.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_query_error_messages.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_server_cli.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_settings.py +0 -0
- {gaard_api-0.2.13 → gaard_api-0.2.14}/tests/test_tls_http.py +0 -0
|
@@ -16,6 +16,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS ix_conversation_turns_turn_id ON conversation_
|
|
|
16
16
|
CREATE TABLE IF NOT EXISTS conversations (id INTEGER NOT NULL, conversation_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, status VARCHAR(50) NOT NULL, datasource_id VARCHAR(255) NOT NULL, datasource_ids_json TEXT NOT NULL, title VARCHAR(255) NOT NULL, summary_json TEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id));
|
|
17
17
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_conversations_conversation_id ON conversations (conversation_id);
|
|
18
18
|
CREATE TABLE IF NOT EXISTS dashboard_user_states (owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, active_dashboard_id VARCHAR(64) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (owner_user_id));
|
|
19
|
+
CREATE TABLE IF NOT EXISTS dashboard_shares (id INTEGER NOT NULL, dashboard_id VARCHAR(64) NOT NULL, target_user_id VARCHAR(255) NOT NULL, target_username VARCHAR(255) NOT NULL, access_level VARCHAR(20) NOT NULL, created_by_user_id VARCHAR(255) NOT NULL, created_by_username VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_shares_dashboard_target UNIQUE (dashboard_id, target_user_id));
|
|
19
20
|
CREATE TABLE IF NOT EXISTS dashboard_widgets (id INTEGER NOT NULL, widget_id VARCHAR(64) NOT NULL, dashboard_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, metric_widget_key VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, visualization_type VARCHAR(50) NOT NULL, x INTEGER NOT NULL, y INTEGER NOT NULL, w INTEGER NOT NULL, h INTEGER NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_widgets_widget_id UNIQUE (widget_id));
|
|
20
21
|
CREATE TABLE IF NOT EXISTS dashboards (id INTEGER NOT NULL, dashboard_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description TEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id));
|
|
21
22
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_dashboards_dashboard_id ON dashboards (dashboard_id);
|
|
@@ -63,6 +64,12 @@ CREATE INDEX IF NOT EXISTS ix_conversations_owner_username ON conversations (own
|
|
|
63
64
|
CREATE INDEX IF NOT EXISTS ix_conversations_status ON conversations (status);
|
|
64
65
|
CREATE INDEX IF NOT EXISTS ix_dashboard_user_states_active_dashboard_id ON dashboard_user_states (active_dashboard_id);
|
|
65
66
|
CREATE INDEX IF NOT EXISTS ix_dashboard_user_states_owner_username ON dashboard_user_states (owner_username);
|
|
67
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_access_level ON dashboard_shares (access_level);
|
|
68
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_user_id ON dashboard_shares (created_by_user_id);
|
|
69
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_username ON dashboard_shares (created_by_username);
|
|
70
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_dashboard_id ON dashboard_shares (dashboard_id);
|
|
71
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_user_id ON dashboard_shares (target_user_id);
|
|
72
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_username ON dashboard_shares (target_username);
|
|
66
73
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_dashboard_id ON dashboard_widgets (dashboard_id);
|
|
67
74
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_metric_widget_key ON dashboard_widgets (metric_widget_key);
|
|
68
75
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_owner_user_id ON dashboard_widgets (owner_user_id);
|
|
@@ -97,6 +104,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS ix_conversation_turns_turn_id ON conversation_
|
|
|
97
104
|
CREATE TABLE IF NOT EXISTS conversations (id SERIAL NOT NULL, conversation_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, status VARCHAR(50) NOT NULL, datasource_id VARCHAR(255) NOT NULL, datasource_ids_json TEXT NOT NULL, title VARCHAR(255) NOT NULL, summary_json TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (id));
|
|
98
105
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_conversations_conversation_id ON conversations (conversation_id);
|
|
99
106
|
CREATE TABLE IF NOT EXISTS dashboard_user_states (owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, active_dashboard_id VARCHAR(64) NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (owner_user_id));
|
|
107
|
+
CREATE TABLE IF NOT EXISTS dashboard_shares (id SERIAL NOT NULL, dashboard_id VARCHAR(64) NOT NULL, target_user_id VARCHAR(255) NOT NULL, target_username VARCHAR(255) NOT NULL, access_level VARCHAR(20) NOT NULL, created_by_user_id VARCHAR(255) NOT NULL, created_by_username VARCHAR(255) NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_shares_dashboard_target UNIQUE (dashboard_id, target_user_id));
|
|
100
108
|
CREATE TABLE IF NOT EXISTS dashboard_widgets (id SERIAL NOT NULL, widget_id VARCHAR(64) NOT NULL, dashboard_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, metric_widget_key VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, visualization_type VARCHAR(50) NOT NULL, x INTEGER NOT NULL, y INTEGER NOT NULL, w INTEGER NOT NULL, h INTEGER NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_widgets_widget_id UNIQUE (widget_id));
|
|
101
109
|
CREATE TABLE IF NOT EXISTS dashboards (id SERIAL NOT NULL, dashboard_id VARCHAR(64) NOT NULL, owner_user_id VARCHAR(255) NOT NULL, owner_username VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (id));
|
|
102
110
|
CREATE UNIQUE INDEX IF NOT EXISTS ix_dashboards_dashboard_id ON dashboards (dashboard_id);
|
|
@@ -144,6 +152,12 @@ CREATE INDEX IF NOT EXISTS ix_conversations_owner_username ON conversations (own
|
|
|
144
152
|
CREATE INDEX IF NOT EXISTS ix_conversations_status ON conversations (status);
|
|
145
153
|
CREATE INDEX IF NOT EXISTS ix_dashboard_user_states_active_dashboard_id ON dashboard_user_states (active_dashboard_id);
|
|
146
154
|
CREATE INDEX IF NOT EXISTS ix_dashboard_user_states_owner_username ON dashboard_user_states (owner_username);
|
|
155
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_access_level ON dashboard_shares (access_level);
|
|
156
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_user_id ON dashboard_shares (created_by_user_id);
|
|
157
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_username ON dashboard_shares (created_by_username);
|
|
158
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_dashboard_id ON dashboard_shares (dashboard_id);
|
|
159
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_user_id ON dashboard_shares (target_user_id);
|
|
160
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_username ON dashboard_shares (target_username);
|
|
147
161
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_dashboard_id ON dashboard_widgets (dashboard_id);
|
|
148
162
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_metric_widget_key ON dashboard_widgets (metric_widget_key);
|
|
149
163
|
CREATE INDEX IF NOT EXISTS ix_dashboard_widgets_owner_user_id ON dashboard_widgets (owner_user_id);
|
|
@@ -8,3 +8,16 @@ UPDATE identity_privilege_datasource_permissions AS permission SET identity_id =
|
|
|
8
8
|
-- table: identity_privilege_table_permissions
|
|
9
9
|
DELETE FROM identity_privilege_table_permissions AS legacy WHERE EXISTS (SELECT 1 FROM admin_users AS mapped_user WHERE legacy.identity_id IN ('local:' || CAST(mapped_user.id AS VARCHAR(255)), mapped_user.auth_provider || ':' || mapped_user.username) AND EXISTS (SELECT 1 FROM identity_privilege_table_permissions AS duplicate WHERE duplicate.connector_id = legacy.connector_id AND duplicate.table_name = legacy.table_name AND duplicate.id <> legacy.id AND (duplicate.identity_id = CAST(mapped_user.id AS VARCHAR(255)) OR (duplicate.id < legacy.id AND duplicate.identity_id IN ('local:' || CAST(mapped_user.id AS VARCHAR(255)), mapped_user.auth_provider || ':' || mapped_user.username)))));
|
|
10
10
|
UPDATE identity_privilege_table_permissions AS permission SET identity_id = (SELECT CAST(mapped_user.id AS VARCHAR(255)) FROM admin_users AS mapped_user WHERE permission.identity_id IN ('local:' || CAST(mapped_user.id AS VARCHAR(255)), mapped_user.auth_provider || ':' || mapped_user.username) ORDER BY mapped_user.id LIMIT 1) WHERE EXISTS (SELECT 1 FROM admin_users AS mapped_user WHERE permission.identity_id IN ('local:' || CAST(mapped_user.id AS VARCHAR(255)), mapped_user.auth_provider || ':' || mapped_user.username));
|
|
11
|
+
|
|
12
|
+
-- tag: 2026-08-01.dashboard-sharing.v1
|
|
13
|
+
-- dialect: sqlite
|
|
14
|
+
CREATE TABLE IF NOT EXISTS dashboard_shares (id INTEGER NOT NULL, dashboard_id VARCHAR(64) NOT NULL, target_user_id VARCHAR(255) NOT NULL, target_username VARCHAR(255) NOT NULL, access_level VARCHAR(20) NOT NULL, created_by_user_id VARCHAR(255) NOT NULL, created_by_username VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_shares_dashboard_target UNIQUE (dashboard_id, target_user_id));
|
|
15
|
+
-- dialect: postgresql
|
|
16
|
+
CREATE TABLE IF NOT EXISTS dashboard_shares (id SERIAL NOT NULL, dashboard_id VARCHAR(64) NOT NULL, target_user_id VARCHAR(255) NOT NULL, target_username VARCHAR(255) NOT NULL, access_level VARCHAR(20) NOT NULL, created_by_user_id VARCHAR(255) NOT NULL, created_by_username VARCHAR(255) NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL, updated_at TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (id), CONSTRAINT uq_dashboard_shares_dashboard_target UNIQUE (dashboard_id, target_user_id));
|
|
17
|
+
-- dialect: all
|
|
18
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_access_level ON dashboard_shares (access_level);
|
|
19
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_user_id ON dashboard_shares (created_by_user_id);
|
|
20
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_created_by_username ON dashboard_shares (created_by_username);
|
|
21
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_dashboard_id ON dashboard_shares (dashboard_id);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_user_id ON dashboard_shares (target_user_id);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS ix_dashboard_shares_target_username ON dashboard_shares (target_username);
|
|
@@ -209,6 +209,31 @@ class DashboardUserState(Base):
|
|
|
209
209
|
)
|
|
210
210
|
|
|
211
211
|
|
|
212
|
+
class DashboardShare(Base):
|
|
213
|
+
__tablename__ = "dashboard_shares"
|
|
214
|
+
__table_args__ = (
|
|
215
|
+
UniqueConstraint(
|
|
216
|
+
"dashboard_id",
|
|
217
|
+
"target_user_id",
|
|
218
|
+
name="uq_dashboard_shares_dashboard_target",
|
|
219
|
+
),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
223
|
+
dashboard_id: Mapped[str] = mapped_column(String(64), index=True)
|
|
224
|
+
target_user_id: Mapped[str] = mapped_column(String(255), index=True)
|
|
225
|
+
target_username: Mapped[str] = mapped_column(String(255), index=True, default="")
|
|
226
|
+
access_level: Mapped[str] = mapped_column(String(20), index=True)
|
|
227
|
+
created_by_user_id: Mapped[str] = mapped_column(String(255), index=True)
|
|
228
|
+
created_by_username: Mapped[str] = mapped_column(String(255), index=True, default="")
|
|
229
|
+
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)
|
|
230
|
+
updated_at: Mapped[datetime] = mapped_column(
|
|
231
|
+
DateTime(timezone=True),
|
|
232
|
+
default=utc_now,
|
|
233
|
+
onupdate=utc_now,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
212
237
|
class UserDatasourceSelection(Base):
|
|
213
238
|
"""Client datasource selections, scoped to one authenticated user."""
|
|
214
239
|
|