diff --git a/fixtures/zvv_responses/hirsch_xxxx.txt b/fixtures/zvv_responses/hirsch_xxxx.txt new file mode 100644 index 0000000..9cc3329 --- /dev/null +++ b/fixtures/zvv_responses/hirsch_xxxx.txt @@ -0,0 +1 @@ +SLs.sls={"suggestions":[{"value":"Ganterschwil, Hirschen","id":"A=1@O=Ganterschwil, Hirschen@X=9086395@Y=47379255@U=85@L=008574001@B=1@p=1423035832@","extId":"008574001","type":"1","typeStr":"[Bhf/Hst]","xcoord":"9086395","ycoord":"47379255","state":"id","prodClass":"64","weight":"389"},{"value":"Zürich, Hirschwiesenstrasse","id":"A=1@O=Zürich, Hirschwiesenstrasse@X=8543213@Y=47399994@U=85@L=008591193@B=1@p=1423035832@","extId":"008591193","type":"1","typeStr":"[Bhf/Hst]","xcoord":"8543213","ycoord":"47399994","state":"id","prodClass":"512","weight":"3268"},{"value":"Hirschberg","id":"A=1@O=Hirschberg@X=9422834@Y=47331316@U=85@L=008506380@B=1@p=1423035832@","extId":"008506380","type":"1","typeStr":"[Bhf/Hst]","xcoord":"9422834","ycoord":"47331316","state":"id","prodClass":"34","weight":"6179"},{"value":"Hirschlang","id":"A=1@O=Hirschlang@X=7755191@Y=47410124@U=85@L=008500094@B=1@p=1423035832@","extId":"008500094","type":"1","typeStr":"[Bhf/Hst]","xcoord":"7755191","ycoord":"47410124","state":"id","prodClass":"96","weight":"6082"},{"value":"Hirschthal","id":"A=1@O=Hirschthal@X=8052815@Y=47319882@U=85@L=008502197@B=1@p=1423035832@","extId":"008502197","type":"1","typeStr":"[Bhf/Hst]","xcoord":"8052815","ycoord":"47319882","state":"id","prodClass":"96","weight":"6082"},{"value":"Schwyz, Hirschen","id":"A=1@O=Schwyz, Hirschen@X=8629698@Y=47046843@U=85@L=008577477@B=1@p=1423035832@","extId":"008577477","type":"1","typeStr":"[Bhf/Hst]","xcoord":"8629698","ycoord":"47046843","state":"id","prodClass":"64","weight":"389"},{"value":"Hirschmatt (Guggisberg), Allme","id":"A=1@O=Hirschmatt (Guggisberg), Allme@X=7312347@Y=46748887@U=85@L=008571690@B=1@p=1423035832@","extId":"008571690","type":"1","typeStr":"[Bhf/Hst]","xcoord":"7312347","ycoord":"46748887","state":"id","prodClass":"64","weight":"124"},{"value":"Hirschmatt (Guggisberg), Fall","id":"A=1@O=Hirschmatt (Guggisberg), Fall@X=7311214@Y=46752447@U=85@L=008571689@B=1@p=1423035832@","extId":"008571689","type":"1","typeStr":"[Bhf/Hst]","xcoord":"7311214","ycoord":"46752447","state":"id","prodClass":"64","weight":"124"},{"value":"Hirschmatt (Guggisberg),Schule","id":"A=1@O=Hirschmatt (Guggisberg),Schule@X=7322361@Y=46755880@U=85@L=008571688@B=1@p=1423035832@","extId":"008571688","type":"1","typeStr":"[Bhf/Hst]","xcoord":"7322361","ycoord":"46755880","state":"id","prodClass":"64","weight":"124"},{"value":"Uznach, Hirschwiese","id":"A=2@O=Uznach, Hirschwiese@X=8975540@Y=47226843@U=103@b=990189668@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8975540","ycoord":"47226843","prodClass":"0","weight":"0"},{"value":"Zürich, Hirschwiesen","id":"A=4@O=Zürich, Hirschwiesen@X=8548004@Y=47412399@U=104@L=970103454@B=1@p=1408002019@","extId":"970103454","type":"4","typeStr":"[POI]","xcoord":"8548004","ycoord":"47412399","state":"id","prodClass":"0","weight":"0"},{"value":"Zürich, Hirschwiesenstrasse","id":"A=2@O=Zürich, Hirschwiesenstrasse@X=8544831@Y=47399904@U=103@b=990214632@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8544831","ycoord":"47399904","prodClass":"0","weight":"0"},{"value":"Bütschwil-Ganterschwil, Hirschen (Restaurant)","id":"A=4@O=Bütschwil-Ganterschwil, Hirschen (Restaurant)@X=9071895@Y=47359515@U=104@L=970055674@B=1@p=1408002019@","extId":"970055674","type":"4","typeStr":"[POI]","xcoord":"9071895","ycoord":"47359515","state":"id","prodClass":"0","weight":"0"},{"value":"Jonschwil, Hirschen (Restaurant)","id":"A=4@O=Jonschwil, Hirschen (Restaurant)@X=9070511@Y=47443259@U=104@L=970053673@B=1@p=1408002019@","extId":"970053673","type":"4","typeStr":"[POI]","xcoord":"9070511","ycoord":"47443259","state":"id","prodClass":"0","weight":"0"},{"value":"Zürich, Post Zürich Hirschwiesen","id":"A=4@O=Zürich, Post Zürich Hirschwiesen@X=8543653@Y=47400236@U=104@L=970010270@B=1@p=1408002019@","extId":"970010270","type":"4","typeStr":"[POI]","xcoord":"8543653","ycoord":"47400236","state":"id","prodClass":"0","weight":"0"},{"value":"Jonschwil - Schwarzenbach, Hirschenstrasse","id":"A=2@O=Jonschwil - Schwarzenbach, Hirschenstrasse@X=9070673@Y=47442306@U=103@b=990086547@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"9070673","ycoord":"47442306","prodClass":"0","weight":"0"},{"value":"Schaffhausen, Hirschwiesenweg","id":"A=2@O=Schaffhausen, Hirschwiesenweg@X=8646454@Y=47718616@U=103@b=990162406@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8646454","ycoord":"47718616","prodClass":"0","weight":"0"},{"value":"Wetzikon, Hirschwiesenstrasse","id":"A=2@O=Wetzikon, Hirschwiesenstrasse@X=8801077@Y=47327621@U=103@b=990202576@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8801077","ycoord":"47327621","prodClass":"0","weight":"0"},{"value":"Heiden, Hirschli","id":"A=1@O=Heiden, Hirschli@X=9519621@Y=47433973@U=85@L=008574080@B=1@p=1423035832@","extId":"008574080","type":"1","typeStr":"[Bhf/Hst]","xcoord":"9519621","ycoord":"47433973","state":"id","prodClass":"64","weight":"1229"},{"value":"Hirschthal, Egg","id":"A=2@O=Hirschthal, Egg@X=8061732@Y=47322605@U=103@b=990080121@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8061732","ycoord":"47322605","prodClass":"0","weight":"0"},{"value":"Honau, Hirschen","id":"A=1@O=Honau, Hirschen@X=8406496@Y=47133113@U=85@L=008582046@B=1@p=1423035832@","extId":"008582046","type":"1","typeStr":"[Bhf/Hst]","xcoord":"8406496","ycoord":"47133113","state":"id","prodClass":"64","weight":"124"},{"value":"Hirschthal, Hard","id":"A=2@O=Hirschthal, Hard@X=8044437@Y=47321518@U=103@b=990080129@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8044437","ycoord":"47321518","prodClass":"0","weight":"0"},{"value":"Hirschthal, Zelgli","id":"A=2@O=Hirschthal, Zelgli@X=8055880@Y=47322390@U=103@b=990080168@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8055880","ycoord":"47322390","prodClass":"0","weight":"0"},{"value":"Herblingen, Hirschen","id":"A=1@O=Herblingen, Hirschen@X=8663210@Y=47723749@U=85@L=008592495@B=1@p=1423035832@","extId":"008592495","type":"1","typeStr":"[Bhf/Hst]","xcoord":"8663210","ycoord":"47723749","state":"id","prodClass":"64","weight":"1229"},{"value":"Hirschthal, Auenweg","id":"A=2@O=Hirschthal, Auenweg@X=8047170@Y=47318398@U=103@b=990080109@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8047170","ycoord":"47318398","prodClass":"0","weight":"0"},{"value":"Hirschthal, Lenzweg","id":"A=2@O=Hirschthal, Lenzweg@X=8059440@Y=47320331@U=103@b=990080136@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8059440","ycoord":"47320331","prodClass":"0","weight":"0"},{"value":"Hirschthal, Weidweg","id":"A=2@O=Hirschthal, Weidweg@X=8057786@Y=47316241@U=103@b=990080166@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8057786","ycoord":"47316241","prodClass":"0","weight":"0"},{"value":"Hirschthal, Wuhrweg","id":"A=2@O=Hirschthal, Wuhrweg@X=8049849@Y=47316879@U=103@b=990080167@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8049849","ycoord":"47316879","prodClass":"0","weight":"0"},{"value":"Hirschthal, Föhreweg","id":"A=2@O=Hirschthal, Föhreweg@X=8073131@Y=47315756@U=103@b=990080126@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8073131","ycoord":"47315756","prodClass":"0","weight":"0"},{"value":"Hirschthal, Kanalweg","id":"A=2@O=Hirschthal, Kanalweg@X=8050343@Y=47317670@U=103@b=990080135@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8050343","ycoord":"47317670","prodClass":"0","weight":"0"},{"value":"Hirschthal, Rebhalde","id":"A=2@O=Hirschthal, Rebhalde@X=8057436@Y=47321931@U=103@b=990080147@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8057436","ycoord":"47321931","prodClass":"0","weight":"0"},{"value":"Hirschthal, Rosenweg","id":"A=2@O=Hirschthal, Rosenweg@X=8061912@Y=47320142@U=103@b=990080148@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8061912","ycoord":"47320142","prodClass":"0","weight":"0"},{"value":"Hirschthal, Becketweg","id":"A=2@O=Hirschthal, Becketweg@X=8065957@Y=47316277@U=103@b=990080110@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8065957","ycoord":"47316277","prodClass":"0","weight":"0"},{"value":"Hirschthal, Blumenweg","id":"A=2@O=Hirschthal, Blumenweg@X=8058406@Y=47320619@U=103@b=990080111@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8058406","ycoord":"47320619","prodClass":"0","weight":"0"},{"value":"Hirschthal, Möösliweg","id":"A=2@O=Hirschthal, Möösliweg@X=8070101@Y=47315171@U=103@b=990080143@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8070101","ycoord":"47315171","prodClass":"0","weight":"0"},{"value":"Hirschthal, Muldenweg","id":"A=2@O=Hirschthal, Muldenweg@X=8066551@Y=47315621@U=103@b=990080140@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8066551","ycoord":"47315621","prodClass":"0","weight":"0"},{"value":"Hirschthal, Stelliweg","id":"A=2@O=Hirschthal, Stelliweg@X=8078264@Y=47315702@U=103@b=990080153@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8078264","ycoord":"47315702","prodClass":"0","weight":"0"},{"value":"Hirschthal, Tränkiweg","id":"A=2@O=Hirschthal, Tränkiweg@X=8064789@Y=47320529@U=103@b=990080161@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8064789","ycoord":"47320529","prodClass":"0","weight":"0"},{"value":"Hirschthal, Zofoldweg","id":"A=2@O=Hirschthal, Zofoldweg@X=8054694@Y=47317580@U=103@b=990080172@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8054694","ycoord":"47317580","prodClass":"0","weight":"0"},{"value":"Hirschthal, Hirschthal","id":"A=4@O=Hirschthal, Hirschthal@X=8052662@Y=47318542@U=104@L=970066621@B=1@p=1408002019@","extId":"970066621","type":"4","typeStr":"[POI]","xcoord":"8052662","ycoord":"47318542","state":"id","prodClass":"0","weight":"0"},{"value":"Hirschthal, Chriesiweg","id":"A=2@O=Hirschthal, Chriesiweg@X=8065211@Y=47319154@U=103@b=990080116@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8065211","ycoord":"47319154","prodClass":"0","weight":"0"},{"value":"Hirschthal, Eggstrasse","id":"A=2@O=Hirschthal, Eggstrasse@X=8059566@Y=47321032@U=103@b=990080122@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8059566","ycoord":"47321032","prodClass":"0","weight":"0"},{"value":"Hirschthal, Im Wechsel","id":"A=2@O=Hirschthal, Im Wechsel@X=8053103@Y=47322515@U=103@b=990080134@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8053103","ycoord":"47322515","prodClass":"0","weight":"0"},{"value":"Hirschthal, Musrainweg","id":"A=2@O=Hirschthal, Musrainweg@X=8056842@Y=47320852@U=103@b=990080142@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8056842","ycoord":"47320852","prodClass":"0","weight":"0"},{"value":"Hirschthal, Sägiserweg","id":"A=2@O=Hirschthal, Sägiserweg@X=8078129@Y=47313248@U=103@b=990080156@B=1@p=1408000921@","type":"2","typeStr":"[Adr]","xcoord":"8078129","ycoord":"47313248","prodClass":"0","weight":"0"}]};SLs.showSuggestion(); diff --git a/project.clj b/project.clj index ba3e17a..427baab 100644 --- a/project.clj +++ b/project.clj @@ -17,6 +17,7 @@ [ring/ring-defaults "0.1.2"] [ring/ring-jetty-adapter "1.2.1"] [ring/ring-mock "0.2.0"] + [ring/ring-codec "1.0.0"] [bk/ring-gzip "0.1.1"] [org.clojars.jws/ring-etag-middleware "0.1.2-SNAPSHOT"]] diff --git a/src/tramboard_clj/core/handler.clj b/src/tramboard_clj/core/handler.clj index 7e955ea..e9b718f 100644 --- a/src/tramboard_clj/core/handler.clj +++ b/src/tramboard_clj/core/handler.clj @@ -18,18 +18,19 @@ (defroutes api-routes (context "/api" [] - (wrap-no-cache (GET "/stationboard/:id{[0-9]+}" [id] (station id))))) + (wrap-routes (GET "/stationboard/:id{[0-9]+}" [id] (station id)) wrap-no-cache) + (wrap-routes (GET "/stations/:query{.+}" [query] (query-stations query)) wrap-no-cache))) (defroutes app-routes - (wrap-cache (GET "/" [] (index-page))) - (wrap-cache (route/resources "/")) + (wrap-routes (GET "/" [] (index-page)) wrap-cache) + (wrap-routes (route/resources "/") wrap-cache) (route/not-found "Not Found")) (def site - (wrap-defaults app-routes (assoc site-defaults :cookies false :session false))) + (wrap-routes app-routes wrap-defaults (assoc site-defaults :cookies false :session false))) (def api - (wrap-defaults api-routes api-defaults)) + (wrap-routes api-routes wrap-defaults api-defaults)) (def app (wrap-gzip (wrap-etag (routes api site)))) diff --git a/src/tramboard_clj/core/views.clj b/src/tramboard_clj/core/views.clj index 576175f..4d18af8 100644 --- a/src/tramboard_clj/core/views.clj +++ b/src/tramboard_clj/core/views.clj @@ -24,3 +24,7 @@ (defn station [id] (json-response (zvv/station id))) + +(defn query-stations [query] + (println query) + (json-response (zvv/query-stations query))) diff --git a/src/tramboard_clj/core/zvv.clj b/src/tramboard_clj/core/zvv.clj index d911ea6..33527d5 100644 --- a/src/tramboard_clj/core/zvv.clj +++ b/src/tramboard_clj/core/zvv.clj @@ -1,5 +1,6 @@ (ns tramboard-clj.core.zvv (:require [cheshire.core :as json] + [ring.util.codec :as codec] [clj-time.core :as t] [clj-time.format :as f] [clojure.string :as str] @@ -11,7 +12,8 @@ ; :user-agent "User-Agent-string" ; :headers {"X-Header" "Value"}}) -(def base-url "http://online.fahrplan.zvv.ch/bin/stboard.exe/dn?L=vs_stbzvv&boardType=dep&productsFilter=1:1111111111111111&additionalTime=0&disableEquivs=false&maxJourneys=30&start=yes&monitor=1&requestType=0&view=preview&input=") +(def query-stations-base-url "http://online.fahrplan.zvv.ch/bin/ajax-getstop.exe/dny?start=1&tpl=suggest2json&REQ0JourneyStopsS0A=7&getstop=1&noSession=yes&REQ0JourneyStopsB=25&REQ0JourneyStopsS0G=") +(def station-base-url "http://online.fahrplan.zvv.ch/bin/stboard.exe/dn?L=vs_stbzvv&boardType=dep&productsFilter=1:1111111111111111&additionalTime=0&disableEquivs=false&maxJourneys=30&start=yes&monitor=1&requestType=0&view=preview&input=") (def zvv-timezone (t/time-zone-for-id "Europe/Zurich")) @@ -26,7 +28,7 @@ (str/replace (str/replace text " " " ") #"S( )+" "S")) ; TODO add 1 day to realtime if it is smaller than scheduled (scheduled 23h59 + 3min delay ...) -(defn departure [zvv-journey] +(defn zvv-departure [zvv-journey] (let [colors (vec (remove str/blank? (str/split (zvv-journey "lc") #" "))) zvv-date-parser (partial zvv-parse-datetime (zvv-journey "da"))] {;:meta zvv-journey @@ -36,22 +38,41 @@ :colors {:fg (when (> (count colors) 0) (str "#" (colors 0))) :bg (when (> (count colors) 1) (str "#" (colors 1)))} :to (zvv-journey "st") - :departure {:scheduled (zvv-date-parser (zvv-journey "ti")) :realtime (zvv-date-parser (get-in zvv-journey ["rt" "dlt"]))}})) + :departure {:scheduled (zvv-date-parser (zvv-journey "ti")) + :realtime (zvv-date-parser (get-in zvv-journey ["rt" "dlt"]))}})) ; TODO tests (=> capture some data from zvv api) -(defn transform-response [response-body] +(defn transform-station-response [response-body] ;(spit "fixtures/zvv_responses/new.txt" response-body) (let [unparsed (clojure.string/replace-first response-body "journeysObj = " "") data (json/parse-string unparsed) journeys (data "journey")] - {:meta {:station_id (data "stationEvaId") :station_name (data "stationName")} :departures (map departure journeys)})) + {:meta {:station_id (data "stationEvaId") + :station_name (data "stationName")} + :departures (map zvv-departure journeys)})) -; TODO error handling -(defn station [id] - (let [request-url (str base-url id) - response (http/get request-url)] - (transform-response (:body @response)))) +(defn zvv-station [zvv-station] + (let [id nil] + {:id (zvv-station "extId") + :name (zvv-station "value")})) + +(defn transform-query-stations-response [response-body] + (let [unparsed (reduce #(clojure.string/replace-first %1 %2 "") response-body [";SLs.showSuggestion();" "SLs.sls="]) + data (json/parse-string unparsed) + stations (data "suggestions")] + {:stations (map zvv-station (remove #(or (nil? (% "extId")) (not= "1" (% "type"))) stations))})) +; TODO error handling +(defn do-api-call [url transform-fn] + (let [response (http/get url)] + (println response) + (transform-fn (:body @response)))) +(defn station [id] + (let [request-url (str station-base-url id)] + (do-api-call request-url transform-station-response))) +(defn query-stations [query] + (let [request-url (str query-stations-base-url (codec/url-encode query))] + (do-api-call request-url transform-query-stations-response))) diff --git a/src/tramboard_clj/script/time.cljs b/src/tramboard_clj/script/time.cljs index 87ba53f..0dec09c 100644 --- a/src/tramboard_clj/script/time.cljs +++ b/src/tramboard_clj/script/time.cljs @@ -16,11 +16,13 @@ (parse (formatters :date-time) unparsed-date)) (defn minutes-from [timestamp from] + "Returns the difference in minutes between from and timestamp." (if (after? from timestamp) (- (in-minutes (interval timestamp from))) (in-minutes (interval from timestamp)))) (defn format-to-hour-minute [timestamp] + "Formats a timestamp to HH:mm" (unparse hour-minute-formatter (to-default-time-zone timestamp))) (defn display-time [timestamp] @@ -40,4 +42,7 @@ " at " hour-minute-format)] display-time)) -(def parse-from-date-time (memoize parse-from-date-time-uncached)) +(def parse-from-date-time + "Parses a date in the format 21-12-2015T12:12:00.000+01:00 into a timestamp. + This call is memoized." + (memoize parse-from-date-time-uncached)) diff --git a/src/tramboard_clj/script/tram.cljs b/src/tramboard_clj/script/tram.cljs index 2fda7c3..982ebee 100644 --- a/src/tramboard_clj/script/tram.cljs +++ b/src/tramboard_clj/script/tram.cljs @@ -50,7 +50,7 @@ (let [view-id (:view-id (:params current-state))] (get configured-views view-id))) -(defn update-updated-date [view] +(defn- update-updated-date [view] (assoc view :last-updated (to-long (now)))) (defn get-stops-in-order [view] @@ -71,7 +71,7 @@ selected-views-ids (into #{} (map #(:view-id (:params (val %))) (:split-states complete-state)))] (remove #(contains? selected-views-ids (:view-id %)) views))) -(defn remove-stop-and-update-date [current-view stop-id] +(defn- remove-stop-and-update-date [current-view stop-id] (let [new-stops (dissoc (:stops current-view) stop-id) new-stops-order (vec (remove #(= stop-id %) (:stops-order current-view))) new-current-view (update-updated-date (assoc current-view @@ -79,7 +79,7 @@ :stops-order new-stops-order))] new-current-view)) -(defn add-stop-and-update-date [current-view {:keys [:id] :as stop}] +(defn- add-stop-and-update-date [current-view {:keys [:id] :as stop}] (let [existing-stops (:stops current-view) existing-stops-order (or (:stops-order current-view) []) existing-stop (get existing-stops id) @@ -90,7 +90,7 @@ :stops-order new-stops-order))] new-current-view)) -(defn delete-view-if-no-stops [configured-views view-id] +(defn- delete-view-if-no-stops [configured-views view-id] (let [current-view (get configured-views view-id) current-stops (:stops current-view)] (if (empty? current-stops) @@ -162,11 +162,11 @@ (when-not (clj (.getResponseJson xhr) :keywordize-keys true)))) + (fn [e] (put! suggestions-ch (:stations (js->clj (.getResponseJson xhr) :keywordize-keys true))))) (goog.events/listen xhr goog.net.EventType.ERROR (fn [e] (println "ERROR"))) - (.send xhr (str "http://tramboard.herokuapp.com/stations/" value) "GET"))) + (.send xhr (str "/api/stations/" value) "GET"))) (go ( + (zvv/transform-station-response (:central_2228 fixtures)) => (contains {:meta (contains {:station_id "8588078" :station_name "Zürich, Central"})})) (fact "also works when there are no color information" - (zvv/transform-response (:flughafen_xxxx fixtures)) => + (zvv/transform-station-response (:flughafen_xxxx fixtures)) => (contains {:departures (contains {:zvv_id "11484850" :name "S2" :type "S" @@ -22,7 +23,7 @@ :scheduled "2015-02-01T19:36:00.000+01:00" :realtime "2015-02-01T19:36:00.000+01:00"}})})) (fact "returns a list of departures" - (zvv/transform-response (:central_2228 fixtures)) => + (zvv/transform-station-response (:central_2228 fixtures)) => (contains {:departures (contains {:zvv_id "32108510" :name "31" :type "Bus-NF" @@ -31,3 +32,19 @@ :departure { :scheduled "2015-01-27T22:38:00.000+01:00" :realtime "2015-01-27T22:38:00.000+01:00"}})}))) + +(facts "transform zvv response for query stations" + (fact "extracts query stations" + (zvv/transform-query-stations-response (:hirsch_xxxx fixtures)) => + (contains {:stations (just [{:id "008574001" :name "Ganterschwil, Hirschen"} + {:id "008591193" :name "Zürich, Hirschwiesenstrasse"} + {:id "008506380" :name "Hirschberg"} + {:id "008500094" :name "Hirschlang"} + {:id "008502197" :name "Hirschthal"} + {:id "008577477" :name "Schwyz, Hirschen"} + {:id "008571690" :name "Hirschmatt (Guggisberg), Allme"} + {:id "008571689" :name "Hirschmatt (Guggisberg), Fall"} + {:id "008571688" :name "Hirschmatt (Guggisberg),Schule"} + {:id "008574080" :name "Heiden, Hirschli"} + {:id "008582046" :name "Honau, Hirschen"} + {:id "008592495" :name "Herblingen, Hirschen"}])})))