You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by am...@apache.org on 2026/09/01 16:21:51 UTC

(superset) 01/15: feat(embedded): add EmbeddedChart model and migration

This is an automated email from the ASF dual-hosted git repository.

amaannawab923 pushed a commit to branch feat/embedded-chart
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 0a61a78980d12e1d21ef0e91a13b018352acc4b5
Author: amaannawab923 <am...@gmail.com>
AuthorDate: Tue Sep 1 18:13:58 2026 +0530

    feat(embedded): add EmbeddedChart model and migration
    
    Mirrors EmbeddedDashboard so both embeddable resource types share the same
    guest-token and allowed-domain semantics, including
    guest_token_revoked_before.
---
 ...10-00_a1c7e4b62f18_add_embedded_charts_table.py | 56 +++++++++++++++++++
 superset/models/embedded_chart.py                  | 64 ++++++++++++++++++++++
 superset/models/slice.py                           |  5 ++
 3 files changed, 125 insertions(+)

diff --git a/superset/migrations/versions/2026-09-01_10-00_a1c7e4b62f18_add_embedded_charts_table.py b/superset/migrations/versions/2026-09-01_10-00_a1c7e4b62f18_add_embedded_charts_table.py
new file mode 100644
index 00000000000..de6017e1ac9
--- /dev/null
+++ b/superset/migrations/versions/2026-09-01_10-00_a1c7e4b62f18_add_embedded_charts_table.py
@@ -0,0 +1,56 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""add embedded_charts table
+
+Revision ID: a1c7e4b62f18
+Revises: 39097d124752
+Create Date: 2026-09-01 10:00:00.000000
+
+"""
+
+import sqlalchemy as sa
+from alembic import op
+from sqlalchemy_utils import UUIDType
+
+from superset.migrations.shared.utils import create_table, drop_table
+
+# revision identifiers, used by Alembic.
+revision = "a1c7e4b62f18"
+down_revision = "39097d124752"
+
+
+def upgrade() -> None:
+    create_table(
+        "embedded_charts",
+        sa.Column("created_on", sa.DateTime(), nullable=True),
+        sa.Column("changed_on", sa.DateTime(), nullable=True),
+        sa.Column("created_by_fk", sa.Integer(), nullable=True),
+        sa.Column("changed_by_fk", sa.Integer(), nullable=True),
+        sa.Column("uuid", UUIDType(binary=True), primary_key=True),
+        sa.Column("allow_domain_list", sa.Text(), nullable=True),
+        sa.Column("guest_token_revoked_before", sa.Integer(), nullable=True),
+        sa.Column("slice_id", sa.Integer(), nullable=False),
+        sa.ForeignKeyConstraint(
+            ["slice_id"], ["slices.id"], ondelete="CASCADE"
+        ),
+        sa.ForeignKeyConstraint(["changed_by_fk"], ["ab_user.id"]),
+        sa.ForeignKeyConstraint(["created_by_fk"], ["ab_user.id"]),
+    )
+
+
+def downgrade() -> None:
+    drop_table("embedded_charts")
diff --git a/superset/models/embedded_chart.py b/superset/models/embedded_chart.py
new file mode 100644
index 00000000000..89335dbb8a4
--- /dev/null
+++ b/superset/models/embedded_chart.py
@@ -0,0 +1,64 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+import uuid
+
+from flask_appbuilder import Model
+from sqlalchemy import Column, ForeignKey, Integer, Text
+from sqlalchemy.orm import relationship
+from sqlalchemy_utils import UUIDType
+
+from superset.models.helpers import AuditMixinNullable
+
+
+class EmbeddedChart(Model, AuditMixinNullable):
+    """
+    A configuration of embedding for a chart.
+
+    References the chart, and contains a config for embedding that chart.
+    Mirrors ``EmbeddedDashboard`` so both embeddable resource types share the
+    same guest-token and allowed-domain semantics.
+
+    This data model allows multiple configurations for a given chart,
+    but at this time the API only allows setting one.
+    """
+
+    __tablename__ = "embedded_charts"
+
+    uuid = Column(UUIDType(binary=True), default=uuid.uuid4, primary_key=True)
+    allow_domain_list = Column(Text)  # reference the `allowed_domains` property instead
+    # Epoch seconds; guest tokens whose `iat` predates this are rejected. Set to
+    # "now" to revoke all currently-issued guest tokens for this embedded
+    # chart. NULL = no revocation.
+    guest_token_revoked_before = Column(Integer, nullable=True)
+    slice_id = Column(
+        Integer,
+        ForeignKey("slices.id", ondelete="CASCADE"),
+        nullable=False,
+    )
+    slice = relationship(
+        "Slice",
+        back_populates="embedded",
+        foreign_keys=[slice_id],
+    )
+
+    @property
+    def allowed_domains(self) -> list[str]:
+        """
+        A list of domains which are allowed to embed the chart.
+        An empty list means any domain can embed.
+        """
+        return self.allow_domain_list.split(",") if self.allow_domain_list else []
diff --git a/superset/models/slice.py b/superset/models/slice.py
index 8540817ee9f..bf33db3fd49 100644
--- a/superset/models/slice.py
+++ b/superset/models/slice.py
@@ -142,6 +142,11 @@ class Slice(  # pylint: disable=too-many-public-methods
         secondary=chart_viewers,
         passive_deletes=True,
     )
+    embedded = relationship(
+        "EmbeddedChart",
+        back_populates="slice",
+        cascade="all, delete-orphan",
+    )
 
     tags = relationship(
         "Tag",