Skip to content
Snippets Groups Projects
Unverified Commit 9b955c5a authored by Cam Saül's avatar Cam Saül
Browse files

Custom GeoJSON setting + proxy endpoint :globe_with_meridians:

parent 83a844fb
Branches
Tags
No related merge requests found
(ns metabase.api.geojson
(:require [cheshire.core :as json]
[compojure.core :refer [defroutes GET]]
[schema.core :as s]
[metabase.api.common :refer :all]
[metabase.models.setting :refer [defsetting], :as setting]
[metabase.util :as u]))
(def ^:private valid-json-url?
"Check that remote URL points to a valid JSON file, or throw an exception.
Since the remote file isn't likely to change, this check isn't repeated for URLs that have already succeded;
if the check fails, an exception is thrown (thereby preventing memoization)."
(memoize (fn [url]
(assert (u/is-url? url)
(str "Invalid URL: " url))
(u/with-timeout 5000
(json/parse-string (slurp url)))
true)))
(def ^:private CustomGeoJSON
{s/Keyword {:name s/Str
:url (s/constrained s/Str valid-json-url? "URL must point to a valid JSON file.")
:region_key (s/maybe s/Str)
:region_name (s/maybe s/Str)}})
(defsetting custom-geojson
"JSON containing information about custom GeoJSON files for use in map visualizations instead of the default US State or World GeoJSON."
:type :json
:setter (fn [new-value]
(when new-value
(s/validate CustomGeoJSON new-value))
(setting/set-json! :custom-geojson new-value)))
(defendpoint GET "/:key"
"Fetch a custom GeoJSON file as defined in the `custom-geojson` setting. (This just acts as a simple proxy for the file specified for KEY)."
[key]
(let [url (or (get-in (custom-geojson) [(keyword key) :url])
(throw (ex-info (str "Invalid custom GeoJSON key: " key)
{:status-code 400})))]
{:status 200
:headers {"Content-Type" "application/json"}
:body (u/with-timeout 5000
(slurp url))}))
(define-routes)
......@@ -9,6 +9,7 @@
[email :as email]
[field :as field]
[getting-started :as getting-started]
[geojson :as geojson]
[label :as label]
[metric :as metric]
[notify :as notify]
......@@ -42,6 +43,7 @@
(context "/email" [] (+auth email/routes))
(context "/field" [] (+auth field/routes))
(context "/getting_started" [] (+auth getting-started/routes))
(context "/geojson" [] (+auth geojson/routes))
(GET "/health" [] (if ((resolve 'metabase.core/initialized?))
{:status 200, :body {:status "ok"}}
{:status 503, :body {:status "initializing", :progress ((resolve 'metabase.core/initialization-progress))}}))
......
......@@ -7,7 +7,7 @@
(defendpoint POST "/password_check"
"Endpoint that checks if the supplied password meets the currently configured password complexity rules."
[:as {{:keys [password]} :body}]
{password [Required ComplexPassword]}
{password [Required ComplexPassword]}
;; checking happens in the
{:valid true})
......@@ -17,4 +17,5 @@
(check-superuser)
(logger/get-messages))
(define-routes)
(ns metabase.api.geojson-test
(:require [expectations :refer :all]
[schema.core :as s]
[metabase.api.geojson :refer [custom-geojson]]
[metabase.test.data.users :refer [user->client]]
[metabase.test.util :as tu]))
(tu/resolve-private-fns metabase.api.geojson
valid-json-url?
CustomGeoJSON)
(def ^:private ^:const ^String test-geojson-url
"URL of a GeoJSON file used for test purposes."
"https://raw.githubusercontent.com/metabase/metabase/master/test_resources/test.geojson")
(def ^:private ^:const test-custom-geojson
{:middle-earth {:name "Middle Earth"
:url test-geojson-url
:region_key nil
:region_name nil}})
;;; test valid-json-url?
(expect
(valid-json-url? test-geojson-url))
;;; test the CustomGeoJSON schema
(expect
(boolean (s/validate @CustomGeoJSON test-custom-geojson)))
;; test that you're not allowed to set invalid URLs
(expect
Exception
(custom-geojson {:name "Middle Earth"
:url "ABC"
:region_key nil
:region_name nil}))
(expect
Exception
(custom-geojson {:name "Middle Earth"
:url "http://google.com"
:region_key nil
:region_name nil}))
;;; test that we can set the value of custom-geojson via the normal routes
(expect
test-custom-geojson
;; bind a temporary value so it will get set back to its old value here after the API calls are done stomping all over it
(tu/with-temporary-setting-values [custom-geojson nil]
((user->client :crowberto) :put 200 "setting/custom-geojson" {:value test-custom-geojson})
((user->client :crowberto) :get 200 "setting/custom-geojson")))
;;; test the endpoint that acts as a proxy for JSON files
(expect
{:type "Point"
:coordinates [37.77986 -122.429]}
(tu/with-temporary-setting-values [custom-geojson test-custom-geojson]
((user->client :rasta) :get 200 "geojson/middle-earth")))
;; try fetching an invalid key; should fail
(expect
"Invalid custom GeoJSON key: invalid-key"
(tu/with-temporary-setting-values [custom-geojson test-custom-geojson]
((user->client :rasta) :get 400 "geojson/invalid-key")))
(ns metabase.http-client
"HTTP client for making API calls against the Metabase API. For test/REPL purposes."
;; TODO - this should be moved to something like `metabase.test.http-client` to clarify that it's only available in test
(:require [clojure.tools.logging :as log]
[cheshire.core :as json]
[clj-http.client :as client]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment