* Remove unused data from embed and public endpoints Public and static-embed card/dashboard/document endpoints now return a minimal placeholder dataset_query (a blank native query against the same database) instead of selecting individual query keys. The frontend only needs the database id here. Parameter combining and :param_fields hydration in public-card now run before the card is trimmed since both read template tags from the full query. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add tests for embed card and dashboard dataset_query Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Assert strictly on dataset_query in public and embed tests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Handle native queries in Table viz * Fix column shadowing in HeaderCellWithColumnInfo Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use param_fields for public question parameters Public and static-embed card payloads carry param_fields instead of the real query, so PublicOrEmbeddedQuestion now builds UI parameters from them via getCardUiParametersFromParamFields, mirroring the saved-mode dashboard path. The query-based helpers are renamed to the FromQuery / FromParamFields scheme on both the card and dashboard sides, and the ParameterWithTarget casts are dropped now that getParameterTargetField accepts an optional target. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use param_fields for embed setup card parameters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use param_fields for guest embed SDK question parameters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Route card UI parameters by param_fields presence Restores getCardUiParameters as the entry point: it delegates to getCardUiParametersFromParamFields when the card carries param_fields (public and static-embed payloads) and to the query-based variant otherwise. The SDK SQL parameter surfaces use it since they serve both guest and authenticated contexts. Also reverts the dashboard helper renames back to getSaved/getUnsavedDashboardUiParameters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix preview embed card param values The preview-embed card values and remapping endpoints get their card via card-for-unsigned-token -> public-card, which now replaces the query with a blank native placeholder, so field-filter parameters could no longer be resolved and the response schema rejected the nil result. Bind qp.perms/*param-values-query* around the card fetch, the escape hatch remove-card-non-public-columns already honors, matching the public sharing values endpoints. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add preview embed test for remapped parameter fields Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix * vscode fix * Backfill template tag parameters in param_fields UI parameters GET /api/card/:id returns parameters as stored, unlike the public and embed endpoints which combine them with template tags, so getCardUiParametersFromParamFields now derives parameters via getParametersFromCard like the query-based variant always did. Guest embed payloads are unaffected: their parameters arrive already combined and the blank query derives nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use getCardUiParameters dispatcher in SDK load-question Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Guard applyTemplateTagParameters by param_fields presence Cards whose payloads carry param_fields have parameters already combined with template tags by the backend, so re-applying from the query would wipe them. Keying the guard on the card payload keeps it in sync with how the card was loaded, replacing the isGuestEmbed flag checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Use getCardUiParameters everywhere and build test queries via Lib Question.parameters and the query builder call sites go back to the getCardUiParameters entry point, which now routes by param_fields presence, leaving those files unchanged relative to master. The template tag fallback test builds its query with Lib.createTestJsNativeQuery instead of an inline legacy map. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Make getCardUiParameters the only entry point The FromQuery and FromParamFields variants are private to cards.ts now; all consumers call getCardUiParameters, which routes by param_fields presence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Build preview embed remapped-fields test query via lib Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Restore null fallback in useAvailableParameters Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Fix * Preserve query type in stripped public and embed card queries Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add placeholder aggregations to stripped MBQL queries Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Keep parameter template tags in stripped native queries and revert FE workarounds Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Export parameter-template-tag? via import-vars Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add test for :param_fields hydration on GET /api/card/:id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
830 lines
58 KiB
Clojure
830 lines
58 KiB
Clojure
(ns ^:mb/driver-tests metabase.embedding-rest.api.preview-embed-test
|
|
{:clj-kondo/config '{:linters {:deprecated-var {:exclude {metabase.test.data/mbql-query {:namespaces [metabase.embedding-rest.api.preview-embed-test]}
|
|
metabase.test.data/query {:namespaces [metabase.embedding-rest.api.preview-embed-test]}
|
|
metabase.test.data/run-mbql-query {:namespaces [metabase.embedding-rest.api.preview-embed-test]}}}}}}
|
|
(:require
|
|
[buddy.sign.jwt :as jwt]
|
|
[clojure.set :as set]
|
|
[clojure.test :refer :all]
|
|
[metabase.dashboards-rest.api-test :as api.dashboard-test]
|
|
[metabase.embedding-rest.api.embed-test :as embed-test]
|
|
[metabase.embedding-rest.api.preview-embed :as api.preview-embed]
|
|
[metabase.lib.core :as lib]
|
|
[metabase.lib.metadata :as lib.metadata]
|
|
[metabase.queries-rest.api.card-test :as api.card-test]
|
|
[metabase.query-processor.pivot.test-util :as api.pivots]
|
|
[metabase.test :as mt]
|
|
[metabase.tiles.api-test :as tiles.api-test]
|
|
[metabase.util :as u]
|
|
[metabase.util.json :as json]
|
|
[metabase.util.random :as u.random]
|
|
[toucan2.core :as t2]))
|
|
|
|
;;; --------------------------------------- GET /api/preview_embed/card/:token ---------------------------------------
|
|
|
|
(defn- card-url [card & [additional-token-params]]
|
|
(str "preview_embed/card/" (embed-test/card-token card (merge {:_embedding_params {}} additional-token-params))))
|
|
|
|
(deftest card-test
|
|
(testing "GET /api/preview_embed/card/:token"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card]
|
|
(testing "it should be possible to use this endpoint successfully if all the conditions are met"
|
|
(is (=? embed-test/successful-card-info
|
|
(mt/user-http-request :crowberto :get 200 (card-url card)))))
|
|
(testing "if the user is not an admin this endpoint should fail"
|
|
(is (= "You don't have permissions to do that."
|
|
(mt/user-http-request :rasta :get 403 (card-url card)))))
|
|
(testing "check that the endpoint doesn't work if embedding isn't enabled"
|
|
(mt/with-temporary-setting-values [enable-embedding-static false]
|
|
(is (= "Embedding is not enabled."
|
|
(embed-test/with-temp-card [card]
|
|
(mt/user-http-request :crowberto :get 400 (card-url card)))))))
|
|
(testing "check that if embedding is enabled globally requests fail if they are signed with the wrong key"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (card-url card))))))
|
|
(testing "Check that only ENABLED params that ARE NOT PRESENT IN THE JWT come back"
|
|
(embed-test/with-temp-card [card {:dataset_query
|
|
{:database (mt/id)
|
|
:type :native
|
|
:native {:query "SELECT 1;"
|
|
:template-tags {:a {:type "date", :name "a", :display_name "a" :id "a"}
|
|
:b {:type "date", :name "b", :display_name "b" :id "b"}
|
|
:c {:type "date", :name "c", :display_name "c" :id "c"}
|
|
:d {:type "date", :name "d", :display_name "d" :id "d"}}}}}]
|
|
(is (= [{:id "d"
|
|
:type "date/single"
|
|
:target ["variable" ["template-tag" "d"]]
|
|
:name "d"
|
|
:slug "d"
|
|
:default nil
|
|
:required false}]
|
|
(-> (mt/user-http-request :crowberto :get 200 (card-url card {:_embedding_params {:a "locked"
|
|
:b "disabled"
|
|
:c "enabled"
|
|
:d "enabled"}
|
|
:params {:c 100}}))
|
|
:parameters)))))))))
|
|
|
|
;;; ------------------------------------ GET /api/preview_embed/card/:token/query ------------------------------------
|
|
|
|
(defn- card-query-url [card & [additional-token-params]]
|
|
(str "preview_embed/card/"
|
|
(embed-test/card-token card (merge {:_embedding_params {}} additional-token-params))
|
|
"/query"))
|
|
|
|
(deftest query-test
|
|
(testing "GET /api/preview_embed/card/:token/query"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card]
|
|
(testing "It should be possible to run a Card successfully if you jump through the right hoops..."
|
|
#_{:clj-kondo/ignore [:deprecated-var]}
|
|
(embed-test/test-query-results
|
|
(mt/user-http-request :crowberto :get 202 (card-query-url card))))
|
|
(testing "if the user is not an admin this endpoint should fail"
|
|
(is (= "You don't have permissions to do that."
|
|
(mt/user-http-request :rasta :get 403 (card-query-url card)))))
|
|
(testing "check that the endpoint doesn't work if embedding isn't enabled"
|
|
(mt/with-temporary-setting-values [enable-embedding-static false]
|
|
(is (= "Embedding is not enabled."
|
|
(mt/user-http-request :crowberto :get 400 (card-query-url card))))))
|
|
(testing "check that if embedding is enabled globally requests fail if they are signed with the wrong key"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (card-query-url card))))))))))
|
|
|
|
(deftest query-locked-params-test
|
|
(testing "GET /api/preview_embed/card/:token/query"
|
|
(testing "LOCKED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card]
|
|
(testing "check that if embedding is enabled globally fail if the token is missing a `:locked` parameter"
|
|
(is (= "You must specify a value for :venue_id in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (card-query-url card {:_embedding_params {:venue_id "locked"}})))))
|
|
(testing "if `:locked` param is supplied, request should succeed"
|
|
#_{:clj-kondo/ignore [:deprecated-var]}
|
|
(embed-test/test-query-results
|
|
(mt/user-http-request :crowberto :get 202 (card-query-url card {:_embedding_params {:venue_id "locked"}
|
|
:params {:venue_id 100}}))))
|
|
(testing "if `:locked` parameter is present in URL params, request should fail"
|
|
(is (= "You can only specify a value for :venue_id in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (str (card-query-url card {:_embedding_params {:venue_id "locked"}
|
|
:params {:venue_id 100}})
|
|
"?venue_id=200"))))))))))
|
|
|
|
(deftest query-disabled-params-test
|
|
(testing "GET /api/preview_embed/card/:token/query"
|
|
(testing "DISABLED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card]
|
|
(testing "check that if embedding is enabled globally and for the object requests fail if they pass a `:disabled` parameter"
|
|
(is (= "You're not allowed to specify a value for :venue_id."
|
|
(mt/user-http-request :crowberto :get 400 (card-query-url card {:_embedding_params {:venue_id "disabled"}
|
|
:params {:venue_id 100}})))))
|
|
(testing "If a `:disabled` param is passed in the URL the request should fail"
|
|
(is (= "You're not allowed to specify a value for :venue_id."
|
|
(mt/user-http-request :crowberto :get 400 (str (card-query-url card {:_embedding_params {:venue_id "disabled"}})
|
|
"?venue_id=200"))))))))))
|
|
|
|
(deftest query-enabled-params-test
|
|
(testing "GET /api/preview_embed/card/:token/query"
|
|
(testing "ENABLED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card]
|
|
(testing "If `:enabled` param is present in both JWT and the URL, the request should fail"
|
|
(is (= "You can't specify a value for :venue_id if it's already set in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (str (card-query-url card {:_embedding_params {:venue_id "enabled"}
|
|
:params {:venue_id 100}})
|
|
"?venue_id=200")))))
|
|
(testing "If an `:enabled` param is present in the JWT, that's ok"
|
|
#_{:clj-kondo/ignore [:deprecated-var]}
|
|
(embed-test/test-query-results
|
|
(mt/user-http-request :crowberto :get 202 (card-query-url card {:_embedding_params {:venue_id "enabled"}
|
|
:params {:venue_id "enabled"}}))))
|
|
(testing "If an `:enabled` param is present in URL params but *not* the JWT, that's ok"
|
|
#_{:clj-kondo/ignore [:deprecated-var]}
|
|
(embed-test/test-query-results
|
|
(mt/user-http-request :crowberto :get 202 (str (card-query-url card {:_embedding_params {:venue_id "enabled"}})
|
|
"?venue_id=200")))))))))
|
|
(deftest default-value-card-query-test
|
|
(testing "GET /api/preview_embed/card/:token/query with default values for params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(testing "if the param is enabled"
|
|
(mt/with-temp
|
|
[:model/Card card (assoc (embed-test/card-with-date-field-filter-default) :embedding_params {:date "enabled"})]
|
|
(testing "the default should apply if no param value is provided"
|
|
(is (= [[107]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (card-query-url card)))))
|
|
(testing "check this is the same result as when a default value is provided"
|
|
(is (= [[107]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (str (card-query-url card {:_embedding_params {:date "enabled"}})
|
|
"?date=Q1-2014")))))))
|
|
(testing "an empty value should apply if provided as an empty string in the query params"
|
|
(is (= [[1000]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (str (card-query-url card {:_embedding_params {:date "enabled"}})
|
|
"?date="))))))
|
|
(testing "an empty value should apply if provided as nil in the JWT params"
|
|
(is (= [[1000]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (card-query-url card {:_embedding_params {:date "enabled"}
|
|
:params {:date nil}}))))))))
|
|
(testing "if the param is disabled"
|
|
(mt/with-temp
|
|
[:model/Card card (assoc (embed-test/card-with-date-field-filter-default) :embedding_params {:date "disabled"})]
|
|
(testing "the default should apply if no param is provided"
|
|
(is (= [[107]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (card-query-url card))))))
|
|
(testing "you can't apply an empty param value if the parameter is disabled"
|
|
(is (= "You're not allowed to specify a value for :date."
|
|
(mt/user-http-request :crowberto :get 400 (str (card-query-url card {:_embedding_params {:date "disabled"}}) "?date=")))))))
|
|
(testing "if the param is locked"
|
|
(mt/with-temp
|
|
[:model/Card card (assoc (embed-test/card-with-date-field-filter-default) :embedding_params {:date "locked"})]
|
|
(testing "an empty value with `nil` as the param's value is invalid and should result in an error"
|
|
(is (= "You must specify a value for :date in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (card-query-url card {:_embedding_params {:date "locked"}
|
|
:params {:date nil}}))))
|
|
(testing "check this is different to when a non-nil value is provided"
|
|
(is (= [[138]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 (card-query-url card {:_embedding_params {:date "locked"}
|
|
:params {:date "Q2-2014"}})))))))
|
|
(testing "an empty string value is invalid and should result in an error"
|
|
(is (= "You must specify a value for :date in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (card-query-url card {:_embedding_params {:date "locked"}
|
|
:params {:date ""}}))))))))))
|
|
|
|
(deftest query-max-results-constraint-test
|
|
(testing "GET /api/preview_embed/card/:token/query"
|
|
(testing "Only 2000 results returned when there are many more"
|
|
(let [orders-row-count (count
|
|
(mt/rows
|
|
(mt/dataset test-data
|
|
(mt/process-query
|
|
(mt/query orders)))))
|
|
expected-row-count 1]
|
|
(with-redefs [api.preview-embed/max-results expected-row-count]
|
|
(mt/dataset test-data
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(let [sample-db-orders-question (mt/query orders)]
|
|
(embed-test/with-temp-card [card {:dataset_query sample-db-orders-question}]
|
|
(let [limited (count
|
|
(mt/rows
|
|
(mt/user-http-request :crowberto :get 202 (card-query-url card))))]
|
|
(is (= expected-row-count limited))
|
|
(is (not= expected-row-count orders-row-count))))))))))))
|
|
|
|
;;; ------------------------------------ GET /api/preview_embed/dashboard/:token -------------------------------------
|
|
|
|
(defn- dashboard-url [dashboard & [additional-token-params]]
|
|
(str "preview_embed/dashboard/" (embed-test/dash-token dashboard (merge {:_embedding_params {}}
|
|
additional-token-params))))
|
|
|
|
(deftest dashboard-test
|
|
(testing "GET /api/preview_embed/dashboard/:token"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Dashboard dash]
|
|
(testing "it should be possible to call this endpoint successfully..."
|
|
(is (=? embed-test/successful-dashboard-info
|
|
(mt/user-http-request :crowberto :get 200 (dashboard-url dash)))))
|
|
(testing "...but if the user is not an admin this endpoint should fail"
|
|
(is (= "You don't have permissions to do that."
|
|
(mt/user-http-request :rasta :get 403 (dashboard-url dash)))))
|
|
(testing "check that the endpoint doesn't work if embedding isn't enabled"
|
|
(mt/with-temporary-setting-values [enable-embedding-static false]
|
|
(is (= "Embedding is not enabled."
|
|
(mt/user-http-request :crowberto :get 400 (dashboard-url dash))))))
|
|
(testing "check that if embedding is enabled globally requests fail if they are signed with the wrong key"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (dashboard-url dash))))))))))
|
|
|
|
(deftest only-enabled-params-not-in-jwt-test
|
|
(testing "Check that only ENABLED params that ARE NOT PRESENT IN THE JWT come back"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Dashboard dash {:parameters [{:id "_a", :slug "a", :name "a", :type "date"}
|
|
{:id "_b", :slug "b", :name "b", :type "date"}
|
|
{:id "_c", :slug "c", :name "c", :type "date"}
|
|
{:id "_d", :slug "d", :name "d", :type "date"}]}]
|
|
(is (=? [{:id "_d", :slug "d", :name "d", :type "date"}]
|
|
(:parameters (mt/user-http-request :crowberto :get 200 (dashboard-url dash
|
|
{:params {:c 100}
|
|
:_embedding_params {:a "locked"
|
|
:b "disabled"
|
|
:c "enabled"
|
|
:d "enabled"}})))))))))
|
|
|
|
;;; ------------------ GET /api/preview_embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id -------------------
|
|
|
|
(defn- dashcard-url [dashcard & [additional-token-params]]
|
|
(str "preview_embed/dashboard/" (embed-test/dash-token (:dashboard_id dashcard) (merge {:_embedding_params {}}
|
|
additional-token-params))
|
|
"/dashcard/" (u/the-id dashcard)
|
|
"/card/" (:card_id dashcard)))
|
|
|
|
(deftest dashcard-test
|
|
(testing "/api/preview_embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard]
|
|
(testing "It should be possible to run a Card successfully if you jump through the right hoops..."
|
|
#_{:clj-kondo/ignore [:deprecated-var]}
|
|
(embed-test/test-query-results
|
|
(mt/user-http-request :crowberto :get 202 (dashcard-url dashcard))))
|
|
(testing "...but if the user is not an admin this endpoint should fail"
|
|
(is (= "You don't have permissions to do that."
|
|
(mt/user-http-request :rasta :get 403 (dashcard-url dashcard)))))
|
|
(testing "check that the endpoint doesn't work if embedding isn't enabled"
|
|
(is (= "Embedding is not enabled."
|
|
(mt/with-temporary-setting-values [enable-embedding-static false]
|
|
(mt/user-http-request :crowberto :get 400 (dashcard-url dashcard))))))
|
|
(testing "check that if embedding is enabled globally requests fail if they are signed with the wrong key"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (dashcard-url dashcard))))))))))
|
|
|
|
(deftest dashcard-locked-params-test
|
|
(testing "/api/preview_embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id"
|
|
(testing "LOCKED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard]
|
|
(testing "check that if embedding is enabled globally fail if the token is missing a `:locked` parameter"
|
|
(is (= "You must specify a value for :venue_id in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (dashcard-url dashcard
|
|
{:_embedding_params {:venue_id "locked"}})))))
|
|
(testing "If `:locked` param is supplied, request should succeed"
|
|
(is (=? {:status "completed"
|
|
:data {:rows [[1]]}}
|
|
(mt/user-http-request :crowberto :get 202
|
|
(dashcard-url dashcard {:_embedding_params {:venue_id "locked"}, :params {:venue_id 100}})))))
|
|
(testing "If `:locked` parameter is present in URL params, request should fail"
|
|
(is (= "You can only specify a value for :venue_id in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (str (dashcard-url dashcard
|
|
{:_embedding_params {:venue_id "locked"}, :params {:venue_id 100}})
|
|
"?venue_id=200"))))))))))
|
|
|
|
(deftest dashcard-disabled-params-test
|
|
(testing "/api/preview_embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id"
|
|
(testing "DISABLED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard]
|
|
(testing "check that if embedding is enabled globally and for the object requests fail if they pass a `:disabled` parameter"
|
|
(is (= "You're not allowed to specify a value for :venue_id."
|
|
(mt/user-http-request :crowberto :get 400 (dashcard-url dashcard
|
|
{:_embedding_params {:venue_id "disabled"}, :params {:venue_id 100}})))))
|
|
(testing "If a `:disabled` param is passed in the URL the request should fail"
|
|
(is (= "You're not allowed to specify a value for :venue_id."
|
|
(mt/user-http-request :crowberto :get 400 (str (dashcard-url dashcard {:_embedding_params {:venue_id "disabled"}})
|
|
"?venue_id=200"))))))))))
|
|
|
|
(deftest dashcard-disabled-params-test-2
|
|
(testing "/api/preview_embed/dashboard/:token/dashcard/:dashcard-id/card/:card-id"
|
|
(testing "ENABLED params"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard]
|
|
(testing "If `:enabled` param is present in both JWT and the URL, the request should fail"
|
|
(is (= "You can't specify a value for :venue_id if it's already set in the JWT."
|
|
(mt/user-http-request :crowberto :get 400 (str (dashcard-url dashcard {:_embedding_params {:venue_id "enabled"}
|
|
:params {:venue_id 100}})
|
|
"?venue_id=200")))))
|
|
(testing "If an `:enabled` param is present in the JWT, that's ok"
|
|
(is (=? {:status "completed"
|
|
:data {:rows [[1]]}}
|
|
(mt/user-http-request :crowberto :get 202 (dashcard-url dashcard {:_embedding_params {:venue_id "enabled"}
|
|
:params {:venue_id 100}})))))
|
|
(testing "If an `:enabled` param is present in URL params but *not* the JWT, that's ok"
|
|
(is (=? {:status "completed"
|
|
:data {:rows [[0]]}}
|
|
(mt/user-http-request :crowberto :get 202 (str (dashcard-url dashcard {:_embedding_params {:venue_id "enabled"}})
|
|
"?venue_id=200"))))))))))
|
|
|
|
(deftest dashcard-editable-query-params-test
|
|
(testing (str "Check that editable query params work correctly and keys get coverted from strings to keywords, even "
|
|
"if they're something that our middleware doesn't normally assume is implicitly convertable to a "
|
|
"keyword. See `ring.middleware.keyword-params/keyword-syntax?` (#6783)")
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard {:dash {:enable_embedding true
|
|
:parameters [{:id "_SECOND_DATE_SEEN_"
|
|
:slug "2nd_date_seen"
|
|
:name "Second Date Seen"
|
|
:type "date"}
|
|
{:id "_NUM_BIRDS_"
|
|
:slug "num_birds"
|
|
:name "Number of Birds"
|
|
:type "number"}]}}]
|
|
(is (=? {:status "completed"}
|
|
(mt/user-http-request :crowberto :get 202 (str (dashcard-url dashcard
|
|
{:_embedding_params {:num_birds :locked
|
|
:2nd_date_seen :enabled}
|
|
:params {:num_birds 2}})
|
|
"?2nd_date_seen=2018-02-14"))))))))
|
|
|
|
(deftest editable-params-should-not-be-invalid-test
|
|
(testing "Make sure that editable params do not result in \"Invalid Parameter\" exceptions (#7212)"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card card {:dataset_query {:database (mt/id)
|
|
:type :native
|
|
:native {:query "SELECT {{num}} AS num"
|
|
:template-tags {:num {:id "X"
|
|
:name "num"
|
|
:display_name "Num"
|
|
:type "number"
|
|
:required true
|
|
:default "1"}}}}}]
|
|
(embed-test/with-temp-dashcard [dashcard {:dash {:parameters [{:name "Num"
|
|
:slug "num"
|
|
:id "_NUM_"
|
|
:type "category"}]}
|
|
:dashcard {:card_id (u/the-id card)
|
|
:parameter_mappings [{:card_id (u/the-id card)
|
|
:target [:variable
|
|
[:template-tag :num]]
|
|
:parameter_id "_NUM_"}]}}]
|
|
(is (= [[50]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202
|
|
(str (dashcard-url dashcard {:_embedding_params {:num "enabled"}})
|
|
"?num=50"))))))))))
|
|
|
|
(deftest postgres-convert-parameters-to-numbers-test
|
|
(mt/test-driver :postgres
|
|
(testing "Make sure that ID params correctly get converted to numbers as needed (Postgres-specific)..."
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card card {:dataset_query (mt/mbql-query venues
|
|
{:aggregation [:count]})}]
|
|
(embed-test/with-temp-dashcard [dashcard {:dash {:parameters [{:name "Venue ID"
|
|
:slug "venue_id"
|
|
:id "_VENUE_ID_"
|
|
:type "id"}]}
|
|
:dashcard {:card_id (u/the-id card)
|
|
:parameter_mappings [{:parameter_id "_VENUE_ID_"
|
|
:card_id (u/the-id card)
|
|
:target [:dimension
|
|
[:field
|
|
(mt/id :venues :id) nil]]}]}}]
|
|
(is (= [[1]]
|
|
(mt/rows (mt/user-http-request :crowberto :get (str (dashcard-url dashcard {:_embedding_params {:venue_id "enabled"}})
|
|
"?venue_id=1")))))))))))
|
|
|
|
;; pivot tables
|
|
|
|
(defn- pivot-card-query-url [card & [additional-token-params]]
|
|
(str "preview_embed/pivot/card/"
|
|
(embed-test/card-token card (merge {:_embedding_params {}} additional-token-params))
|
|
"/query"))
|
|
|
|
(deftest pivot-query-test
|
|
(mt/test-drivers (api.pivots/applicable-drivers)
|
|
(mt/dataset test-data
|
|
(testing "GET /api/preview_embed/pivot/card/:token/query"
|
|
(testing "successful preview"
|
|
(let [result (embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card (api.pivots/pivot-card)]
|
|
(mt/user-http-request :crowberto :get 202 (pivot-card-query-url card))))
|
|
rows (mt/rows result)]
|
|
(is (nil? (:row_count result))) ;; row_count isn't included in public endpoints
|
|
(is (= "completed" (:status result)))
|
|
(is (= 6 (count (get-in result [:data :cols]))))
|
|
(is (= 1144 (count rows)))))
|
|
(testing "should fail if user is not an admin"
|
|
(is (= "You don't have permissions to do that."
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card (api.pivots/pivot-card)]
|
|
(mt/user-http-request :rasta :get 403 (pivot-card-query-url card)))))))
|
|
(testing "should fail if embedding is disabled"
|
|
(is (= "Embedding is not enabled."
|
|
(mt/with-temporary-setting-values [enable-embedding false]
|
|
(embed-test/with-new-secret-key!
|
|
(embed-test/with-temp-card [card (api.pivots/pivot-card)]
|
|
(mt/user-http-request :crowberto :get 400 (pivot-card-query-url card))))))))
|
|
(testing "should fail if embedding is enabled and the wrong key is used"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-card [card (api.pivots/pivot-card)]
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (pivot-card-query-url card))))))))))))
|
|
|
|
(defn- pivot-dashcard-url [dashcard & [additional-token-params]]
|
|
(str "preview_embed/pivot/dashboard/"
|
|
(embed-test/dash-token (:dashboard_id dashcard) (merge {:_embedding_params {}}
|
|
additional-token-params))
|
|
"/dashcard/" (u/the-id dashcard)
|
|
"/card/" (:card_id dashcard)))
|
|
|
|
(deftest pivot-card-id-test
|
|
(mt/test-drivers (api.pivots/applicable-drivers)
|
|
(mt/dataset test-data
|
|
(testing "GET /api/preview_embed/pivot/dashboard/:token/dashcard/:dashcard-id/card/:card-id"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(embed-test/with-temp-dashcard [dashcard {:dash {:parameters []}
|
|
:card (api.pivots/pivot-card)
|
|
:dashcard {:parameter_mappings []}}]
|
|
(testing "successful preview"
|
|
(let [result (mt/user-http-request :crowberto :get 202 (pivot-dashcard-url dashcard))
|
|
rows (mt/rows result)]
|
|
(is (nil? (:row_count result))) ;; row_count isn't included in public endpoints
|
|
(is (= "completed" (:status result)))
|
|
(is (= 6 (count (get-in result [:data :cols]))))
|
|
(is (= 1144 (count rows)))))
|
|
(testing "should fail if user is not an admin"
|
|
(is (= "You don't have permissions to do that."
|
|
(mt/user-http-request :rasta :get 403 (pivot-dashcard-url dashcard)))))
|
|
(testing "should fail if embedding is disabled"
|
|
(is (= "Embedding is not enabled."
|
|
(mt/with-temporary-setting-values [enable-embedding-static false]
|
|
(embed-test/with-new-secret-key!
|
|
(mt/user-http-request :crowberto :get 400 (pivot-dashcard-url dashcard)))))))
|
|
(testing "should fail if embedding is enabled and the wrong key is used"
|
|
(is (= "Message seems corrupt or manipulated"
|
|
(mt/user-http-request :crowberto :get 400 (embed-test/with-new-secret-key! (pivot-dashcard-url dashcard))))))))))))
|
|
|
|
(deftest handle-single-params-for-operator-filters-test
|
|
(testing "Query endpoints should work with a single URL parameter for an operator filter (#20438)"
|
|
(mt/dataset test-data
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card {card-id :id, :as card} {:dataset_query (mt/native-query
|
|
{:query "SELECT count(*) AS count FROM PUBLIC.PEOPLE WHERE true [[AND {{NAME}}]]"
|
|
:template-tags {"NAME"
|
|
{:name "NAME"
|
|
:display-name "Name"
|
|
:id "_name_"
|
|
:type :dimension
|
|
:dimension [:field (mt/id :people :name) nil]
|
|
:widget-type :string/=
|
|
:default nil}}})
|
|
:enable_embedding true
|
|
:embedding_params {"NAME" "enabled"}}]
|
|
(testing "Card"
|
|
(let [url (card-query-url card {:_embedding_params {:NAME "enabled"}})]
|
|
(is (= [[1]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 url :NAME "Hudson Borer"))
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 url :NAME "Hudson Borer" :NAME "x"))))))
|
|
(testing "Dashcard"
|
|
(mt/with-temp [:model/Dashboard {dashboard-id :id} {:enable_embedding true
|
|
:embedding_params {:name "enabled"}
|
|
:parameters [{:name "Name"
|
|
:slug "name"
|
|
:id "_name_"
|
|
:type "string/="
|
|
:sectionId "string"}]}
|
|
|
|
:model/DashboardCard dashcard {:card_id card-id
|
|
:dashboard_id dashboard-id
|
|
:parameter_mappings [{:parameter_id "_name_"
|
|
:card_id card-id
|
|
:type "string/="
|
|
:target [:dimension [:template-tag "NAME"]]}]}]
|
|
(let [url (dashcard-url dashcard {:_embedding_params {:name "enabled"}})]
|
|
(is (= [[1]]
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 url :name "Hudson Borer"))
|
|
(mt/rows (mt/user-http-request :crowberto :get 202 url :name "Hudson Borer" :name "x"))))))))))))
|
|
|
|
;;; ------------------------------------------------ Chain filtering -------------------------------------------------
|
|
|
|
(defn random-embedding-secret-key [] (u.random/secure-hex 32))
|
|
|
|
(def ^:dynamic *secret-key* nil)
|
|
|
|
(defn sign [claims] (jwt/sign claims *secret-key*))
|
|
|
|
(defn do-with-new-secret-key! [f]
|
|
(binding [*secret-key* (random-embedding-secret-key)]
|
|
(mt/with-temporary-setting-values [embedding-secret-key *secret-key*]
|
|
(f))))
|
|
|
|
(defmacro with-new-secret-key! {:style/indent 0} [& body]
|
|
`(do-with-new-secret-key! (fn [] ~@body)))
|
|
|
|
(defmacro with-embedding-enabled-and-new-secret-key! {:style/indent 0} [& body]
|
|
`(mt/with-temporary-setting-values [~'enable-embedding-static true]
|
|
(with-new-secret-key!
|
|
~@body)))
|
|
|
|
(defn dash-token
|
|
[dash-or-id & [additional-token-params]]
|
|
(sign (merge {:resource {:dashboard (u/the-id dash-or-id)}
|
|
:params {}}
|
|
additional-token-params)))
|
|
|
|
;;; ----------------------------- GET /api/preview_embed/card/:token/params/:param-key/values --------------------------
|
|
|
|
(deftest card-params-values-test
|
|
(testing "GET /api/preview_embed/card/:token/params/:param-key/values"
|
|
;; Card endpoint uses check-and-unsign which requires enable-embedding-static,
|
|
;; unlike dashboard endpoints which skip the check in preview mode
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card card {:dataset_query (mt/mbql-query venues)
|
|
:parameters [{:name "Static Category"
|
|
:slug "static_category"
|
|
:id "_STATIC_CATEGORY_"
|
|
:type "category"
|
|
:values_source_type "static-list"
|
|
:values_source_config {:values ["African" "American" "Asian"]}}]}]
|
|
(let [signed-token (embed-test/card-token card {:_embedding_params {:static_category "enabled"}})]
|
|
(testing "Should work if the param we're fetching values for is enabled"
|
|
(is (= {:values [["African"] ["American"] ["Asian"]]
|
|
:has_more_values false}
|
|
(mt/user-http-request :crowberto :get 200
|
|
(format "preview_embed/card/%s/params/%s/values"
|
|
signed-token "_STATIC_CATEGORY_"))))))))))
|
|
|
|
(deftest card-params-values-field-filter-test
|
|
(testing "GET /api/preview_embed/card/:token/params/:param-key/values with a field filter parameter"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(api.card-test/with-card-param-values-fixtures [{:keys [field-filter-card param-keys]}]
|
|
(let [embedding-params (zipmap (map (comp keyword :slug) (:parameters field-filter-card))
|
|
(repeat "enabled"))
|
|
signed-token (embed-test/card-token field-filter-card
|
|
{:_embedding_params embedding-params})
|
|
response (mt/user-http-request :crowberto :get 200
|
|
(format "preview_embed/card/%s/params/%s/values"
|
|
signed-token (:field-values param-keys)))]
|
|
(is (false? (:has_more_values response)))
|
|
(is (set/subset? #{["20th Century Cafe"] ["33 Taps"]}
|
|
(-> response :values set))))))))
|
|
|
|
(deftest card-params-values-remapped-fields-test
|
|
(testing "preview embed card values/remapping endpoints work for parameters mapped to remapped fields"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-column-remappings [orders.quantity {5 "N5"}
|
|
orders.product_id products.title]
|
|
(mt/with-temp [:model/Card card
|
|
(let [mp (mt/metadata-provider)]
|
|
{:dataset_query
|
|
(-> (lib/native-query mp "SELECT * FROM ORDERS JOIN PEOPLE ON ORDERS.USER_ID = PEOPLE.ID WHERE {{quantity}} AND {{product_id_fk}} AND {{user_id_pk}}")
|
|
(lib/with-template-tags
|
|
{"quantity" {:id "quantity"
|
|
:name "quantity"
|
|
:display-name "Internal"
|
|
:type :dimension
|
|
:widget-type :number/=
|
|
:dimension (lib/ref (lib.metadata/field mp (mt/id :orders :quantity)))}
|
|
"product_id_fk" {:id "product_id_fk"
|
|
:name "product_id_fk"
|
|
:display-name "FK"
|
|
:type :dimension
|
|
:widget-type :id
|
|
:dimension (lib/ref (lib.metadata/field mp (mt/id :orders :product_id)))}
|
|
"user_id_pk" {:id "user_id_pk"
|
|
:name "user_id_pk"
|
|
:display-name "PK->Name"
|
|
:type :dimension
|
|
:widget-type :id
|
|
:dimension (lib/ref (lib.metadata/field mp (mt/id :people :id)))}}))
|
|
:parameters [{:id "quantity", :name "Internal", :slug "quantity", :type "number/="
|
|
:target ["dimension" ["template-tag" "quantity"]]}
|
|
{:id "product_id_fk", :name "FK", :slug "product_id_fk", :type "id"
|
|
:target ["dimension" ["template-tag" "product_id_fk"]]}
|
|
{:id "user_id_pk", :name "PK->Name", :slug "user_id_pk", :type "id"
|
|
:target ["dimension" ["template-tag" "user_id_pk"]]}]})]
|
|
(let [token (embed-test/card-token card {:_embedding_params {:quantity "enabled"
|
|
:product_id_fk "enabled"
|
|
:user_id_pk "enabled"}})]
|
|
(testing "values for internally-remapped param"
|
|
(is (map? (mt/user-http-request :crowberto :get 200
|
|
(format "preview_embed/card/%s/params/quantity/values" token)))))
|
|
(testing "values for FK-remapped param"
|
|
(is (map? (mt/user-http-request :crowberto :get 200
|
|
(format "preview_embed/card/%s/params/product_id_fk/values" token)))))
|
|
(testing "remapping for PK param"
|
|
(is (some? (mt/user-http-request :crowberto :get 200
|
|
(format "preview_embed/card/%s/params/user_id_pk/remapping" token)
|
|
:value "1"))))))))))
|
|
|
|
(deftest params-with-static-list-test
|
|
(testing "embedding with parameter that has source is a static list"
|
|
(with-embedding-enabled-and-new-secret-key!
|
|
(api.dashboard-test/with-chain-filter-fixtures [{:keys [dashboard]}]
|
|
(t2/update! :model/Dashboard (u/the-id dashboard) {:enable_embedding false ;; works without enabling embedding on the dashboard (#44962)
|
|
:embedding_params {"static_category" "enabled"
|
|
"static_category_label" "enabled"}})
|
|
(let [signed-token (dash-token dashboard)
|
|
url (format "preview_embed/dashboard/%s/params/%s/values" signed-token "_STATIC_CATEGORY_")]
|
|
(testing "Should work if the param we're fetching values for is enabled"
|
|
(testing "\nGET /api/preview_embed/dashboard/:token/params/:param-key/values"
|
|
(is (= {:values [["African"] ["American"] ["Asian"]]
|
|
:has_more_values false}
|
|
(mt/user-http-request :crowberto :get 200 url))))))))))
|
|
|
|
(deftest preview-locked-linked-chain-filter-values-test
|
|
(testing "GET /api/preview_embed/dashboard/:token/params/:key/values constrains a linked enabled param by a locked param (#41635)"
|
|
(with-embedding-enabled-and-new-secret-key!
|
|
(api.dashboard-test/with-chain-filter-fixtures [{:keys [dashboard]}]
|
|
(let [signed-token (dash-token dashboard {:_embedding_params {:category_id "enabled"
|
|
:category_name "enabled"
|
|
:price "locked"}
|
|
:params {:price 4}})
|
|
url (format "preview_embed/dashboard/%s/params/%s/values" signed-token "_CATEGORY_ID_")]
|
|
(is (= {:values [[40 "Japanese"] [67 "Steakhouse"]]
|
|
:has_more_values false}
|
|
(mt/user-http-request :crowberto :get 200 url))))))))
|
|
|
|
(deftest dashboard-params-search-test
|
|
(testing "GET /api/preview_embed/dashboard/:token/params/:param-key/search/:prefix"
|
|
(with-embedding-enabled-and-new-secret-key!
|
|
(api.dashboard-test/with-chain-filter-fixtures [{:keys [dashboard]}]
|
|
(t2/update! :model/Dashboard (u/the-id dashboard) {:enable_embedding false ;; works without enabling embedding on the dashboard (#44962)
|
|
:embedding_params {"static_category_label" "enabled"}})
|
|
(let [signed-token (dash-token dashboard)
|
|
search-url (format "preview_embed/dashboard/%s/params/%s/search/%s" signed-token "_STATIC_CATEGORY_LABEL_" "AF")]
|
|
(testing "Should work if the param we're fetching values for is enabled"
|
|
(is (= {:values [["African" "Af"]]
|
|
:has_more_values false}
|
|
(mt/user-http-request :crowberto :get 200 search-url)))))))))
|
|
|
|
(deftest boolean-parameter-values-test
|
|
(testing "embedding endpoint supports boolean parameter values (#27643)"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/dataset places-cam-likes
|
|
(mt/with-temp [:model/Card {card-id :id :as card} {:dataset_query
|
|
{:database (mt/id)
|
|
:type :native
|
|
:native
|
|
{:template-tags
|
|
{"LIKED"
|
|
{:widget-type :string/=
|
|
:default [true]
|
|
:name "LIKED"
|
|
:type :dimension
|
|
:id "LIKED"
|
|
:dimension [:field (mt/id :places :liked) nil]
|
|
:display-name "Liked"
|
|
:options nil
|
|
:required true}}
|
|
:query "SELECT * FROM PLACES WHERE {{LIKED}}"}}}
|
|
:model/Dashboard {dashboard-id :id} {:parameters
|
|
[{:name "LIKED"
|
|
:slug "LIKED"
|
|
:id "ccb91bc"
|
|
:type :string/=
|
|
:sectionId "string"
|
|
:required true
|
|
:default [true]}]}
|
|
:model/DashboardCard dashcard {:dashboard_id dashboard-id
|
|
:parameter_mappings
|
|
[{:parameter_id "ccb91bc"
|
|
:card_id card-id
|
|
:target [:dimension [:template-tag "LIKED"]]}]
|
|
:card_id card-id}]
|
|
(testing "for card embeds"
|
|
(let [url (card-query-url card {:_embedding_params {:LIKED "enabled"}})]
|
|
(is (= [[3 "The Dentist" false]]
|
|
(-> (mt/user-http-request :crowberto :get 202 url
|
|
:parameters (json/encode {:LIKED false}))
|
|
:data
|
|
:rows)))
|
|
(is (= [[1 "Tempest" true]
|
|
[2 "Bullit" true]]
|
|
(-> (mt/user-http-request :crowberto :get 202 url
|
|
:parameters (json/encode {:LIKED true}))
|
|
:data
|
|
:rows)))))
|
|
(testing "for dashboard embeds"
|
|
(let [url (dashcard-url dashcard {:_embedding_params {:LIKED "enabled"}})]
|
|
(is (= [[3 "The Dentist" false]]
|
|
(-> (mt/user-http-request :crowberto :get 202 url
|
|
:parameters (json/encode {:LIKED false}))
|
|
:data
|
|
:rows)))
|
|
(is (= [[1 "Tempest" true]
|
|
[2 "Bullit" true]]
|
|
(-> (mt/user-http-request :crowberto :get 202 url
|
|
:parameters (json/encode {:LIKED true}))
|
|
:data
|
|
:rows))))))))))
|
|
|
|
(deftest string-parameter-values-test
|
|
(testing "embedding endpoint should not parse string values into numbers (#46240)"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/dataset airports
|
|
(mt/with-temp [:model/Card {card-id :id} {:dataset_query
|
|
{:database (mt/id)
|
|
:type :query
|
|
:query
|
|
{:source-table (mt/id :airport)
|
|
:fields [[:field (mt/id :airport :name) nil]]}}}
|
|
:model/Dashboard {dashboard-id :id} {:parameters
|
|
[{:name "NAME"
|
|
:slug "NAME"
|
|
:id "ccb91bc"
|
|
:type :string/contains
|
|
:sectionId "number"}]}
|
|
:model/DashboardCard dashcard {:dashboard_id dashboard-id
|
|
:parameter_mappings
|
|
[{:parameter_id "ccb91bc"
|
|
:card_id card-id
|
|
:target [:dimension [:field (mt/id :airport :name) nil]]}]
|
|
:card_id card-id}]
|
|
(testing "for dashboard embeds"
|
|
(let [url (dashcard-url dashcard {:_embedding_params {:NAME "enabled"}})]
|
|
(is (= [["Cheongju International Airport/Cheongju Air Base (K-59/G-513)"]]
|
|
(-> (mt/user-http-request :crowberto :get 202 url
|
|
:parameters (json/encode {:NAME "513"}))
|
|
:data
|
|
:rows))))))))))
|
|
|
|
;;; ------------------------------------------ Tile endpoints ---------------------------------------------------------
|
|
|
|
(defn- png? [s]
|
|
(= [\P \N \G] (drop 1 (take 4 s))))
|
|
|
|
(defn- venues-query
|
|
[]
|
|
{:database (mt/id)
|
|
:type :query
|
|
:query {:source-table (mt/id :people)
|
|
:fields [[:field (mt/id :people :id) nil]
|
|
[:field (mt/id :people :state) nil]
|
|
[:field (mt/id :people :latitude) nil]
|
|
[:field (mt/id :people :longitude) nil]]}})
|
|
|
|
(deftest card-tile-query-test
|
|
(testing "GET api/preview_embed/tiles/card/:uuid/:zoom/:x/:y"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card {card-id :id} {:dataset_query (venues-query)
|
|
:enable_embedding true}]
|
|
(let [token (embed-test/card-token card-id)]
|
|
(is (png? (mt/user-http-request
|
|
:crowberto :get 200 (format "preview_embed/tiles/card/%s/1/1/1"
|
|
token)
|
|
:latField (tiles.api-test/encoded-lat-field-ref)
|
|
:lonField (tiles.api-test/encoded-lon-field-ref)))))))))
|
|
|
|
(deftest dashcard-tile-query-test
|
|
(testing "GET api/preview_embed/tiles/dashboard/:uuid/dashcard/:dashcard-id/card/:card-id/:zoom/:x/:y"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Dashboard {dashboard-id :id} {:enable_embedding true}
|
|
|
|
:model/Card {card-id :id} {:dataset_query (venues-query)}
|
|
:model/DashboardCard {dashcard-id :id} {:card_id card-id
|
|
:dashboard_id dashboard-id}]
|
|
(let [token (embed-test/dash-token dashboard-id)]
|
|
(is (png? (mt/user-http-request
|
|
:crowberto :get 200 (format "preview_embed/tiles/dashboard/%s/dashcard/%d/card/%d/1/1/1"
|
|
token
|
|
dashcard-id
|
|
card-id)
|
|
:latField (tiles.api-test/encoded-lat-field-ref)
|
|
:lonField (tiles.api-test/encoded-lon-field-ref)))))))))
|
|
|
|
(deftest card-tile-query-implicit-join-ref-test
|
|
(testing "GET api/preview_embed/tiles/card/:uuid/:zoom/:x/:y returns a 400 when the lat/lon refs use an implicit join"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Card {card-id :id} {:dataset_query (tiles.api-test/implicit-join-query)
|
|
:enable_embedding true}]
|
|
(let [token (embed-test/card-token card-id)]
|
|
(is (= "Fields referenced via implicit joins are not supported."
|
|
(mt/user-http-request
|
|
:crowberto :get 400 (format "preview_embed/tiles/card/%s/1/1/1" token)
|
|
:latField (tiles.api-test/encoded-implicit-join-field-ref :latitude)
|
|
:lonField (tiles.api-test/encoded-implicit-join-field-ref :longitude)))))))))
|
|
|
|
(deftest dashcard-tile-query-implicit-join-ref-test
|
|
(testing "GET api/preview_embed/tiles/dashboard/:uuid/dashcard/:dashcard-id/card/:card-id/:zoom/:x/:y returns a 400 when the lat/lon refs use an implicit join"
|
|
(embed-test/with-embedding-enabled-and-new-secret-key!
|
|
(mt/with-temp [:model/Dashboard {dashboard-id :id} {:enable_embedding true}
|
|
:model/Card {card-id :id} {:dataset_query (tiles.api-test/implicit-join-query)}
|
|
:model/DashboardCard {dashcard-id :id} {:card_id card-id
|
|
:dashboard_id dashboard-id}]
|
|
(let [token (embed-test/dash-token dashboard-id)]
|
|
(is (= "Fields referenced via implicit joins are not supported."
|
|
(mt/user-http-request
|
|
:crowberto :get 400 (format "preview_embed/tiles/dashboard/%s/dashcard/%d/card/%d/1/1/1"
|
|
token
|
|
dashcard-id
|
|
card-id)
|
|
:latField (tiles.api-test/encoded-implicit-join-field-ref :latitude)
|
|
:lonField (tiles.api-test/encoded-implicit-join-field-ref :longitude)))))))))
|